Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
||
|---|---|---|---|---|---|---|---|
| 0x60a06040 | 5201386 | 654 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
IPAssetRegistry
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: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { IIPAccount } from "contracts/interfaces/IIPAccount.sol";
import { IMetadataProvider } from "contracts/interfaces/registries/metadata/IMetadataProvider.sol";
import { IIPAssetRegistry } from "contracts/interfaces/registries/IIPAssetRegistry.sol";
import { IPAccountRegistry } from "contracts/registries/IPAccountRegistry.sol";
import { IMetadataProviderMigratable } from "contracts/interfaces/registries/metadata/IMetadataProviderMigratable.sol";
import { MetadataProviderV1 } from "contracts/registries/metadata/MetadataProviderV1.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { IResolver } from "contracts/interfaces/resolvers/IResolver.sol";
/// @title IP Asset Registry
/// @notice This contract acts as the source of truth for all IP registered in
/// Story Protocol. An IP is identified by its contract address, token
/// id, and coin type, meaning any NFT may be conceptualized as an IP.
/// Once an IP is registered into the protocol, a corresponding IP
/// asset is generated, which references an IP resolver for metadata
/// attribution and an IP account for protocol authorization.
/// IMPORTANT: The IP account address, besides being used for protocol
/// auth, is also the canonical IP identifier for the IP NFT.
contract IPAssetRegistry is IIPAssetRegistry, IPAccountRegistry {
/// @notice Attributes for the IP asset type.
struct Record {
// Metadata provider for Story Protocol canonicalized metadata.
IMetadataProviderMigratable metadataProvider;
address resolver;
}
/// @notice Tracks the total number of IP assets in existence.
uint256 public totalSupply = 0;
/// @notice Protocol governance administrator of the IP record registry.
address owner;
/// @dev Maps an IP, identified by its IP ID, to an IP record.
mapping(address => Record) internal _records;
/// @notice Tracks the current metadata provider used for IP registrations.
IMetadataProviderMigratable internal _metadataProvider;
/// @notice Ensures only protocol governance owner may call a function.
modifier onlyOwner() {
if (msg.sender != owner) {
revert Errors.IPAssetRegistry__Unauthorized();
}
_;
}
/// @notice Initializes the IP Asset Registry.
/// @param erc6551Registry The address of the ERC6551 registry.
/// @param accessController The address of the access controller.
/// @param ipAccountImpl The address of the IP account implementation.
constructor(
address accessController,
address erc6551Registry,
address ipAccountImpl
) IPAccountRegistry(erc6551Registry, accessController, ipAccountImpl) {
// TODO: Migrate this to a parameterized governance owner address.
owner = msg.sender;
_metadataProvider = IMetadataProviderMigratable(new MetadataProviderV1(address(this)));
}
/// @notice Registers an NFT as an IP, creating a corresponding IP asset.
/// @param chainId The chain identifier of where the NFT resides.
/// @param tokenContract The address of the NFT.
/// @param tokenId The token identifier of the NFT.
/// @param createAccount Whether to create an IP account when registering.
function register(
uint256 chainId,
address tokenContract,
uint256 tokenId,
address resolverAddr,
bool createAccount,
bytes calldata data
) external returns (address id) {
id = ipId(chainId, tokenContract, tokenId);
if (_records[id].resolver != address(0)) {
revert Errors.IPAssetRegistry__AlreadyRegistered();
}
if (id.code.length == 0 && createAccount && id != registerIpAccount(chainId, tokenContract, tokenId)) {
revert Errors.IPAssetRegistry__InvalidAccount();
}
_setResolver(id, resolverAddr);
_setMetadata(id, _metadataProvider, data);
totalSupply++;
emit IPRegistered(id, chainId, tokenContract, tokenId, resolverAddr, address(_metadataProvider), data);
}
/// @notice Gets the canonical IP identifier associated with an IP NFT.
/// @dev This is equivalent to the address of its bound IP account.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @return The IP's canonical address identifier.
function ipId(uint256 chainId, address tokenContract, uint256 tokenId) public view returns (address) {
return super.ipAccount(chainId, tokenContract, tokenId);
}
/// @notice Checks whether an IP was registered based on its ID.
/// @param id The canonical identifier for the IP.
/// @return Whether the IP was registered into the protocol.
function isRegistered(address id) external view returns (bool) {
return _records[id].resolver != address(0);
}
/// @notice Gets the resolver bound to an IP based on its ID.
/// @param id The canonical identifier for the IP.
/// @return The IP resolver address if registered, else the zero address.
function resolver(address id) external view returns (address) {
return _records[id].resolver;
}
/// @notice Gets the metadata provider used for new metadata registrations.
/// @return The address of the metadata provider used for new IP registrations.
function metadataProvider() external view returns (address) {
return address(_metadataProvider);
}
/// @notice Gets the metadata provider linked to an IP based on its ID.
/// @param id The canonical identifier for the IP.
/// @return The metadata provider that was bound to this IP at creation time.
function metadataProvider(address id) external view returns (address) {
return address(_records[id].metadataProvider);
}
/// @notice Gets the underlying canonical metadata linked to an IP asset.
/// @param id The canonical ID of the IP asset.
function metadata(address id) external view returns (bytes memory) {
if (address(_records[id].metadataProvider) == address(0)) {
revert Errors.IPAssetRegistry__NotYetRegistered();
}
return _records[id].metadataProvider.getMetadata(id);
}
/// @notice Sets the provider for storage of new IP metadata, while enabling
/// existing IP assets to migrate their metadata to the new provider.
/// @param newMetadataProvider Address of the new metadata provider contract.
function setMetadataProvider(address newMetadataProvider) external onlyOwner {
_metadataProvider.setUpgradeProvider(newMetadataProvider);
_metadataProvider = IMetadataProviderMigratable(newMetadataProvider);
}
/// @notice Sets the underlying metadata for an IP asset.
/// @dev As metadata is immutable but additive, this will only be used when
/// an IP migrates from a new provider that introduces new attributes.
/// @param id The canonical ID of the IP.
/// @param data Canonical metadata to associate with the IP.
function setMetadata(address id, address provider, bytes calldata data) external {
// Metadata is set on registration and immutable thereafter, with new fields
// only added during a migration to new protocol-approved metadata provider.
if (address(_records[id].metadataProvider) != msg.sender) {
revert Errors.IPAssetRegistry__Unauthorized();
}
_setMetadata(id, IMetadataProviderMigratable(provider), data);
}
/// @notice Sets the resolver for an IP based on its canonical ID.
/// @param id The canonical ID of the IP.
/// @param resolverAddr The address of the resolver being set.
function setResolver(address id, address resolverAddr) public {
if (_records[id].resolver == address(0)) {
revert Errors.IPAssetRegistry__NotYetRegistered();
}
// TODO: Update authorization logic to use the access controller.
if (msg.sender != IIPAccount(payable(id)).owner()) {
revert Errors.IPAssetRegistry__Unauthorized();
}
_setResolver(id, resolverAddr);
}
/// @dev Sets the resolver for the specified IP.
/// @param id The canonical ID of the IP.
/// @param resolverAddr The address of the resolver being set.
function _setResolver(address id, address resolverAddr) internal {
ERC165Checker.supportsInterface(resolverAddr, type(IResolver).interfaceId);
_records[id].resolver = resolverAddr;
emit IPResolverSet(id, resolverAddr);
}
/// @dev Sets the for the specified IP asset.
/// @param id The canonical identifier for the specified IP asset.
/// @param provider The metadata provider hosting the data.
/// @param data The metadata to set for the IP asset.
function _setMetadata(address id, IMetadataProviderMigratable provider, bytes calldata data) internal {
_records[id].metadataProvider = provider;
provider.setMetadata(id, data);
emit MetadataSet(id, address(provider), data);
}
}// 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) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
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 "lib/reference/src/interfaces/IERC6551Account.sol";
/// @title IIPAccount
/// @dev IPAccount is a token-bound account that adopts the EIP-6551 standard.
/// These accounts are deployed at deterministic addresses through the official 6551 account registry.
/// As a deployed smart contract, IPAccount can store IP-related information,
/// like ownership of other NFTs such as license NFT or Royalty NFT.
/// IPAccount can interact with modules by making calls as a normal transaction sender.
/// This allows for seamless operations on the state and data of IP.
/// IPAccount is core identity for all actions.
interface IIPAccount is IERC6551Account, IERC721Receiver, IERC1155Receiver {
/// @notice Emitted when a transaction is executed.
event Executed(address indexed to, uint256 value, bytes data, uint256 nonce);
/// @notice Emitted when a transaction is executed on behalf of the signer.
event ExecutedWithSig(
address indexed to,
uint256 value,
bytes data,
uint256 nonce,
uint256 deadline,
address indexed signer,
bytes 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 The return data from the transaction.
function execute(address to_, uint256 value_, bytes calldata data_) external payable returns (bytes memory);
/// @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);
/// @notice Returns the owner of the IP Account.
/// @return The address of the owner.
function owner() external view returns (address);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
/// @title Metadata Provider Interface
interface IMetadataProvider {
/// @notice Emits when canonical metadata was set for a specific IP asset.
event MetadataSet(address ipId, bytes metadata);
/// @notice Gets the metadata associated with an IP asset.
/// @param ipId The address identifier of the IP asset.
function getMetadata(address ipId) external view returns (bytes memory);
/// @notice Sets the metadata associated with an IP asset.
/// @param ipId The address identifier of the IP asset.
/// @param metadata Metadata in bytes to associate with the IP asset.
function setMetadata(address ipId, bytes memory metadata) external;
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IIPAccountRegistry } from "contracts/interfaces/registries/IIPAccountRegistry.sol";
import { IMetadataProvider } from "contracts/interfaces/registries/metadata/IMetadataProvider.sol";
/// @title Interface for IP Account Registry
/// @notice This interface manages the registration and tracking of IP Accounts
interface IIPAssetRegistry is IIPAccountRegistry {
/// @notice Emits when an IP is officially registered into the protocol.
/// @param ipId The canonical identifier for the IP.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @param resolver The address of the resolver linked to the IP.
/// @param provider The address of the metadata provider linked to the IP.
/// @param metadata Canonical metadata that was linked to the IP.
event IPRegistered(
address ipId,
uint256 indexed chainId,
address indexed tokenContract,
uint256 indexed tokenId,
address resolver,
address provider,
bytes metadata
);
/// @notice Emits when an IP resolver is bound to an IP.
/// @param ipId The canonical identifier of the specified IP.
/// @param resolver The address of the new resolver bound to the IP.
event IPResolverSet(address ipId, address resolver);
/// @notice Emits when metadata is set for an IP asset.
/// @param ipId The canonical identifier of the specified IP.
/// @param metadataProvider Address of the metadata provider associated with the IP.
/// @param metadata The canonical metadata in bytes associated with the IP.
event MetadataSet(
address indexed ipId,
address indexed metadataProvider,
bytes metadata
);
/// @notice Upgrades the metadata for an IP asset, migrating to a new provider.
/// @param id The canonical ID of the IP.
/// @param metadataProvider Address of the new metadata provider hosting the data.
/// @param data Canonical metadata to associate with the IP.
function setMetadata(address id, address metadataProvider, bytes calldata data) external;
/// @notice Sets the metadata provider to use for new registrations.
/// @param metadataProvider The address of the new metadata provider to use.
function setMetadataProvider(address metadataProvider) external;
/// @notice Registers an NFT as IP, creating a corresponding IP record.
/// @dev This is only callable by an authorized registration module.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @param resolverAddr The address of the resolver to associate with the IP.
/// @param createAccount Whether to create an IP account in the process.
/// @param metadata Metadata in bytes to associate with the IP.
function register(
uint256 chainId,
address tokenContract,
uint256 tokenId,
address resolverAddr,
bool createAccount,
bytes calldata metadata
) external returns (address);
/// @notice Sets the resolver for an IP based on its canonical ID.
/// @param id The canonical ID of the IP.
/// @param resolverAddr The address of the resolver being set.
function setResolver(address id, address resolverAddr) external;
/// @notice Gets the canonical IP identifier associated with an IP (NFT).
/// @dev This is the same as the address of the IP account bound to the IP.
/// @param chainId The chain identifier of where the IP resides.
/// @param tokenContract The address of the IP.
/// @param tokenId The token identifier of the IP.
/// @return The address of the associated IP account.
function ipId(uint256 chainId, address tokenContract, uint256 tokenId) external view returns (address);
/// @notice Checks whether an IP was registered based on its ID.
/// @param id The canonical identifier for the IP.
/// @return Whether the IP was registered into the protocol.
function isRegistered(address id) external view returns (bool);
/// @notice Gets the resolver bound to an IP based on its ID.
/// @param id The canonical identifier for the IP.
/// @return The IP resolver address if registered, else the zero address.
function resolver(address id) external view returns (address);
/// @notice Gets the metadata provider currently used for metadata storage.
function metadataProvider() external view returns (address);
/// @notice Gets the metadata provider linked to an IP based on its ID.
/// @param id The canonical identifier for the IP.
/// @return The metadata provider that was bound to this IP at creation time.
function metadataProvider(address id) external view returns (address);
/// @notice Gets the metadata linked to an IP based on its ID.
/// @param id The canonical identifier for the IP.
/// @return The metadata that was bound to this IP at creation time.
function metadata(address id) external view returns (bytes memory);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IIPAccountRegistry } from "contracts/interfaces/registries/IIPAccountRegistry.sol";
import { IERC6551Registry } from "lib/reference/src/interfaces/IERC6551Registry.sol";
import { Errors } from "contracts/lib/Errors.sol";
/// @title IPAccountRegistry
/// @notice This contract is responsible for managing the registration and tracking of IP Accounts.
/// It leverages a public ERC6551 registry to deploy IPAccount contracts.
contract IPAccountRegistry is IIPAccountRegistry {
address public immutable IP_ACCOUNT_IMPL;
bytes32 public immutable IP_ACCOUNT_SALT;
address public immutable ERC6551_PUBLIC_REGISTRY;
address public immutable ACCESS_CONTROLLER;
/// @notice Constructor for the IPAccountRegistry contract.
/// @param erc6551Registry_ The address of the ERC6551 registry.
/// @param accessController_ The address of the access controller.
/// @param ipAccountImpl_ The address of the IP account implementation.
constructor(address erc6551Registry_, address accessController_, address ipAccountImpl_) {
if (ipAccountImpl_ == address(0)) revert Errors.IPAccountRegistry_InvalidIpAccountImpl();
IP_ACCOUNT_IMPL = ipAccountImpl_;
IP_ACCOUNT_SALT = bytes32(0);
ERC6551_PUBLIC_REGISTRY = erc6551Registry_;
ACCESS_CONTROLLER = accessController_;
}
/// @notice Deploys an IPAccount contract with the IPAccount implementation and returns the address of the new IP.
/// @param chainId_ The chain ID where the IP Account will be created.
/// @param tokenContract_ The address of the token contract to be associated with the IP Account.
/// @param tokenId_ The ID of the token to be associated with the IP Account.
/// @return ipAccountAddress The address of the newly created IP Account.
function registerIpAccount(
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) public returns (address ipAccountAddress) {
bytes memory initData = abi.encodeWithSignature("initialize(address)", ACCESS_CONTROLLER);
ipAccountAddress = IERC6551Registry(ERC6551_PUBLIC_REGISTRY).createAccount(
IP_ACCOUNT_IMPL,
IP_ACCOUNT_SALT,
chainId_,
tokenContract_,
tokenId_
);
(bool success, bytes memory result) = ipAccountAddress.call(initData);
if (!success) {
assembly {
revert(add(result, 32), mload(result))
}
}
emit IPAccountRegistered(ipAccountAddress, IP_ACCOUNT_IMPL, chainId_, tokenContract_, tokenId_);
}
/// @notice Returns the IPAccount address for the given NFT token.
/// @param chainId_ The chain ID where the IP Account is located.
/// @param tokenContract_ The address of the token contract associated with the IP Account.
/// @param tokenId_ The ID of the token associated with the IP Account.
/// @return The address of the IP Account associated with the given NFT token.
function ipAccount(uint256 chainId_, address tokenContract_, uint256 tokenId_) public view returns (address) {
return _get6551AccountAddress(chainId_, tokenContract_, tokenId_);
}
/// @notice Returns the IPAccount implementation address.
/// @return The address of the IPAccount implementation.
function getIPAccountImpl() external view override returns (address) {
return IP_ACCOUNT_IMPL;
}
function _get6551AccountAddress(
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) internal view returns (address) {
return
IERC6551Registry(ERC6551_PUBLIC_REGISTRY).account(
IP_ACCOUNT_IMPL,
IP_ACCOUNT_SALT,
chainId_,
tokenContract_,
tokenId_
);
}
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IMetadataProvider } from "contracts/interfaces/registries/metadata/IMetadataProvider.sol";
/// @title Metadata Provider Interface
interface IMetadataProviderMigratable is IMetadataProvider {
/// @notice Returns the new metadata provider IP assets may migrate to.
/// @return Address of the new metadata provider if set, else the zero address.
function upgradeProvider() external returns(IMetadataProvider);
/// @notice Sets a new metadata provider that IP assets may migrate to.
/// @param provider The address of the new metadata provider.
function setUpgradeProvider(address provider) external;
/// @notice Updates the provider used by the IP asset, migrating existing
/// metadata to the new provider, and adding new metadata.
/// @param ipId The address identifier of the IP asset.
/// @param extraMetadata Additional metadata used by the new metadata provider.
function upgrade(address payable ipId, bytes memory extraMetadata) external;
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IP } from "contracts/lib/IP.sol";
import { MetadataProviderBase } from "./MetadataProviderBase.sol";
import { Errors } from "contracts/lib/Errors.sol";
/// @title IP Metadata Provider v1
/// @notice Storage provider for Story Protocol canonical IP metadata (v1).
contract MetadataProviderV1 is MetadataProviderBase {
/// @notice Initializes the metadata provider contract.
/// @param ipAssetRegistry The protocol-wide IP asset registry.
constructor(address ipAssetRegistry) MetadataProviderBase(ipAssetRegistry) {}
/// @notice Gets the name associated with the IP asset.
/// @param ipId The address identifier of the IP asset.
function name(address ipId) external view returns (string memory) {
return _metadataV1(ipId).name;
}
/// @notice Gets the hash associated with the IP asset.
/// @param ipId The address identifier of the IP asset.
function hash(address ipId) external view returns (bytes32) {
return _metadataV1(ipId).hash;
}
/// @notice Gets the date in which the IP asset was registered.
/// @param ipId The address identifier of the IP asset.
function registrationDate(address ipId) external view returns (uint64) {
return _metadataV1(ipId).registrationDate;
}
/// @notice Gets the initial registrant address of the IP asset.
/// @param ipId The address identifier of the IP asset.
function registrant(address ipId) external view returns (address) {
return _metadataV1(ipId).registrant;
}
/// @notice Gets the external URI associated with the IP asset.
/// @param ipId The address identifier of the IP asset.
function uri(address ipId) external view returns (string memory) {
return _metadataV1(ipId).uri;
}
/// @dev Checks that the data conforms to the canonical metadata standards.
/// @param data The canonical metadata in bytes to verify.
function _verifyMetadata(bytes memory data) internal virtual override {
IP.MetadataV1 memory decodedMetadata = abi.decode(data, (IP.MetadataV1));
if (bytes(decodedMetadata.name).length == 0) {
revert Errors.MetadataProvider__NameInvalid();
}
if (decodedMetadata.hash == "") {
revert Errors.MetadataProvider__HashInvalid();
}
// if (decodedMetadata.registrationDate != uint64(block.timestamp)) {
// revert Errors.MetadataProvider__RegistrationDateInvalid();
// }
if (decodedMetadata.registrant == address(0)) {
revert Errors.MetadataProvider__RegistrantInvalid();
}
if (bytes(decodedMetadata.uri).length == 0) {
revert Errors.MetadataProvider__URIInvalid();
}
}
/// @dev Checks whether two sets of metadata are compatible with one another.
/// TODO: Add try-catch for ABI-decoding error handling.
function _compatible(bytes memory m1, bytes memory m2) internal virtual override pure returns (bool) {
IP.MetadataV1 memory m1Decoded = abi.decode(m1, (IP.MetadataV1));
IP.MetadataV1 memory m2Decoded = abi.decode(m2, (IP.MetadataV1));
return _hash(m1Decoded) == _hash(m2Decoded);
}
/// @dev Gets the bytes32 hash for a MetadataV1 data struct.
function _hash(IP.MetadataV1 memory data) internal pure returns(bytes32) {
return keccak256(
abi.encode(
data.name,
data.hash,
data.registrationDate,
data.registrant,
data.uri
)
);
}
/// @dev Get the decoded canonical metadata belonging to an IP asset.
function _metadataV1(address ipId) internal view returns (IP.MetadataV1 memory) {
return abi.decode(_ipMetadata[ipId], (IP.MetadataV1));
}
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.19;
/// @title Errors Library
/// @notice Library for all Story Protocol contract errors.
library Errors {
////////////////////////////////////////////////////////////////////////////
// Governance //
////////////////////////////////////////////////////////////////////////////
error Governance__OnlyProtocolAdmin();
error Governance__ZeroAddress();
error Governance__ProtocolPaused();
error Governance__InconsistentState();
error Governance__NewStateIsTheSameWithOldState();
error Governance__UnsupportedInterface(string interfaceName);
////////////////////////////////////////////////////////////////////////////
// IPAccount //
////////////////////////////////////////////////////////////////////////////
error IPAccount__InvalidSigner();
error IPAccount__InvalidSignature();
error IPAccount__ExpiredSignature();
////////////////////////////////////////////////////////////////////////////
// Module //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not allowed to call the provided module.
error Module_Unauthorized();
////////////////////////////////////////////////////////////////////////////
// IPAccountRegistry //
////////////////////////////////////////////////////////////////////////////
error IPAccountRegistry_InvalidIpAccountImpl();
////////////////////////////////////////////////////////////////////////////
// IPAssetRegistry //
////////////////////////////////////////////////////////////////////////////
/// @notice The IP asset has already been registered.
error IPAssetRegistry__AlreadyRegistered();
/// @notice The IP account has already been created.
error IPAssetRegistry__IPAccountAlreadyCreated();
/// @notice The IP asset has not yet been registered.
error IPAssetRegistry__NotYetRegistered();
/// @notice The specified IP resolver is not valid.
error IPAssetRegistry__ResolverInvalid();
/// @notice Caller not authorized to perform the IP registry function call.
error IPAssetRegistry__Unauthorized();
/// @notice The deployed address of account doesn't match with IP ID.
error IPAssetRegistry__InvalidAccount();
/// @notice The metadata provider is not valid.
error IPAssetRegistry__InvalidMetadataProvider();
////////////////////////////////////////////////////////////////////////////
// IPResolver ///
////////////////////////////////////////////////////////////////////////////
/// @notice The targeted IP does not yet have an IP account.
error IPResolver_InvalidIP();
/// @notice Caller not authorized to perform the IP resolver function call.
error IPResolver_Unauthorized();
////////////////////////////////////////////////////////////////////////////
// Metadata Provider ///
////////////////////////////////////////////////////////////////////////////
/// @notice Provided hash metadata is not valid.
error MetadataProvider__HashInvalid();
/// @notice The caller is not the authorized IP asset owner.
error MetadataProvider__IPAssetOwnerInvalid();
/// @notice Provided hash metadata is not valid.
error MetadataProvider__NameInvalid();
/// @notice The new metadata provider is not compatible with the old provider.
error MetadataProvider__MetadataNotCompatible();
/// @notice Provided registrant metadata is not valid.
error MetadataProvider__RegistrantInvalid();
/// @notice Provided registration date is not valid.
error MetadataProvider__RegistrationDateInvalid();
/// @notice Caller does not access to set metadata storage for the provider.
error MetadataProvider__Unauthorized();
/// @notice A metadata provider upgrade is not currently available.
error MetadataProvider__UpgradeUnavailable();
/// @notice The upgrade provider is not valid.
error MetadataProvider__UpgradeProviderInvalid();
/// @notice Provided metadata URI is not valid.
error MetadataProvider__URIInvalid();
////////////////////////////////////////////////////////////////////////////
// LicenseRegistry //
////////////////////////////////////////////////////////////////////////////
error LicenseRegistry__PolicyAlreadySetForIpId();
error LicenseRegistry__FrameworkNotFound();
error LicenseRegistry__EmptyLicenseUrl();
error LicenseRegistry__InvalidPolicyFramework();
error LicenseRegistry__PolicyAlreadyAdded();
error LicenseRegistry__ParamVerifierLengthMismatch();
error LicenseRegistry__PolicyNotFound();
error LicenseRegistry__NotLicensee();
error LicenseRegistry__ParentIdEqualThanChild();
error LicenseRegistry__LicensorDoesntHaveThisPolicy();
error LicenseRegistry__MintLicenseParamFailed();
error LicenseRegistry__LinkParentParamFailed();
error LicenseRegistry__TransferParamFailed();
error LicenseRegistry__InvalidLicensor();
error LicenseRegistry__ParamVerifierAlreadySet();
error LicenseRegistry__CommercialTermInNonCommercialPolicy();
error LicenseRegistry__EmptyParamName();
error LicenseRegistry__UnregisteredFrameworkAddingPolicy();
error LicenseRegistry__UnauthorizedAccess();
error LicenseRegistry__LicensorNotRegistered();
error LicenseRegistry__CallerNotLicensorAndPolicyNotSet();
////////////////////////////////////////////////////////////////////////////
// LicenseRegistryAware //
////////////////////////////////////////////////////////////////////////////
error LicenseRegistryAware__CallerNotLicenseRegistry();
////////////////////////////////////////////////////////////////////////////
// PolicyFrameworkManager //
////////////////////////////////////////////////////////////////////////////
error PolicyFrameworkManager__GettingPolicyWrongFramework();
////////////////////////////////////////////////////////////////////////////
// LicensorApprovalChecker //
////////////////////////////////////////////////////////////////////////////
error LicensorApprovalChecker__Unauthorized();
////////////////////////////////////////////////////////////////////////////
// Dispute Module //
////////////////////////////////////////////////////////////////////////////
error DisputeModule__ZeroArbitrationPolicy();
error DisputeModule__ZeroArbitrationRelayer();
error DisputeModule__ZeroDisputeTag();
error DisputeModule__ZeroLinkToDisputeEvidence();
error DisputeModule__NotWhitelistedArbitrationPolicy();
error DisputeModule__NotWhitelistedDisputeTag();
error DisputeModule__NotWhitelistedArbitrationRelayer();
error DisputeModule__NotDisputeInitiator();
error DisputeModule__NotInDisputeState();
error DisputeModule__NotAbleToResolve();
error ArbitrationPolicySP__ZeroDisputeModule();
error ArbitrationPolicySP__ZeroPaymentToken();
error ArbitrationPolicySP__NotDisputeModule();
////////////////////////////////////////////////////////////////////////////
// Royalty Module //
////////////////////////////////////////////////////////////////////////////
error RoyaltyModule__ZeroRoyaltyPolicy();
error RoyaltyModule__NotWhitelistedRoyaltyPolicy();
error RoyaltyModule__AlreadySetRoyaltyPolicy();
error RoyaltyModule__ZeroRoyaltyToken();
error RoyaltyModule__NotWhitelistedRoyaltyToken();
error RoyaltyModule__NoRoyaltyPolicySet();
error RoyaltyModule__IncompatibleRoyaltyPolicy();
error RoyaltyPolicyLS__ZeroRoyaltyModule();
error RoyaltyPolicyLS__ZeroLiquidSplitFactory();
error RoyaltyPolicyLS__ZeroLiquidSplitMain();
error RoyaltyPolicyLS__NotRoyaltyModule();
error RoyaltyPolicyLS__TransferFailed();
error RoyaltyPolicyLS__InvalidMinRoyalty();
error RoyaltyPolicyLS__InvalidRoyaltyStack();
error RoyaltyPolicyLS__ZeroMinRoyalty();
error RoyaltyPolicyLS__ZeroLicenseRegistry();
error LSClaimer__InvalidPath();
error LSClaimer__InvalidPathFirstPosition();
error LSClaimer__InvalidPathLastPosition();
error LSClaimer__AlreadyClaimed();
error LSClaimer__ZeroRNFT();
error LSClaimer__RNFTAlreadySet();
error LSClaimer__ETHBalanceNotZero();
error LSClaimer__ERC20BalanceNotZero();
error LSClaimer__ZeroIpId();
error LSClaimer__ZeroLicenseRegistry();
error LSClaimer__ZeroRoyaltyPolicyLS();
error LSClaimer__NotRoyaltyPolicyLS();
////////////////////////////////////////////////////////////////////////////
// ModuleRegistry //
////////////////////////////////////////////////////////////////////////////
error ModuleRegistry__ModuleAddressZeroAddress();
error ModuleRegistry__ModuleAddressNotContract();
error ModuleRegistry__ModuleAlreadyRegistered();
error ModuleRegistry__NameEmptyString();
error ModuleRegistry__NameAlreadyRegistered();
error ModuleRegistry__NameDoesNotMatch();
error ModuleRegistry__ModuleNotRegistered();
////////////////////////////////////////////////////////////////////////////
// RegistrationModule //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not the owner of the root IP NFT.
error RegistrationModule__InvalidOwner();
////////////////////////////////////////////////////////////////////////////
// AccessController //
////////////////////////////////////////////////////////////////////////////
error AccessController__IPAccountIsZeroAddress();
error AccessController__IPAccountIsNotValid();
error AccessController__SignerIsZeroAddress();
error AccessController__CallerIsNotIPAccount();
error AccessController__PermissionIsNotValid();
////////////////////////////////////////////////////////////////////////////
// TaggingModule //
////////////////////////////////////////////////////////////////////////////
error TaggingModule__InvalidRelationTypeName();
error TaggingModule__RelationTypeAlreadyExists();
error TaggingModule__SrcIpIdDoesNotHaveSrcTag();
error TaggingModule__DstIpIdDoesNotHaveDstTag();
error TaggingModule__RelationTypeDoesNotExist();
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IModule } from "contracts/interfaces/modules/base/IModule.sol";
/// @notice Resolver Interface
interface IResolver is IModule {
/// @notice Checks whether the resolver IP interface is supported.
function supportsInterface(bytes4 id) view external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/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
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: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
/// @title Interface for IP Account Registry
/// @notice This interface manages the registration and tracking of IP Accounts
interface IIPAccountRegistry {
/// @notice Event emitted when a new IP Account is created
/// @param account The address of the new IP Account
/// @param implementation The address of the IP Account implementation
/// @param chainId The chain ID where the token contract deployed
/// @param tokenContract The address of the token contract associated with the IP Account
/// @param tokenId The ID of the token associated with the IP Account
event IPAccountRegistered(
address indexed account,
address indexed implementation,
uint256 indexed chainId,
address tokenContract,
uint256 tokenId
);
/// @notice Deploys an IPAccount contract with the IPAccount implementation and returns the address of the new IP
/// @dev The IPAccount deployment deltegates to public ERC6551 Registry
/// @param chainId_ The chain ID where the token contract deployed
/// @param tokenContract_ The address of the token contract to be associated with the IP Account
/// @param tokenId_ The ID of the token to be associated with the IP Account
/// @return The address of the newly created IP Account
function registerIpAccount(
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) external returns (address);
/// @notice Returns the IPAccount address for the given NFT token
/// @param chainId_ The chain ID where the token contract deployed
/// @param tokenContract_ The address of the token contract associated with the IP Account
/// @param tokenId_ The ID of the token associated with the IP Account
/// @return The address of the IP Account associated with the given NFT token
function ipAccount(
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) external view returns (address);
/// @notice Returns the IPAccount implementation address
/// @return The address of the IPAccount implementation
function getIPAccountImpl() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC6551Registry {
/**
* @dev The registry MUST emit the ERC6551AccountCreated event upon successful account creation.
*/
event ERC6551AccountCreated(
address account,
address indexed implementation,
bytes32 salt,
uint256 chainId,
address indexed tokenContract,
uint256 indexed tokenId
);
/**
* @dev The registry MUST revert with AccountCreationFailed error if the create2 operation fails.
*/
error AccountCreationFailed();
/**
* @dev Creates a token bound account for a non-fungible token.
*
* If account has already been created, returns the account address without calling create2.
*
* Emits ERC6551AccountCreated event.
*
* @return account The address of the token bound account
*/
function createAccount(
address implementation,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external returns (address account);
/**
* @dev Returns the computed token bound account address for a non-fungible token.
*
* @return account The address of the token bound account
*/
function account(
address implementation,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external view returns (address account);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
/// @title IP Library
/// @notice Library for constants, structs, and helper functions used for IP.
library IP {
/// @notice Core metadata to associate with each IP.
struct MetadataV1 {
// The name associated with the IP.
string name;
// A keccak-256 hash of the IP content.
bytes32 hash;
// The date which the IP was registered.
uint64 registrationDate;
// The address of the initial IP registrant.
address registrant;
// An external URI associated with the IP.
string uri;
}
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IP } from "contracts/lib/IP.sol";
import { IIPAccount } from "contracts/interfaces/IIPAccount.sol";
import { IMetadataProvider } from "contracts/interfaces/registries/metadata/IMetadataProvider.sol";
import { IMetadataProviderMigratable } from "contracts/interfaces/registries/metadata/IMetadataProviderMigratable.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { IPAssetRegistry } from "contracts/registries/IPAssetRegistry.sol";
/// @title IP Metadata Provider Base Contract
/// @notice Metadata provider base contract for storing canonical IP metadata.
abstract contract MetadataProviderBase is IMetadataProviderMigratable {
/// @notice Gets the protocol-wide IP asset registry.
IPAssetRegistry public immutable IP_ASSET_REGISTRY;
/// @notice Returns the new metadata provider users may migrate to.
IMetadataProvider public upgradeProvider;
/// @notice Maps IP assets (via their IP ID) to their canonical metadata.
mapping(address ip => bytes metadata) internal _ipMetadata;
/// @notice Restricts calls to only originate from a protocol-authorized caller.
modifier onlyIPAssetRegistry {
if (msg.sender != address(IP_ASSET_REGISTRY)) {
revert Errors.MetadataProvider__Unauthorized();
}
_;
}
/// @notice Initializes the metadata provider contract.
/// @param ipAssetRegistry The protocol-wide IP asset registry.
constructor(address ipAssetRegistry) {
IP_ASSET_REGISTRY = IPAssetRegistry(ipAssetRegistry);
}
/// @notice Gets the IP metadata associated with an IP asset based on its IP ID.
/// @param ipId The IP id of the target IP asset.
function getMetadata(address ipId) external view virtual override returns (bytes memory) {
return _ipMetadata[ipId];
}
/// @notice Sets a upgrade provider for users to migrate their metadata to.
/// @param provider The address of the new metadata provider to migrate to.
function setUpgradeProvider(address provider) external onlyIPAssetRegistry {
if (provider == address(0)) {
revert Errors.MetadataProvider__UpgradeProviderInvalid();
}
// TODO: We may want to add interface detection here if auth changes.
upgradeProvider = IMetadataProviderMigratable(provider);
}
/// @notice Upgrades the metadata provider of an IP asset.
/// @param ipId The IP id of the target IP asset.
/// @param metadata The existing metadata paired with new metadata to add.
function upgrade(address payable ipId, bytes memory metadata) external override {
if (address(upgradeProvider) == address(0)) {
revert Errors.MetadataProvider__UpgradeUnavailable();
}
// TODO: Provide more flexible IPAsset authorization via access controller.
if (msg.sender != IIPAccount(ipId).owner()) {
revert Errors.MetadataProvider__IPAssetOwnerInvalid();
}
if (!_compatible(_ipMetadata[ipId], metadata)) {
revert Errors.MetadataProvider__MetadataNotCompatible();
}
IP_ASSET_REGISTRY.setMetadata(ipId, address(upgradeProvider), metadata);
}
/// @notice Sets the IP metadata associated with an IP asset based on its IP ID.
/// @param ipId The IP id of the IP asset to set metadata for.
/// @param data The metadata in bytes to set for the IP asset.
function setMetadata(address ipId, bytes memory data) external virtual onlyIPAssetRegistry {
_verifyMetadata(data);
_ipMetadata[ipId] = data;
emit MetadataSet(ipId, data);
}
/// @dev Checks that the data conforms to the canonical metadata standards.
/// @param data The canonical metadata in bytes to verify.
function _verifyMetadata(bytes memory data) internal virtual;
/// @dev Checks whether two sets of metadata are compatible with one another.
/// @param m1 The first set of bytes metadata being compared.
/// @param m2 The second set of bytes metadata being compared.
function _compatible(bytes memory m1, bytes memory m2) internal virtual pure returns (bool);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
/// @notice Module Interface
interface IModule {
/// @notice Returns the string identifier associated with the module.
function name() external returns (string memory);
}{
"remappings": [
"@openzeppelin/=node_modules/@openzeppelin/",
"base64-sol/=node_modules/base64-sol/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"openzeppelin-contracts/=lib/reference/lib/openzeppelin-contracts/",
"reference/=lib/reference/"
],
"optimizer": {
"enabled": true,
"runs": 20000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {
"contracts/lib/registries/IPAccountChecker.sol": {
"IPAccountChecker": "0x4687d14d30ea46a60499c2dcc07a56d2d1590fc3"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"accessController","type":"address"},{"internalType":"address","name":"erc6551Registry","type":"address"},{"internalType":"address","name":"ipAccountImpl","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"IPAccountRegistry_InvalidIpAccountImpl","type":"error"},{"inputs":[],"name":"IPAssetRegistry__AlreadyRegistered","type":"error"},{"inputs":[],"name":"IPAssetRegistry__InvalidAccount","type":"error"},{"inputs":[],"name":"IPAssetRegistry__NotYetRegistered","type":"error"},{"inputs":[],"name":"IPAssetRegistry__Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"implementation","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"IPAccountRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ipId","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenContract","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"resolver","type":"address"},{"indexed":false,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"IPRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ipId","type":"address"},{"indexed":false,"internalType":"address","name":"resolver","type":"address"}],"name":"IPResolverSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":true,"internalType":"address","name":"metadataProvider","type":"address"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"MetadataSet","type":"event"},{"inputs":[],"name":"ACCESS_CONTROLLER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERC6551_PUBLIC_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IP_ACCOUNT_IMPL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IP_ACCOUNT_SALT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIPAccountImpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId_","type":"uint256"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"ipAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ipId","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"id","type":"address"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"id","type":"address"}],"name":"metadata","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"id","type":"address"}],"name":"metadataProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"resolverAddr","type":"address"},{"internalType":"bool","name":"createAccount","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"register","outputs":[{"internalType":"address","name":"id","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId_","type":"uint256"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"registerIpAccount","outputs":[{"internalType":"address","name":"ipAccountAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"id","type":"address"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"id","type":"address"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMetadataProvider","type":"address"}],"name":"setMetadataProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"id","type":"address"},{"internalType":"address","name":"resolverAddr","type":"address"}],"name":"setResolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610100604052600080553480156200001657600080fd5b506040516200297a3803806200297a833981016040819052620000399162000126565b8183826001600160a01b0381166200006457604051638f54663f60e01b815260040160405180910390fd5b6001600160a01b03908116608052600060a05291821660c0521660e052600180546001600160a01b031916331790556040513090620000a390620000fb565b6001600160a01b039091168152602001604051809103906000f080158015620000d0573d6000803e3d6000fd5b50600380546001600160a01b0319166001600160a01b03929092169190911790555062000170915050565b6111ac80620017ce83390190565b80516001600160a01b03811681146200012157600080fd5b919050565b6000806000606084860312156200013c57600080fd5b620001478462000109565b9250620001576020850162000109565b9150620001676040850162000109565b90509250925092565b60805160a05160c05160e0516115e5620001e96000396000818161021b01526109bd0152600081816101b601528181610b020152610f040152600081816101f401528181610ac30152610ec5015260008181610262015281816102d401528181610a9b01528181610c180152610e9d01526115e56000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c806364b09402116100b25780639787b61811610081578063d26bb83f11610066578063d26bb83f14610382578063d3d72d2a14610395578063db4fdb31146103b357600080fd5b80639787b618146102f8578063c3c5a5471461033457600080fd5b806364b0940214610299578063689c275a146102ac57806387020f95146102bf57806395a3dfb2146102d257600080fd5b80631a8bb07b116101095780632ba21572116100ee5780632ba215721461023d5780635796ffbc1461025d578063597e99cb1461028457600080fd5b80631a8bb07b146101ef5780631b8b10731461021657600080fd5b8063015c15801461013b57806306d61f3d1461019e5780630c3c7264146101b157806318160ddd146101d8575b600080fd5b61017461014936600461110b565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600260205260409020541690565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101746101ac366004611171565b6103c6565b6101747f000000000000000000000000000000000000000000000000000000000000000081565b6101e160005481565b604051908152602001610195565b6101e17f000000000000000000000000000000000000000000000000000000000000000081565b6101747f000000000000000000000000000000000000000000000000000000000000000081565b61025061024b36600461110b565b610582565b6040516101959190611229565b6101747f000000000000000000000000000000000000000000000000000000000000000081565b61029761029236600461127a565b6106af565b005b6102976102a736600461110b565b6107f1565b6102976102ba3660046112b3565b61090f565b6101746102cd366004611318565b610981565b7f0000000000000000000000000000000000000000000000000000000000000000610174565b61017461030636600461110b565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600260205260409020600101541690565b61037261034236600461110b565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526002602052604090206001015416151590565b6040519015158152602001610195565b610174610390366004611318565b610996565b60035473ffffffffffffffffffffffffffffffffffffffff16610174565b6101746103c1366004611318565b6109a3565b60006103d3888888610996565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600260205260409020600101549192501615610438576040517f8325658800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163b15801561045a5750835b801561049c575061046c8888886109a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b156104d3576040517f596edc1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104dd8186610c73565b60035461050390829073ffffffffffffffffffffffffffffffffffffffff168585610d31565b60008054908061051283611350565b9091555050600354604051879173ffffffffffffffffffffffffffffffffffffffff808b16928c927fa3028b46ff4aeba585ebfa1c241ad4a453b6f10dc7bc3d3ebaa9cecc680a6f719261056f9288928d9216908b908b906113f8565b60405180910390a4979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260026020526040902054606091166105e3576040517f1b7bf33a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600081815260026020526040908190205490517f2a50c146000000000000000000000000000000000000000000000000000000008152600481019290925290911690632a50c14690602401600060405180830381865afa158015610663573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106a99190810190611469565b92915050565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526002602052604090206001015416610710576040517f1b7bf33a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561075b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190611529565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107e3576040517faa24098a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107ed8282610c73565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610842576040517faa24098a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003546040517f9c1bbc0300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015290911690639c1bbc0390602401600060405180830381600087803b1580156108af57600080fd5b505af11580156108c3573d6000803e3d6000fd5b5050600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555050565b73ffffffffffffffffffffffffffffffffffffffff84811660009081526002602052604090205416331461096f576040517faa24098a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61097b84848484610d31565b50505050565b600061098e848484610e60565b949350505050565b600061098e848484610981565b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc4d66de800000000000000000000000000000000000000000000000000000000179052517f8a54c52f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527f00000000000000000000000000000000000000000000000000000000000000006024830152604482018890528681166064830152608482018690529192507f000000000000000000000000000000000000000000000000000000000000000090911690638a54c52f9060a4016020604051808303816000875af1158015610b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b719190611529565b91506000808373ffffffffffffffffffffffffffffffffffffffff1683604051610b9b9190611546565b6000604051808303816000865af19150503d8060008114610bd8576040519150601f19603f3d011682016040523d82523d6000602084013e610bdd565b606091505b509150915081610bef57805160208201fd5b6040805173ffffffffffffffffffffffffffffffffffffffff88811682526020820188905289927f0000000000000000000000000000000000000000000000000000000000000000821692918816917f5be70b68c8361762980ec7d425d79fd33f6d49cac8a498e6ddf514f995b987f7910160405180910390a45050509392505050565b610c9d817f01ffc9a700000000000000000000000000000000000000000000000000000000610f71565b5073ffffffffffffffffffffffffffffffffffffffff82811660008181526002602090815260409182902060010180547fffffffffffffffffffffffff000000000000000000000000000000000000000016948616948517905581519283528201929092527f45d82cad942fa2e4cfe12a8e0c0b8ecb938b1c95496042dc75f0ecf94cc794f2910160405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152600260205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169286169283179055517f9fd8b5fa000000000000000000000000000000000000000000000000000000008152639fd8b5fa90610dc190879086908690600401611562565b600060405180830381600087803b158015610ddb57600080fd5b505af1158015610def573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f9c8e2e143101fc3123c702e45f91bf26ceec5c14066c4577b98299d3c7ef61f78484604051610e5292919061159b565b60405180910390a350505050565b6040517f246a002100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527f00000000000000000000000000000000000000000000000000000000000000006024830152604482018590528381166064830152608482018390526000917f00000000000000000000000000000000000000000000000000000000000000009091169063246a00219060a401602060405180830381865afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098e9190611529565b6000610f7c83610f94565b8015610f8d5750610f8d8383610ff8565b9392505050565b6000610fc0827f01ffc9a700000000000000000000000000000000000000000000000000000000610ff8565b80156106a95750610ff1827fffffffff00000000000000000000000000000000000000000000000000000000610ff8565b1592915050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d915060005190508280156110cf575060208210155b80156110db5750600081115b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461110857600080fd5b50565b60006020828403121561111d57600080fd5b8135610f8d816110e6565b60008083601f84011261113a57600080fd5b50813567ffffffffffffffff81111561115257600080fd5b60208301915083602082850101111561116a57600080fd5b9250929050565b600080600080600080600060c0888a03121561118c57600080fd5b87359650602088013561119e816110e6565b95506040880135945060608801356111b5816110e6565b9350608088013580151581146111ca57600080fd5b925060a088013567ffffffffffffffff8111156111e657600080fd5b6111f28a828b01611128565b989b979a50959850939692959293505050565b60005b83811015611220578181015183820152602001611208565b50506000910152565b6020815260008251806020840152611248816040850160208701611205565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000806040838503121561128d57600080fd5b8235611298816110e6565b915060208301356112a8816110e6565b809150509250929050565b600080600080606085870312156112c957600080fd5b84356112d4816110e6565b935060208501356112e4816110e6565b9250604085013567ffffffffffffffff81111561130057600080fd5b61130c87828801611128565b95989497509550505050565b60008060006060848603121561132d57600080fd5b83359250602084013561133f816110e6565b929592945050506040919091013590565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036113a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600073ffffffffffffffffffffffffffffffffffffffff80881683528087166020840152808616604084015250608060608301526110db6080830184866113af565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561147b57600080fd5b815167ffffffffffffffff8082111561149357600080fd5b818401915084601f8301126114a757600080fd5b8151818111156114b9576114b961143a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156114ff576114ff61143a565b8160405282815287602084870101111561151857600080fd5b6110db836020830160208801611205565b60006020828403121561153b57600080fd5b8151610f8d816110e6565b60008251611558818460208701611205565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082015260006115926040830184866113af565b95945050505050565b60208152600061098e6020830184866113af56fea26469706673582212201fd527ecf2928fa0f7b4b50e63747920075cab3a57235922516aafb9dd2a92a564736f6c6343000817003360a060405234801561001057600080fd5b506040516111ac3803806111ac83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161110c6100a06000396000818161010f0152818161033101528181610434015261077c015261110c6000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80639c1bbc0311610081578063c29fab6d1161005b578063c29fab6d146101de578063c987336c146101f1578063d091b7c21461020457600080fd5b80639c1bbc031461018a5780639fd8b5fa1461019f578063a2911fcd146101b257600080fd5b806341c782c5116100b257806341c782c51461010a578063426eb017146101565780637e8099731461016957600080fd5b806301984892146100ce5780632a50c146146100f7575b600080fd5b6100e16100dc366004610ac1565b610224565b6040516100ee9190610b53565b60405180910390f35b6100e1610105366004610ac1565b610236565b6101317f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ee565b6100e1610164366004610ac1565b6102ef565b61017c610177366004610ac1565b610304565b6040519081526020016100ee565b61019d610198366004610ac1565b610319565b005b61019d6101ad366004610ca9565b61041c565b6101c56101c0366004610ac1565b610501565b60405167ffffffffffffffff90911681526020016100ee565b6101316101ec366004610ac1565b610516565b61019d6101ff366004610ca9565b61052b565b6000546101319073ffffffffffffffffffffffffffffffffffffffff1681565b606061022f826107ec565b5192915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260016020526040902080546060919061026a90610cf9565b80601f016020809104026020016040519081016040528092919081815260200182805461029690610cf9565b80156102e35780601f106102b8576101008083540402835291602001916102e3565b820191906000526020600020905b8154815290600101906020018083116102c657829003601f168201915b50505050509050919050565b60606102fa826107ec565b6080015192915050565b600061030f826107ec565b6020015192915050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610388576040517f94b1485700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166103d5576040517f4c80890800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461048b576040517f94b1485700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610494816108e0565b73ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090206104c38282610d99565b507feb93c52781456784fc831a72052881602fbd4b0251d0715f7e0852cdec233d1e82826040516104f5929190610eb3565b60405180910390a15050565b600061050c826107ec565b6040015192915050565b6000610521826107ec565b6060015192915050565b60005473ffffffffffffffffffffffffffffffffffffffff1661057a576040517fe88f0e8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e99190610efa565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461064d576040517f425ec99900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090208054610706919061068290610cf9565b80601f01602080910402602001604051908101604052809291908181526020018280546106ae90610cf9565b80156106fb5780601f106106d0576101008083540402835291602001916106fb565b820191906000526020600020905b8154815290600101906020018083116106de57829003601f168201915b505050505082610a07565b61073c576040517fbe1f6fe500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546040517f689c275a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169263689c275a926107b692879216908690600401610f17565b600060405180830381600087803b1580156107d057600080fd5b505af11580156107e4573d6000803e3d6000fd5b505050505050565b6040805160a081018252606080825260006020830181905292820183905280820192909252608081019190915273ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020805461084990610cf9565b80601f016020809104026020016040519081016040528092919081815260200182805461087590610cf9565b80156108c25780601f10610897576101008083540402835291602001916108c2565b820191906000526020600020905b8154815290600101906020018083116108a557829003601f168201915b50505050508060200190518101906108da9190610fb6565b92915050565b6000818060200190518101906108f69190610fb6565b805151909150600003610935576040517f281d076900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060200151600003610973576040517f293bb8c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081015173ffffffffffffffffffffffffffffffffffffffff166109c4576040517fc3af260700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806080015151600003610a03576040517f439192a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60008083806020019051810190610a1e9190610fb6565b9050600083806020019051810190610a369190610fb6565b9050610a4181610a54565b610a4a83610a54565b1495945050505050565b8051602080830151604080850151606086015160808701519251600096610a7f969095949101611073565b604051602081830303815290604052805190602001209050919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610abe57600080fd5b50565b600060208284031215610ad357600080fd5b8135610ade81610a9c565b9392505050565b60005b83811015610b00578181015183820152602001610ae8565b50506000910152565b60008151808452610b21816020860160208601610ae5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610ade6020830184610b09565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715610bb857610bb8610b66565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c0557610c05610b66565b604052919050565b600067ffffffffffffffff821115610c2757610c27610b66565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610c6457600080fd5b8135610c77610c7282610c0d565b610bbe565b818152846020838601011115610c8c57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215610cbc57600080fd5b8235610cc781610a9c565b9150602083013567ffffffffffffffff811115610ce357600080fd5b610cef85828601610c53565b9150509250929050565b600181811c90821680610d0d57607f821691505b602082108103610d46577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610d94576000816000526020600020601f850160051c81016020861015610d755750805b601f850160051c820191505b818110156107e457828155600101610d81565b505050565b815167ffffffffffffffff811115610db357610db3610b66565b610dc781610dc18454610cf9565b84610d4c565b602080601f831160018114610e1a5760008415610de45750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556107e4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610e6757888601518255948401946001909101908401610e48565b5085821015610ea357878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610ee26040830184610b09565b949350505050565b8051610ef581610a9c565b919050565b600060208284031215610f0c57600080fd5b8151610ade81610a9c565b600073ffffffffffffffffffffffffffffffffffffffff808616835280851660208401525060606040830152610f506060830184610b09565b95945050505050565b600082601f830112610f6a57600080fd5b8151610f78610c7282610c0d565b818152846020838601011115610f8d57600080fd5b610ee2826020830160208701610ae5565b805167ffffffffffffffff81168114610ef557600080fd5b600060208284031215610fc857600080fd5b815167ffffffffffffffff80821115610fe057600080fd5b9083019060a08286031215610ff457600080fd5b610ffc610b95565b82518281111561100b57600080fd5b61101787828601610f59565b8252506020830151602082015261103060408401610f9e565b604082015261104160608401610eea565b606082015260808301518281111561105857600080fd5b61106487828601610f59565b60808301525095945050505050565b60a08152600061108660a0830188610b09565b86602084015267ffffffffffffffff8616604084015273ffffffffffffffffffffffffffffffffffffffff8516606084015282810360808401526110ca8185610b09565b9897505050505050505056fea2646970667358221220114b38e05040f1206bac623a3e06c0ac49ab2bbba254abe78e27eca0fddc769964736f6c63430008170033000000000000000000000000031400de2e7694898eab1936868e77e88e240de9000000000000000000000000000000006551c19487814612e58fe0681377575800000000000000000000000034aa510361a47b1ec6bcd4cf8a480c8324354208
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101365760003560e01c806364b09402116100b25780639787b61811610081578063d26bb83f11610066578063d26bb83f14610382578063d3d72d2a14610395578063db4fdb31146103b357600080fd5b80639787b618146102f8578063c3c5a5471461033457600080fd5b806364b0940214610299578063689c275a146102ac57806387020f95146102bf57806395a3dfb2146102d257600080fd5b80631a8bb07b116101095780632ba21572116100ee5780632ba215721461023d5780635796ffbc1461025d578063597e99cb1461028457600080fd5b80631a8bb07b146101ef5780631b8b10731461021657600080fd5b8063015c15801461013b57806306d61f3d1461019e5780630c3c7264146101b157806318160ddd146101d8575b600080fd5b61017461014936600461110b565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600260205260409020541690565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101746101ac366004611171565b6103c6565b6101747f000000000000000000000000000000006551c19487814612e58fe0681377575881565b6101e160005481565b604051908152602001610195565b6101e17f000000000000000000000000000000000000000000000000000000000000000081565b6101747f000000000000000000000000031400de2e7694898eab1936868e77e88e240de981565b61025061024b36600461110b565b610582565b6040516101959190611229565b6101747f00000000000000000000000034aa510361a47b1ec6bcd4cf8a480c832435420881565b61029761029236600461127a565b6106af565b005b6102976102a736600461110b565b6107f1565b6102976102ba3660046112b3565b61090f565b6101746102cd366004611318565b610981565b7f00000000000000000000000034aa510361a47b1ec6bcd4cf8a480c8324354208610174565b61017461030636600461110b565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600260205260409020600101541690565b61037261034236600461110b565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526002602052604090206001015416151590565b6040519015158152602001610195565b610174610390366004611318565b610996565b60035473ffffffffffffffffffffffffffffffffffffffff16610174565b6101746103c1366004611318565b6109a3565b60006103d3888888610996565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600260205260409020600101549192501615610438576040517f8325658800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163b15801561045a5750835b801561049c575061046c8888886109a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b156104d3576040517f596edc1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104dd8186610c73565b60035461050390829073ffffffffffffffffffffffffffffffffffffffff168585610d31565b60008054908061051283611350565b9091555050600354604051879173ffffffffffffffffffffffffffffffffffffffff808b16928c927fa3028b46ff4aeba585ebfa1c241ad4a453b6f10dc7bc3d3ebaa9cecc680a6f719261056f9288928d9216908b908b906113f8565b60405180910390a4979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260026020526040902054606091166105e3576040517f1b7bf33a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600081815260026020526040908190205490517f2a50c146000000000000000000000000000000000000000000000000000000008152600481019290925290911690632a50c14690602401600060405180830381865afa158015610663573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106a99190810190611469565b92915050565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526002602052604090206001015416610710576040517f1b7bf33a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561075b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190611529565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107e3576040517faa24098a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107ed8282610c73565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610842576040517faa24098a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003546040517f9c1bbc0300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015290911690639c1bbc0390602401600060405180830381600087803b1580156108af57600080fd5b505af11580156108c3573d6000803e3d6000fd5b5050600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555050565b73ffffffffffffffffffffffffffffffffffffffff84811660009081526002602052604090205416331461096f576040517faa24098a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61097b84848484610d31565b50505050565b600061098e848484610e60565b949350505050565b600061098e848484610981565b60405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000031400de2e7694898eab1936868e77e88e240de91660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc4d66de800000000000000000000000000000000000000000000000000000000179052517f8a54c52f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000034aa510361a47b1ec6bcd4cf8a480c8324354208811660048301527f00000000000000000000000000000000000000000000000000000000000000006024830152604482018890528681166064830152608482018690529192507f000000000000000000000000000000006551c19487814612e58fe0681377575890911690638a54c52f9060a4016020604051808303816000875af1158015610b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b719190611529565b91506000808373ffffffffffffffffffffffffffffffffffffffff1683604051610b9b9190611546565b6000604051808303816000865af19150503d8060008114610bd8576040519150601f19603f3d011682016040523d82523d6000602084013e610bdd565b606091505b509150915081610bef57805160208201fd5b6040805173ffffffffffffffffffffffffffffffffffffffff88811682526020820188905289927f00000000000000000000000034aa510361a47b1ec6bcd4cf8a480c8324354208821692918816917f5be70b68c8361762980ec7d425d79fd33f6d49cac8a498e6ddf514f995b987f7910160405180910390a45050509392505050565b610c9d817f01ffc9a700000000000000000000000000000000000000000000000000000000610f71565b5073ffffffffffffffffffffffffffffffffffffffff82811660008181526002602090815260409182902060010180547fffffffffffffffffffffffff000000000000000000000000000000000000000016948616948517905581519283528201929092527f45d82cad942fa2e4cfe12a8e0c0b8ecb938b1c95496042dc75f0ecf94cc794f2910160405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff8481166000908152600260205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169286169283179055517f9fd8b5fa000000000000000000000000000000000000000000000000000000008152639fd8b5fa90610dc190879086908690600401611562565b600060405180830381600087803b158015610ddb57600080fd5b505af1158015610def573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f9c8e2e143101fc3123c702e45f91bf26ceec5c14066c4577b98299d3c7ef61f78484604051610e5292919061159b565b60405180910390a350505050565b6040517f246a002100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000034aa510361a47b1ec6bcd4cf8a480c8324354208811660048301527f00000000000000000000000000000000000000000000000000000000000000006024830152604482018590528381166064830152608482018390526000917f000000000000000000000000000000006551c19487814612e58fe068137757589091169063246a00219060a401602060405180830381865afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098e9190611529565b6000610f7c83610f94565b8015610f8d5750610f8d8383610ff8565b9392505050565b6000610fc0827f01ffc9a700000000000000000000000000000000000000000000000000000000610ff8565b80156106a95750610ff1827fffffffff00000000000000000000000000000000000000000000000000000000610ff8565b1592915050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d915060005190508280156110cf575060208210155b80156110db5750600081115b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461110857600080fd5b50565b60006020828403121561111d57600080fd5b8135610f8d816110e6565b60008083601f84011261113a57600080fd5b50813567ffffffffffffffff81111561115257600080fd5b60208301915083602082850101111561116a57600080fd5b9250929050565b600080600080600080600060c0888a03121561118c57600080fd5b87359650602088013561119e816110e6565b95506040880135945060608801356111b5816110e6565b9350608088013580151581146111ca57600080fd5b925060a088013567ffffffffffffffff8111156111e657600080fd5b6111f28a828b01611128565b989b979a50959850939692959293505050565b60005b83811015611220578181015183820152602001611208565b50506000910152565b6020815260008251806020840152611248816040850160208701611205565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000806040838503121561128d57600080fd5b8235611298816110e6565b915060208301356112a8816110e6565b809150509250929050565b600080600080606085870312156112c957600080fd5b84356112d4816110e6565b935060208501356112e4816110e6565b9250604085013567ffffffffffffffff81111561130057600080fd5b61130c87828801611128565b95989497509550505050565b60008060006060848603121561132d57600080fd5b83359250602084013561133f816110e6565b929592945050506040919091013590565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036113a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600073ffffffffffffffffffffffffffffffffffffffff80881683528087166020840152808616604084015250608060608301526110db6080830184866113af565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561147b57600080fd5b815167ffffffffffffffff8082111561149357600080fd5b818401915084601f8301126114a757600080fd5b8151818111156114b9576114b961143a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156114ff576114ff61143a565b8160405282815287602084870101111561151857600080fd5b6110db836020830160208801611205565b60006020828403121561153b57600080fd5b8151610f8d816110e6565b60008251611558818460208701611205565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082015260006115926040830184866113af565b95945050505050565b60208152600061098e6020830184866113af56fea26469706673582212201fd527ecf2928fa0f7b4b50e63747920075cab3a57235922516aafb9dd2a92a564736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000031400de2e7694898eab1936868e77e88e240de9000000000000000000000000000000006551c19487814612e58fe0681377575800000000000000000000000034aa510361a47b1ec6bcd4cf8a480c8324354208
-----Decoded View---------------
Arg [0] : accessController (address): 0x031400de2e7694898eAB1936868e77E88e240DE9
Arg [1] : erc6551Registry (address): 0x000000006551c19487814612e58FE06813775758
Arg [2] : ipAccountImpl (address): 0x34aA510361a47B1eC6bcd4cF8a480c8324354208
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000031400de2e7694898eab1936868e77e88e240de9
Arg [1] : 000000000000000000000000000000006551c19487814612e58fe06813775758
Arg [2] : 00000000000000000000000034aa510361a47b1ec6bcd4cf8a480c8324354208
Loading...
Loading
Loading...
Loading
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.