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
|
|||
---|---|---|---|---|---|---|
6555960 | 169 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Minimal Proxy Contract for 0x36a5f0d61f6bab3c6dde211e5a6762cb18a8060d
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/ERC165.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/access/IAccessController.sol"; import { IIPAccount } from "./interfaces/IIPAccount.sol"; import { MetaTx } from "./lib/MetaTx.sol"; import { Errors } from "./lib/Errors.sol"; import { IPAccountStorage } from "./IPAccountStorage.sol"; /// @title IPAccountImpl /// @notice The Story Protocol's implementation of the IPAccount. contract IPAccountImpl is IPAccountStorage, IIPAccount { address public immutable ACCESS_CONTROLLER; /// @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, address ipAssetRegistry, address licenseRegistry, address moduleRegistry ) IPAccountStorage(ipAssetRegistry, licenseRegistry, moduleRegistry) { if (accessController == address(0)) revert Errors.IPAccount__ZeroAccessController(); ACCESS_CONTROLLER = 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) public view override(IPAccountStorage, IERC165) returns (bool) { return (interfaceId == type(IIPAccount).interfaceId || interfaceId == type(IERC6551Account).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC721Receiver).interfaceId || super.supportsInterface(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(ACCESS_CONTROLLER).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/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// 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 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 Sets permission to a signer for all functions across all modules. /// @param ipAccount The address of the IP account that grants the permission for `signer`. /// @param signer The address of the signer receiving the permissions. /// @param permission The new permission. function setAllPermissions(address ipAccount, address signer, 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"; import { IIPAccountStorage } from "./IIPAccountStorage.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, IIPAccountStorage { /// @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 { //////////////////////////////////////////////////////////////////////////// // IP Account // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Controller. error IPAccount__ZeroAccessController(); /// @notice Invalid signer provided. error IPAccount__InvalidSigner(); /// @notice Invalid signature provided, must be an EIP-712 signature. error IPAccount__InvalidSignature(); /// @notice Signature is expired. error IPAccount__ExpiredSignature(); /// @notice Provided calldata is invalid. error IPAccount__InvalidCalldata(); //////////////////////////////////////////////////////////////////////////// // IP Account Storage // //////////////////////////////////////////////////////////////////////////// /// @notice Caller writing to IP Account storage is not a registered module. error IPAccountStorage__NotRegisteredModule(address module); //////////////////////////////////////////////////////////////////////////// // IP Account Registry // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for IP Account implementation. error IPAccountRegistry_ZeroIpAccountImpl(); //////////////////////////////////////////////////////////////////////////// // IP Asset Registry // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error IPAssetRegistry__ZeroAccessManager(); /// @notice The IP asset has already been registered. error IPAssetRegistry__AlreadyRegistered(); /// @notice The NFT token contract is not valid ERC721 contract. error IPAssetRegistry__UnsupportedIERC721(address contractAddress); /// @notice The NFT token contract does not support ERC721Metadata. error IPAssetRegistry__UnsupportedIERC721Metadata(address contractAddress); /// @notice The NFT token id does not exist or invalid. error IPAssetRegistry__InvalidToken(address contractAddress, uint256 tokenId); //////////////////////////////////////////////////////////////////////////// // License Registry // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error LicenseRegistry__ZeroAccessManager(); /// @notice Zero address provided for IP Asset Registry. error LicensingModule__ZeroRoyaltyModule(); /// @notice Zero address provided for Licensing Module. error LicensingModule__ZeroLicenseRegistry(); /// @notice Zero address provided for Dispute Module. error LicensingModule__ZeroDisputeModule(); /// @notice Zero address provided for License Token. error LicensingModule__ZeroLicenseToken(); /// @notice Zero address provided for Module Registry. error LicensingModule__ZeroModuleRegistry(); /// @notice Zero address provided for Licensing Module. error LicenseRegistry__ZeroLicensingModule(); /// @notice Zero address provided for Dispute Module. error LicenseRegistry__ZeroDisputeModule(); /// @notice Caller is not the Licensing Module. error LicenseRegistry__CallerNotLicensingModule(); /// @notice Emitted when trying to transfer a license that is not transferable (by policy) error LicenseRegistry__NotTransferable(); /// @notice License Template is not registered in the License Registry. error LicenseRegistry__UnregisteredLicenseTemplate(address licenseTemplate); /// @notice License Terms or License Template not found. error LicenseRegistry__LicenseTermsNotExists(address licenseTemplate, uint256 licenseTermsId); /// @notice Licensor IP does not have the provided license terms attached. error LicenseRegistry__LicensorIpHasNoLicenseTerms(address ipId, address licenseTemplate, uint256 licenseTermsId); /// @notice Invalid License Template address provided. error LicenseRegistry__NotLicenseTemplate(address licenseTemplate); /// @notice IP is expired. error LicenseRegistry__IpExpired(address ipId); /// @notice Parent IP is expired. error LicenseRegistry__ParentIpExpired(address ipId); /// @notice Parent IP is dispute tagged. error LicenseRegistry__ParentIpTagged(address ipId); /// @notice Parent IP does not have the provided license terms attached. error LicenseRegistry__ParentIpHasNoLicenseTerms(address ipId, uint256 licenseTermsId); /// @notice Empty Parent IP list provided. error LicenseRegistry__NoParentIp(); /// @notice Provided derivative IP already has license terms attached. error LicenseRegistry__DerivativeIpAlreadyHasLicense(address childIpId); /// @notice Provided derivative IP is already registered. error LicenseRegistry__DerivativeAlreadyRegistered(address childIpId); /// @notice Provided derivative IP is the same as the parent IP. error LicenseRegistry__DerivativeIsParent(address ipId); /// @notice Provided license template does not match the parent IP's current license template. error LicenseRegistry__ParentIpUnmatchedLicenseTemplate(address ipId, address licenseTemplate); /// @notice Index out of bounds. error LicenseRegistry__IndexOutOfBounds(address ipId, uint256 index, uint256 length); /// @notice Provided license template and terms ID is already attached to IP. error LicenseRegistry__LicenseTermsAlreadyAttached(address ipId, address licenseTemplate, uint256 licenseTermsId); /// @notice Provided license template does not match the IP's current license template. error LicenseRegistry__UnmatchedLicenseTemplate(address ipId, address licenseTemplate, address newLicenseTemplate); /// @notice Provided license template and terms ID is a duplicate. error LicenseRegistry__DuplicateLicense(address ipId, address licenseTemplate, uint256 licenseTermsId); //////////////////////////////////////////////////////////////////////////// // License Token // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error LicenseToken__ZeroAccessManager(); /// @notice Zero address provided for Licensing Module. error LicenseToken__ZeroLicensingModule(); /// @notice Zero address provided for Dispute Module. error LicenseToken__ZeroDisputeModule(); /// @notice Caller is not the Licensing Module. error LicenseToken__CallerNotLicensingModule(); /// @notice License token is revoked. error LicenseToken__RevokedLicense(uint256 tokenId); /// @notice License token is not transferable. error LicenseToken__NotTransferable(); /// @notice License token is not owned by the caller. error LicenseToken__NotLicenseTokenOwner(uint256 tokenId, address iPowner, address tokenOwner); /// @notice All license tokens must be from the same license template. error LicenseToken__AllLicenseTokensMustFromSameLicenseTemplate( address licenseTemplate, address anotherLicenseTemplate ); //////////////////////////////////////////////////////////////////////////// // Licensing Module // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error LicensingModule__ZeroAccessManager(); /// @notice Receiver is zero address. error LicensingModule__ReceiverZeroAddress(); /// @notice Mint amount is zero. error LicensingModule__MintAmountZero(); /// @notice IP is dispute tagged. error LicensingModule__DisputedIpId(); /// @notice License template and terms ID is not found. error LicensingModule__LicenseTermsNotFound(address licenseTemplate, uint256 licenseTermsId); /// @notice Derivative IP cannot add license terms. error LicensingModule__DerivativesCannotAddLicenseTerms(); /// @notice Receiver check failed. error LicensingModule__ReceiverCheckFailed(address receiver); /// @notice IP list and license terms list length mismatch. error LicensingModule__LicenseTermsLengthMismatch(uint256 ipLength, uint256 licenseTermsLength); /// @notice Parent IP list is empty. error LicensingModule__NoParentIp(); /// @notice Incompatible royalty policy. error LicensingModule__IncompatibleRoyaltyPolicy(address royaltyPolicy, address anotherRoyaltyPolicy); /// @notice License template and terms are not compatible for the derivative IP. error LicensingModule__LicenseNotCompatibleForDerivative(address childIpId); /// @notice License token list is empty. error LicensingModule__NoLicenseToken(); /// @notice License tokens are not compatible for the derivative IP. error LicensingModule__LicenseTokenNotCompatibleForDerivative(address childIpId, uint256[] licenseTokenIds); /// @notice License template denied minting license token during the verification stage. error LicensingModule__LicenseDenyMintLicenseToken( address licenseTemplate, uint256 licenseTermsId, address licensorIpId ); /// @notice Licensing hook is invalid either not support ILicensingHook interface or not registered as module error LicensingModule__InvalidLicensingHook(address hook); /// @notice The license terms ID is invalid or license template doesn't exist. error LicensingModule__InvalidLicenseTermsId(address licenseTemplate, uint256 licenseTermsId); //////////////////////////////////////////////////////////////////////////// // Dispute Module // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error DisputeModule__ZeroAccessManager(); /// @notice Zero address provided for License Registry. error DisputeModule__ZeroLicenseRegistry(); /// @notice Zero address provided for IP Asset Registry. error DisputeModule__ZeroIPAssetRegistry(); /// @notice Zero address provided for Access Controller. error DisputeModule__ZeroAccessController(); /// @notice Zero address provided for Arbitration Policy. error DisputeModule__ZeroArbitrationPolicy(); /// @notice Zero address provided for Arbitration Relayer. error DisputeModule__ZeroArbitrationRelayer(); /// @notice Zero bytes provided for Dispute Tag. error DisputeModule__ZeroDisputeTag(); /// @notice Zero bytes provided for Dispute Evidence. error DisputeModule__ZeroLinkToDisputeEvidence(); /// @notice Not a whitelisted arbitration policy. error DisputeModule__NotWhitelistedArbitrationPolicy(); /// @notice Not a whitelisted arbitration relayer. error DisputeModule__NotWhitelistedArbitrationRelayer(); /// @notice Not a whitelisted dispute tag. error DisputeModule__NotWhitelistedDisputeTag(); /// @notice Not the dispute initiator. error DisputeModule__NotDisputeInitiator(); /// @notice Not in dispute state, the dispute is not IN_DISPUTE. error DisputeModule__NotInDisputeState(); /// @notice Not able to resolve a dispute, either the dispute is IN_DISPUTE or empty. error DisputeModule__NotAbleToResolve(); /// @notice Not a registered IP. error DisputeModule__NotRegisteredIpId(); /// @notice Provided parent IP and the parent dispute's target IP is different. error DisputeModule__ParentIpIdMismatch(); /// @notice Provided parent dispute's target IP is not dispute tagged. error DisputeModule__ParentNotTagged(); /// @notice Provided parent dispute's target IP is not the derivative IP's parent. error DisputeModule__NotDerivative(); /// @notice Provided parent dispute has not been resolved. error DisputeModule__ParentDisputeNotResolved(); //////////////////////////////////////////////////////////////////////////// // ArbitrationPolicy SP // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error ArbitrationPolicySP__ZeroAccessManager(); /// @notice Zero address provided for Dispute Module. error ArbitrationPolicySP__ZeroDisputeModule(); /// @notice Zero address provided for Payment Token. error ArbitrationPolicySP__ZeroPaymentToken(); /// @notice Caller is not the Dispute Module. error ArbitrationPolicySP__NotDisputeModule(); //////////////////////////////////////////////////////////////////////////// // Royalty Module // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error RoyaltyModule__ZeroAccessManager(); /// @notice Zero address provided for Dispute Module. error RoyaltyModule__ZeroDisputeModule(); /// @notice Zero address provided for License Registry. error RoyaltyModule__ZeroLicenseRegistry(); /// @notice Zero address provided for Licensing Module. error RoyaltyModule__ZeroLicensingModule(); /// @notice Zero address provided for Royalty Policy. error RoyaltyModule__ZeroRoyaltyPolicy(); /// @notice Zero address provided for Royalty Token. error RoyaltyModule__ZeroRoyaltyToken(); /// @notice Not a whitelisted royalty policy. error RoyaltyModule__NotWhitelistedRoyaltyPolicy(); /// @notice Not a whitelisted royalty token. error RoyaltyModule__NotWhitelistedRoyaltyToken(); /// @notice Royalty policy for IP is unset. error RoyaltyModule__NoRoyaltyPolicySet(); /// @notice Royalty policy between IPs are incompatible (different). error RoyaltyModule__IncompatibleRoyaltyPolicy(); /// @notice Caller is unauthorized. error RoyaltyModule__NotAllowedCaller(); /// @notice IP can only mint licenses of selected royalty policy. error RoyaltyModule__CanOnlyMintSelectedPolicy(); /// @notice Parent IP list for linking is empty. error RoyaltyModule__NoParentsOnLinking(); /// @notice IP is expired. error RoyaltyModule__IpIsExpired(); /// @notice IP is dipute tagged. error RoyaltyModule__IpIsTagged(); //////////////////////////////////////////////////////////////////////////// // Royalty Policy LAP // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error RoyaltyPolicyLAP__ZeroAccessManager(); /// @notice Zero address provided for IP Royalty Vault Beacon. error RoyaltyPolicyLAP__ZeroIpRoyaltyVaultBeacon(); /// @notice Zero address provided for Royalty Module. error RoyaltyPolicyLAP__ZeroRoyaltyModule(); /// @notice Zero address provided for Licensing Module. error RoyaltyPolicyLAP__ZeroLicensingModule(); /// @notice Caller is not the Royalty Module. error RoyaltyPolicyLAP__NotRoyaltyModule(); /// @notice Size of parent IP list is above the LAP royalty policy limit. error RoyaltyPolicyLAP__AboveParentLimit(); /// @notice Amount of ancestors for derivative IP is above the LAP royalty policy limit. error RoyaltyPolicyLAP__AboveAncestorsLimit(); /// @notice Total royalty stack exceeds the protocol limit. error RoyaltyPolicyLAP__AboveRoyaltyStackLimit(); /// @notice Size of parent royalties list and parent IP list mismatch. error RoyaltyPolicyLAP__InvalidParentRoyaltiesLength(); /// @notice IP cannot be linked to a parent, because it is either already linked to parents or derivatives (root). error RoyaltyPolicyLAP__UnlinkableToParents(); /// @notice Policy is already initialized and IP is at the ancestors limit, so it can't mint more licenses. error RoyaltyPolicyLAP__LastPositionNotAbleToMintLicense(); //////////////////////////////////////////////////////////////////////////// // IP Royalty Vault // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Royalty Policy LAP. error IpRoyaltyVault__ZeroRoyaltyPolicyLAP(); /// @notice Zero address provided for Dispute Module. error IpRoyaltyVault__ZeroDisputeModule(); /// @notice Caller is not the Royalty Policy LAP. error IpRoyaltyVault__NotRoyaltyPolicyLAP(); /// @notice Snapshot interval is too short, wait for the interval to pass for the next snapshot. error IpRoyaltyVault__SnapshotIntervalTooShort(); /// @notice Royalty Tokens is already claimed. error IpRoyaltyVault__AlreadyClaimed(); /// @notice Royalty Tokens claimer is not an ancestor of derivative IP. error IpRoyaltyVault__ClaimerNotAnAncestor(); /// @notice IP is dispute tagged. error IpRoyaltyVault__IpTagged(); /// @notice IP Royalty Vault is paused. error IpRoyaltyVault__EnforcedPause(); //////////////////////////////////////////////////////////////////////////// // Module Registry // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error ModuleRegistry__ZeroAccessManager(); /// @notice Module is zero address. error ModuleRegistry__ModuleAddressZeroAddress(); /// @notice Provided module address is not a contract. error ModuleRegistry__ModuleAddressNotContract(); /// @notice Module is already registered. error ModuleRegistry__ModuleAlreadyRegistered(); /// @notice Provided module name is empty string. error ModuleRegistry__NameEmptyString(); /// @notice Provided module name is already regsitered. error ModuleRegistry__NameAlreadyRegistered(); /// @notice Module name does not match the given name. error ModuleRegistry__NameDoesNotMatch(); /// @notice Module is not registered error ModuleRegistry__ModuleNotRegistered(); /// @notice Provided interface ID is zero bytes4. error ModuleRegistry__InterfaceIdZero(); /// @notice Module type is already registered. error ModuleRegistry__ModuleTypeAlreadyRegistered(); /// @notice Module type is not registered. error ModuleRegistry__ModuleTypeNotRegistered(); /// @notice Module address does not support the interface ID (module type). error ModuleRegistry__ModuleNotSupportExpectedModuleTypeInterfaceId(); /// @notice Module type is empty string. error ModuleRegistry__ModuleTypeEmptyString(); //////////////////////////////////////////////////////////////////////////// // Access Controller // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address provided for Access Manager in initializer. error AccessController__ZeroAccessManager(); /// @notice Zero address provided for IP Account Registry. error AccessController__ZeroIPAccountRegistry(); /// @notice Zero address provided for Module Registry. error AccessController__ZeroModuleRegistry(); /// @notice IP Account is zero address. error AccessController__IPAccountIsZeroAddress(); /// @notice IP Account is not a valid SP IP Account address. error AccessController__IPAccountIsNotValid(address ipAccount); /// @notice Signer is zero address. error AccessController__SignerIsZeroAddress(); /// @notice Caller is not the IP Account or its owner. error AccessController__CallerIsNotIPAccountOrOwner(); /// @notice Invalid permission value, must be 0 (ABSTAIN), 1 (ALLOW) or 2 (DENY). error AccessController__PermissionIsNotValid(); /// @notice Both the caller and recipient (to) are not registered modules. error AccessController__BothCallerAndRecipientAreNotRegisteredModule(address signer, address to); /// @notice Permission denied. error AccessController__PermissionDenied(address ipAccount, address signer, address to, bytes4 func); /// @notice Both recipient (to) and function selectors are zero address means delegate all permissions to signer. error AccessController__ToAndFuncAreZeroAddressShouldCallSetAllPermissions(); //////////////////////////////////////////////////////////////////////////// // Access Controlled // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address passed. error AccessControlled__ZeroAddress(); /// @notice IP Account is not a valid SP IP Account address. error AccessControlled__NotIpAccount(address ipAccount); /// @notice Caller is not the IP Account. error AccessControlled__CallerIsNotIpAccount(address caller); //////////////////////////////////////////////////////////////////////////// // Core Metadata Module // //////////////////////////////////////////////////////////////////////////// /// @notice Core metadata is already frozen (immutable). error CoreMetadataModule__MetadataAlreadyFrozen(); //////////////////////////////////////////////////////////////////////////// // Protocol Pause Admin // //////////////////////////////////////////////////////////////////////////// /// @notice Zero address passed. error ProtocolPauseAdmin__ZeroAddress(); /// @notice Adding a contract that is paused. error ProtocolPauseAdmin__AddingPausedContract(); /// @notice Contract is already added to the pausable list. error ProtocolPauseAdmin__PausableAlreadyAdded(); /// @notice Removing a contract that is not in the pausable list. error ProtocolPauseAdmin__PausableNotFound(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { IIPAccountStorage } from "./interfaces/IIPAccountStorage.sol"; import { IModuleRegistry } from "./interfaces/registries/IModuleRegistry.sol"; import { Errors } from "./lib/Errors.sol"; import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol"; /// @title IPAccount Storage /// @dev Implements the IIPAccountStorage interface for managing IPAccount's state using a namespaced storage pattern. /// Inherits all functionalities from IIPAccountStorage, providing concrete implementations for the interface's methods. /// This contract allows Modules to store and retrieve data in a structured and conflict-free manner /// by utilizing namespaces, where the default namespace is determined by the /// `msg.sender` (the caller Module's address). contract IPAccountStorage is ERC165, IIPAccountStorage { using ShortStrings for *; address public immutable MODULE_REGISTRY; address public immutable LICENSE_REGISTRY; address public immutable IP_ASSET_REGISTRY; mapping(bytes32 => mapping(bytes32 => bytes)) public bytesData; mapping(bytes32 => mapping(bytes32 => bytes32)) public bytes32Data; modifier onlyRegisteredModule() { if ( msg.sender != IP_ASSET_REGISTRY && msg.sender != LICENSE_REGISTRY && !IModuleRegistry(MODULE_REGISTRY).isRegistered(msg.sender) ) { revert Errors.IPAccountStorage__NotRegisteredModule(msg.sender); } _; } constructor(address ipAssetRegistry, address licenseRegistry, address moduleRegistry) { MODULE_REGISTRY = moduleRegistry; LICENSE_REGISTRY = licenseRegistry; IP_ASSET_REGISTRY = ipAssetRegistry; } /// @inheritdoc IIPAccountStorage function setBytes(bytes32 key, bytes calldata value) external onlyRegisteredModule { bytesData[_toBytes32(msg.sender)][key] = value; } /// @inheritdoc IIPAccountStorage function getBytes(bytes32 key) external view returns (bytes memory) { return bytesData[_toBytes32(msg.sender)][key]; } /// @inheritdoc IIPAccountStorage function getBytes(bytes32 namespace, bytes32 key) external view returns (bytes memory) { return bytesData[namespace][key]; } /// @inheritdoc IIPAccountStorage function setBytes32(bytes32 key, bytes32 value) external onlyRegisteredModule { bytes32Data[_toBytes32(msg.sender)][key] = value; } /// @inheritdoc IIPAccountStorage function getBytes32(bytes32 key) external view returns (bytes32) { return bytes32Data[_toBytes32(msg.sender)][key]; } /// @inheritdoc IIPAccountStorage function getBytes32(bytes32 namespace, bytes32 key) external view returns (bytes32) { return bytes32Data[namespace][key]; } /// @notice ERC165 interface identifier for IIPAccountStorage function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165) returns (bool) { return interfaceId == type(IIPAccountStorage).interfaceId || super.supportsInterface(interfaceId); } function _toBytes32(string memory s) internal pure returns (bytes32) { return ShortString.unwrap(s.toShortString()); } function _toBytes32(address a) internal pure returns (bytes32) { return bytes32(uint256(uint160(a))); } }
// 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) (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: UNLICENSED // See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf pragma solidity ^0.8.23; /// @title IPAccount Namespaced Storage Interface /// @dev Provides a structured way to store IPAccount's state using a namespaced storage pattern. /// This interface facilitates conflict-free data writing by different Modules into the same IPAccount /// by utilizing namespaces. /// The default namespace for write operations is determined by the `msg.sender`, ensuring that only the owning Module /// (i.e., the Module calling the write functions) can write data into its respective namespace. /// However, read operations are unrestricted and can access any namespace. /// /// Rules: /// - The default namespace for a Module is its own address. /// - Every Module can read data from any namespace. /// - Only the owning Module (i.e., the Module whose address is used as the namespace) can write data into /// its respective namespace. interface IIPAccountStorage { /// @dev Sets a bytes value under a given key within the default namespace, determined by `msg.sender`. /// @param key The key under which to store the value. /// @param value The bytes value to be stored. function setBytes(bytes32 key, bytes calldata value) external; /// @dev Retrieves a bytes value by a given key from the default namespace. /// @param key The key whose value is to be retrieved. /// @return The bytes value stored under the specified key. function getBytes(bytes32 key) external view returns (bytes memory); /// @dev Retrieves a bytes value by a given key from a specified namespace. /// @param namespace The namespace from which to retrieve the value. /// @param key The key whose value is to be retrieved. /// @return The bytes value stored under the specified key in the given namespace. function getBytes(bytes32 namespace, bytes32 key) external view returns (bytes memory); /// @dev Sets a bytes32 value under a given key within the default namespace, determined by `msg.sender`. /// @param key The key under which to store the value. /// @param value The bytes32 value to be stored. function setBytes32(bytes32 key, bytes32 value) external; /// @dev Retrieves a bytes32 value by a given key from the default namespace. /// @param key The key whose value is to be retrieved. /// @return The bytes32 value stored under the specified key. function getBytes32(bytes32 key) external view returns (bytes32); /// @dev Retrieves a bytes32 value by a given key from a specified namespace. /// @param namespace The namespace from which to retrieve the value. /// @param key The key whose value is to be retrieved. /// @return The bytes32 value stored under the specified key in the given namespace. function getBytes32(bytes32 namespace, bytes32 key) external view returns (bytes32); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; /// @title IModuleRegistry /// @dev This interface defines the methods for a module registry in the Story Protocol. interface IModuleRegistry { /// @notice Emitted when a new module is added to the registry. /// @param name The name of the module. /// @param module The address of the module. event ModuleAdded(string name, address indexed module, bytes4 indexed moduleTypeInterfaceId, string moduleType); /// @notice Emitted when a module is removed from the registry. /// @param name The name of the module. /// @param module The address of the module. event ModuleRemoved(string name, address indexed module); /// @notice Returns the address of a registered module by its name. /// @param name The name of the module. /// @return moduleAddress The address of the module. function getModule(string memory name) external view returns (address); /// @notice Returns the module type of a registered module by its address. /// @param moduleAddress The address of the module. /// @return moduleType The type of the module as a string. function getModuleType(address moduleAddress) external view returns (string memory); /// @notice Returns the interface ID of a registered module type. /// @param moduleType The name of the module type. /// @return moduleTypeInterfaceId The interface ID of the module type as bytes4. function getModuleTypeInterfaceId(string memory moduleType) external view returns (bytes4); /// @notice Registers a new module type in the registry associate with an interface. /// @dev Enforced to be only callable by the protocol admin in governance. /// @param name The name of the module type to be registered. /// @param interfaceId The interface ID associated with the module type. function registerModuleType(string memory name, bytes4 interfaceId) external; /// @notice Removes a module type from the registry. /// @dev Enforced to be only callable by the protocol admin in governance. /// @param name The name of the module type to be removed. function removeModuleType(string memory name) external; /// @notice Registers a new module in the registry. /// @dev Enforced to be only callable by the protocol admin in governance. /// @param name The name of the module. /// @param moduleAddress The address of the module. function registerModule(string memory name, address moduleAddress) external; /// @notice Registers a new module in the registry with an associated module type. /// @param name The name of the module to be registered. /// @param moduleAddress The address of the module. /// @param moduleType The type of the module being registered. function registerModule(string memory name, address moduleAddress, string memory moduleType) external; /// @notice Removes a module from the registry. /// @dev Enforced to be only callable by the protocol admin in governance. /// @param name The name of the module. function removeModule(string memory name) external; /// @notice Checks if a module is registered in the protocol. /// @param moduleAddress The address of the module. /// @return isRegistered True if the module is registered, false otherwise. function isRegistered(address moduleAddress) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol) pragma solidity ^0.8.20; import {StorageSlot} from "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using * {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// 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); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
{ "remappings": [ "ds-test/=node_modules/ds-test/src/", "forge-std/=node_modules/forge-std/src/", "@openzeppelin/=node_modules/@openzeppelin/", "@openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/", "@create3-deployer/=lib/create3-deployer/", "base64-sol/=node_modules/base64-sol/", "create3-deployer/=lib/create3-deployer/", "erc6551/=node_modules/erc6551/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/", "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", "solady/=node_modules/solady/", "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/" ], "optimizer": { "enabled": true, "runs": 20000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": { "test/foundry/utils/Users.t.sol": { "UsersLib": "0x4790fd9437BfBDfB46bce1d48BcB90F4d3611F51" } } }
[{"inputs":[{"internalType":"address","name":"accessController","type":"address"},{"internalType":"address","name":"ipAssetRegistry","type":"address"},{"internalType":"address","name":"licenseRegistry","type":"address"},{"internalType":"address","name":"moduleRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"IPAccountStorage__NotRegisteredModule","type":"error"},{"inputs":[],"name":"IPAccount__ExpiredSignature","type":"error"},{"inputs":[],"name":"IPAccount__InvalidCalldata","type":"error"},{"inputs":[],"name":"IPAccount__InvalidSignature","type":"error"},{"inputs":[],"name":"IPAccount__InvalidSigner","type":"error"},{"inputs":[],"name":"IPAccount__ZeroAccessController","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":"ACCESS_CONTROLLER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IP_ASSET_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LICENSE_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MODULE_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bytes32Data","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bytesData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"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":"bytes32","name":"key","type":"bytes32"}],"name":"getBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"namespace","type":"bytes32"},{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"namespace","type":"bytes32"},{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBytes32","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBytes32","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","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":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes","name":"value","type":"bytes"}],"name":"setBytes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes32","name":"value","type":"bytes32"}],"name":"setBytes32","outputs":[],"stateMutability":"nonpayable","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":"view","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.