Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
6255487 | 225 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Minimal Proxy Contract for 0x79792dccc6c58c303510fc1f7649e481c431afb1
Contract Name:
IPAccountImpl
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 20000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol"; import { IAccessController } from "./interfaces/IAccessController.sol"; import { IIPAccount } from "./interfaces/IIPAccount.sol"; import { MetaTx } from "./lib/MetaTx.sol"; import { Errors } from "./lib/Errors.sol"; /// @title IPAccountImpl /// @notice The Story Protocol's implementation of the IPAccount. contract IPAccountImpl is IERC165, IIPAccount { address public immutable accessController; /// @notice Returns the IPAccount's internal nonce for transaction ordering. uint256 public state; receive() external payable override(IERC6551Account) {} /// @notice Creates a new IPAccountImpl contract instance /// @dev Initializes the IPAccountImpl with an AccessController address which is stored /// in the implementation code's storage. /// This means that each cloned IPAccount will inherently use the same AccessController /// without the need for individual configuration. /// @param accessController_ The address of the AccessController contract to be used for permission checks constructor(address accessController_) { if (accessController_ == address(0)) revert Errors.IPAccount__InvalidAccessController(); accessController = accessController_; } /// @notice Checks if the contract supports a specific interface /// @param interfaceId The interface identifier, as specified in ERC-165 /// @return bool is true if the contract supports the interface, false otherwise function supportsInterface(bytes4 interfaceId) external pure returns (bool) { return (interfaceId == type(IIPAccount).interfaceId || interfaceId == type(IERC6551Account).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC721Receiver).interfaceId || interfaceId == type(IERC165).interfaceId); } /// @notice Returns the identifier of the non-fungible token which owns the account /// @return chainId The EIP-155 ID of the chain the token exists on /// @return tokenContract The contract address of the token /// @return tokenId The ID of the token function token() public view override returns (uint256, address, uint256) { bytes memory footer = new bytes(0x60); // 0x4d = 77 bytes (ERC-1167 Header, address, ERC-1167 Footer, salt) // 0x60 = 96 bytes (chainId, tokenContract, tokenId) // ERC-1167 Header (10 bytes) // <implementation (address)> (20 bytes) // ERC-1167 Footer (15 bytes) // <salt (uint256)> (32 bytes) // <chainId (uint256)> (32 bytes) // <tokenContract (address)> (32 bytes) // <tokenId (uint256)> (32 bytes) assembly { extcodecopy(address(), add(footer, 0x20), 0x4d, 0x60) } return abi.decode(footer, (uint256, address, uint256)); } /// @notice Checks if the signer is valid for the given data /// @param signer The signer to check /// @param data The data to check against /// @return The function selector if the signer is valid, 0 otherwise function isValidSigner(address signer, bytes calldata data) external view returns (bytes4) { if (_isValidSigner(signer, address(0), data)) { return IERC6551Account.isValidSigner.selector; } return bytes4(0); } /// @notice Returns the owner of the IP Account. /// @return The address of the owner. function owner() public view returns (address) { (uint256 chainId, address contractAddress, uint256 tokenId) = token(); if (chainId != block.chainid) return address(0); return IERC721(contractAddress).ownerOf(tokenId); } /// @dev Checks if the signer is valid for the given data and recipient via the AccessController permission system. /// @param signer The signer to check /// @param to The recipient of the transaction /// @param data The calldata to check against /// @return bool is true if the signer is valid, false otherwise function _isValidSigner(address signer, address to, bytes calldata data) internal view returns (bool) { if (data.length > 0 && data.length < 4) { revert Errors.IPAccount__InvalidCalldata(); } bytes4 selector = bytes4(0); if (data.length >= 4) { selector = bytes4(data[:4]); } // the check will revert if permission is denied IAccessController(accessController).checkPermission(address(this), signer, to, selector); return true; } /// @notice Executes a transaction from the IP Account on behalf of the signer. /// @param to The recipient of the transaction. /// @param value The amount of Ether to send. /// @param data The data to send along with the transaction. /// @param signer The signer of the transaction. /// @param deadline The deadline of the transaction signature. /// @param signature The signature of the transaction, EIP-712 encoded. function executeWithSig( address to, uint256 value, bytes calldata data, address signer, uint256 deadline, bytes calldata signature ) external payable returns (bytes memory result) { if (signer == address(0)) { revert Errors.IPAccount__InvalidSigner(); } if (deadline < block.timestamp) { revert Errors.IPAccount__ExpiredSignature(); } ++state; bytes32 digest = MessageHashUtils.toTypedDataHash( MetaTx.calculateDomainSeparator(), MetaTx.getExecuteStructHash( MetaTx.Execute({ to: to, value: value, data: data, nonce: state, deadline: deadline }) ) ); if (!SignatureChecker.isValidSignatureNow(signer, digest, signature)) { revert Errors.IPAccount__InvalidSignature(); } result = _execute(signer, to, value, data); emit ExecutedWithSig(to, value, data, state, deadline, signer, signature); } /// @notice Executes a transaction from the IP Account. /// @param to The recipient of the transaction. /// @param value The amount of Ether to send. /// @param data The data to send along with the transaction. /// @return result The return data from the transaction. function execute(address to, uint256 value, bytes calldata data) external payable returns (bytes memory result) { ++state; result = _execute(msg.sender, to, value, data); emit Executed(to, value, data, state); } /// @inheritdoc IERC721Receiver function onERC721Received(address, address, uint256, bytes memory) public pure returns (bytes4) { return this.onERC721Received.selector; } /// @inheritdoc IERC1155Receiver function onERC1155Received(address, address, uint256, uint256, bytes memory) public pure returns (bytes4) { return this.onERC1155Received.selector; } /// @inheritdoc IERC1155Receiver function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public pure returns (bytes4) { return this.onERC1155BatchReceived.selector; } /// @dev Executes a transaction from the IP Account. function _execute( address signer, address to, uint256 value, bytes calldata data ) internal returns (bytes memory result) { require(_isValidSigner(signer, to, data), "Invalid signer"); bool success; (success, result) = to.call{ value: value }(data); if (!success) { assembly { revert(add(result, 32), mload(result)) } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.20; import {ECDSA} from "./ECDSA.sol"; import {IERC1271} from "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like * Argent and Safe Wallet (previously Gnosis Safe). */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature); return (error == ECDSA.RecoverError.NoError && recovered == signer) || isValidERC1271SignatureNow(signer, hash, signature); } /** * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated * against the signer smart contract using ERC1271. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidERC1271SignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (bool success, bytes memory result) = signer.staticcall( abi.encodeCall(IERC1271.isValidSignature, (hash, signature)) ); return (success && result.length >= 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @dev the ERC-165 identifier for this interface is `0x6faff5f1` interface IERC6551Account { /** * @dev Allows the account to receive Ether. * * Accounts MUST implement a `receive` function. * * Accounts MAY perform arbitrary logic to restrict conditions * under which Ether can be received. */ receive() external payable; /** * @dev Returns the identifier of the non-fungible token which owns the account. * * The return value of this function MUST be constant - it MUST NOT change over time. * * @return chainId The EIP-155 ID of the chain the token exists on * @return tokenContract The contract address of the token * @return tokenId The ID of the token */ function token() external view returns (uint256 chainId, address tokenContract, uint256 tokenId); /** * @dev Returns a value that SHOULD be modified each time the account changes state. * * @return The current account state */ function state() external view returns (uint256); /** * @dev Returns a magic value indicating whether a given signer is authorized to act on behalf * of the account. * * MUST return the bytes4 magic value 0x523e3260 if the given signer is valid. * * By default, the holder of the non-fungible token the account is bound to MUST be considered * a valid signer. * * Accounts MAY implement additional authorization logic which invalidates the holder as a * signer or grants signing permissions to other non-holder accounts. * * @param signer The address to check signing authorization for * @param context Additional data used to determine whether the signer is valid * @return magicValue Magic value indicating whether the signer is valid */ function isValidSigner(address signer, bytes calldata context) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import { AccessPermission } from "../lib/AccessPermission.sol"; interface IAccessController { /// @notice Emitted when a permission is set. /// @param ipAccount The address of the IP account that grants the permission for `signer` /// @param signer The address that can call `to` on behalf of the IP account /// @param to The address that can be called by the `signer` (currently only modules can be `to`) /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount` /// @param permission The permission level event PermissionSet( address ipAccountOwner, address indexed ipAccount, address indexed signer, address indexed to, bytes4 func, uint8 permission ); /// @notice Sets a batch of permissions in a single transaction. /// @dev This function allows setting multiple permissions at once. Pausable. /// @param permissions An array of `Permission` structs, each representing the permission to be set. function setBatchPermissions(AccessPermission.Permission[] memory permissions) external; /// @notice Sets the permission for all IPAccounts /// @dev Enforced to be only callable by the protocol admin in governance. /// @param signer The address that can call `to` on behalf of the IP account /// @param to The address that can be called by the `signer` (currently only modules can be `to`) /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount` /// @param permission The new permission level function setGlobalPermission(address signer, address to, bytes4 func, uint8 permission) external; /// @notice Sets the permission for a specific function call /// @dev Each policy is represented as a mapping from an IP account address to a signer address to a recipient /// address to a function selector to a permission level. The permission level can be 0 (ABSTAIN), 1 (ALLOW), or /// 2 (DENY). /// @dev By default, all policies are set to 0 (ABSTAIN), which means that the permission is not set. /// The owner of ipAccount by default has all permission. /// address(0) => wildcard /// bytes4(0) => wildcard /// Specific permission overrides wildcard permission. /// @param ipAccount The address of the IP account that grants the permission for `signer` /// @param signer The address that can call `to` on behalf of the `ipAccount` /// @param to The address that can be called by the `signer` (currently only modules can be `to`) /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount` /// @param permission The new permission level function setPermission(address ipAccount, address signer, address to, bytes4 func, uint8 permission) external; /// @notice Checks the permission level for a specific function call. Reverts if permission is not granted. /// Otherwise, the function is a noop. /// @dev This function checks the permission level for a specific function call. /// If a specific permission is set, it overrides the general (wildcard) permission. /// If the current level permission is ABSTAIN, the final permission is determined by the upper level. /// @param ipAccount The address of the IP account that grants the permission for `signer` /// @param signer The address that can call `to` on behalf of the `ipAccount` /// @param to The address that can be called by the `signer` (currently only modules can be `to`) /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount` function checkPermission(address ipAccount, address signer, address to, bytes4 func) external view; /// @notice Returns the permission level for a specific function call. /// @param ipAccount The address of the IP account that grants the permission for `signer` /// @param signer The address that can call `to` on behalf of the `ipAccount` /// @param to The address that can be called by the `signer` (currently only modules can be `to`) /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount` /// @return permission The current permission level for the function call on `to` by the `signer` for `ipAccount` function getPermission(address ipAccount, address signer, address to, bytes4 func) external view returns (uint8); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; import { IERC6551Account } from "erc6551/interfaces/IERC6551Account.sol"; /// @title IIPAccount /// @dev IPAccount is a token-bound account that adopts the EIP-6551 standard. /// These accounts are deployed at deterministic addresses through the official 6551 account registry. /// As a deployed smart contract, IPAccount can store IP-related information, /// like ownership of other NFTs such as license NFT or Royalty NFT. /// IPAccount can interact with modules by making calls as a normal transaction sender. /// This allows for seamless operations on the state and data of IP. /// IPAccount is core identity for all actions. interface IIPAccount is IERC6551Account, IERC721Receiver, IERC1155Receiver { /// @notice Emitted when a transaction is executed. /// @param to The recipient of the transaction. /// @param value The amount of Ether sent. /// @param data The data sent along with the transaction. /// @param nonce The nonce of the transaction. event Executed(address indexed to, uint256 value, bytes data, uint256 nonce); /// @notice Emitted when a transaction is executed on behalf of the signer. /// @param to The recipient of the transaction. /// @param value The amount of Ether sent. /// @param data The data sent along with the transaction. /// @param nonce The nonce of the transaction. /// @param deadline The deadline of the transaction signature. /// @param signer The signer of the transaction. /// @param signature The signature of the transaction, EIP-712 encoded. event ExecutedWithSig( address indexed to, uint256 value, bytes data, uint256 nonce, uint256 deadline, address indexed signer, bytes signature ); /// @notice Returns the IPAccount's internal nonce for transaction ordering. function state() external view returns (uint256); /// @notice Returns the identifier of the non-fungible token which owns the account /// @return chainId The EIP-155 ID of the chain the token exists on /// @return tokenContract The contract address of the token /// @return tokenId The ID of the token function token() external view returns (uint256, address, uint256); /// @notice Checks if the signer is valid for the given data /// @param signer The signer to check /// @param data The data to check against /// @return The function selector if the signer is valid, 0 otherwise function isValidSigner(address signer, bytes calldata data) external view returns (bytes4); /// @notice Returns the owner of the IP Account. /// @return owner The address of the owner. function owner() external view returns (address); /// @notice Executes a transaction from the IP Account on behalf of the signer. /// @param to The recipient of the transaction. /// @param value The amount of Ether to send. /// @param data The data to send along with the transaction. /// @param signer The signer of the transaction. /// @param deadline The deadline of the transaction signature. /// @param signature The signature of the transaction, EIP-712 encoded. /// @return result The return data from the transaction. function executeWithSig( address to, uint256 value, bytes calldata data, address signer, uint256 deadline, bytes calldata signature ) external payable returns (bytes memory); /// @notice Executes a transaction from the IP Account. /// @param to The recipient of the transaction. /// @param value The amount of Ether to send. /// @param data The data to send along with the transaction. /// @return result The return data from the transaction. function execute(address to, uint256 value, bytes calldata data) external payable returns (bytes memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; /// @title MetaTx /// @dev This library provides functions for handling meta transactions in the Story Protocol. library MetaTx { /// @dev Version of the EIP712 domain. string public constant EIP712_DOMAIN_VERSION = "1"; /// @dev Hash of the EIP712 domain version. bytes32 public constant EIP712_DOMAIN_VERSION_HASH = keccak256(bytes(EIP712_DOMAIN_VERSION)); /// @dev EIP712 domain type hash. bytes32 public constant EIP712_DOMAIN = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @dev Execute type hash. bytes32 public constant EXECUTE = keccak256("Execute(address to,uint256 value,bytes data,uint256 nonce,uint256 deadline)"); /// @dev Structure for the Execute type. struct Execute { address to; uint256 value; bytes data; uint256 nonce; uint256 deadline; } /// @dev Calculates the EIP712 domain separator for the current contract. /// @return The EIP712 domain separator. function calculateDomainSeparator() internal view returns (bytes32) { return calculateDomainSeparator(address(this)); } /// @dev Calculates the EIP712 domain separator for a given IP account. /// @param ipAccount The IP account for which to calculate the domain separator. /// @return The EIP712 domain separator. function calculateDomainSeparator(address ipAccount) internal view returns (bytes32) { return keccak256( abi.encode( EIP712_DOMAIN, keccak256("Story Protocol IP Account"), EIP712_DOMAIN_VERSION_HASH, block.chainid, ipAccount ) ); } /// @dev Calculates the EIP712 struct hash of an Execute. /// @param execute The Execute to hash. /// @return The EIP712 struct hash of the Execute. function getExecuteStructHash(Execute memory execute) internal pure returns (bytes32) { return keccak256( abi.encode( MetaTx.EXECUTE, execute.to, execute.value, keccak256(execute.data), execute.nonce, execute.deadline ) ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; /// @title Errors Library /// @notice Library for all Story Protocol contract errors. library Errors { //////////////////////////////////////////////////////////////////////////// // Governance // //////////////////////////////////////////////////////////////////////////// error Governance__OnlyProtocolAdmin(); error Governance__ZeroAddress(); error Governance__ProtocolPaused(); error Governance__InconsistentState(); error Governance__NewStateIsTheSameWithOldState(); error Governance__UnsupportedInterface(string interfaceName); //////////////////////////////////////////////////////////////////////////// // IPAccount // //////////////////////////////////////////////////////////////////////////// error IPAccount__InvalidSigner(); error IPAccount__InvalidSignature(); error IPAccount__ExpiredSignature(); error IPAccount__InvalidCalldata(); error IPAccount__InvalidAccessController(); //////////////////////////////////////////////////////////////////////////// // Module // //////////////////////////////////////////////////////////////////////////// /// @notice The caller is not allowed to call the provided module. error Module_Unauthorized(); //////////////////////////////////////////////////////////////////////////// // IPAccountRegistry // //////////////////////////////////////////////////////////////////////////// error IPAccountRegistry_InvalidIpAccountImpl(); //////////////////////////////////////////////////////////////////////////// // IPAssetRegistry // //////////////////////////////////////////////////////////////////////////// /// @notice The IP asset has already been registered. error IPAssetRegistry__AlreadyRegistered(); /// @notice The IP account has already been created. error IPAssetRegistry__IPAccountAlreadyCreated(); /// @notice The IP asset has not yet been registered. error IPAssetRegistry__NotYetRegistered(); /// @notice The IP asset registrant is not authorized. error IPAssetRegistry__RegistrantUnauthorized(); /// @notice The specified IP resolver is not valid. error IPAssetRegistry__ResolverInvalid(); /// @notice Caller not authorized to perform the IP registry function call. error IPAssetRegistry__Unauthorized(); /// @notice The deployed address of account doesn't match with IP ID. error IPAssetRegistry__InvalidAccount(); /// @notice The metadata provider is not valid. error IPAssetRegistry__InvalidMetadataProvider(); //////////////////////////////////////////////////////////////////////////// // IPResolver /// //////////////////////////////////////////////////////////////////////////// /// @notice The targeted IP does not yet have an IP account. error IPResolver_InvalidIP(); /// @notice Caller not authorized to perform the IP resolver function call. error IPResolver_Unauthorized(); //////////////////////////////////////////////////////////////////////////// // Metadata Provider /// //////////////////////////////////////////////////////////////////////////// /// @notice Provided hash metadata is not valid. error MetadataProvider__HashInvalid(); /// @notice The caller is not the authorized IP asset owner. error MetadataProvider__IPAssetOwnerInvalid(); /// @notice Provided hash metadata is not valid. error MetadataProvider__NameInvalid(); /// @notice The new metadata provider is not compatible with the old provider. error MetadataProvider__MetadataNotCompatible(); /// @notice Provided registrant metadata is not valid. error MetadataProvider__RegistrantInvalid(); /// @notice Provided registration date is not valid. error MetadataProvider__RegistrationDateInvalid(); /// @notice Caller does not access to set metadata storage for the provider. error MetadataProvider__Unauthorized(); /// @notice A metadata provider upgrade is not currently available. error MetadataProvider__UpgradeUnavailable(); /// @notice The upgrade provider is not valid. error MetadataProvider__UpgradeProviderInvalid(); /// @notice Provided metadata URI is not valid. error MetadataProvider__URIInvalid(); //////////////////////////////////////////////////////////////////////////// // LicenseRegistry // //////////////////////////////////////////////////////////////////////////// error LicenseRegistry__CallerNotLicensingModule(); error LicenseRegistry__ZeroLicensingModule(); error LicensingModule__CallerNotLicenseRegistry(); error LicenseRegistry__RevokedLicense(); /// @notice emitted when trying to transfer a license that is not transferable (by policy) error LicenseRegistry__NotTransferable(); /// @notice emitted on constructor if dispute module is not set error LicenseRegistry__ZeroDisputeModule(); //////////////////////////////////////////////////////////////////////////// // LicensingModule // //////////////////////////////////////////////////////////////////////////// error LicensingModule__PolicyAlreadySetForIpId(); error LicensingModule__FrameworkNotFound(); error LicensingModule__EmptyLicenseUrl(); error LicensingModule__InvalidPolicyFramework(); error LicensingModule__ParamVerifierLengthMismatch(); error LicensingModule__PolicyNotFound(); error LicensingModule__NotLicensee(); error LicensingModule__ParentIdEqualThanChild(); error LicensingModule__LicensorDoesntHaveThisPolicy(); error LicensingModule__MintLicenseParamFailed(); error LicensingModule__LinkParentParamFailed(); error LicensingModule__TransferParamFailed(); error LicensingModule__InvalidLicensor(); error LicensingModule__ParamVerifierAlreadySet(); error LicensingModule__CommercialTermInNonCommercialPolicy(); error LicensingModule__EmptyParamName(); error LicensingModule__UnregisteredFrameworkAddingPolicy(); error LicensingModule__UnauthorizedAccess(); error LicensingModule__LicensorNotRegistered(); error LicensingModule__CallerNotLicensorAndPolicyNotSet(); error LicensingModule__DerivativesCannotAddPolicy(); error LicensingModule__IncompatibleRoyaltyPolicyAddress(); error LicensingModule__IncompatibleRoyaltyPolicyDerivativeRevShare(); error LicensingModule__IncompatibleLicensorCommercialPolicy(); error LicensingModule__IncompatibleLicensorRoyaltyDerivativeRevShare(); error LicensingModule__DerivativeRevShareSumExceedsMaxRNFTSupply(); error LicensingModule__MismatchBetweenRoyaltyPolicy(); error LicensingModule__RegisterPolicyFrameworkMismatch(); error LicensingModule__RoyaltyPolicyNotWhitelisted(); error LicensingModule__MintingFeeTokenNotWhitelisted(); error LicensingModule__ReceiverZeroAddress(); error LicensingModule__MintAmountZero(); /// @notice emitted when trying to interact with an IP that has been disputed in the DisputeModule error LicensingModule__DisputedIpId(); /// @notice emitted when linking a license from a licensor that has been disputed in the DisputeModule error LicensingModule__LinkingRevokedLicense(); //////////////////////////////////////////////////////////////////////////// // LicensingModuleAware // //////////////////////////////////////////////////////////////////////////// error LicensingModuleAware__CallerNotLicensingModule(); //////////////////////////////////////////////////////////////////////////// // PolicyFrameworkManager // //////////////////////////////////////////////////////////////////////////// error PolicyFrameworkManager__GettingPolicyWrongFramework(); error PolicyFrameworkManager__CommercializerCheckerDoesNotSupportHook(address commercializer); //////////////////////////////////////////////////////////////////////////// // LicensorApprovalChecker // //////////////////////////////////////////////////////////////////////////// error LicensorApprovalChecker__Unauthorized(); //////////////////////////////////////////////////////////////////////////// // Dispute Module // //////////////////////////////////////////////////////////////////////////// error DisputeModule__ZeroArbitrationPolicy(); error DisputeModule__ZeroArbitrationRelayer(); error DisputeModule__ZeroDisputeTag(); error DisputeModule__ZeroLinkToDisputeEvidence(); error DisputeModule__NotWhitelistedArbitrationPolicy(); error DisputeModule__NotWhitelistedDisputeTag(); error DisputeModule__NotWhitelistedArbitrationRelayer(); error DisputeModule__NotDisputeInitiator(); error DisputeModule__NotInDisputeState(); error DisputeModule__NotAbleToResolve(); error DisputeModule__NotRegisteredIpId(); error DisputeModule__UnauthorizedAccess(); error ArbitrationPolicySP__ZeroDisputeModule(); error ArbitrationPolicySP__ZeroPaymentToken(); error ArbitrationPolicySP__NotDisputeModule(); //////////////////////////////////////////////////////////////////////////// // Royalty Module // //////////////////////////////////////////////////////////////////////////// error RoyaltyModule__ZeroRoyaltyPolicy(); error RoyaltyModule__NotWhitelistedRoyaltyPolicy(); error RoyaltyModule__ZeroRoyaltyToken(); error RoyaltyModule__NotWhitelistedRoyaltyToken(); error RoyaltyModule__NoRoyaltyPolicySet(); error RoyaltyModule__IncompatibleRoyaltyPolicy(); error RoyaltyModule__NotAllowedCaller(); error RoyaltyModule__ZeroLicensingModule(); error RoyaltyModule__CanOnlyMintSelectedPolicy(); error RoyaltyModule__NoParentsOnLinking(); error RoyaltyModule__NotRegisteredIpId(); error RoyaltyPolicyLAP__ZeroRoyaltyModule(); error RoyaltyPolicyLAP__ZeroLiquidSplitFactory(); error RoyaltyPolicyLAP__ZeroLiquidSplitMain(); error RoyaltyPolicyLAP__NotRoyaltyModule(); error RoyaltyPolicyLAP__ZeroLicensingModule(); error RoyaltyPolicyLAP__AboveParentLimit(); error RoyaltyPolicyLAP__AboveAncestorsLimit(); error RoyaltyPolicyLAP__AboveRoyaltyStackLimit(); error RoyaltyPolicyLAP__InvalidAncestorsLength(); error RoyaltyPolicyLAP__InvalidAncestors(); error RoyaltyPolicyLAP__InvalidRoyaltyAmountLength(); error RoyaltyPolicyLAP__InvalidAncestorsHash(); error RoyaltyPolicyLAP__InvalidParentRoyaltiesLength(); error RoyaltyPolicyLAP__InvalidAncestorsRoyalty(); error RoyaltyPolicyLAP__ImplementationAlreadySet(); error RoyaltyPolicyLAP__ZeroAncestorsVaultImpl(); error RoyaltyPolicyLAP__NotFullOwnership(); error RoyaltyPolicyLAP__UnlinkableToParents(); error RoyaltyPolicyLAP__TransferFailed(); error RoyaltyPolicyLAP__LastPositionNotAbleToMintLicense(); error AncestorsVaultLAP__ZeroRoyaltyPolicyLAP(); error AncestorsVaultLAP__AlreadyClaimed(); error AncestorsVaultLAP__InvalidAncestorsHash(); error AncestorsVaultLAP__InvalidClaimer(); error AncestorsVaultLAP__ClaimerNotAnAncestor(); error AncestorsVaultLAP__ETHBalanceNotZero(); error AncestorsVaultLAP__ERC20BalanceNotZero(); error AncestorsVaultLAP__TransferFailed(); //////////////////////////////////////////////////////////////////////////// // ModuleRegistry // //////////////////////////////////////////////////////////////////////////// error ModuleRegistry__ModuleAddressZeroAddress(); error ModuleRegistry__ModuleAddressNotContract(); error ModuleRegistry__ModuleAlreadyRegistered(); error ModuleRegistry__NameEmptyString(); error ModuleRegistry__NameAlreadyRegistered(); error ModuleRegistry__NameDoesNotMatch(); error ModuleRegistry__ModuleNotRegistered(); error ModuleRegistry__InterfaceIdZero(); error ModuleRegistry__ModuleTypeAlreadyRegistered(); error ModuleRegistry__ModuleTypeNotRegistered(); error ModuleRegistry__ModuleNotSupportExpectedModuleTypeInterfaceId(); error ModuleRegistry__ModuleTypeEmptyString(); //////////////////////////////////////////////////////////////////////////// // RegistrationModule // //////////////////////////////////////////////////////////////////////////// /// @notice The caller is not the owner of the root IP NFT. error RegistrationModule__InvalidOwner(); //////////////////////////////////////////////////////////////////////////// // AccessController // //////////////////////////////////////////////////////////////////////////// error AccessController__IPAccountIsZeroAddress(); error AccessController__IPAccountIsNotValid(address ipAccount); error AccessController__SignerIsZeroAddress(); error AccessController__CallerIsNotIPAccount(); error AccessController__PermissionIsNotValid(); error AccessController__BothCallerAndRecipientAreNotRegisteredModule(address signer, address to); error AccessController__PermissionDenied(address ipAccount, address signer, address to, bytes4 func); //////////////////////////////////////////////////////////////////////////// // AccessControlled // //////////////////////////////////////////////////////////////////////////// error AccessControlled__ZeroAddress(); error AccessControlled__NotIpAccount(address ipAccount); error AccessControlled__CallerIsNotIpAccount(address caller); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError, bytes32) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; /// @title Access Permission Library /// @notice Library for IPAccount access control permissions. /// These permissions are used by the AccessController. library AccessPermission { /// @notice ABSTAIN means having not enough information to make decision at current level, deferred decision to up /// level permission. uint8 public constant ABSTAIN = 0; /// @notice ALLOW means the permission is granted to transaction signer to call the function. uint8 public constant ALLOW = 1; /// @notice DENY means the permission is denied to transaction signer to call the function. uint8 public constant DENY = 2; /// @notice This struct is used to represent permissions in batch operations within the AccessController. /// @param ipAccount The address of the IP account that grants the permission for `signer` /// @param signer The address that can call `to` on behalf of the `ipAccount` /// @param to The address that can be called by the `signer` (currently only modules can be `to`) /// @param func The function selector of `to` that can be called by the `signer` on behalf of the `ipAccount` /// @param permission The permission level for the transaction (0 = ABSTAIN, 1 = ALLOW, 2 = DENY). struct Permission { address ipAccount; address signer; address to; bytes4 func; uint8 permission; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
{ "remappings": [ "@ethereum-waffle/=node_modules/@ethereum-waffle/", "@openzeppelin/=node_modules/@openzeppelin/", "forge-std/=node_modules/forge-std/src/", "ds-test/=node_modules/ds-test/src/", "base64-sol/=node_modules/base64-sol/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/", "erc6551/=node_modules/erc6551/", "openzeppelin-contracts/=lib/reference/lib/openzeppelin-contracts/", "reference/=lib/reference/" ], "optimizer": { "enabled": true, "runs": 20000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": { "contracts/lib/registries/IPAccountChecker.sol": { "IPAccountChecker": "0x36e93affeca875ebcef53e922a4b716ad2a508a9" } } }
[{"inputs":[{"internalType":"address","name":"accessController_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"IPAccount__ExpiredSignature","type":"error"},{"inputs":[],"name":"IPAccount__InvalidAccessController","type":"error"},{"inputs":[],"name":"IPAccount__InvalidCalldata","type":"error"},{"inputs":[],"name":"IPAccount__InvalidSignature","type":"error"},{"inputs":[],"name":"IPAccount__InvalidSigner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"},{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"ExecutedWithSig","type":"event"},{"inputs":[],"name":"accessController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"executeWithSig","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"isValidSigner","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.