Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 19 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | Contract Creation | 0 ETH | |||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5206013 | 15 days ago | 0 ETH | ||||
5205882 | 15 days ago | 0 ETH | ||||
5205789 | 15 days ago | 0 ETH | ||||
5205789 | 15 days ago | Contract Creation | 0 ETH | |||
5205789 | 15 days ago | 0 ETH | ||||
5205789 | 15 days ago | 0 ETH | ||||
5205789 | 15 days ago | 0 ETH | ||||
5205789 | 15 days ago | 0 ETH | ||||
5205789 | 15 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ZkSignedZoneControllerV16Royalty
Compiler Version
v0.8.17+commit.8df45f5f
ZkSolc Version
v1.5.7
Optimization Enabled:
Yes with Mode 3
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {SignedZoneV16Royalty} from "./SignedZoneV16Royalty.sol"; import {ZoneInterfaceV16} from "../interfaces/ZoneInterfaceV16.sol"; import {SignedZoneInterface} from "./interfaces/SignedZoneInterface.sol"; import {SignedZoneControllerV16RoyaltyInterface} from "./interfaces/SignedZoneControllerV16RoyaltyInterface.sol"; import {SignedZoneControllerV16RoyaltyEventsAndErrors} from "./interfaces/SignedZoneControllerV16RoyaltyEventsAndErrors.sol"; import "./lib/SignedZoneV16RoyaltyConstants.sol"; /** * @title SignedZoneControllerV16Royalty * @author BCLeFevre * @notice SignedZoneControllerV16Royalty enables the deploying of SignedZones and * managing new SignedZone. * SignedZones are an implementation of SIP-7 that requires orders to * be signed by an approved signer. * https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md */ contract ZkSignedZoneControllerV16Royalty is SignedZoneControllerV16RoyaltyInterface, SignedZoneControllerV16RoyaltyEventsAndErrors { /** * @dev The struct for storing signer info. */ struct SignerInfo { /// @dev If the signer is currently active. bool active; /// @dev If the signer has been active before. bool previouslyActive; } // Properties used by the signed zone, stored on the controller. struct SignedZoneProperties { /// @dev Owner of the signed zone (used for permissioned functions) address owner; /// @dev Potential owner of the signed zone address potentialOwner; /// @dev The name for this zone returned in getSeaportMetadata(). string zoneName; /// @dev The API endpoint where orders for this zone can be signed. /// Request and response payloads are defined in SIP-7. string apiEndpoint; /// @dev The URI to the documentation describing the behavior of the /// contract. string documentationURI; /// @dev The substandards supported by this zone. /// Substandards are defined in SIP-7. uint256[] substandards; /// @dev Mapping of signer information keyed by signer Address mapping(address => SignerInfo) signers; /// @dev List of active signers address[] activeSignerList; } /// @dev Mapping of signed zone properties keyed by the Signed Zone /// address. mapping(address => SignedZoneProperties) internal _signedZones; /// @dev The EIP-712 digest parameters for the SignedZone. bytes32 internal immutable _VERSION_HASH = keccak256(bytes("2.0")); // prettier-ignore bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH = keccak256( abi.encodePacked( "EIP712Domain(", "string name,", "string version,", "uint256 chainId,", "address verifyingContract", ")" ) ); uint256 internal immutable _CHAIN_ID = block.chainid; // Set the signed zone runtime code hash as an immutable argument. bytes32 internal immutable _SIGNED_ZONE_RUNTIME_CODE_HASH; /** * @dev Initialize contract */ constructor() { // Deploy a SignedZone with the zero hash as the salt. SignedZoneV16Royalty zeroSignedZone = new SignedZoneV16Royalty{salt: bytes32(0)}(""); // Set the runtime code hash for the signed zone. _SIGNED_ZONE_RUNTIME_CODE_HASH = address(zeroSignedZone).codehash; } /** * @notice Deploy a SignedZone to a precomputed address. * * @param zoneName The name for the zone returned in * getSeaportMetadata(). * @param apiEndpoint The API endpoint where orders for this zone can * be signed. * @param documentationURI The URI to the documentation describing the * behavior of the contract. Request and response * payloads are defined in SIP-7. * @param salt The salt to be used to derive the zone address * @param initialOwner The initial owner to set for the new zone. * * @return derivedAddress The derived address for the zone. */ function createZone( string memory zoneName, string memory apiEndpoint, string memory documentationURI, address initialOwner, bytes32 salt ) external override returns (address derivedAddress) { // Ensure that an initial owner has been supplied. if (initialOwner == address(0)) { revert InvalidInitialOwner(); } // Ensure the first 20 bytes of the salt are the same as the msg.sender. if ((address(uint160(bytes20(salt))) != msg.sender)) { // Revert with an error indicating that the creator is invalid. revert InvalidCreator(); } // Derive the SignedZone address from the deployer, salt and runtime // code hash. bytes32 hash = keccak256( bytes.concat( keccak256("zksyncCreate2"), bytes32(uint256(uint160(address(this)))), salt, _SIGNED_ZONE_RUNTIME_CODE_HASH, keccak256(abi.encode(bytes(zoneName))) ) ); derivedAddress = address(uint160(uint256(hash))); // Revert if a zone is currently deployed to the derived address. if (derivedAddress.code.length != 0) { revert ZoneAlreadyExists(derivedAddress); } // Deploy the zone using the supplied salt. address signedZoneAddress = address(new SignedZoneV16Royalty{salt: salt}(zoneName)); // Ensure the derived address matches the deployed address. if (derivedAddress != signedZoneAddress) { revert ZoneAddressMismatch(signedZoneAddress, derivedAddress); } // Initialize storage variable referencing signed zone properties. SignedZoneProperties storage signedZoneProperties = _signedZones[derivedAddress]; // Set the supplied intial owner as the owner of the zone. signedZoneProperties.owner = initialOwner; // Set the zone name. signedZoneProperties.zoneName = zoneName; // Set the API endpoint. signedZoneProperties.apiEndpoint = apiEndpoint; // Set the documentation URI. signedZoneProperties.documentationURI = documentationURI; // Set the substandard. signedZoneProperties.substandards = [1, 7, 8, 9]; // Emit an event signifying that the zone was created. emit ZoneCreated(derivedAddress, zoneName, apiEndpoint, documentationURI, salt); // Emit an event indicating that zone ownership has been assigned. emit OwnershipTransferred(derivedAddress, address(0), initialOwner); } /** * @notice Initiate zone ownership transfer by assigning a new potential * owner for the given zone. Once set, the new potential owner * may call `acceptOwnership` to claim ownership of the zone. * Only the owner of the zone in question may call this function. * * @param zone The zone for which to initiate ownership * transfer. * @param newPotentialOwner The new potential owner of the zone. */ function transferOwnership(address zone, address newPotentialOwner) external override { // Ensure the caller is the current owner of the zone in question. _assertCallerIsZoneOwner(zone); // Ensure the new potential owner is not an invalid address. if (newPotentialOwner == address(0)) { revert NewPotentialOwnerIsNullAddress(zone); } // Ensure the new potential owner is not already set. if (newPotentialOwner == _signedZones[zone].potentialOwner) { revert NewPotentialOwnerAlreadySet(zone, newPotentialOwner); } // Emit an event indicating that the potential owner has been updated. emit PotentialOwnerUpdated(newPotentialOwner); // Set the new potential owner as the potential owner of the zone. _signedZones[zone].potentialOwner = newPotentialOwner; } /** * @notice Clear the currently set potential owner, if any, from a zone. * Only the owner of the zone in question may call this function. * * @param zone The zone for which to cancel ownership transfer. */ function cancelOwnershipTransfer(address zone) external override { // Ensure the caller is the current owner of the zone in question. _assertCallerIsZoneOwner(zone); // Ensure that ownership transfer is currently possible. if (_signedZones[zone].potentialOwner == address(0)) { revert NoPotentialOwnerCurrentlySet(zone); } // Emit an event indicating that the potential owner has been cleared. emit PotentialOwnerUpdated(address(0)); // Clear the current new potential owner from the zone. _signedZones[zone].potentialOwner = address(0); } /** * @notice Accept ownership of a supplied zone. Only accounts that the * current owner has set as the new potential owner may call this * function. * * @param zone The zone for which to accept ownership. */ function acceptOwnership(address zone) external override { // Ensure that the zone in question exists. _assertZoneExists(zone); // If caller does not match current potential owner of the zone... if (msg.sender != _signedZones[zone].potentialOwner) { // Revert, indicating that caller is not current potential owner. revert CallerIsNotNewPotentialOwner(zone); } // Emit an event indicating that the potential owner has been cleared. emit PotentialOwnerUpdated(address(0)); // Clear the current new potential owner from the zone. _signedZones[zone].potentialOwner = address(0); // Emit an event indicating zone ownership has been transferred. emit OwnershipTransferred(zone, _signedZones[zone].owner, msg.sender); // Set the caller as the owner of the zone. _signedZones[zone].owner = msg.sender; } /** * @notice Update the API endpoint returned by a zone. * Only the owner or an active signer of the supplied zone can call * this function. * * @param zone The signed zone to update the API endpoint for. * @param newApiEndpoint The new API endpoint. */ function updateAPIEndpoint(address zone, string calldata newApiEndpoint) external override { // Ensure the caller is the owner of the signed zone. _assertCallerIsZoneOwner(zone); // Retrieve storage region where the singers for the signedZone are // stored. SignedZoneProperties storage signedZoneProperties = _signedZones[zone]; // Update the API endpoint on the signed zone. signedZoneProperties.apiEndpoint = newApiEndpoint; } /** * @notice Update the documentationURI returned by a zone. * Only the owner or an active signer of the supplied zone can call * this function. * * @param zone The signed zone to update the documentationURI * for. * @param documentationURI The new documentation URI. */ function updateDocumentationURI( address zone, string calldata documentationURI ) external override { // Ensure the caller is the owner of the signed zone. _assertCallerIsZoneOwner(zone); // Retrieve storage region where the singers for the signedZone are // stored. SignedZoneProperties storage signedZoneProperties = _signedZones[zone]; // Update the documentationURI on the signed zone. signedZoneProperties.documentationURI = documentationURI; } /** * @notice Add or remove a signer from the supplied zone. * Only the owner or an active signer of the supplied zone can call * this function. * * @param zone The signed zone to update the signer permissions for. * @param signer The signer to update the permissions for. * @param active Whether the signer should be active or not. */ function updateSigner(address zone, address signer, bool active) external override { // Ensure the caller is the owner of the signed zone. _assertCallerIsZoneOwner(zone); // Retrieve storage region where the singers for the signedZone are // stored. SignedZoneProperties storage signedZoneProperties = _signedZones[zone]; // Validate signer permissions. _assertSignerPermissions(signedZoneProperties, signer, active); // Update the signer on the signed zone. SignedZoneInterface(zone).updateSigner(signer, active); // Update the signer information. signedZoneProperties.signers[signer].active = active; signedZoneProperties.signers[signer].previouslyActive = true; // Add the signer to the list of signers if they are active. if (active) { signedZoneProperties.activeSignerList.push(signer); } else { // Remove the signer from the list of signers. for (uint256 i = 0; i < signedZoneProperties.activeSignerList.length; ) { if (signedZoneProperties.activeSignerList[i] == signer) { signedZoneProperties.activeSignerList[i] = signedZoneProperties.activeSignerList[ signedZoneProperties.activeSignerList.length - 1 ]; signedZoneProperties.activeSignerList.pop(); break; } unchecked { ++i; } } } // Emit an event signifying that the signer was updated. emit SignerUpdated(zone, signer, active); } /** * @notice Retrieve the current owner of a deployed zone. * * @param zone The zone for which to retrieve the associated owner. * * @return owner The owner of the supplied zone. */ function ownerOf(address zone) external view override returns (address owner) { // Ensure that the zone in question exists. _assertZoneExists(zone); // Retrieve the current owner of the zone in question. owner = _signedZones[zone].owner; } /** * @notice Retrieve the potential owner, if any, for a given zone. The * current owner may set a new potential owner via * `transferOwnership` and that owner may then accept ownership of * the zone in question via `acceptOwnership`. * * @param zone The zone for which to retrieve the potential owner. * * @return potentialOwner The potential owner, if any, for the zone. */ function getPotentialOwner(address zone) external view override returns (address potentialOwner) { // Ensure that the zone in question exists. _assertZoneExists(zone); // Retrieve the current potential owner of the zone in question. potentialOwner = _signedZones[zone].potentialOwner; } /** * @notice Returns the active signers for the zone. Note that the array of * active signers could grow to a size that this function could not * return, the array of active signers is expected to be small, * and is managed by the controller. * * @param zone The zone to return the active signers for. * * @return signers The active signers. */ function getActiveSigners( address zone ) external view override returns (address[] memory signers) { // Ensure that the zone in question exists. _assertZoneExists(zone); // Retrieve storage region where the singers for the signedZone are // stored. SignedZoneProperties storage signedZoneProperties = _signedZones[zone]; // Return the active signers for the zone. signers = signedZoneProperties.activeSignerList; } /** * @notice Returns if the given address is an active signer for the zone. * * @param zone The zone to return the active signers for. * @param signer The address to check if it is an active signer. * * @return The address is an active signer, false otherwise. */ function isActiveSigner(address zone, address signer) external view override returns (bool) { // Ensure that the zone in question exists. _assertZoneExists(zone); // Retrieve storage region where the singers for the signedZone are // stored. SignedZoneProperties storage signedZoneProperties = _signedZones[zone]; // Return whether the signer is an active signer for the zone. return signedZoneProperties.signers[signer].active; } /** * @notice Derive the zone address associated with a salt. * * @param zoneName The name of the zone. * @param salt The salt to be used to derive the zone address. * * @return derivedAddress The derived address of the signed zone. */ function getZone( string memory zoneName, bytes32 salt ) external view override returns (address derivedAddress) { // Derive the SignedZoneV16 address from deployer, salt and creation code // hash. bytes32 hash = keccak256( bytes.concat( keccak256("zksyncCreate2"), bytes32(uint256(uint160(address(this)))), salt, _SIGNED_ZONE_RUNTIME_CODE_HASH, keccak256(abi.encode(bytes(zoneName))) ) ); derivedAddress = address(uint160(uint256(hash))); } /** * @notice External call to return the signing information, substandards, * and documentation about the zone. * * @return domainSeparator The domain separator used for signing. * @return zoneName The name of the zone. * @return apiEndpoint The API endpoint for the zone. * @return substandards The substandards supported by the zone. * @return documentationURI The documentation URI for the zone. */ function getAdditionalZoneInformation( address zone ) external view override returns ( bytes32 domainSeparator, string memory zoneName, string memory apiEndpoint, uint256[] memory substandards, string memory documentationURI ) { // Ensure the zone exists. _assertZoneExists(zone); // Return the zone's additional information. return _additionalZoneInformation(zone); } /** * @notice Internal call to return the signing information, substandards, * and documentation about the zone. * * @return domainSeparator The domain separator used for signing. * @return zoneName The name of the zone. * @return apiEndpoint The API endpoint for the zone. * @return substandards The substandards supported by the zone. * @return documentationURI The documentation URI for the zone. */ function _additionalZoneInformation( address zone ) internal view returns ( bytes32 domainSeparator, string memory zoneName, string memory apiEndpoint, uint256[] memory substandards, string memory documentationURI ) { // Get the zone properties. SignedZoneProperties storage signedZoneProperties = _signedZones[zone]; // Return the SIP-7 information. domainSeparator = _domainSeparator(zone); zoneName = signedZoneProperties.zoneName; apiEndpoint = signedZoneProperties.apiEndpoint; substandards = signedZoneProperties.substandards; documentationURI = signedZoneProperties.documentationURI; } /** * @dev Internal view function to get the EIP-712 domain separator. If the * chainId matches the chainId set on deployment, the cached domain * separator will be returned; otherwise, it will be derived from * scratch. * * @return The domain separator. */ function _domainSeparator(address zone) internal view returns (bytes32) { // prettier-ignore return _deriveDomainSeparator(zone); } /** * @dev Internal view function to derive the EIP-712 domain separator. * * @return domainSeparator The derived domain separator. */ function _deriveDomainSeparator(address zone) internal view returns (bytes32 domainSeparator) { bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH; // Get the name hash from the zone properties. SignedZoneProperties storage signedZoneProperties = _signedZones[zone]; bytes32 nameHash = keccak256(bytes(signedZoneProperties.zoneName)); bytes32 versionHash = _VERSION_HASH; // Leverage scratch space and other memory to perform an efficient hash. assembly { // Retrieve the free memory pointer; it will be replaced afterwards. let freeMemoryPointer := mload(FreeMemoryPointerSlot) // Retrieve value at 0x80; it will also be replaced afterwards. let slot0x80 := mload(Slot0x80) // Place typehash, name hash, and version hash at start of memory. mstore(0, typehash) mstore(OneWord, nameHash) mstore(TwoWords, versionHash) // Place chainId in the next memory location. mstore(ThreeWords, chainid()) // Place the address of the signed zone contract in the next memory location. mstore(FourWords, zone) // Hash relevant region of memory to derive the domain separator. domainSeparator := keccak256(0, FiveWords) // Restore the free memory pointer. mstore(FreeMemoryPointerSlot, freeMemoryPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) // Restore the value at 0x80. mstore(Slot0x80, slot0x80) } } /** * @dev Private view function to revert if the caller is not the owner of a * given zone. * * @param zone The zone for which to assert ownership. */ function _assertCallerIsZoneOwner(address zone) private view { // Ensure that the zone in question exists. _assertZoneExists(zone); // If the caller does not match the current owner of the zone... if (msg.sender != _signedZones[zone].owner) { // Revert, indicating that the caller is not the owner. revert CallerIsNotOwner(zone); } } /** * @dev Private view function to revert if a given zone does not exist. * * @param zone The zone for which to assert existence. */ function _assertZoneExists(address zone) private view { // Attempt to retrieve a the owner for the zone in question. if (_signedZones[zone].owner == address(0)) { // Revert if no ownerwas located. revert NoZone(); } } /** * @dev Private view function to revert if a signer being added to a zone * is the null address or the signer already exists, or the signer was * previously authorized. If the signer is being removed, the * function will revert if the signer is not active. * * @param signedZoneProperties The signed zone properties for the zone. * @param signer The signer to add or remove. * @param active Whether the signer is being added or * removed. */ function _assertSignerPermissions( SignedZoneProperties storage signedZoneProperties, address signer, bool active ) private view { // Do not allow the null address to be added as a signer. if (signer == address(0)) { revert SignerCannotBeNullAddress(); } // If the signer is being added... if (active) { // Revert if the signer is already added. if (signedZoneProperties.signers[signer].active) { revert SignerAlreadyAdded(signer); } // Revert if the signer was previously authorized. if (signedZoneProperties.signers[signer].previouslyActive) { revert SignerCannotBeReauthorized(signer); } } else { // Revert if the signer is not active. if (!signedZoneProperties.signers[signer].active) { revert SignerNotPresent(signer); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {ZoneParameters, Schema} from "../lib/ConsiderationStructs.sol"; import {ZoneInterfaceV16} from "../interfaces/ZoneInterfaceV16.sol"; import {SignedZoneV16RoyaltyEventsAndErrors} from "./interfaces/SignedZoneV16RoyaltyEventsAndErrors.sol"; import {SIP5Interface} from "./interfaces/SIP5Interface.sol"; import {SignedZoneControllerInterface} from "./interfaces/SignedZoneControllerInterface.sol"; import {IAuthorizedTransferSecurityRegistry} from "./interfaces/IAuthorizedTransferSecurityRegistry.sol"; import "./lib/SignedZoneV16RoyaltyConstants.sol"; /** * @title SignedZoneV16Royalty * @author ryanio, BCLeFevre * @notice SignedZoneV16Royalty is an implementation of SIP-7 that requires orders * to be signed by an approved signer. * https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md */ contract SignedZoneV16Royalty is SignedZoneV16RoyaltyEventsAndErrors, ZoneInterfaceV16, SIP5Interface { /// @dev The zone's controller that is set during deployment. address private immutable _controller; /// @dev The authorized signers, and if they are active. mapping(address => bool) private _signers; /// @dev The EIP-712 digest parameters. bytes32 internal immutable _NAME_HASH; bytes32 internal immutable _VERSION_HASH = keccak256(bytes("2.0")); // prettier-ignore bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH = keccak256( abi.encodePacked( "EIP712Domain(", "string name,", "string version,", "uint256 chainId,", "address verifyingContract", ")" ) ); // prettier-ignore bytes32 internal immutable _SIGNED_ORDER_TYPEHASH = keccak256( abi.encodePacked( "SignedOrder(", "address fulfiller,", "uint64 expiration,", "bytes32 orderHash,", "bytes context", ")" ) ); uint256 internal immutable _CHAIN_ID = block.chainid; bytes32 internal immutable _DOMAIN_SEPARATOR; address private immutable SEAPORT = 0x0000000000000068F116a894984e2DB1123eB395; /** * @notice Constructor to deploy the contract. * * @param zoneName The name for the zone used in the domain separator * derivation. */ constructor(string memory zoneName) { // Set the deployer as the controller. _controller = msg.sender; // Set the name hash. _NAME_HASH = keccak256(bytes(zoneName)); // Derive and set the domain separator. _DOMAIN_SEPARATOR = _deriveDomainSeparator(); // Emit an event to signal a SIP-5 contract has been deployed. emit SeaportCompatibleContractDeployed(); } /** * @notice The fallback function is used as a dispatcher for the * `updateSigner`, `isActiveSigner`, `getActiveSigners` and * `supportsInterface` functions. */ // prettier-ignore fallback(bytes calldata) external returns (bytes memory output) { // Get the function selector. bytes4 selector = msg.sig; if (selector == UPDATE_SIGNER_SELECTOR) { // abi.encodeWithSignature("updateSigner(address,bool)", signer, // active) // Get the signer, and active status. address signer = abi.decode(msg.data[4:], (address)); bool active = abi.decode(msg.data[36:], (bool)); // Call to update the signer. _updateSigner(signer, active); } else if (selector == GET_ACTIVE_SIGNERS_SELECTOR) { // abi.encodeWithSignature("getActiveSigners()") // Call the internal function to get the active signers. return abi.encode(_getActiveSigners()); } else if (selector == IS_ACTIVE_SIGNER_SELECTOR) { // abi.encodeWithSignature("isActiveSigner(address)", signer) // Get the signer. address signer = abi.decode(msg.data[4:], (address)); // Call the internal function to determine if the signer is active. return abi.encode(_isActiveSigner(signer)); } else { // Revert if the function selector is not supported. assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, UnsupportedFunctionSelector_error_selector) // revert(abi.encodeWithSignature( // "UnsupportedFunctionSelector()" // )) revert(0x1c, UnsupportedFunctionSelector_error_length) } } } /** * @notice Check if a given order including extraData is currently valid. * * @dev This function is called by Seaport whenever any extraData is * provided by the caller. * * @return authorizedOrderMagicValue A magic value indicating if the order * is currently valid. */ function authorizeOrder( ZoneParameters calldata zoneParameters ) external override returns (bytes4 authorizedOrderMagicValue) { if (msg.sender != SEAPORT) { // Revert if the caller is not Seaport. revert CallerNotSeaport(); } // Check Zone Parameters validity. _assertValidZoneParameters(); // Put the extraData and orderHash on the stack for cheaper access. bytes calldata extraData = zoneParameters.extraData; bytes32 orderHash = zoneParameters.orderHash; // Declare a variable to hold the expiration. uint64 expiration; // Declare a variable to hold the substandard version byte. uint256 subStandardVersionByte; // Validate the extraData. assembly { // Get the length of the extraData. let extraDataPtr := add(0x24, calldataload(Zone_extraData_cdPtr)) let extraDataLength := calldataload(extraDataPtr) // Validate the extra data length. if lt(extraDataLength, InvalidExtraDataLength_expected_length_substandard_1) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidExtraDataLength_error_selector) mstore(InvalidExtraDataLength_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidExtraDataLength(bytes32)", orderHash) // ) revert(0x1c, InvalidExtraDataLength_error_length) } // extraData bytes 0-1: SIP-6 version byte (MUST be 0x00) let versionByte := shr(248, calldataload(add(extraDataPtr, 0x20))) // Validate the SIP6 Version byte. if iszero(eq(versionByte, 0x00)) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidSIP6Version_error_selector) mstore(InvalidSIP6Version_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidSIP6Version(bytes32)", orderHash) // ) revert(0x1c, InvalidSIP6Version_error_length) } // extraData bytes 93-94: Substandard #1 // (MUST be 0x00, 0x01, 0x07, 0x08, or 0x09) subStandardVersionByte := shr( 248, calldataload(add(extraDataPtr, ExtraData_substandard_version_byte_offset)) ) // Validate the substandard version byte. if or( gt(subStandardVersionByte, 0x09), and(gt(subStandardVersionByte, 0x01), lt(subStandardVersionByte, 0x07)) ) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidSubstandardVersion_error_selector) mstore(InvalidSubstandardVersion_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidSubstandardVersion(bytes32)", orderHash) // ) revert(0x1c, InvalidSubstandardVersion_error_length) } // extraData bytes 21-29: expiration timestamp (uint64) expiration := shr(192, calldataload(add(extraDataPtr, ExtraData_expiration_offset))) // Revert if expired. if lt(expiration, timestamp()) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, SignatureExpired_error_selector) mstore(SignatureExpired_error_expiration_ptr, expiration) mstore(SignatureExpired_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "SignatureExpired(uint256,bytes32)", expiration, orderHash) // ) revert(0x1c, SignatureExpired_error_length) } // Get the length of the consideration array. let considerationLength := calldataload( add(0x24, calldataload(Zone_consideration_head_cdPtr)) ) // Revert if the order does not have any consideration items due to // the Substandard #1 requirement. if iszero(considerationLength) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidSubstandardSupport_error_selector) mstore(InvalidSubstandardSupport_error_reason_offset_ptr, 0x60) mstore(InvalidSubstandardSupport_error_substandard_version_ptr, 1) mstore(InvalidSubstandardSupport_error_orderHash_ptr, orderHash) mstore(InvalidSubstandardSupport_error_reason_length_ptr, 0x2a) mstore(InvalidSubstandardSupport_error_reason_ptr, "Consideration must have at least") mstore(InvalidSubstandardSupport_error_reason_2_ptr, " one item.") // revert(abi.encodeWithSignature( // "InvalidSubstandardSupport(string,uint256,bytes32)", // reason, // substandardVersion, // orderHash // )) revert(0x1c, InvalidSubstandardSupport_error_length) } } // Check the validity of the Substandard #1 extraData and get the // expected fulfiller address. address expectedFulfiller = (_assertValidSubstandardAndGetExpectedFulfiller(orderHash)); // extraData bytes 29-93: signature // (strictly requires 64 byte compact sig, EIP-2098) bytes calldata signature = extraData[29:93]; // extraData bytes 93-126: context (fixed length, 32 bytes + 1 byte) bytes calldata context; if (subStandardVersionByte < 2) { context = extraData[93:126]; } else if (subStandardVersionByte == 7) { if (extraData.length < 166) { assembly { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidExtraDataLength_error_selector) mstore(InvalidExtraDataLength_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidExtraDataLength(bytes32)", orderHash) // ) revert(0x1c, InvalidExtraDataLength_error_length) } } context = extraData[93:166]; } else { if (extraData.length < 146) { assembly { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidExtraDataLength_error_selector) mstore(InvalidExtraDataLength_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidExtraDataLength(bytes32)", orderHash) // ) revert(0x1c, InvalidExtraDataLength_error_length) } } context = extraData[93:146]; } // Derive the signedOrder hash. bytes32 signedOrderHash = _deriveSignedOrderHash( expectedFulfiller, expiration, orderHash, context ); // Derive the EIP-712 digest using the domain separator and signedOrder // hash. bytes32 digest = _deriveEIP712Digest(_domainSeparator(), signedOrderHash); // Recover the signer address from the digest and signature. address recoveredSigner = _recoverSigner(digest, signature); // Revert if the signer is not active. if (!_signers[recoveredSigner]) { revert SignerNotActive(recoveredSigner, orderHash); } // Set the transfer status of the tokens to true. _setTransferStatus(zoneParameters, true); // Return the selector of authorizeOrder as the magic value. authorizedOrderMagicValue = ZoneInterfaceV16.authorizeOrder.selector; } /** * @notice Check if a given order including extraData is currently valid. * * @dev This function is called by Seaport whenever any extraData is * provided by the caller. * * @return validOrderMagicValue A magic value indicating if the order is * currently valid. */ function validateOrder( ZoneParameters calldata zoneParameters ) external override returns (bytes4 validOrderMagicValue) { if (msg.sender != SEAPORT) { // Revert if the caller is not Seaport. revert CallerNotSeaport(); } // Set the transfer status of the tokens to false. _setTransferStatus(zoneParameters, false); // Return the selector of validateOrder as the magic value. validOrderMagicValue = ZoneInterfaceV16.validateOrder.selector; } /** * @dev Returns Seaport metadata for this contract, returning the * contract name and supported schemas. * * @return name The contract name * @return schemas The supported SIPs */ function getSeaportMetadata() external view override(SIP5Interface, ZoneInterfaceV16) returns (string memory name, Schema[] memory schemas) { // Return the supported SIPs. schemas = new Schema[](1); schemas[0].id = 7; // Get the SIP-7 information. ( bytes32 domainSeparator, string memory zoneName, string memory apiEndpoint, uint256[] memory substandards, string memory documentationURI ) = _sip7Information(); // Return the zone name. name = zoneName; // Encode the SIP-7 information. schemas[0].metadata = abi.encode(domainSeparator, apiEndpoint, substandards, documentationURI); } /** * @dev Sets the transfer status of the token based on the consideration * items or offer items. * * @param zoneParameters The zone parameters. * @param active The transfer status of the token. */ function _setTransferStatus(ZoneParameters calldata zoneParameters, bool active) internal { uint8 subStandardVersionByte = uint8(bytes1(zoneParameters.extraData[93])); if (subStandardVersionByte < 2) { return; } address registry = address(bytes20(zoneParameters.extraData[126:146])); address token; uint256 identifier; uint256 amount; if (uint256(zoneParameters.consideration[0].itemType) > 1) { // Call on first consideration token = zoneParameters.consideration[0].token; identifier = zoneParameters.consideration[0].identifier; amount = zoneParameters.consideration[0].amount; } else { // Call on first offer token = zoneParameters.offer[0].token; identifier = zoneParameters.offer[0].identifier; amount = zoneParameters.offer[0].amount; } if (subStandardVersionByte == 7) { address operator = address(bytes20(zoneParameters.extraData[146:166])); if (active) { IAuthorizedTransferSecurityRegistry(registry).beforeAuthorizedTransfer(operator, token); } else { IAuthorizedTransferSecurityRegistry(registry).afterAuthorizedTransfer(token); } } else if (subStandardVersionByte == 8) { if (active) { IAuthorizedTransferSecurityRegistry(registry).beforeAuthorizedTransfer(token, identifier); } else { IAuthorizedTransferSecurityRegistry(registry).afterAuthorizedTransfer(token, identifier); } } /* subStandardVersionByte == 9 */ else { if (active) { IAuthorizedTransferSecurityRegistry(registry).beforeAuthorizedTransferWithAmount( token, identifier, amount ); } else { IAuthorizedTransferSecurityRegistry(registry).afterAuthorizedTransferWithAmount( token, identifier ); } } } /** * @notice Add or remove a signer to the zone. * Only the controller can call this function. * * @param signer The signer address to add or remove. */ function _updateSigner(address signer, bool active) internal { // Only the controller can call this function. _assertCallerIsController(); // Add or remove the signer. active ? _addSigner(signer) : _removeSigner(signer); } /** * @notice Add a new signer to the zone. * Only the controller or an active signer can call this function. * * @param signer The new signer address to add. */ function _addSigner(address signer) internal { // Set the signer's active status to true. _signers[signer] = true; // Emit an event that the signer was added. emit SignerAdded(signer); } /** * @notice Remove an active signer from the zone. * Only the controller or an active signer can call this function. * * @param signer The signer address to remove. */ function _removeSigner(address signer) internal { // Set the signer's active status to false. _signers[signer] = false; // Emit an event that the signer was removed. emit SignerRemoved(signer); } /** * @notice Returns the active signers for the zone. Note that the array of * active signers could grow to a size that this function could not * return, the array of active signers is expected to be small, * and is managed by the controller. * * @return signers The active signers. */ function _getActiveSigners() internal view returns (address[] memory signers) { // Return the active signers for the zone by calling the controller. signers = SignedZoneControllerInterface(_controller).getActiveSigners(address(this)); } /** * @notice Returns if the given address is an active signer for the zone. * * @param signer The address to check if it is an active signer. * * @return The address is an active signer, false otherwise. */ function _isActiveSigner(address signer) internal view returns (bool) { // Return the active status of the caller. return _signers[signer]; } /** * @notice Returns whether the interface is supported. * * @param interfaceId The interface id to check against. */ function _supportsInterface(bytes4 interfaceId) internal pure returns (bool) { // Determine if the interface is supported. return (interfaceId == type(SIP5Interface).interfaceId || // SIP-5 interfaceId == type(ZoneInterfaceV16).interfaceId || // ZoneInterface interfaceId == 0x01ffc9a7); // ERC-165 } /** * @notice Internal call to return the signing information, substandards, * and documentation about the zone. * * @return domainSeparator The domain separator used for signing. * @return zoneName The zone name. * @return apiEndpoint The API endpoint for the zone. * @return substandards The substandards supported by the zone. * @return documentationURI The documentation URI for the zone. */ function _sip7Information() internal view returns ( bytes32 domainSeparator, string memory zoneName, string memory apiEndpoint, uint256[] memory substandards, string memory documentationURI ) { // Return the SIP-7 information. domainSeparator = _domainSeparator(); // Get the SIP-7 information from the controller. (, zoneName, apiEndpoint, substandards, documentationURI) = SignedZoneControllerInterface( _controller ).getAdditionalZoneInformation(address(this)); } /** * @dev Derive the signedOrder hash from the orderHash and expiration. * * @param fulfiller The expected fulfiller address. * @param expiration The signature expiration timestamp. * @param orderHash The order hash. * @param context The optional variable-length context. * * @return signedOrderHash The signedOrder hash. * */ function _deriveSignedOrderHash( address fulfiller, uint64 expiration, bytes32 orderHash, bytes calldata context ) internal view returns (bytes32 signedOrderHash) { // Derive the signed order hash. signedOrderHash = keccak256( abi.encode(_SIGNED_ORDER_TYPEHASH, fulfiller, expiration, orderHash, keccak256(context)) ); } /** * @dev Internal view function to return the signer of a signature. * * @param digest The digest to verify the signature against. * @param signature A signature from the signer indicating that the order * has been approved. * * @return recoveredSigner The recovered signer. */ function _recoverSigner( bytes32 digest, bytes memory signature ) internal view returns (address recoveredSigner) { // Utilize assembly to perform optimized signature verification check. assembly { // Ensure that first word of scratch space is empty. mstore(0, 0) // Declare value for v signature parameter. let v // Get the length of the signature. let signatureLength := mload(signature) // Get the pointer to the value preceding the signature length. // This will be used for temporary memory overrides - either the // signature head for isValidSignature or the digest for ecrecover. let wordBeforeSignaturePtr := sub(signature, OneWord) // Cache the current value behind the signature to restore it later. let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr) // Declare lenDiff + recoveredSigner scope to manage stack pressure. { // Take the difference between the max ECDSA signature length // and the actual signature length. Overflow desired for any // values > 65. If the diff is not 0 or 1, it is not a valid // ECDSA signature - move on to EIP1271 check. let lenDiff := sub(ECDSA_MaxLength, signatureLength) // If diff is 0 or 1, it may be an ECDSA signature. // Try to recover signer. if iszero(gt(lenDiff, 1)) { // Read the signature `s` value. let originalSignatureS := mload(add(signature, ECDSA_signature_s_offset)) // Read the first byte of the word after `s`. If the // signature is 65 bytes, this will be the real `v` value. // If not, it will need to be modified - doing it this way // saves an extra condition. v := byte(0, mload(add(signature, ECDSA_signature_v_offset))) // If lenDiff is 1, parse 64-byte signature as ECDSA. if lenDiff { // Extract yParity from highest bit of vs and add 27 to // get v. v := add(shr(MaxUint8, originalSignatureS), Signature_lower_v) // Extract canonical s from vs, all but the highest bit. // Temporarily overwrite the original `s` value in the // signature. mstore( add(signature, ECDSA_signature_s_offset), and(originalSignatureS, EIP2098_allButHighestBitMask) ) } // Temporarily overwrite the signature length with `v` to // conform to the expected input for ecrecover. mstore(signature, v) // Temporarily overwrite the word before the length with // `digest` to conform to the expected input for ecrecover. mstore(wordBeforeSignaturePtr, digest) // Attempt to recover the signer for the given signature. Do // not check the call status as ecrecover will return a null // address if the signature is invalid. pop( staticcall( gas(), Ecrecover_precompile, // Call ecrecover precompile. wordBeforeSignaturePtr, // Use data memory location. Ecrecover_args_size, // Size of digest, v, r, and s. 0, // Write result to scratch space. OneWord // Provide size of returned result. ) ) // Restore cached word before signature. mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature) // Restore cached signature length. mstore(signature, signatureLength) // Restore cached signature `s` value. mstore(add(signature, ECDSA_signature_s_offset), originalSignatureS) // Read the recovered signer from the buffer given as return // space for ecrecover. recoveredSigner := mload(0) } } // Restore the cached values overwritten by selector, digest and // signature head. mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature) } } /** * @dev Internal view function to get the EIP-712 domain separator. If the * chainId matches the chainId set on deployment, the cached domain * separator will be returned; otherwise, it will be derived from * scratch. * * @return The domain separator. */ function _domainSeparator() internal view returns (bytes32) { // prettier-ignore return block.chainid == _CHAIN_ID ? _DOMAIN_SEPARATOR : _deriveDomainSeparator(); } /** * @dev Internal view function to derive the EIP-712 domain separator. * * @return domainSeparator The derived domain separator. */ function _deriveDomainSeparator() internal view returns (bytes32 domainSeparator) { bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH; bytes32 nameHash = _NAME_HASH; bytes32 versionHash = _VERSION_HASH; // Leverage scratch space and other memory to perform an efficient hash. assembly { // Retrieve the free memory pointer; it will be replaced afterwards. let freeMemoryPointer := mload(FreeMemoryPointerSlot) // Retrieve value at 0x80; it will also be replaced afterwards. let slot0x80 := mload(Slot0x80) // Place typehash, name hash, and version hash at start of memory. mstore(0, typehash) mstore(OneWord, nameHash) mstore(TwoWords, versionHash) // Place chainId in the next memory location. mstore(ThreeWords, chainid()) // Place the address of this contract in the next memory location. mstore(FourWords, address()) // Hash relevant region of memory to derive the domain separator. domainSeparator := keccak256(0, FiveWords) // Restore the free memory pointer. mstore(FreeMemoryPointerSlot, freeMemoryPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) // Restore the value at 0x80. mstore(Slot0x80, slot0x80) } } /** * @dev Internal pure function to efficiently derive an digest to sign for * an order in accordance with EIP-712. * * @param domainSeparator The domain separator. * @param signedOrderHash The signedOrder hash. * * @return digest The digest hash. */ function _deriveEIP712Digest( bytes32 domainSeparator, bytes32 signedOrderHash ) internal pure returns (bytes32 digest) { // Leverage scratch space to perform an efficient hash. assembly { // Place the EIP-712 prefix at the start of scratch space. mstore(0, EIP_712_PREFIX) // Place the domain separator in the next region of scratch space. mstore(EIP712_DomainSeparator_offset, domainSeparator) // Place the signed order hash in scratch space, spilling into the // first two bytes of the free memory pointer — this should never be // set as memory cannot be expanded to that size, and will be // zeroed out after the hash is performed. mstore(EIP712_SignedOrderHash_offset, signedOrderHash) // Hash the relevant region digest := keccak256(0, EIP712_DigestPayload_size) // Clear out the dirtied bits in the memory pointer. mstore(EIP712_SignedOrderHash_offset, 0) } } /** * @dev Internal view function to revert if the caller is not the * controller. */ function _assertCallerIsController() internal view { // Get the controller address to use in the assembly block. address controller = _controller; assembly { // Revert if the caller is not the controller. if iszero(eq(caller(), controller)) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidController_error_selector) // revert(abi.encodeWithSignature( // "InvalidController()") // ) revert(0x1c, InvalidController_error_length) } } } /** * @dev Internal pure function to validate calldata offsets for the * dyanamic type in ZoneParameters. This ensures that functions using * the calldata object normally will be using the same data as the * assembly functions and that values that are bound to a given range * are within that range. */ function _assertValidZoneParameters() internal pure { // Utilize assembly in order to read offset data directly from calldata. assembly { /* * Checks: * 1. Zone parameters struct offset == 0x20 */ // Zone parameters at calldata 0x04 must have offset of 0x20. if iszero(eq(calldataload(Zone_parameters_cdPtr), Zone_parameters_ptr)) { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidZoneParameterEncoding_error_selector) // revert(abi.encodeWithSignature( // "InvalidZoneParameterEncoding()" // )) revert(0x1c, InvalidZoneParameterEncoding_error_length) } } } /** * @dev Internal pure function to ensure that the context argument for the * supplied extra data follows the substandard #1 format. Returns the * expected fulfiller of the order for deriving the signed order hash. * * @param orderHash The order hash. * * @return expectedFulfiller The expected fulfiller of the order. */ function _assertValidSubstandardAndGetExpectedFulfiller( bytes32 orderHash ) internal pure returns (address expectedFulfiller) { // Revert if the expected fulfiller is not the zero address and does // not match the actual fulfiller or if the expected received // identifier does not match the actual received identifier. assembly { // Get the actual fulfiller. let actualFulfiller := calldataload(Zone_parameters_fulfiller_cdPtr) let extraDataPtr := calldataload(Zone_extraData_cdPtr) let considerationPtr := calldataload(Zone_consideration_head_cdPtr) // Get the expected fulfiller. expectedFulfiller := shr(96, calldataload(add(expectedFulfiller_offset, extraDataPtr))) // Get the actual received identifier. let actualReceivedIdentifier := calldataload( add(actualReceivedIdentifier_offset, considerationPtr) ) // Get the expected received identifier. let expectedReceivedIdentifier := calldataload( add(expectedReceivedIdentifier_offset, extraDataPtr) ) // Revert if expected fulfiller is not the zero address and does // not match the actual fulfiller. if and(iszero(iszero(expectedFulfiller)), iszero(eq(expectedFulfiller, actualFulfiller))) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidFulfiller_error_selector) mstore(InvalidFulfiller_error_expectedFulfiller_ptr, expectedFulfiller) mstore(InvalidFulfiller_error_actualFulfiller_ptr, actualFulfiller) mstore(InvalidFulfiller_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidFulfiller(address,address,bytes32)", // expectedFulfiller, // actualFulfiller, // orderHash // )) revert(0x1c, InvalidFulfiller_error_length) } // Revert if expected received item does not match the actual // received item. if iszero(eq(expectedReceivedIdentifier, actualReceivedIdentifier)) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InvalidReceivedItem_error_selector) mstore(InvalidReceivedItem_error_expectedReceivedItem_ptr, expectedReceivedIdentifier) mstore(InvalidReceivedItem_error_actualReceivedItem_ptr, actualReceivedIdentifier) mstore(InvalidReceivedItem_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidReceivedItem(uint256,uint256,bytes32)", // expectedReceivedIdentifier, // actualReceievedIdentifier, // orderHash // )) revert(0x1c, InvalidReceivedItem_error_length) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {ZoneParameters, Schema} from "../lib/ConsiderationStructs.sol"; interface ZoneInterfaceV16 { function authorizeOrder( ZoneParameters calldata zoneParameters ) external returns (bytes4 authorizeOrderMagicValue); function validateOrder( ZoneParameters calldata zoneParameters ) external returns (bytes4 validOrderMagicValue); function getSeaportMetadata() external view returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title SignedZone * @author ryanio, BCLeFevre * @notice SignedZone is an implementation of SIP-7 that requires orders * to be signed by an approved signer. * https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md * */ interface SignedZoneInterface { /** * @notice Update the active status of a signer. * * @param signer The signer address to update. * @param active The new active status of the signer. */ function updateSigner(address signer, bool active) external; /** * @notice Returns the active signers for the zone. * * @return signers The active signers. */ function getActiveSigners() external view returns (address[] memory signers); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title SignedZoneControllerV16RoyaltyInterface * @author BCLeFevre * @notice SignedZoneControllerV16RoyaltyInterface enables the deploying of SignedZones. * SignedZones are an implementation of SIP-7 that requires orders * to be signed by an approved signer. * https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md * */ interface SignedZoneControllerV16RoyaltyInterface { /** * @notice Returns the active signers for the zone. * * @param signedZone The signed zone to get the active signers for. * * @return signers The active signers. */ function getActiveSigners(address signedZone) external view returns (address[] memory signers); /** * @notice Returns additional information about the zone. * * @param zone The zone to get the additional information for. * * @return domainSeparator The domain separator used for signing. * @return zoneName The name of the zone. * @return apiEndpoint The API endpoint for the zone. * @return substandards The substandards supported by the zone. * @return documentationURI The documentation URI for the zone. */ function getAdditionalZoneInformation( address zone ) external view returns ( bytes32 domainSeparator, string memory zoneName, string memory apiEndpoint, uint256[] memory substandards, string memory documentationURI ); /** * @notice Update the API endpoint returned by the supplied zone. * Only the owner or an active signer can call this function. * * @param signedZone The signed zone to update the API endpoint for. * @param newApiEndpoint The new API endpoint. */ function updateAPIEndpoint(address signedZone, string calldata newApiEndpoint) external; /** * @notice Update the documentationURI returned by a zone. * Only the owner or an active signer of the supplied zone can call * this function. * * @param zone The signed zone to update the API endpoint for. * @param documentationURI The new documentation URI. */ function updateDocumentationURI(address zone, string calldata documentationURI) external; /** * @notice Update the signer for a given signed zone. * * @param signedZone The signed zone to update the signer for. * @param signer The signer to update. * @param active If the signer should be active or not. */ function updateSigner(address signedZone, address signer, bool active) external; /** * @notice Initiate zone ownership transfer by assigning a new potential * owner for the given zone. Once set, the new potential owner * may call `acceptOwnership` to claim ownership of the zone. * Only the owner of the zone in question may call this function. * * @param zone The zone for which to initiate ownership * transfer. * @param newPotentialOwner The new potential owner of the zone. */ function transferOwnership(address zone, address newPotentialOwner) external; /** * @notice Clear the currently set potential owner, if any, from a zone. * Only the owner of the zone in question may call this function. * * @param zone The zone for which to cancel ownership transfer. */ function cancelOwnershipTransfer(address zone) external; /** * @notice Accept ownership of a supplied zone. Only accounts that the * current owner has set as the new potential owner may call this * function. * * @param zone The zone for which to accept ownership. */ function acceptOwnership(address zone) external; /** * @notice Retrieve the current owner of a deployed zone. * * @param zone The zone for which to retrieve the associated owner. * * @return owner The owner of the supplied zone. */ function ownerOf(address zone) external view returns (address owner); /** * @notice Retrieve the potential owner, if any, for a given zone. The * current owner may set a new potential owner via * `transferOwnership` and that owner may then accept ownership of * the zone in question via `acceptOwnership`. * * @param zone The zone for which to retrieve the potential owner. * * @return potentialOwner The potential owner, if any, for the zone. */ function getPotentialOwner(address zone) external view returns (address potentialOwner); /** * @notice Returns whether or not the supplied address is an active signer * for the supplied zone. * * @param zone The zone to check if the supplied address is an active * signer for. * @param signer The address to check if it is an active signer for * * @return active If the supplied address is an active signer for the * supplied zone. */ function isActiveSigner(address zone, address signer) external view returns (bool); /** * @notice Deploy a SignedZone to a precomputed address. * * @param zoneName The name for the zone returned in * getSeaportMetadata(). * @param apiEndpoint The API endpoint where orders for this zone can * be signed. * @param documentationURI The URI to the documentation describing the * behavior of the contract. Request and response * payloads are defined in SIP-7. * @param salt The salt to be used to derive the zone address * @param initialOwner The initial owner to set for the new zone. * * @return signedZone The derived address for the zone. */ function createZone( string memory zoneName, string memory apiEndpoint, string memory documentationURI, address initialOwner, bytes32 salt ) external returns (address signedZone); /** * @notice Derive the zone address associated with a salt. * * @param zoneName The name of the zone. * @param salt The salt to be used to derive the zone address. * * @return derivedAddress The derived address of the signed zone. */ function getZone( string memory zoneName, bytes32 salt ) external view returns (address derivedAddress); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @notice SignedZoneControllerV16RoyaltyEventsAndErrors contains errors and events * related to deploying and managing new signed zones. */ interface SignedZoneControllerV16RoyaltyEventsAndErrors { /** * @dev Emit an event whenever a new zone is created. * * @param zoneAddress The address of the zone. * @param zoneName The name for the zone returned in * getSeaportMetadata(). * @param apiEndpoint The API endpoint where orders for this zone can * be signed. * @param documentationURI The URI to the documentation describing the * behavior of the contract. * Request and response payloads are defined in * SIP-7. * @param salt The salt used to deploy the zone. */ event ZoneCreated( address zoneAddress, string zoneName, string apiEndpoint, string documentationURI, bytes32 salt ); /** * @dev Emit an event whenever zone ownership is transferred. * * @param zone The zone for which ownership has been * transferred. * @param previousOwner The previous owner of the zone. * @param newOwner The new owner of the zone. */ event OwnershipTransferred( address indexed zone, address indexed previousOwner, address indexed newOwner ); /** * @dev Emit an event whenever a zone owner registers a new potential * owner for that zone. * * @param newPotentialOwner The new potential owner of the zone. */ event PotentialOwnerUpdated(address indexed newPotentialOwner); /** * @dev Emit an event when a signer has been updated. */ event SignerUpdated(address signedZone, address signer, bool active); /** * @dev Revert with an error when attempting to update zone information or * transfer ownership of a zone when the caller is not the owner of * the zone in question. */ error CallerIsNotOwner(address zone); /** * @dev Revert with an error when attempting to claim ownership of a zone * with a caller that is not the current potential owner for the * zone in question. */ error CallerIsNotNewPotentialOwner(address zone); /** * @dev Revert with an error when attempting to create a new signed zone * using a salt where the first twenty bytes do not match the address * of the caller or are not set to zero. */ error InvalidCreator(); /** * @dev Revert with an error when attempting to create a new zone when no * initial owner address is supplied. */ error InvalidInitialOwner(); /** * @dev Revert with an error when attempting to set a new potential owner * that is already set. */ error NewPotentialOwnerAlreadySet(address zone, address newPotentialOwner); /** * @dev Revert with an error when attempting to cancel ownership transfer * when no new potential owner is currently set. */ error NoPotentialOwnerCurrentlySet(address zone); /** * @dev Revert with an error when attempting to register a new potential * owner and supplying the null address. */ error NewPotentialOwnerIsNullAddress(address zone); /** * @dev Revert with an error when attempting to interact with a zone that * does not yet exist. */ error NoZone(); /** * @dev Revert with an error if trying to add a signer that is * already active. */ error SignerAlreadyAdded(address signer); /** * @dev Revert with an error if a new signer is the null address. */ error SignerCannotBeNullAddress(); /** * @dev Revert with an error if a removed signer is trying to be * reauthorized. */ error SignerCannotBeReauthorized(address signer); /** * @dev Revert with an error if trying to remove a signer that is * not present. */ error SignerNotPresent(address signer); /** * @dev Revert with an error when attempting to deploy a zone that is * currently deployed. */ error ZoneAlreadyExists(address zone); /** * @dev Revert with an error when deployed address does not match the * derived address. */ error ZoneAddressMismatch(address zone, address derivedAddress); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /// @dev ECDSA signature offsets. uint256 constant ECDSA_MaxLength = 65; uint256 constant ECDSA_signature_s_offset = 0x40; uint256 constant ECDSA_signature_v_offset = 0x60; /// @dev Helpers for memory offsets. uint256 constant OneWord = 0x20; uint256 constant TwoWords = 0x40; uint256 constant ThreeWords = 0x60; uint256 constant FourWords = 0x80; uint256 constant FiveWords = 0xa0; uint256 constant Signature_lower_v = 27; uint256 constant MaxUint8 = 0xff; bytes32 constant EIP2098_allButHighestBitMask = ( 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ); uint256 constant Ecrecover_precompile = 1; uint256 constant Ecrecover_args_size = 0x80; uint256 constant FreeMemoryPointerSlot = 0x40; uint256 constant ZeroSlot = 0x60; uint256 constant Slot0x80 = 0x80; /// @dev The EIP-712 digest offsets. uint256 constant EIP712_DomainSeparator_offset = 0x02; uint256 constant EIP712_SignedOrderHash_offset = 0x22; uint256 constant EIP712_DigestPayload_size = 0x42; uint256 constant EIP_712_PREFIX = ( 0x1901000000000000000000000000000000000000000000000000000000000000 ); // @dev Function selectors used in the fallback function.. bytes4 constant UPDATE_SIGNER_SELECTOR = 0xf460590b; bytes4 constant GET_ACTIVE_SIGNERS_SELECTOR = 0xa784b80c; bytes4 constant IS_ACTIVE_SIGNER_SELECTOR = 0x7dff5a79; bytes4 constant SUPPORTS_INTERFACE_SELECTOR = 0x01ffc9a7; /* * error InvalidController() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidController_error_selector = 0x6d5769be; uint256 constant InvalidController_error_length = 0x04; /* * error InvalidFulfiller(address expectedFulfiller, address actualFulfiller, bytes32 orderHash) * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: expectedFulfiller * - 0x40: actualFullfiller * - 0x60: orderHash * Revert buffer is memory[0x1c:0x80] */ uint256 constant InvalidFulfiller_error_selector = 0x1bcf9bb7; uint256 constant InvalidFulfiller_error_expectedFulfiller_ptr = 0x20; uint256 constant InvalidFulfiller_error_actualFulfiller_ptr = 0x40; uint256 constant InvalidFulfiller_error_orderHash_ptr = 0x60; uint256 constant InvalidFulfiller_error_length = 0x64; /* * error InvalidReceivedItem(uint256 expectedReceivedIdentifier, uint256 actualReceievedIdentifier, bytes32 orderHash) * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: expectedReceivedIdentifier * - 0x40: actualReceievedIdentifier * - 0x60: orderHash * Revert buffer is memory[0x1c:0x80] */ uint256 constant InvalidReceivedItem_error_selector = 0xb36c03e8; uint256 constant InvalidReceivedItem_error_expectedReceivedItem_ptr = 0x20; uint256 constant InvalidReceivedItem_error_actualReceivedItem_ptr = 0x40; uint256 constant InvalidReceivedItem_error_orderHash_ptr = 0x60; uint256 constant InvalidReceivedItem_error_length = 0x64; /* * error InvalidZoneParameterEncoding() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidZoneParameterEncoding_error_selector = 0x46d5d895; uint256 constant InvalidZoneParameterEncoding_error_length = 0x04; /* * error InvalidExtraDataLength() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidExtraDataLength_error_selector = 0xd232fd2c; uint256 constant InvalidExtraDataLength_error_orderHash_ptr = 0x20; uint256 constant InvalidExtraDataLength_error_length = 0x24; uint256 constant InvalidExtraDataLength_expected_length_substandard_1 = 0x7e; // 126 uint256 constant InvalidExtraDataLength_expected_length_substandard_7 = 0xa6; // 166 uint256 constant InvalidExtraDataLength_expected_length_substandard_8_or_9 = 0x92; // 146 uint256 constant ExtraData_expiration_offset = 0x35; uint256 constant ExtraData_substandard_version_byte_offset = 0x7d; /* * error InvalidSIP6Version() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidSIP6Version_error_selector = 0x64115774; uint256 constant InvalidSIP6Version_error_orderHash_ptr = 0x20; uint256 constant InvalidSIP6Version_error_length = 0x24; /* * error InvalidSubstandardVersion() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidSubstandardVersion_error_selector = 0x26787999; uint256 constant InvalidSubstandardVersion_error_orderHash_ptr = 0x20; uint256 constant InvalidSubstandardVersion_error_length = 0x24; /* * error InvalidSubstandardSupport() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: reason * - 0x40: substandardVersion * - 0x60: orderHash * Revert buffer is memory[0x1c:0xe0] */ uint256 constant InvalidSubstandardSupport_error_selector = 0x2be76224; uint256 constant InvalidSubstandardSupport_error_reason_offset_ptr = 0x20; uint256 constant InvalidSubstandardSupport_error_substandard_version_ptr = 0x40; uint256 constant InvalidSubstandardSupport_error_orderHash_ptr = 0x60; uint256 constant InvalidSubstandardSupport_error_reason_length_ptr = 0x80; uint256 constant InvalidSubstandardSupport_error_reason_ptr = 0xa0; uint256 constant InvalidSubstandardSupport_error_reason_2_ptr = 0xc0; uint256 constant InvalidSubstandardSupport_error_length = 0xc4; /* * error SignatureExpired() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: expiration * - 0x40: orderHash * Revert buffer is memory[0x1c:0x60] */ uint256 constant SignatureExpired_error_selector = 0x16546071; uint256 constant SignatureExpired_error_expiration_ptr = 0x20; uint256 constant SignatureExpired_error_orderHash_ptr = 0x40; uint256 constant SignatureExpired_error_length = 0x44; /* * error UnsupportedFunctionSelector() * - Defined in SignedZoneEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant UnsupportedFunctionSelector_error_selector = 0x54c91b87; uint256 constant UnsupportedFunctionSelector_error_length = 0x04; // Zone parameter calldata pointers uint256 constant Zone_parameters_cdPtr = 0x04; uint256 constant Zone_parameters_fulfiller_cdPtr = 0x44; uint256 constant Zone_consideration_head_cdPtr = 0xa4; uint256 constant Zone_extraData_cdPtr = 0xc4; // Zone parameter memory pointers uint256 constant Zone_parameters_ptr = 0x20; // Zone parameter offsets uint256 constant Zone_parameters_offset = 0x24; uint256 constant expectedFulfiller_offset = 0x45; uint256 constant actualReceivedIdentifier_offset = 0x84; uint256 constant expectedReceivedIdentifier_offset = 0xa2; // Spent Item Size uint256 constant SpentItem_size = 0x80; // Received Item Size uint256 constant ReceivedItem_size = 0xa0;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { OrderType, BasicOrderType, ItemType, Side } from "./ConsiderationEnums.sol"; /** * @dev An order contains eleven components: an offerer, a zone (or account that * can cancel the order or restrict who can fulfill the order depending on * the type), the order type (specifying partial fill support as well as * restricted order status), the start and end time, a hash that will be * provided to the zone when validating restricted orders, a salt, a key * corresponding to a given conduit, a counter, and an arbitrary number of * offer items that can be spent along with consideration items that must * be received by their respective recipient. */ struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 counter; } /** * @dev An offer item has five components: an item type (ETH or other native * tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and * ERC1155), a token address, a dual-purpose "identifierOrCriteria" * component that will either represent a tokenId or a merkle root * depending on the item type, and a start and end amount that support * increasing or decreasing amounts over the duration of the respective * order. */ struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } /** * @dev A consideration item has the same five components as an offer item and * an additional sixth component designating the required recipient of the * item. */ struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } /** * @dev A spent item is translated from a utilized offer item and has four * components: an item type (ETH or other native tokens, ERC20, ERC721, and * ERC1155), a token address, a tokenId, and an amount. */ struct SpentItem { ItemType itemType; address token; uint256 identifier; uint256 amount; } /** * @dev A received item is translated from a utilized consideration item and has * the same four components as a spent item, as well as an additional fifth * component designating the required recipient of the item. */ struct ReceivedItem { ItemType itemType; address token; uint256 identifier; uint256 amount; address payable recipient; } /** * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155 * matching, a group of six functions may be called that only requires a * subset of the usual order arguments. Note the use of a "basicOrderType" * enum; this represents both the usual order type as well as the "route" * of the basic order (a simple derivation function for the basic order * type is `basicOrderType = orderType + (4 * basicOrderRoute)`.) */ struct BasicOrderParameters { // calldata offset address considerationToken; // 0x24 uint256 considerationIdentifier; // 0x44 uint256 considerationAmount; // 0x64 address payable offerer; // 0x84 address zone; // 0xa4 address offerToken; // 0xc4 uint256 offerIdentifier; // 0xe4 uint256 offerAmount; // 0x104 BasicOrderType basicOrderType; // 0x124 uint256 startTime; // 0x144 uint256 endTime; // 0x164 bytes32 zoneHash; // 0x184 uint256 salt; // 0x1a4 bytes32 offererConduitKey; // 0x1c4 bytes32 fulfillerConduitKey; // 0x1e4 uint256 totalOriginalAdditionalRecipients; // 0x204 AdditionalRecipient[] additionalRecipients; // 0x224 bytes signature; // 0x244 // Total length, excluding dynamic array data: 0x264 (580) } /** * @dev Basic orders can supply any number of additional recipients, with the * implied assumption that they are supplied from the offered ETH (or other * native token) or ERC20 token for the order. */ struct AdditionalRecipient { uint256 amount; address payable recipient; } /** * @dev The full set of order components, with the exception of the counter, * must be supplied when fulfilling more sophisticated orders or groups of * orders. The total number of original consideration items must also be * supplied, as the caller may specify additional consideration items. */ struct OrderParameters { address offerer; // 0x00 address zone; // 0x20 OfferItem[] offer; // 0x40 ConsiderationItem[] consideration; // 0x60 OrderType orderType; // 0x80 uint256 startTime; // 0xa0 uint256 endTime; // 0xc0 bytes32 zoneHash; // 0xe0 uint256 salt; // 0x100 bytes32 conduitKey; // 0x120 uint256 totalOriginalConsiderationItems; // 0x140 // offer.length // 0x160 } /** * @dev Orders require a signature in addition to the other order parameters. */ struct Order { OrderParameters parameters; bytes signature; } /** * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill) * and a denominator (the total size of the order) in addition to the * signature and other order parameters. It also supports an optional field * for supplying extra data; this data will be provided to the zone if the * order type is restricted and the zone is not the caller, or will be * provided to the offerer as context for contract order types. */ struct AdvancedOrder { OrderParameters parameters; uint120 numerator; uint120 denominator; bytes signature; bytes extraData; } /** * @dev Orders can be validated (either explicitly via `validate`, or as a * consequence of a full or partial fill), specifically cancelled (they can * also be cancelled in bulk via incrementing a per-zone counter), and * partially or fully filled (with the fraction filled represented by a * numerator and denominator). */ struct OrderStatus { bool isValidated; bool isCancelled; uint120 numerator; uint120 denominator; } /** * @dev A criteria resolver specifies an order, side (offer vs. consideration), * and item index. It then provides a chosen identifier (i.e. tokenId) * alongside a merkle proof demonstrating the identifier meets the required * criteria. */ struct CriteriaResolver { uint256 orderIndex; Side side; uint256 index; uint256 identifier; bytes32[] criteriaProof; } /** * @dev A fulfillment is applied to a group of orders. It decrements a series of * offer and consideration items, then generates a single execution * element. A given fulfillment can be applied to as many offer and * consideration items as desired, but must contain at least one offer and * at least one consideration that match. The fulfillment must also remain * consistent on all key parameters across all offer items (same offerer, * token, type, tokenId, and conduit preference) as well as across all * consideration items (token, type, tokenId, and recipient). */ struct Fulfillment { FulfillmentComponent[] offerComponents; FulfillmentComponent[] considerationComponents; } /** * @dev Each fulfillment component contains one index referencing a specific * order and another referencing a specific offer or consideration item. */ struct FulfillmentComponent { uint256 orderIndex; uint256 itemIndex; } /** * @dev An execution is triggered once all consideration items have been zeroed * out. It sends the item in question from the offerer to the item's * recipient, optionally sourcing approvals from either this contract * directly or from the offerer's chosen conduit if one is specified. An * execution is not provided as an argument, but rather is derived via * orders, criteria resolvers, and fulfillments (where the total number of * executions will be less than or equal to the total number of indicated * fulfillments) and returned as part of `matchOrders`. */ struct Execution { ReceivedItem item; address offerer; bytes32 conduitKey; } /** * @dev Restricted orders are validated post-execution by calling validateOrder * on the zone. This struct provides context about the order fulfillment * and any supplied extraData, as well as all order hashes fulfilled in a * call to a match or fulfillAvailable method. */ struct ZoneParameters { bytes32 orderHash; address fulfiller; address offerer; SpentItem[] offer; ReceivedItem[] consideration; bytes extraData; bytes32[] orderHashes; uint256 startTime; uint256 endTime; bytes32 zoneHash; } /** * @dev Zones and contract offerers can communicate which schemas they implement * along with any associated metadata related to each schema. */ struct Schema { uint256 id; bytes metadata; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @notice SignedZoneV16RoyaltyEventsAndErrors contains errors and events * related to zone interaction. */ interface SignedZoneV16RoyaltyEventsAndErrors { /** * @dev Emit an event when a new signer is added. */ event SignerAdded(address signer); /** * @dev Emit an event when a signer is removed. */ event SignerRemoved(address signer); /** * @dev Revert with an error when the signature has expired. */ error SignatureExpired(uint256 expiration, bytes32 orderHash); /** * @dev Revert with an error when the caller is not seaport. */ error CallerNotSeaport(); /** * @dev Revert with an error when attempting to update the signers of a * the zone from a caller that is not the zone's controller. */ error InvalidController(); /** * @dev Revert with an error if supplied order extraData is an invalid * length. */ error InvalidExtraDataLength(bytes32 orderHash); /** * @dev Revert with an error if the supplied order extraData does not * support the zone's SIP6 version. */ error InvalidSIP6Version(bytes32 orderHash); /** * @dev Revert with an error if the supplied order extraData does not * support the zone's substandard requirements. */ error InvalidSubstandardSupport(string reason, uint256 substandardVersion, bytes32 orderHash); /** * @dev Revert with an error if the supplied order extraData does not * support the zone's substandard version. */ error InvalidSubstandardVersion(bytes32 orderHash); /** * @dev Revert with an error if the fulfiller does not match. */ error InvalidFulfiller(address expectedFulfiller, address actualFulfiller, bytes32 orderHash); /** * @dev Revert with an error if the received item does not match. */ error InvalidReceivedItem( uint256 expectedReceivedIdentifier, uint256 actualReceievedIdentifier, bytes32 orderHash ); /** * @dev Revert with an error if the zone parameter encoding is invalid. */ error InvalidZoneParameterEncoding(); /** * @dev Revert with an error when an order is signed with a signer * that is not active. */ error SignerNotActive(address signer, bytes32 orderHash); /** * @dev Revert when an unsupported function selector is found. */ error UnsupportedFunctionSelector(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { Schema } from "../../lib/ConsiderationStructs.sol"; /** * @dev SIP-5: Contract Metadata Interface for Seaport Contracts * https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-5.md */ interface SIP5Interface { /** * @dev An event that is emitted when a SIP-5 compatible contract is deployed. */ event SeaportCompatibleContractDeployed(); /** * @dev Returns Seaport metadata for this contract, returning the * contract name and supported schemas. * * @return name The contract name * @return schemas The supported SIPs */ function getSeaportMetadata() external view returns (string memory name, Schema[] memory schemas); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title SignedZoneControllerInterface * @author BCLeFevre * @notice SignedZoneControllerInterface enables the deploying of SignedZones. * SignedZones are an implementation of SIP-7 that requires orders * to be signed by an approved signer. * https://github.com/ProjectOpenSea/SIPs/blob/main/SIPS/sip-7.md * */ interface SignedZoneControllerInterface { /** * @notice Deploy a SignedZone to a precomputed address. * * @param zoneName The name for the zone returned in * getSeaportMetadata(). * @param apiEndpoint The API endpoint where orders for this zone can be * signed. * @param documentationURI The URI to the documentation describing the * behavior of the contract. * Request and response payloads are defined in SIP-7. * @param salt The salt to be used to derive the zone address * @param initialOwner The initial owner to set for the new zone. * * @return derivedAddress The derived address for the zone. */ function createZone( string memory zoneName, string memory apiEndpoint, string memory documentationURI, address initialOwner, bytes32 salt ) external returns (address derivedAddress); /** * @notice Returns the active signers for the zone. * * @param signedZone The signed zone to get the active signers for. * * @return signers The active signers. */ function getActiveSigners(address signedZone) external view returns (address[] memory signers); /** * @notice Returns additional information about the zone. * * @param zone The zone to get the additional information for. * * @return domainSeparator The domain separator used for signing. * @return zoneName The name of the zone. * @return apiEndpoint The API endpoint for the zone. * @return substandards The substandards supported by the zone. * @return documentationURI The documentation URI for the zone. */ function getAdditionalZoneInformation(address zone) external view returns ( bytes32 domainSeparator, string memory zoneName, string memory apiEndpoint, uint256[] memory substandards, string memory documentationURI ); /** * @notice Update the API endpoint returned by the supplied zone. * Only the owner or an active signer can call this function. * * @param signedZone The signed zone to update the API endpoint for. * @param newApiEndpoint The new API endpoint. */ function updateAPIEndpoint( address signedZone, string calldata newApiEndpoint ) external; /** * @notice Update the signer for a given signed zone. * * @param signedZone The signed zone to update the signer for. * @param signer The signer to update. * @param active If the signer should be active or not. */ function updateSigner( address signedZone, address signer, bool active ) external; /** * @notice Initiate zone ownership transfer by assigning a new potential * owner for the given zone. Once set, the new potential owner * may call `acceptOwnership` to claim ownership of the zone. * Only the owner of the zone in question may call this function. * * @param zone The zone for which to initiate ownership transfer. * @param newPotentialOwner The new potential owner of the zone. */ function transferOwnership(address zone, address newPotentialOwner) external; /** * @notice Clear the currently set potential owner, if any, from a zone. * Only the owner of the zone in question may call this function. * * @param zone The zone for which to cancel ownership transfer. */ function cancelOwnershipTransfer(address zone) external; /** * @notice Accept ownership of a supplied zone. Only accounts that the * current owner has set as the new potential owner may call this * function. * * @param zone The zone for which to accept ownership. */ function acceptOwnership(address zone) external; /** * @notice Retrieve the current owner of a deployed zone. * * @param zone The zone for which to retrieve the associated owner. * * @return owner The owner of the supplied zone. */ function ownerOf(address zone) external view returns (address owner); /** * @notice Retrieve the potential owner, if any, for a given zone. The * current owner may set a new potential owner via * `transferOwnership` and that owner may then accept ownership of * the zone in question via `acceptOwnership`. * * @param zone The zone for which to retrieve the potential owner. * * @return potentialOwner The potential owner, if any, for the zone. */ function getPotentialOwner(address zone) external view returns (address potentialOwner); /** * @notice Derive the zone address associated with a salt. * * @param salt The salt to be used to derive the zone address * * @return derivedAddress The derived address of the signed zone. */ function getZone(bytes32 salt) external view returns (address derivedAddress); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; enum ListTypes { AuthorizerList, OperatorList } /// @title IAuthorizedTransferSecurityRegistry /// @dev Interface for the Authorized Transfer Security Registry, a simplified version of the Transfer /// Security Registry that only supports authorizers and whitelisted operators, and assumes a /// security level of OperatorWhitelistEnableOTC + authorizers for all collections that use it. /// Note that a number of view functions on collections that add this validator will not work. interface IAuthorizedTransferSecurityRegistry { event CreatedList(uint256 indexed id, string name); event AppliedListToCollection(address indexed collection, uint120 indexed id); event ReassignedListOwnership(uint256 indexed id, address indexed newOwner); event AddedAccountToList(ListTypes indexed kind, uint256 indexed id, address indexed account); event RemovedAccountFromList(ListTypes indexed kind, uint256 indexed id, address indexed account); error AuthorizedTransferSecurityRegistry__ListDoesNotExist(); error AuthorizedTransferSecurityRegistry__CallerDoesNotOwnList(); error AuthorizedTransferSecurityRegistry__ArrayLengthCannotBeZero(); error AuthorizedTransferSecurityRegistry__CallerMustHaveElevatedPermissionsForSpecifiedNFT(); error AuthorizedTransferSecurityRegistry__ListOwnershipCannotBeTransferredToZeroAddress(); error AuthorizedTransferSecurityRegistry__ZeroAddressNotAllowed(); error AuthorizedTransferSecurityRegistry__UnauthorizedTransfer(); error AuthorizedTransferSecurityRegistry__CallerIsNotValidAuthorizer(); /// Manage lists of authorizers & operators that can be applied to collections function createList(string calldata name) external returns (uint120); function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120); function reassignOwnershipOfList(uint120 id, address newOwner) external; function renounceOwnershipOfList(uint120 id) external; function applyListToCollection(address collection, uint120 id) external; function listOwners(uint120 id) external view returns (address); /// Manage and query for authorizers on lists function addAuthorizers(uint120 id, address[] calldata accounts) external; function removeAuthorizers(uint120 id, address[] calldata accounts) external; function getAuthorizers(uint120 id) external view returns (address[] memory); function isAuthorizer(uint120 id, address account) external view returns (bool); function getAuthorizersByCollection(address collection) external view returns (address[] memory); function isAuthorizerByCollection( address collection, address account ) external view returns (bool); /// Manage and query for operators on lists function addOperators(uint120 id, address[] calldata accounts) external; function removeOperators(uint120 id, address[] calldata accounts) external; function getOperators(uint120 id) external view returns (address[] memory); function isOperator(uint120 id, address account) external view returns (bool); function getOperatorsByCollection(address collection) external view returns (address[] memory); function isOperatorByCollection(address collection, address account) external view returns (bool); /// Ensure that a specific operator has been authorized to transfer tokens function validateTransfer(address caller, address from, address to) external view; /// Ensure that a transfer has been authorized for a specific tokenId function validateTransfer( address caller, address from, address to, uint256 tokenId ) external view; /// Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and /// reduce the transferable amount remaining function validateTransfer( address caller, address from, address to, uint256 tokenId, uint256 amount ) external; /// Legacy alias for validateTransfer (address caller, address from, address to) function applyCollectionTransferPolicy(address caller, address from, address to) external view; /// Temporarily assign a specific allowed operator for a given collection function beforeAuthorizedTransfer(address operator, address token) external; /// Clear assignment of a specific allowed operator for a given collection function afterAuthorizedTransfer(address token) external; /// Temporarily allow a specific tokenId from a given collection to be transferred function beforeAuthorizedTransfer(address token, uint256 tokenId) external; /// Clear assignment of an specific tokenId's transfer allowance function afterAuthorizedTransfer(address token, uint256 tokenId) external; /// Temporarily allow a specific amount of a specific tokenId from a given collection to be transferred function beforeAuthorizedTransferWithAmount( address token, uint256 tokenId, uint256 amount ) external; /// Clear assignment of a tokenId's transfer allowance for a specific amount function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; // prettier-ignore enum OrderType { // 0: no partial fills, anyone can execute FULL_OPEN, // 1: partial fills supported, anyone can execute PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute PARTIAL_RESTRICTED, // 4: contract order type CONTRACT } // prettier-ignore enum BasicOrderType { // 0: no partial fills, anyone can execute ETH_TO_ERC721_FULL_OPEN, // 1: partial fills supported, anyone can execute ETH_TO_ERC721_PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute ETH_TO_ERC721_FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute ETH_TO_ERC721_PARTIAL_RESTRICTED, // 4: no partial fills, anyone can execute ETH_TO_ERC1155_FULL_OPEN, // 5: partial fills supported, anyone can execute ETH_TO_ERC1155_PARTIAL_OPEN, // 6: no partial fills, only offerer or zone can execute ETH_TO_ERC1155_FULL_RESTRICTED, // 7: partial fills supported, only offerer or zone can execute ETH_TO_ERC1155_PARTIAL_RESTRICTED, // 8: no partial fills, anyone can execute ERC20_TO_ERC721_FULL_OPEN, // 9: partial fills supported, anyone can execute ERC20_TO_ERC721_PARTIAL_OPEN, // 10: no partial fills, only offerer or zone can execute ERC20_TO_ERC721_FULL_RESTRICTED, // 11: partial fills supported, only offerer or zone can execute ERC20_TO_ERC721_PARTIAL_RESTRICTED, // 12: no partial fills, anyone can execute ERC20_TO_ERC1155_FULL_OPEN, // 13: partial fills supported, anyone can execute ERC20_TO_ERC1155_PARTIAL_OPEN, // 14: no partial fills, only offerer or zone can execute ERC20_TO_ERC1155_FULL_RESTRICTED, // 15: partial fills supported, only offerer or zone can execute ERC20_TO_ERC1155_PARTIAL_RESTRICTED, // 16: no partial fills, anyone can execute ERC721_TO_ERC20_FULL_OPEN, // 17: partial fills supported, anyone can execute ERC721_TO_ERC20_PARTIAL_OPEN, // 18: no partial fills, only offerer or zone can execute ERC721_TO_ERC20_FULL_RESTRICTED, // 19: partial fills supported, only offerer or zone can execute ERC721_TO_ERC20_PARTIAL_RESTRICTED, // 20: no partial fills, anyone can execute ERC1155_TO_ERC20_FULL_OPEN, // 21: partial fills supported, anyone can execute ERC1155_TO_ERC20_PARTIAL_OPEN, // 22: no partial fills, only offerer or zone can execute ERC1155_TO_ERC20_FULL_RESTRICTED, // 23: partial fills supported, only offerer or zone can execute ERC1155_TO_ERC20_PARTIAL_RESTRICTED } // prettier-ignore enum BasicOrderRouteType { // 0: provide Ether (or other native token) to receive offered ERC721 item. ETH_TO_ERC721, // 1: provide Ether (or other native token) to receive offered ERC1155 item. ETH_TO_ERC1155, // 2: provide ERC20 item to receive offered ERC721 item. ERC20_TO_ERC721, // 3: provide ERC20 item to receive offered ERC1155 item. ERC20_TO_ERC1155, // 4: provide ERC721 item to receive offered ERC20 item. ERC721_TO_ERC20, // 5: provide ERC1155 item to receive offered ERC20 item. ERC1155_TO_ERC20 } // prettier-ignore enum ItemType { // 0: ETH on mainnet, MATIC on polygon, etc. NATIVE, // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work) ERC20, // 2: ERC721 items ERC721, // 3: ERC1155 items ERC1155, // 4: ERC721 items where a number of tokenIds are supported ERC721_WITH_CRITERIA, // 5: ERC1155 items where a number of ids are supported ERC1155_WITH_CRITERIA } // prettier-ignore enum Side { // 0: Items that can be spent OFFER, // 1: Items that must be received CONSIDERATION }
{ "viaIR": false, "codegen": "yul", "evmVersion": "london", "outputSelection": { "*": { "*": [ "abi", "metadata" ], "": [ "ast" ] } }, "optimizer": { "enabled": true, "mode": "3", "fallback_to_optimizing_for_size": false, "disable_system_request_memoization": true }, "metadata": {}, "libraries": {}, "enableEraVMExtensions": false, "forceEVMLA": false }
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"CallerIsNotNewPotentialOwner","type":"error"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"CallerIsNotOwner","type":"error"},{"inputs":[],"name":"InvalidCreator","type":"error"},{"inputs":[],"name":"InvalidInitialOwner","type":"error"},{"inputs":[{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"NewPotentialOwnerAlreadySet","type":"error"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"NewPotentialOwnerIsNullAddress","type":"error"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"NoPotentialOwnerCurrentlySet","type":"error"},{"inputs":[],"name":"NoZone","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"SignerAlreadyAdded","type":"error"},{"inputs":[],"name":"SignerCannotBeNullAddress","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"SignerCannotBeReauthorized","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"SignerNotPresent","type":"error"},{"inputs":[{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"derivedAddress","type":"address"}],"name":"ZoneAddressMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"ZoneAlreadyExists","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"zone","type":"address"},{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"PotentialOwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"signedZone","type":"address"},{"indexed":false,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"SignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"zoneAddress","type":"address"},{"indexed":false,"internalType":"string","name":"zoneName","type":"string"},{"indexed":false,"internalType":"string","name":"apiEndpoint","type":"string"},{"indexed":false,"internalType":"string","name":"documentationURI","type":"string"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"ZoneCreated","type":"event"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"zoneName","type":"string"},{"internalType":"string","name":"apiEndpoint","type":"string"},{"internalType":"string","name":"documentationURI","type":"string"},{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"createZone","outputs":[{"internalType":"address","name":"derivedAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"getActiveSigners","outputs":[{"internalType":"address[]","name":"signers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"getAdditionalZoneInformation","outputs":[{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"string","name":"zoneName","type":"string"},{"internalType":"string","name":"apiEndpoint","type":"string"},{"internalType":"uint256[]","name":"substandards","type":"uint256[]"},{"internalType":"string","name":"documentationURI","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"getPotentialOwner","outputs":[{"internalType":"address","name":"potentialOwner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"zoneName","type":"string"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"getZone","outputs":[{"internalType":"address","name":"derivedAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"signer","type":"address"}],"name":"isActiveSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"},{"internalType":"string","name":"newApiEndpoint","type":"string"}],"name":"updateAPIEndpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"},{"internalType":"string","name":"documentationURI","type":"string"}],"name":"updateDocumentationURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bool","name":"active","type":"bool"}],"name":"updateSigner","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
9c4d535b00000000000000000000000000000000000000000000000000000000000000000100039578e3a68d00ac1de154619b8bc452eed95f8fc9ef55687595c06bcda000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x0003000000000002000f000000000002000000000302001900000060021002700000034002200197000200000021035500010000000103550000000100300190000000490000c13d0000008003000039000000400030043f000000040020008c000006860000413d000000000301043b000000e003300270000003540030009c0000007a0000a13d000003550030009c000000e50000a13d000003560030009c000001c60000213d000003590030009c000002550000613d0000035a0030009c000006860000c13d000000440020008c000006860000413d0000000003000416000000000003004b000006860000c13d0000000401100370000000000101043b000003650010009c000006860000213d00000004011000390cfd0c0b0000040f0000000002010019000000400100043d000c00000001001d0000002001100039000b00000001001d0cfd0c550000040f0000000c030000290000000002310049000000200120008a000000000013043500000000010300190cfd0bf90000040f0000000c0100002900000000020104330000000b010000290cfd0cc00000040f0000000002000412000e00000002001d000d00600000003d000c00000001001d0000800501000039000000440300003900000000040004150000000e0440008a000000050440021000000378020000410cfd0cd50000040f00000024020000390000000102200367000000000202043b000000000301001900000000010004100000000c040000290cfd0c6a0000040f00000000120104340cfd0cc00000040f000002690000013d0000000001000416000000000001004b000006860000c13d0000014001000039000000400010043f0000000301000039000001000010043f0000034101000041000001200010043f0000000001000414000003400010009c0000034001008041000000c00110021000000342011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000800010043f000000400400043d0000002001400039000003430200004100000000002104350000002d024000390000034403000041000000000032043500000039024000390000034503000041000000000032043500000048024000390000034603000041000000000032043500000058024000390000034703000041000000000032043500000071024000390000034803000041000000000032043500000052020000390000000000240435000003490040009c000000950000413d0000037201000041000000000010043f0000004101000039000000040010043f000003680100004100000cff000104300000035e0030009c0000012b0000213d000003620030009c000003310000613d000003630030009c000003920000613d000003640030009c000006860000c13d000000240020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000401100370000000000201043b000003510020009c000006860000213d0000000001020019000c00000002001d0cfd0ca40000040f0000000c01000029000000000010043f000000200000043f000000400200003900000000010000190cfd0cc00000040f000002680000013d0000008002400039000b00000002001d000000400020043f000003400010009c00000340010080410000004001100210000c00000004001d0000000002040433000003400020009c00000340020080410000006002200210000000000112019f0000000002000414000003400020009c0000034002008041000000c002200210000000000112019f0000034a011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000a00010043f0000034b0100004100000000001004430000000001000414000003400010009c0000034001008041000000c0011002100000034c011001c70000800b020000390cfd0cf80000040f0000000100200190000007eb0000613d000000000101043b000000c00010043f0000000c040000290000034d0040009c0000000b05000029000000740000213d0000010401400039000000000051004b000000740000413d000000a4024000390000034e030000410000000000320435000000200200003900000000002104350000012401400039000000000001043500000000010004140000034f020000410000000000250435000000e40240003900000040030000390000000000320435000000c4024000390000006003000039000000000032043500000084024000390000000000020435000003400050009c00000340050080410000004002500210000003400010009c0000034001008041000000c001100210000000000112019f00000350011001c700008006020000390cfd0cf30000040f0000000100200190000004730000613d000000000101043b000000000001004b000004970000c13d00000002010003670000000002000031000004770000013d0000035b0030009c000002bd0000613d0000035c0030009c000002fb0000613d0000035d0030009c000006860000c13d000000240020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000401100370000000000101043b000c00000001001d000003510010009c000006860000213d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351001001980000046b0000613d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351011001970000000002000411000000000012004b000005050000c13d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000101100039000000000101041a0000035100100198000005830000c13d000000400100043d0000037b020000410000050a0000013d0000035f0030009c000003730000613d000003600030009c000004510000613d000003610030009c000006860000c13d000000440020008c000006860000413d0000000003000416000000000003004b000006860000c13d0000000403100370000000000303043b000c00000003001d000003510030009c000006860000213d0000002403100370000000000303043b000003650030009c000006860000213d0000002304300039000000000024004b000006860000813d000a00040030003d0000000a01100360000000000101043b000b00000001001d000003650010009c000006860000213d0000002403300039000900000003001d0000000b01300029000000000021004b000006860000213d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351001001980000046b0000613d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351011001970000000002000411000000000012004b000005050000c13d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000401100039000c00000001001d000000000101041a000000010010019000000001021002700000007f0220618f000800000002001d0000001f0020008c00000000020000390000000102002039000000000121013f00000001001001900000036d0000c13d0000000801000029000000200010008c000001a80000413d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d0000000b030000290000001f023000390000000502200270000000200030008c0000000002004019000000000301043b00000008010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b000001a80000813d000000000002041b0000000102200039000000000012004b000001a40000413d0000000b010000290000001f0010008c000006880000a13d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000200200008a0000000b02200180000000000101043b000002530000613d0000000104000367000000000300001900000009060000290000000005630019000000000554034f000000000505043b000000000051041b00000001011000390000002003300039000000000023004b000001bd0000413d000006a70000013d000003570030009c000002710000613d000003580030009c000006860000c13d000000440020008c000006860000413d0000000003000416000000000003004b000006860000c13d0000000403100370000000000303043b000c00000003001d000003510030009c000006860000213d0000002403100370000000000303043b000003650030009c000006860000213d0000002304300039000000000024004b000006860000813d000a00040030003d0000000a01100360000000000101043b000b00000001001d000003650010009c000006860000213d0000002403300039000900000003001d0000000b01300029000000000021004b000006860000213d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351001001980000046b0000613d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351011001970000000002000411000000000012004b000005050000c13d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000301100039000c00000001001d000000000101041a000000010010019000000001021002700000007f0220618f000800000002001d0000001f0020008c00000000020000390000000102002039000000000121013f00000001001001900000036d0000c13d0000000801000029000000200010008c000002410000413d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d0000000b030000290000001f023000390000000502200270000000200030008c0000000002004019000000000301043b00000008010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b000002410000813d000000000002041b0000000102200039000000000012004b0000023d0000413d0000000b010000290000001f0010008c000006880000a13d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000200200008a0000000b02200180000000000101043b0000069c0000c13d0000000003000019000006a70000013d000000240020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000401100370000000000201043b000003510020009c000006860000213d0000000001020019000c00000002001d0cfd0ca40000040f0000000c01000029000000000010043f000000200000043f000000400200003900000000010000190cfd0cc00000040f0000000101100039000000000101041a0000035101100197000000400200043d0000000000120435000003400020009c0000034002008041000000400120021000000379011001c700000cfe0001042e000000640020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000402100370000000000202043b000a00000002001d000003510020009c000006860000213d0000002402100370000000000202043b000900000002001d000003510020009c000006860000213d0000004401100370000000000201043b000000000002004b0000000001000039000000010100c039000700000002001d000000000012004b000006860000c13d0000000a01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351001001980000046b0000613d0000000a01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351011001970000000002000411000000000012004b000005570000c13d0000000a01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000c00000001001d000000090000006b000005970000c13d000000400100043d00000376020000410000046d0000013d000000240020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000401100370000000000101043b000c00000001001d000003510010009c000006860000213d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351001001980000046b0000613d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000701100039000000000301041a000000400200043d000b00000002001d000c00000003001d0000000002320436000a00000002001d000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d0000000c05000029000000000005004b000005130000c13d0000000b060000290000000a040000290000051e0000013d000000440020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000402100370000000000202043b000c00000002001d000003510020009c000006860000213d0000002401100370000000000101043b000b00000001001d000003510010009c000006860000213d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351001001980000046b0000613d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351011001970000000002000411000000000012004b000005050000c13d0000000b0000006b0000055d0000c13d000000400100043d0000037d020000410000050a0000013d000000240020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000401100370000000000101043b000c00000001001d000003510010009c000006860000213d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a00000351001001980000046b0000613d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000b00000001001d0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000201100039000000000201041a000000010320019000000001062002700000007f0660618f0000001f0060008c00000000040000390000000104002039000000000043004b000005420000613d0000037201000041000000000010043f0000002201000039000000040010043f000003680100004100000cff00010430000000440020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000402100370000000000302043b000003510030009c000006860000213d0000002401100370000000000101043b000c00000001001d000003510010009c000006860000213d000b00000003001d00000000010300190cfd0ca40000040f0000000b01000029000000000010043f000000200000043f000000400200003900000000010000190cfd0cc00000040f00000006011000390000000c020000290cfd0c940000040f000000000101041a000000ff001001900000000001000039000000010100c0390000026a0000013d000000a40020008c000006860000413d0000000003000416000000000003004b000006860000c13d0000000403100370000000000403043b000003650040009c000006860000213d0000002303400039000000000023004b000006860000813d0000000405400039000000000351034f000000000303043b000003650030009c000000740000213d0000001f063000390000038c066001970000003f066000390000038c06600197000003800060009c000000740000213d0000008006600039000000400060043f000000800030043f00000000043400190000002404400039000000000024004b000006860000213d0000002004500039000000000541034f0000038c063001980000001f0730018f000000a004600039000003bc0000613d000000a008000039000000000905034f000000009a09043c0000000008a80436000000000048004b000003b80000c13d000000000007004b000003c90000613d000000000565034f0000000306700210000000000704043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f0000000000540435000000a00330003900000000000304350000002403100370000000000403043b000003650040009c000006860000213d0000002303400039000000000023004b000006860000813d0000000405400039000000000351034f000000000303043b000003650030009c000000740000213d0000001f063000390000038c066001970000003f066000390000038c06600197000000400800043d0000000006680019000000000086004b00000000070000390000000107004039000003650060009c000000740000213d0000000100700190000000740000c13d000000400060043f000b00000008001d0000000006380436000c00000006001d00000000043400190000002404400039000000000024004b000006860000213d0000002004500039000000000541034f0000038c063001980000001f0730018f0000000c04600029000003f80000613d000000000805034f0000000c09000029000000008a08043c0000000009a90436000000000049004b000003f40000c13d000000000007004b000004050000613d000000000565034f0000000306700210000000000704043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f00000000005404350000000c0330002900000000000304350000004403100370000000000403043b000003650040009c000006860000213d0000002303400039000000000023004b000006860000813d0000000405400039000000000351034f000000000303043b000003650030009c000000740000213d0000001f063000390000038c066001970000003f066000390000038c06600197000000400700043d0000000006670019000a00000007001d000000000076004b00000000070000390000000107004039000003650060009c000000740000213d0000000100700190000000740000c13d000000400060043f0000000a060000290000000006360436000900000006001d00000000043400190000002404400039000000000024004b000006860000213d0000002002500039000000000421034f0000038c053001980000001f0630018f0000000902500029000004350000613d000000000704034f0000000908000029000000007907043c0000000008980436000000000028004b000004310000c13d000000000006004b000004420000613d000000000454034f0000000305600210000000000602043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f0000000000420435000000090230002900000000000204350000006402100370000000000202043b000800000002001d000003510020009c000006860000213d000000400200043d0000008401100370000000000101043b000700000001001d000000080000006b000007280000c13d0000038901000041000007f40000013d000000240020008c000006860000413d0000000002000416000000000002004b000006860000c13d0000000401100370000000000101043b000c00000001001d000003510010009c000006860000213d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a0000035100100198000004b30000c13d000000400100043d0000038b020000410000000000210435000003400010009c0000034001008041000000400110021000000377011001c700000cff0001043000020000000103550000006002100270000003400020019d00000340022001970000038c052001980000001f0620018f000000400300043d0000000004530019000004820000613d000000000701034f0000000008030019000000007907043c0000000008980436000000000048004b0000047e0000c13d000000000006004b0000048f0000613d000000000151034f0000000305600210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000003400020009c00000340020080410000006001200210000003400030009c00000340030080410000004002300210000000000112019f00000cff00010430000f03510010019b0000800201000039000000240300003900000000040004150000000f0440008a000000050440021000000352020000410cfd0cd50000040f000000e00010043f000000800200043d00000140000004430000016000200443000000a00200043d00000020030000390000018000300443000001a000200443000000c00200043d0000004004000039000001c000400443000001e000200443000000600200003900000200002004430000022000100443000001000030044300000004010000390000012000100443000003530100004100000cfe0001042e0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000101100039000000000101041a00000351011001970000000002000411000000000012004b000005080000c13d0000000001000414000003400010009c0000034001008041000000c0011002100000034a011001c70000800d0200003900000002030000390000037a0400004100000000050000190cfd0cf30000040f0000000100200190000006860000613d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000101100039000000000201041a0000037102200197000000000021041b0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a0000000002000414000003400020009c0000034002008041000000c00220021000000351061001970000034a012001c70000800d0200003900000004030000390000037f040000410000000c0500002900000000070004110cfd0cf30000040f0000000100200190000006860000613d0000000c010000290cfd0c840000040f000000000201041a00000371022001970000000003000411000005c10000013d000000400100043d00000367020000410000050a0000013d000000400100043d0000037e02000041000000000021043500000004021000390000000c030000290000000000320435000003400010009c0000034001008041000000400110021000000368011001c700000cff00010430000000000101043b00000000020000190000000b060000290000000a04000029000000000301041a0000035103300197000000000434043600000001011000390000000102200039000000000052004b000005170000413d00000000016400490000001f011000390000038c021001970000000001620019000000000021004b00000000020000390000000102004039000003650010009c000000740000213d0000000100200190000000740000c13d000000400010043f00000020020000390000000002210436000000000306043300000000003204350000004002100039000000000003004b000005390000613d000000000400001900000020066000390000000005060433000003510550019700000000025204360000000104400039000000000034004b000005320000413d0000000002120049000003400020009c00000340020080410000006002200210000003400010009c00000340010080410000004001100210000000000112019f00000cfe0001042e000000400400043d0000000005640436000000000003004b000a00000005001d0000057d0000613d000900000006001d000800000004001d000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000090000006b000005c50000c13d0000000001000019000005d00000013d000000400100043d0000036702000041000000000021043500000004021000390000000a030000290000050d0000013d0000000c01000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000101100039000000000101041a00000351011001970000000b0010006b000005af0000c13d000000400100043d00000024021000390000000b0300002900000000003204350000037c02000041000000000021043500000004021000390000000c030000290000000000320435000003400010009c000003400100804100000040011002100000036f011001c700000cff000104300000038d012001970000000000150435000000000006004b00000020010000390000000001006039000005d10000013d0000000001000414000003400010009c0000034001008041000000c0011002100000034a011001c70000800d0200003900000002030000390000037a0400004100000000050000190cfd0cf30000040f0000000100200190000006860000613d0000000c010000290cfd0c840000040f0000000101100039000000000201041a0000037102200197000000000021041b000000000100001900000cfe0001042e0000000901000029000000000010043f0000000c010000290000000601100039000b00000001001d000000200010043f000000070000006b000006580000c13d0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a000000ff00100190000006760000c13d000000400100043d0000037502000041000006980000013d0000000001000414000003400010009c0000034001008041000000c0011002100000034a011001c70000800d0200003900000002030000390000037a040000410000000b050000290cfd0cf30000040f0000000100200190000006860000613d0000000c010000290cfd0c840000040f0000000101100039000000000201041a00000371022001970000000b03000029000000000232019f000000000021041b000000000100001900000cfe0001042e000000000201043b00000000010000190000000a0500002900000009060000290000000003510019000000000402041a000000000043043500000001022000390000002001100039000000000061004b000005c90000413d00000008040000290000003f011000390000038c021001970000000001420019000000000021004b00000000020000390000000102004039000003650010009c000000740000213d0000000100200190000000740000c13d000000400010043f0000000a01000029000003400010009c000003400100804100000040011002100000000002040433000003400020009c00000340020080410000006002200210000000000112019f0000000002000414000003400020009c0000034002008041000000c002200210000000000112019f0000034a011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000a00000001001d000000800100043d000800000001001d000000400100043d000900000001001d0000037801000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000003400010009c0000034001008041000000c00110021000000382011001c700008005020000390cfd0cf80000040f0000000100200190000007eb0000613d000000000101043b000000000010043f0000000a01000029000000200010043f000003780100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000003400010009c0000034001008041000000c00110021000000382011001c700008005020000390cfd0cf80000040f0000000100200190000007eb0000613d000000000101043b000000400010043f0000034b0100004100000000001004430000000001000414000003400010009c0000034001008041000000c0011002100000034c011001c70000800b020000390cfd0cf80000040f0000000100200190000007eb0000613d000000000101043b000000600010043f0000000c01000029000000800010043f0000000001000414000003400010009c0000034001008041000000c0011002100000038a011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000a00000001001d0000000901000029000000400010043f000000600000043f0000000801000029000000800010043f0000000b010000290000000201100039000000000201041a000000010320019000000001042002700000007f0440618f000c00000004001d0000001f0040008c00000000040000390000000104002039000000000442013f00000001004001900000036d0000c13d00000009040000290000000c050000290000000004540436000800000004001d000000000003004b000007ec0000613d000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d0000000c0000006b000008190000c13d0000000001000019000008240000013d0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a000000ff00100190000006960000c13d0000000901000029000000000010043f0000000b01000029000000200010043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000101041a0000ff0000100190000007250000c13d0000036c0100004100000000001004430000000a0100002900000004001004430000000001000414000003400010009c0000034001008041000000c0011002100000036d011001c700008002020000390cfd0cf80000040f0000000100200190000007eb0000613d000000000101043b000000000001004b000006bb0000c13d000000000100001900000cff000104300000000b0000006b00000000010000190000068f0000613d0000000a0100002900000020011000390000000101100367000000000101043b0000000b0400002900000003024002100000038e0220027f0000038e02200167000000000221016f0000000101400210000006b60000013d000000400100043d0000036a020000410000000000210435000000040210003900000009030000290000050d0000013d0000000104000367000000000300001900000009060000290000000005630019000000000554034f000000000505043b000000000051041b00000001011000390000002003300039000000000023004b0000069f0000413d0000000b0020006c000006b30000813d0000000b020000290000000302200210000000f80220018f0000038e0220027f0000038e0220016700000009033000290000000103300367000000000303043b000000000223016f000000000021041b00000001010000390000000b020000290000000102200210000000000112019f0000000c02000029000000000012041b000000000100001900000cfe0001042e000000400300043d0000002401300039000000070200002900000000002104350000036e010000410000000000130435000800000003001d00000004013000390000000902000029000000000021043500000000010004140000000a02000029000000040020008c000006d90000613d0000000802000029000003400020009c00000340020080410000004002200210000003400010009c0000034001008041000000c001100210000000000121019f0000036f011001c70000000a020000290cfd0cf30000040f0000006003100270000003400030019d00020000000103550000000100200190000007fa0000613d0000000801000029000003650010009c000000740000213d0000000801000029000000400010043f0000000901000029000000000010043f0000000b01000029000000200010043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000201041a0000038d0220019700000007022001af000000000021041b0000000901000029000000000010043f0000000b01000029000000200010043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000000000201041a0000038f0220019700000100022001bf000000000021041b0000000c010000290000000701100039000c00000001001d000000000101041a000800000001001d000000070000006b000008590000c13d000000080000006b000008700000613d000b00000000001d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000b0400002900000000024100190000000c01000029000000000101041a000000000202041a0000035102200197000000090020006c000008f40000613d000b00010040003d0000000b0010006b000800000001001d0000070c0000413d000008700000013d000000400100043d0000036b02000041000006980000013d000000070100002900000060011002700000000003000411000000000031004b000007f30000c13d00000020012000390000002003000039000600000003001d00000000003104350000004004200039000000800300043d00000000003404350000006004200039000000000003004b0000073f0000613d00000000050000190000000006450019000000a007500039000000000707043300000000007604350000002005500039000000000035004b000007380000413d000000000443001900000000000404350000001f033000390000038c03300197000000400430003900000000004204350000007f033000390000038c043001970000000003240019000000000043004b00000000040000390000000104004039000003650030009c000000740000213d0000000100400190000000740000c13d000000400030043f000003400010009c000003400100804100000040011002100000000002020433000003400020009c00000340020080410000006002200210000000000112019f0000000002000414000003400020009c0000034002008041000000c002200210000000000112019f0000034a011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b000500000001001d0000037801000041000000000010044300000000010004120000000400100443000000600100003900000024001004430000000001000414000003400010009c0000034001008041000000c00110021000000382011001c700008005020000390cfd0cf80000040f0000000100200190000007eb0000613d000000000201043b000000400100043d000000a0031000390000000504000029000000000043043500000080031000390000000000230435000000600210003900000007030000290000000000320435000000400210003900000000030004100000000000320435000000200210003900000383030000410000000000320435000000a0030000390000000000310435000003840010009c000000740000213d000000c003100039000000400030043f000003400020009c000003400200804100000040022002100000000001010433000003400010009c00000340010080410000006001100210000000000121019f0000000002000414000003400020009c0000034002008041000000c002200210000000000112019f0000034a011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000036c0200004100000000002004430000035101100197000500000001001d00000004001004430000000001000414000003400010009c0000034001008041000000c0011002100000036d011001c700008002020000390cfd0cf80000040f0000000100200190000007eb0000613d000000400200043d000000000101043b000000000001004b0000099d0000c13d000003860020009c000000740000213d00000084012000390000002003000039000000000031043500000024012000390000034e030000410000000000310435000000a403200039000000800100043d0000000000130435000000c403200039000000000001004b000007c40000613d00000000040000190000000005340019000000a006400039000000000606043300000000006504350000002004400039000000000014004b000007bd0000413d000000000331001900000000000304350000001f011000390000038c0110019700000040031000390000006404200039000000000500041400000000003404350000004403200039000000600400003900000000004304350000034f030000410000000000320435000000040320003900000007040000290000000000430435000000c401100039000003400010009c00000340010080410000006001100210000003400020009c00000340020080410000004002200210000000000121019f000003400050009c0000034005008041000000c002500210000000000112019f0000034a011001c700008006020000390cfd0cf30000040f0000000100200190000009b30000613d000000000101043b000000000001004b000009c30000c13d00000002010003670000000002000031000009b70000013d000000000001042f0000038d01200197000000080200002900000000001204350000000c0000006b00000020010000390000000001006039000008240000013d00000381010000410000000000120435000003400020009c0000034002008041000000400120021000000377011001c700000cff0001043000000340033001970000001f0530018f0000037006300198000000400200043d0000000004620019000008060000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000008020000c13d000000000005004b000008130000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000003400020009c00000340020080410000004002200210000000000112019f00000cff00010430000000000201043b000000000100001900000008050000290000000c060000290000000003510019000000000402041a000000000043043500000001022000390000002001100039000000000061004b0000081d0000413d0000003f011000390000038c011001970000000902100029000000000012004b00000000010000390000000101004039000c00000002001d000003650020009c000000740000213d0000000100100190000000740000c13d0000000c01000029000000400010043f0000000b010000290000000301100039000000000201041a000000010320019000000001042002700000007f0440618f000700000004001d0000001f0040008c00000000040000390000000104002039000000000442013f00000001004001900000036d0000c13d0000000c0400002900000007050000290000000004540436000600000004001d000000000003004b000008520000613d000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000070000006b0000088c0000c13d0000000001000019000008970000013d0000038d0120019700000006020000290000000000120435000000070000006b00000020010000390000000001006039000008970000013d0000000801000029000003650010009c000000740000213d000000080100002900000001011000390000000c02000029000000000012041b000000000020043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000801100029000000000201041a000003710220019700000009022001af000000000021041b000000400100043d00000040021000390000000703000029000000000032043500000009020000290000035102200197000000200310003900000000002304350000000a0200002900000351022001970000000000210435000003400010009c000003400100804100000040011002100000000002000414000003400020009c0000034002008041000000c002200210000000000112019f00000373011001c70000800d02000039000000010300003900000374040000410cfd0cf30000040f0000000100200190000006860000613d000000000100001900000cfe0001042e000000000201043b0000000001000019000000060500002900000007060000290000000003510019000000000402041a000000000043043500000001022000390000002001100039000000000061004b000008900000413d00000006020000290000000c0220006a00000000011200190000001f011000390000038c011001970000000c02100029000000000012004b00000000010000390000000101004039000700000002001d000003650020009c000000740000213d0000000100100190000000740000c13d0000000702000029000000400020043f0000000b010000290000000501100039000000000301041a000500000003001d0000000002320436000400000002001d000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000050000006b000008bb0000c13d0000000404000029000008c50000013d000000000101043b000000000200001900000004040000290000000505000029000000000301041a000000000434043600000001011000390000000102200039000000000052004b000008bf0000413d000000070140006a0000001f011000390000038c011001970000000702100029000000000012004b00000000010000390000000101004039000500000002001d000003650020009c000000740000213d0000000100100190000000740000c13d0000000501000029000000400010043f0000000b010000290000000401100039000000000201041a000000010320019000000001042002700000007f0440618f000b00000004001d0000001f0040008c00000000040000390000000104002039000000000442013f00000001004001900000036d0000c13d00000005040000290000000b050000290000000004540436000400000004001d000000000003004b000009290000613d000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d0000000b0000006b000009a70000c13d00000000010000190000092f0000013d00000008020000290008000100200092000000080010006c000009970000a13d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000c02000029000000000202041a0000000b0020006c000009970000a13d0000000801100029000000000101041a000800000001001d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d00000008020000290000035102200197000000000101043b0000000b01100029000000000301041a0000037103300197000000000223019f000000000021041b0000000c01000029000000000101041a000b00000001001d000000000001004b00000a1d0000c13d0000037201000041000000000010043f0000003101000039000000040010043f000003680100004100000cff000104300000038d01200197000000040200002900000000001204350000000b0000006b000000200100003900000000010060390000000402000029000000050220006a00000000011200190000001f011000390000038c021001970000000501200029000000000021004b00000000020000390000000102004039000003650010009c000000740000213d0000000100200190000000740000c13d000000400010043f0000002002100039000000a00300003900000000003204350000000a02000029000000000021043500000009020000290000000002020433000000a0031000390000000000230435000000c003100039000000000002004b0000000807000029000009520000613d000000000400001900000000053400190000000006470019000000000606043300000000006504350000002004400039000000000024004b0000094b0000413d000000000423001900000000000404350000001f022000390000038c0220019700000000022300190000000003120049000000400410003900000000003404350000000c0300002900000000030304330000000002320436000000000003004b0000000607000029000009680000613d000000000400001900000000052400190000000006470019000000000606043300000000006504350000002004400039000000000034004b000009610000413d000000000432001900000000000404350000001f033000390000038c033001970000000002320019000000000312004900000060041000390000000000340435000000070300002900000000040304330000000003420436000000000004004b0000097e0000613d0000000005000019000000070600002900000000020300190000002006600039000000000306043300000000033204360000000105500039000000000045004b000009770000413d0000000004130049000000800510003900000000004504350000000504000029000000000404043300000000004304350000004002200039000000000004004b0000000407000029000009900000613d000000000300001900000000052300190000000006370019000000000606043300000000006504350000002003300039000000000043004b000009890000413d0000001f034000390000038c0330019700000000044200190000000000040435000000000313004900000000022300190000053a0000013d0000037201000041000000000010043f0000003201000039000000040010043f000003680100004100000cff0001043000000385010000410000000000120435000000040120003900000005030000290000000000310435000003400020009c0000034002008041000000400120021000000368011001c700000cff00010430000000000201043b000000000100001900000004050000290000000b060000290000000003510019000000000402041a000000000043043500000001022000390000002001100039000000000061004b000009ab0000413d0000092f0000013d00020000000103550000006002100270000003400020019d00000340022001970000038c052001980000001f0620018f000000400300043d0000000004530019000004820000613d000000000701034f0000000008030019000000007907043c0000000008980436000000000048004b000009be0000c13d000004820000013d0000035101100197000000050010006b00000a310000c13d0000000501000029000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000301043b000000000103041a000003710110019700000008011001af000400000003001d000000000013041b000000800100043d000300000001001d000003650010009c000000740000213d00000004010000290000000201100039000200000001001d000000000101041a000000010010019000000001021002700000007f0220618f000100000002001d0000001f0020008c00000000020000390000000102002039000000000121013f00000001001001900000036d0000c13d0000000101000029000000200010008c00000a090000413d0000000201000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d00000003030000290000001f023000390000000502200270000000200030008c0000000002004019000000000301043b00000001010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b00000a090000813d000000000002041b0000000102200039000000000012004b00000a050000413d0000000301000029000000200010008c00000a3e0000413d0000000201000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000200200008a0000000302200180000000000101043b00000a4a0000c13d000000200300003900000a560000013d0000000c01000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d0000000b02000029000000010220008a000000000101043b0000000001210019000000000301041a0000037103300197000000000031041b0000000c010000290000086f0000013d000000400200043d0000002403200039000000050400002900000000004304350000038703000041000000000032043500000004032000390000000000130435000003400020009c000003400200804100000040012002100000036f011001c700000cff00010430000000030000006b000000000100001900000a640000613d000000030300002900000003013002100000038e0110027f0000038e01100167000000a00200043d000000000112016f0000000102300210000000000121019f00000a640000013d000000010320008a000000050330027000000000043100190000002003000039000000010440003900000080053000390000000005050433000000000051041b00000020033000390000000101100039000000000041004b00000a4f0000c13d000000030020006c00000a610000813d00000003020000290000000302200210000000f80220018f0000038e0220027f0000038e0220016700000080033000390000000003030433000000000223016f000000000021041b0000000301000029000000010110021000000001011001bf0000000202000029000000000012041b0000000b010000290000000001010433000300000001001d000003650010009c000000740000213d00000004010000290000000301100039000200000001001d000000000101041a000000010010019000000001021002700000007f0220618f000100000002001d0000001f0020008c00000000020000390000000102002039000000000121013f00000001001001900000036d0000c13d0000000101000029000000200010008c00000a980000413d0000000201000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d00000003030000290000001f023000390000000502200270000000200030008c0000000002004019000000000301043b00000001010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b00000a980000813d000000000002041b0000000102200039000000000012004b00000a940000413d0000000301000029000000200010008c00000aac0000413d0000000201000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000200200008a0000000302200180000000000101043b00000ab90000c13d000000200300003900000ac50000013d000000030000006b000000000100001900000ad30000613d000000030300002900000003013002100000038e0110027f0000038e011001670000000c020000290000000002020433000000000112016f0000000102300210000000000121019f00000ad30000013d000000010320008a00000005033002700000000004310019000000200300003900000001044000390000000b053000290000000005050433000000000051041b00000020033000390000000101100039000000000041004b00000abe0000c13d000000030020006c00000ad00000813d00000003020000290000000302200210000000f80220018f0000038e0220027f0000038e022001670000000b033000290000000003030433000000000223016f000000000021041b0000000301000029000000010110021000000001011001bf0000000202000029000000000012041b0000000a010000290000000001010433000300000001001d000003650010009c000000740000213d00000004010000290000000401100039000200000001001d000000000101041a000000010010019000000001021002700000007f0220618f000100000002001d0000001f0020008c00000000020000390000000102002039000000000121013f00000001001001900000036d0000c13d0000000101000029000000200010008c00000b070000413d0000000201000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d00000003030000290000001f023000390000000502200270000000200030008c0000000002004019000000000301043b00000001010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b00000b070000813d000000000002041b0000000102200039000000000012004b00000b030000413d0000000301000029000000200010008c00000b360000413d0000000201000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000200200008a0000000302200180000000000101043b00000b260000613d000000010320008a00000005033002700000000003310019000600200000003d000000010330003900000006050000290000000a045000290000000004040433000000000041041b000600200050003d0000000101100039000000000031004b00000b1e0000c13d000000030020006c00000b320000813d00000003020000290000000302200210000000f80220018f0000038e0220027f0000038e0220016700000006040000290000000a034000290000000003030433000000000223016f000000000021041b0000000301000029000000010110021000000001011001bf00000b420000013d000000030000006b000000000100001900000b420000613d000000030300002900000003013002100000038e0110027f0000038e0110016700000009020000290000000002020433000000000112016f0000000102300210000000000121019f0000000202000029000000000012041b000000400100043d000600000001001d000003800010009c000000740000213d00000006030000290000008001300039000000400010043f0000006001300039000000090200003900000000002104350000004001300039000000080200003900000000002104350000002001300039000000070200003900000000002104350000000101000039000000000013043500000004010000290000000502100039000000000302041a0000000401000039000400000002001d000000000012041b000300000003001d000000050030008c00000b730000413d0000000401000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000201043b00000003012000290000000402200039000000000012004b00000b730000813d000000000002041b0000000102200039000000000012004b00000b6f0000413d0000000401000029000000000010043f0000000001000414000003400010009c0000034001008041000000c00110021000000369011001c700008010020000390cfd0cf80000040f0000000100200190000006860000613d000000000101043b0000000002000019000000000312001900000006050000290000000054050434000600000005001d000000ff0440018f000000000043041b000000030020008c000000010220003900000b800000413d000000400100043d0000002002100039000000a003000039000000000032043500000005020000290000000000210435000000a003100039000000800200043d0000000000230435000000c003100039000000000002004b00000b9d0000613d00000000040000190000000005340019000000a006400039000000000606043300000000006504350000002004400039000000000024004b00000b960000413d000000000432001900000000000404350000001f022000390000038c0220019700000000023200190000000003120049000000400410003900000000003404350000000b0300002900000000030304330000000002320436000000000003004b00000bb20000613d000000000400001900000000052400190000000c06400029000000000606043300000000006504350000002004400039000000000034004b00000bab0000413d000000000423001900000000000404350000001f033000390000038c0330019700000000022300190000000003120049000000600410003900000000003404350000000a0300002900000000030304330000000002320436000000000003004b00000bc70000613d000000000400001900000000052400190000000906400029000000000606043300000000006504350000002004400039000000000034004b00000bc00000413d000000000423001900000000000404350000008004100039000000070500002900000000005404350000001f033000390000038c0330019700000000021200490000000002320019000003400020009c00000340020080410000006002200210000003400010009c00000340010080410000004001100210000000000112019f0000000002000414000003400020009c0000034002008041000000c002200210000000000112019f0000034a011001c70000800d02000039000000010300003900000388040000410cfd0cf30000040f0000000100200190000006860000613d0000000001000414000003400010009c0000034001008041000000c0011002100000034a011001c70000800d0200003900000004030000390000037f040000410000000505000029000000000600001900000008070000290cfd0cf30000040f0000000100200190000006860000613d000000400100043d00000005020000290000000000210435000003400010009c0000034001008041000000400110021000000379011001c700000cfe0001042e0000001f022000390000038c022001970000000001120019000000000021004b00000000020000390000000102004039000003650010009c00000c050000213d000000010020019000000c050000c13d000000400010043f000000000001042d0000037201000041000000000010043f0000004101000039000000040010043f000003680100004100000cff0001043000000000030100190000001f01100039000000000021004b0000000004000019000003900400404100000390052001970000039001100197000000000651013f000000000051004b00000000010000190000039001002041000003900060009c000000000104c019000000000001004b00000c530000613d0000000106000367000000000136034f000000000401043b000003910040009c00000c4d0000813d0000001f014000390000038c011001970000003f011000390000038c05100197000000400100043d0000000005510019000000000015004b00000000080000390000000108004039000003650050009c00000c4d0000213d000000010080019000000c4d0000c13d000000400050043f000000000541043600000020033000390000000008430019000000000028004b00000c530000213d000000000336034f0000038c064001980000001f0740018f000000000265001900000c3d0000613d000000000803034f0000000009050019000000008a08043c0000000009a90436000000000029004b00000c390000c13d000000000007004b00000c4a0000613d000000000363034f0000000306700210000000000702043300000000076701cf000000000767022f000000000303043b0000010006600089000000000363022f00000000036301cf000000000373019f000000000032043500000000024500190000000000020435000000000001042d0000037201000041000000000010043f0000004101000039000000040010043f000003680100004100000cff00010430000000000100001900000cff0001043000000020030000390000000004310436000000003202043400000000002404350000004001100039000000000002004b00000c640000613d000000000400001900000000051400190000000006430019000000000606043300000000006504350000002004400039000000000024004b00000c5d0000413d000000000321001900000000000304350000001f022000390000038c022001970000000001210019000000000001042d0000000005010019000000400100043d000000a0061000390000000000460435000000800410003900000000003404350000006003100039000000000023043500000040021000390000000000520435000000200210003900000383030000410000000000320435000000a0020000390000000000210435000003920010009c00000c7e0000813d000000c002100039000000400020043f000000000001042d0000037201000041000000000010043f0000004101000039000000040010043f000003680100004100000cff000104300000035101100197000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f000000010020019000000c920000613d000000000101043b000000000001042d000000000100001900000cff000104300000035102200197000000000020043f000000200010043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f000000010020019000000ca20000613d000000000101043b000000000001042d000000000100001900000cff000104300000035101100197000000000010043f000000200000043f0000000001000414000003400010009c0000034001008041000000c00110021000000366011001c700008010020000390cfd0cf80000040f000000010020019000000cb50000613d000000000101043b000000000101041a000003510010019800000cb70000613d000000000001042d000000000100001900000cff00010430000000400100043d0000038b020000410000000000210435000003400010009c0000034001008041000000400110021000000377011001c700000cff00010430000000000001042f000003400010009c00000340010080410000004001100210000003400020009c00000340020080410000006002200210000000000112019f0000000002000414000003400020009c0000034002008041000000c002200210000000000112019f0000034a011001c700008010020000390cfd0cf80000040f000000010020019000000cd30000613d000000000101043b000000000001042d000000000100001900000cff0001043000000000050100190000000000200443000000050030008c00000ce30000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b00000cdb0000413d000003400030009c000003400300804100000060013002100000000002000414000003400020009c0000034002008041000000c002200210000000000112019f00000393011001c700000000020500190cfd0cf80000040f000000010020019000000cf20000613d000000000101043b000000000001042d000000000001042f00000cf6002104210000000102000039000000000001042d0000000002000019000000000001042d00000cfb002104230000000102000039000000000001042d0000000002000019000000000001042d00000cfd0000043200000cfe0001042e00000cff0001043000000000000000000000000000000000000000000000000000000000ffffffff322e3000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000003000001200000000000000000454950373132446f6d61696e2800000000000000000000000000000000000000737472696e67206e616d652c0000000000000000000000000000000000000000737472696e672076657273696f6e2c000000000000000000000000000000000075696e7432353620636861696e49642c000000000000000000000000000000006164647265737320766572696679696e67436f6e7472616374000000000000002900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff8002000000000000000000000000000000000000000000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffefb01000301ad1e17143e909bc74b32334540f0aab4611887369a05994c896ec1cb3cda33511d41a8a5431b1770c5bc0ddd62e1cd30555d16659b89c0d60f4f9f5702000000000000000000000000000000000000c4000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffe03fe177bb050a40ea1b3ecd64121a3fa063a94b6d404b2f45c64697555efe0e00000002000000000000000000000000000001400000010000000000000000000000000000000000000000000000000000000000000000000000000066a2489e00000000000000000000000000000000000000000000000000000000906c87cb00000000000000000000000000000000000000000000000000000000dca0938200000000000000000000000000000000000000000000000000000000dca0938300000000000000000000000000000000000000000000000000000000e89fad5800000000000000000000000000000000000000000000000000000000906c87cc00000000000000000000000000000000000000000000000000000000ad07dd7e0000000000000000000000000000000000000000000000000000000066a2489f000000000000000000000000000000000000000000000000000000006d435421000000000000000000000000000000000000000000000000000000007b37e56100000000000000000000000000000000000000000000000000000000515cf7eb00000000000000000000000000000000000000000000000000000000515cf7ec0000000000000000000000000000000000000000000000000000000051710e4500000000000000000000000000000000000000000000000000000000541bbd320000000000000000000000000000000000000000000000000000000004789c98000000000000000000000000000000000000000000000000000000000eb925160000000000000000000000000000000000000000000000000000000014afd79e000000000000000000000000000000000000000000000000ffffffffffffffff0200000000000000000000000000000000000040000000000000000000000000d4ed9a1700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000002000000000000000000000000000000000000200000000000000000000000009fb0d64c000000000000000000000000000000000000000000000000000000009d066d5a000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000f460590b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffe0ffffffffffffffffffffffff00000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000000000000000000000b658b57f3a8d73a4f3bb96789edcebed831f44d5cc4a513d4416c6bb25ea0e8bde0cce5000000000000000000000000000000000000000000000000000000000b7474e01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e000000000000000000000000000000000000002000000000000000000000000011a3cf439fb225bfe74225716b6774765670ec1060e3796802e62139d69974da6b01361600000000000000000000000000000000000000000000000000000000cbc080ca000000000000000000000000000000000000000000000000000000003dfa446b0000000000000000000000000000000000000000000000000000000088c3a11500000000000000000000000000000000000000000000000000000000c8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec000000000000000000000000000000000000000000000000ffffffffffffff7fcb6e53440000000000000000000000000000000000000000000000000000000002000002000000000000000000000000000000440000000000000000000000002020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494000000000000000000000000000000000000000000000000ffffffffffffff3f0083438500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7b09d64a7700000000000000000000000000000000000000000000000000000000106160dca18b77e6926325d074dd8328fbec25f496d6fd313ef44f3e581e2afe99faaa040000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000a0000000000000000000000000b1a69e4800000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000ffffffffffffff40020000020000000000000000000000000000000000000000000000000000000090c42c141d97f5ee45a1102c7f393aadee4c3f3ad13d9a21dead01bbadf4c021
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.