Source Code
Overview
ETH Balance
0 ETH
Multichain Info
N/A
Latest 5 from a total of 5 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Link Ip To Paren... | 5201389 | 652 days ago | IN | 0 ETH | 0.02426783 | ||||
| Mint License | 5201389 | 652 days ago | IN | 0 ETH | 0.01672356 | ||||
| Mint License | 5201389 | 652 days ago | IN | 0 ETH | 0.01808504 | ||||
| Add Policy To Ip | 5201389 | 652 days ago | IN | 0 ETH | 0.01371955 | ||||
| Register Policy ... | 5201389 | 652 days ago | IN | 0 ETH | 0.00523922 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
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 Source Code Verified (Exact Match)
Contract Name:
LicenseRegistry
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 20000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
// external
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
// contracts
import { ShortStringOps } from "contracts/utils/ShortStringOps.sol";
import { IPolicyVerifier } from "contracts/interfaces/licensing/IPolicyVerifier.sol";
import { IMintParamVerifier } from "contracts/interfaces/licensing/IMintParamVerifier.sol";
import { ILinkParamVerifier } from "contracts/interfaces/licensing/ILinkParamVerifier.sol";
import { ITransferParamVerifier } from "contracts/interfaces/licensing/ITransferParamVerifier.sol";
import { ILicenseRegistry } from "contracts/interfaces/registries/ILicenseRegistry.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { Licensing } from "contracts/lib/Licensing.sol";
import { IPolicyFrameworkManager } from "contracts/interfaces/licensing/IPolicyFrameworkManager.sol";
import { IAccessController } from "contracts/interfaces/IAccessController.sol";
import { IIPAccountRegistry } from "contracts/interfaces/registries/IIPAccountRegistry.sol";
import { IPAccountChecker } from "contracts/lib/registries/IPAccountChecker.sol";
// TODO: consider disabling operators/approvals on creation
contract LicenseRegistry is ERC1155, ILicenseRegistry {
using IPAccountChecker for IIPAccountRegistry;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableSet for EnumerableSet.AddressSet;
using Strings for *;
using ShortStrings for *;
using Licensing for *;
struct PolicySetup {
uint256 index;
bool isSet;
bool active;
bool inheritedPolicy;
}
IAccessController public immutable ACCESS_CONTROLLER;
IIPAccountRegistry public immutable IP_ACCOUNT_REGISTRY;
mapping(address framework => bool registered) private _registeredFrameworkManagers;
mapping(bytes32 policyHash => uint256 policyId) private _hashedPolicies;
mapping(uint256 policyId => Licensing.Policy policyData) private _policies;
uint256 private _totalPolicies;
/// @notice internal mapping to track if a policy was set by linking or minting, and the
/// index of the policy in the ipId policy set
/// Policies can't be removed, but they can be deactivated by setting active to false
mapping(address ipId => mapping(uint256 policyId => PolicySetup setup)) private _policySetups;
mapping(address ipId => EnumerableSet.UintSet policyIds) private _policiesPerIpId;
mapping(address ipId => EnumerableSet.AddressSet parentIpIds) private _ipIdParents;
mapping(bytes32 licenseHash => uint256 ids) private _hashedLicenses;
mapping(uint256 licenseIds => Licensing.License licenseData) private _licenses;
/// This tracks the number of licenses registered in the protocol, it will not decrease when a license is burnt.
uint256 private _totalLicenses;
constructor(address accessController, address ipAccountRegistry) ERC1155("") {
ACCESS_CONTROLLER = IAccessController(accessController);
IP_ACCOUNT_REGISTRY = IIPAccountRegistry(ipAccountRegistry);
}
/// @notice registers a policy framework manager into the contract, so it can add policy data for
/// licenses.
/// @param manager the address of the manager. Will be ERC165 checked for IPolicyFrameworkManager
function registerPolicyFrameworkManager(address manager) external {
if (!ERC165Checker.supportsInterface(manager, type(IPolicyFrameworkManager).interfaceId)) {
revert Errors.LicenseRegistry__InvalidPolicyFramework();
}
IPolicyFrameworkManager fwManager = IPolicyFrameworkManager(manager);
string memory licenseUrl = fwManager.licenseTextUrl();
if (bytes(licenseUrl).length == 0 || licenseUrl.equal("")) {
revert Errors.LicenseRegistry__EmptyLicenseUrl();
}
_registeredFrameworkManagers[manager] = true;
emit PolicyFrameworkRegistered(manager, fwManager.name(), licenseUrl);
}
/// Adds a policy to an ipId, which can be used to mint licenses.
/// Licnses are permissions for ipIds to be derivatives (children).
/// if policyId is not defined in LicenseRegistry, reverts.
/// Will revert if ipId already has the same policy
/// @param ipId to receive the policy
/// @param polId id of the policy data
/// @return indexOnIpId position of policy within the ipIds policy set
function addPolicyToIp(address ipId, uint256 polId) external returns (uint256 indexOnIpId) {
if (
msg.sender != ipId &&
!ACCESS_CONTROLLER.checkPermission(ipId, msg.sender, address(this), this.addPolicyToIp.selector)
) {
revert Errors.LicenseRegistry__UnauthorizedAccess();
}
if (!isPolicyDefined(polId)) {
revert Errors.LicenseRegistry__PolicyNotFound();
}
return _addPolicyIdToIp(ipId, polId, false);
}
/// @notice Registers a policy into the contract. MUST be called by a registered
/// framework or it will revert. The policy data and its integrity must be
/// verified by the policy framework manager.
/// @param data The policy data
function registerPolicy(bytes memory data) external returns (uint256 policyId) {
_verifyRegisteredFramework(address(msg.sender));
Licensing.Policy memory pol = Licensing.Policy({ policyFramework: msg.sender, data: data });
(uint256 polId, bool newPol) = _addIdOrGetExisting(abi.encode(pol), _hashedPolicies, _totalPolicies);
if (!newPol) {
revert Errors.LicenseRegistry__PolicyAlreadyAdded();
} else {
_totalPolicies = polId;
_policies[polId] = pol;
emit PolicyRegistered(msg.sender, polId, data);
}
return polId;
}
/// Mints license NFTs representing a policy granted by a set of ipIds (licensors). This NFT needs to be burned
/// in order to link a derivative IP with its parents.
/// If this is the first combination of policy and licensors, a new licenseId
/// will be created (by incrementing prev totalLicenses).
/// If not, the license is fungible and an id will be reused.
/// The licensing terms that regulate creating new licenses will be verified to allow minting.
/// Reverts if caller is not authorized by licensors.
/// @param policyId id of the policy to be minted
/// @param licensorIp IP Id granting the license
/// @param amount of licenses to be minted. License NFT is fungible for same policy and same licensors
/// @param receiver of the License NFT(s).
/// @return licenseId of the NFT(s).
function mintLicense(
uint256 policyId,
address licensorIp,
uint256 amount, // mint amount
address receiver
) external returns (uint256 licenseId) {
// TODO: check if licensor has been tagged by disputer
if (!IP_ACCOUNT_REGISTRY.isIpAccount(licensorIp)) {
revert Errors.LicenseRegistry__LicensorNotRegistered();
}
// If the IP ID doesn't have a policy (meaning, no permissionless derivatives)
if (!_policiesPerIpId[licensorIp].contains(policyId)) {
// We have to check if the caller is licensor or authorized to mint.
if (
msg.sender != licensorIp &&
!ACCESS_CONTROLLER.checkPermission(licensorIp, msg.sender, address(this), this.mintLicense.selector)
) {
revert Errors.LicenseRegistry__CallerNotLicensorAndPolicyNotSet();
}
}
// If a policy is set, then is only up to the policy params.
// Verify minting param
Licensing.Policy memory pol = policy(policyId);
bool inheritedPolicy = _policySetups[licensorIp][policyId].inheritedPolicy;
if (ERC165Checker.supportsInterface(pol.policyFramework, type(IMintParamVerifier).interfaceId)) {
if (
!IMintParamVerifier(pol.policyFramework).verifyMint(
msg.sender,
inheritedPolicy,
licensorIp,
receiver,
amount,
pol.data
)
) {
revert Errors.LicenseRegistry__MintLicenseParamFailed();
}
}
Licensing.License memory licenseData = Licensing.License({ policyId: policyId, licensorIpId: licensorIp });
bool isNew;
(licenseId, isNew) = _addIdOrGetExisting(abi.encode(licenseData), _hashedLicenses, _totalLicenses);
if (isNew) {
_totalLicenses = licenseId;
_licenses[licenseId] = licenseData;
emit LicenseMinted(msg.sender, receiver, licenseId, amount, licenseData);
}
_mint(receiver, licenseId, amount, "");
return licenseId;
}
/// @notice Links an IP to the licensors (parent IP IDs) listed in the License NFTs, if their policies allow it,
/// burning the NFTs in the proccess. The caller must be the owner of the NFTs and the IP owner.
/// @param licenseIds The id of the licenses to burn
/// @param childIpId The id of the child IP to be linked
/// @param holder The address that holds the license
function linkIpToParents(uint256[] calldata licenseIds, address childIpId, address holder) external {
// check the caller is owner or authorized by the childIp
if (
msg.sender != childIpId &&
!ACCESS_CONTROLLER.checkPermission(childIpId, msg.sender, address(this), this.linkIpToParents.selector)
) {
revert Errors.LicenseRegistry__UnauthorizedAccess();
}
uint256 licenses = licenseIds.length;
address[] memory licensors = new address[](licenses);
uint256[] memory values = new uint256[](licenses);
for (uint256 i = 0; i < licenses; i++) {
uint256 licenseId = licenseIds[i];
if (balanceOf(holder, licenseId) == 0) {
revert Errors.LicenseRegistry__NotLicensee();
}
Licensing.License memory licenseData = _licenses[licenseId];
licensors[i] = licenseData.licensorIpId;
// TODO: check licensor not part of a branch tagged by disputer
if (licensors[i] == childIpId) {
revert Errors.LicenseRegistry__ParentIdEqualThanChild();
}
// Verify linking params
Licensing.Policy memory pol = policy(licenseData.policyId);
if (ERC165Checker.supportsInterface(pol.policyFramework, type(ILinkParamVerifier).interfaceId)) {
if (
!ILinkParamVerifier(pol.policyFramework).verifyLink(
licenseId,
msg.sender,
childIpId,
licensors[i],
pol.data
)
) {
revert Errors.LicenseRegistry__LinkParentParamFailed();
}
}
// Add policy to kid
_addPolicyIdToIp(childIpId, licenseData.policyId, true);
// Set parent
_ipIdParents[childIpId].add(licensors[i]);
values[i] = 1;
}
emit IpIdLinkedToParents(msg.sender, childIpId, licensors);
// Burn licenses
_burnBatch(holder, licenseIds, values);
}
/// @notice True if the framework address is registered in LicenseRegistry
function isFrameworkRegistered(address policyFramework) external view returns (bool) {
return _registeredFrameworkManagers[policyFramework];
}
function name() external pure returns (string memory) {
return "LICENSE_REGISTRY";
}
/// Returns true if holder has positive balance for licenseId
function isLicensee(uint256 licenseId, address holder) external view returns (bool) {
return balanceOf(holder, licenseId) > 0;
}
function policyIdForLicense(uint256 licenseId) external view returns (uint256) {
return _licenses[licenseId].policyId;
}
function policyForLicense(uint256 licenseId) public view returns (Licensing.Policy memory) {
return policy(_licenses[licenseId].policyId);
}
/// Returns amount of distinct licensing policies in LicenseRegistry
function totalPolicies() external view returns (uint256) {
return _totalPolicies;
}
/// Gets policy data for policyId, reverts if not found
function policy(uint256 policyId) public view returns (Licensing.Policy memory pol) {
pol = _policies[policyId];
_verifyPolicy(pol);
return pol;
}
/// Returns true if policyId is defined in LicenseRegistry, false otherwise.
function isPolicyDefined(uint256 policyId) public view returns (bool) {
return _policies[policyId].policyFramework != address(0);
}
/// Gets the policy set for an IpId
/// @dev potentially expensive operation, use with care
function policyIdsForIp(address ipId) external view returns (uint256[] memory policyIds) {
return _policiesPerIpId[ipId].values();
}
function totalPoliciesForIp(address ipId) external view returns (uint256) {
return _policiesPerIpId[ipId].length();
}
function isPolicyIdSetForIp(address ipId, uint256 policyId) external view returns (bool) {
return _policiesPerIpId[ipId].contains(policyId);
}
function policyIdForIpAtIndex(address ipId, uint256 index) external view returns (uint256 policyId) {
return _policiesPerIpId[ipId].at(index);
}
function policyForIpAtIndex(address ipId, uint256 index) external view returns (Licensing.Policy memory) {
return _policies[_policiesPerIpId[ipId].at(index)];
}
function indexOfPolicyForIp(address ipId, uint256 policyId) external view returns (uint256 index) {
return _policySetups[ipId][policyId].index;
}
function isPolicyInherited(address ipId, uint256 policyId) external view returns (bool) {
return _policySetups[ipId][policyId].inheritedPolicy;
}
/// Returns true if the child is derivative from the parent, by at least 1 policy.
function isParent(address parentIpId, address childIpId) external view returns (bool) {
return _ipIdParents[childIpId].contains(parentIpId);
}
function parentIpIds(address ipId) external view returns (address[] memory) {
return _ipIdParents[ipId].values();
}
function totalParentsForIpId(address ipId) external view returns (uint256) {
return _ipIdParents[ipId].length();
}
function license(uint256 licenseId) external view returns (Licensing.License memory) {
return _licenses[licenseId];
}
function licensorIpId(uint256 licenseId) external view returns (address) {
return _licenses[licenseId].licensorIpId;
}
/// @notice ERC1155 OpenSea metadata JSON representation of the LNFT parameters
function uri(uint256 id) public view virtual override returns (string memory) {
Licensing.License memory licenseData = _licenses[id];
Licensing.Policy memory pol = policy(licenseData.policyId);
return IPolicyFrameworkManager(pol.policyFramework).policyToJson(pol.data);
}
/// @dev Pre-hook for ERC1155's _update() called on transfers.
function _update(
address from,
address to,
uint256[] memory ids,
uint256[] memory values
) internal virtual override {
// We are interested in transfers, minting and burning are checked in mintLicense and
// linkIpToParent respectively.
if (from != address(0) && to != address(0)) {
for (uint256 i = 0; i < ids.length; i++) {
// Verify transfer params
Licensing.Policy memory pol = policy(_licenses[ids[i]].policyId);
if (ERC165Checker.supportsInterface(pol.policyFramework, type(ITransferParamVerifier).interfaceId)) {
if (
!ITransferParamVerifier(pol.policyFramework).verifyTransfer(
ids[i],
from,
to,
values[i],
pol.data
)
) {
revert Errors.LicenseRegistry__TransferParamFailed();
}
}
}
}
super._update(from, to, ids, values);
}
function _verifyRegisteredFramework(address policyFramework) internal view {
if (!_registeredFrameworkManagers[policyFramework]) {
revert Errors.LicenseRegistry__FrameworkNotFound();
}
}
/// Adds a policy id to the ipId policy set
/// Will revert if policy set already has policyId
/// @param ipId the IP identifier
/// @param policyId id of the policy data
/// @param inheritedPolicy true if set in linkIpToParent, false otherwise
/// @return index of the policy added to the set
function _addPolicyIdToIp(address ipId, uint256 policyId, bool inheritedPolicy) internal returns (uint256 index) {
EnumerableSet.UintSet storage _pols = _policiesPerIpId[ipId];
if (!_pols.add(policyId)) {
revert Errors.LicenseRegistry__PolicyAlreadySetForIpId();
}
// TODO: check for policy compatibility.
// compatibilityManager.isPolicyCompatible(newPolicy, policiesInIpId);
index = _pols.length() - 1;
PolicySetup storage setup = _policySetups[ipId][policyId];
// This should not happen, but just in case
if (setup.isSet) {
revert Errors.LicenseRegistry__PolicyAlreadySetForIpId();
}
setup.index = index;
setup.isSet = true;
setup.active = true;
setup.inheritedPolicy = inheritedPolicy;
emit PolicyAddedToIpId(msg.sender, ipId, policyId, index, inheritedPolicy);
return index;
}
/// Stores data without repetition, assigning an id to it if new or reusing existing one if already stored
/// @param data raw bytes, abi.encode() a value to be hashed
/// @param _hashToIds storage ref to the mapping of hash -> data id
/// @param existingIds amount of distinct data stored.
/// @return id new sequential id if new data, reused id if not new
/// @return isNew True if a new id was generated, signaling the value was stored in _hashToIds.
/// False if id is reused and data was not stored
function _addIdOrGetExisting(
bytes memory data,
mapping(bytes32 => uint256) storage _hashToIds,
uint256 existingIds
) private returns (uint256 id, bool isNew) {
// We could just use the hash of the policy as id to save some gas, but the UX/DX of having huge random
// numbers for ID is bad enough to justify the cost, plus we have accountability on current number of
// policies.
bytes32 hash = keccak256(data);
id = _hashToIds[hash];
if (id != 0) {
return (id, false);
}
id = existingIds + 1;
_hashToIds[hash] = id;
return (id, true);
}
function _verifyPolicy(Licensing.Policy memory pol) private pure {
if (pol.policyFramework == address(0)) {
revert Errors.LicenseRegistry__PolicyNotFound();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.20;
import {IERC1155} from "./IERC1155.sol";
import {IERC1155Receiver} from "./IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol";
import {Context} from "../../utils/Context.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {Arrays} from "../../utils/Arrays.sol";
import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*/
abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors {
using Arrays for uint256[];
using Arrays for address[];
mapping(uint256 id => mapping(address account => uint256)) private _balances;
mapping(address account => mapping(address operator => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256 /* id */) public view virtual returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*/
function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] memory accounts,
uint256[] memory ids
) public view virtual returns (uint256[] memory) {
if (accounts.length != ids.length) {
revert ERC1155InvalidArrayLength(ids.length, accounts.length);
}
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeTransferFrom(from, to, id, value, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeBatchTransferFrom(from, to, ids, values, data);
}
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
* (or `to`) is the zero address.
*
* Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
* or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
* - `ids` and `values` must have the same length.
*
* NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
*/
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
if (ids.length != values.length) {
revert ERC1155InvalidArrayLength(ids.length, values.length);
}
address operator = _msgSender();
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids.unsafeMemoryAccess(i);
uint256 value = values.unsafeMemoryAccess(i);
if (from != address(0)) {
uint256 fromBalance = _balances[id][from];
if (fromBalance < value) {
revert ERC1155InsufficientBalance(from, fromBalance, value, id);
}
unchecked {
// Overflow not possible: value <= fromBalance
_balances[id][from] = fromBalance - value;
}
}
if (to != address(0)) {
_balances[id][to] += value;
}
}
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
emit TransferSingle(operator, from, to, id, value);
} else {
emit TransferBatch(operator, from, to, ids, values);
}
}
/**
* @dev Version of {_update} that performs the token acceptance check by calling
* {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
* contains code (eg. is a smart contract at the moment of execution).
*
* IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
* update to the contract state after this function would break the check-effect-interaction pattern. Consider
* overriding {_update} instead.
*/
function _updateWithAcceptanceCheck(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal virtual {
_update(from, to, ids, values);
if (to != address(0)) {
address operator = _msgSender();
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
_doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
} else {
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
}
}
}
/**
* @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
* - `ids` and `values` must have the same length.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the values in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev Destroys a `value` amount of tokens of type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
*/
function _burn(address from, uint256 id, uint256 value) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
* - `ids` and `values` must have the same length.
*/
function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the zero address.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (operator == address(0)) {
revert ERC1155InvalidOperator(address(0));
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 value,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Creates an array in memory with only one value for each of the elements provided.
*/
function _asSingletonArrays(
uint256 element1,
uint256 element2
) private pure returns (uint256[] memory array1, uint256[] memory array2) {
/// @solidity memory-safe-assembly
assembly {
// Load the free memory pointer
array1 := mload(0x40)
// Set array length to 1
mstore(array1, 1)
// Store the single element at the next word after the length (where content starts)
mstore(add(array1, 0x20), element1)
// Repeat for next array locating it right after the first array
array2 := add(array1, 0x40)
mstore(array2, 1)
mstore(add(array2, 0x20), element2)
// Update the free memory pointer by pointing after the second array
mstore(0x40, add(array2, 0x40))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.19;
import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";
/// @notice Library for working with Openzeppelin's ShortString data types.
library ShortStringOps {
using ShortStrings for *;
/// @dev Compares whether two ShortStrings are equal.
function equal(ShortString a, ShortString b) internal pure returns (bool) {
return ShortString.unwrap(a) == ShortString.unwrap(b);
}
/// @dev Checks whether a ShortString and a regular string are equal.
function equal(ShortString a, string memory b) internal pure returns (bool) {
return equal(a, b.toShortString());
}
/// @dev Checks whether a regular string and a ShortString are equal.
function equal(string memory a, ShortString b) internal pure returns (bool) {
return equal(a.toShortString(), b);
}
/// @dev Checks whether a bytes32 object and ShortString are equal.
function equal(bytes32 a, ShortString b) internal pure returns (bool) {
return a == ShortString.unwrap(b);
}
/// @dev Checks whether a string and bytes32 object are equal.
function equal(string memory a, bytes32 b) internal pure returns (bool) {
return equal(a, ShortString.wrap(b));
}
/// @dev Checks whether a bytes32 object and string are equal.
function equal(bytes32 a, string memory b) internal pure returns (bool) {
return equal(ShortString.wrap(a), b);
}
function stringToBytes32(string memory s) internal pure returns (bytes32) {
return ShortString.unwrap(s.toShortString());
}
function bytes32ToString(bytes32 b) internal pure returns (string memory) {
return ShortString.wrap(b).toString();
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";
/// @title IPolicyVerifier
/// @notice Placeholder interface for verifying policy parameters.
interface IPolicyVerifier is IERC165 {
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import { IPolicyVerifier } from "contracts/interfaces/licensing/IPolicyVerifier.sol";
/// @title IMintParamVerifier
/// @notice LicenseRegistry will call this to verify the minting parameters are compliant
/// with the policy associated with the license to mint.
interface IMintParamVerifier is IPolicyVerifier {
function verifyMint(
address caller,
bool policyWasInherited,
address licensor,
address receiver,
uint256 mintAmount,
bytes memory policyData
) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import { IPolicyVerifier } from "contracts/interfaces/licensing/IPolicyVerifier.sol";
/// @title ILinkParamVerifier
/// @notice LicenseRegistry will call this to verify the linking an IP to its parent
/// with the policy referenced by the license in use.
interface ILinkParamVerifier is IPolicyVerifier {
function verifyLink(
uint256 licenseId,
address caller,
address ipId,
address parentIpId,
bytes calldata policyData
) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import { IPolicyVerifier } from "contracts/interfaces/licensing/IPolicyVerifier.sol";
/// @title ITransferParamVerifier
/// @notice LicenseRegistry will call this to verify the transfer parameters are compliant
/// with the policy
interface ITransferParamVerifier is IPolicyVerifier {
function verifyTransfer(
uint256 licenseId,
address from,
address to,
uint256 amount,
bytes memory policyData
) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import { Licensing } from "contracts/lib/Licensing.sol";
/// @title ILicenseRegistry
/// @notice Interface for the LicenseRegistry contract, which is the main entry point for the licensing system.
/// It is responsible for:
/// - Registering policy frameworks
/// - Registering policies
/// - Minting licenses
/// - Linking IP to its parent
/// - Verifying transfer parameters (through the ITransferParamVerifier interface implementation by the policy framework)
/// - Verifying linking parameters (through the ILinkParamVerifier interface implementation by the policy framework)
/// - Verifying policy parameters (through the IPolicyVerifier interface implementation by the policy framework)
interface ILicenseRegistry {
/// @notice Emitted when a policy framework is created by registering a policy framework manager
/// @param framework The address of the IPolicyFrameworkManager
/// @param framework The policy framework data
event PolicyFrameworkRegistered(
address indexed framework,
string name,
string licenseTextUrl
);
/// @notice Emitted when a policy is added to the contract
/// @param policyFrameworkManager The address that created the policy
/// @param policyId The id of the policy
/// @param policy The encoded policy data
event PolicyRegistered(
address indexed policyFrameworkManager,
uint256 indexed policyId,
bytes policy
);
/// @notice Emitted when a policy is added to an IP
/// @param caller The address that called the function
/// @param ipId The id of the IP
/// @param policyId The id of the policy
/// @param index The index of the policy in the IP's policy list
/// @param inheritedPolicy Whether the policy was inherited from a parent IP (linking) or set by IP owner
event PolicyAddedToIpId(
address indexed caller,
address indexed ipId,
uint256 indexed policyId,
uint256 index,
bool inheritedPolicy
);
/// @notice Emitted when a license is minted
/// @param creator The address that created the license
/// @param receiver The address that received the license
/// @param licenseId The id of the license
/// @param amount The amount of licenses minted
/// @param licenseData The license data
event LicenseMinted(
address indexed creator,
address indexed receiver,
uint256 indexed licenseId,
uint256 amount,
Licensing.License licenseData
);
/// @notice Emitted when an IP is linked to its parent by burning a license
/// @param caller The address that called the function
/// @param ipId The id of the IP
/// @param parentIpIds The ids of the parent IP
event IpIdLinkedToParents(address indexed caller, address indexed ipId, address[] indexed parentIpIds);
/// @notice Registers a policy framework manager into the contract, so it can add policy data for
/// licenses.
/// @param manager the address of the manager. Will be ERC165 checked for IPolicyFrameworkManager
function registerPolicyFrameworkManager(address manager) external;
/// @notice Registers a policy into the contract. MUST be called by a registered
/// framework or it will revert. The policy data and its integrity must be
/// verified by the policy framework manager.
/// @param data The policy data
function registerPolicy(bytes memory data) external returns (uint256 policyId);
/// @notice Adds a policy to an IP policy list
/// @param ipId The id of the IP
/// @param polId The id of the policy
/// @return indexOnIpId The index of the policy in the IP's policy list
function addPolicyToIp(address ipId, uint256 polId) external returns (uint256 indexOnIpId);
/// @notice Mints a license to create derivative IP
/// @param policyId The id of the policy with the licensing parameters
/// @param licensorIpId The id of the licensor IP
/// @param amount The amount of licenses to mint
/// @param receiver The address that will receive the license
function mintLicense(
uint256 policyId,
address licensorIpId,
uint256 amount,
address receiver
) external returns (uint256 licenseId);
/// @notice Links an IP to the licensors (parent IP IDs) listed in the License NFTs, if their policies allow it,
/// burning the NFTs in the proccess. The caller must be the owner of the NFTs and the IP owner.
/// @param licenseIds The id of the licenses to burn
/// @param childIpId The id of the child IP to be linked
/// @param holder The address that holds the license
function linkIpToParents(uint256[] calldata licenseIds, address childIpId, address holder) external;
///
/// Getters
///
/// @notice True if the framework address is registered in LicenseRegistry
function isFrameworkRegistered(address framework) external view returns (bool);
/// @notice Gets total number of policies (framework parameter configurations) in the contract
function totalPolicies() external view returns (uint256);
/// @notice Gets policy data by id
function policy(uint256 policyId) external view returns (Licensing.Policy memory pol);
/// @notice True if policy is defined in the contract
function isPolicyDefined(uint256 policyId) external view returns (bool);
/// @notice Gets the policy ids for an IP
function policyIdsForIp(address ipId) external view returns (uint256[] memory policyIds);
/// @notice Gets total number of policies for an IP
function totalPoliciesForIp(address ipId) external view returns (uint256);
/// @notice True if policy is part of an IP's policy list
function isPolicyIdSetForIp(address ipId, uint256 policyId) external view returns (bool);
/// @notice Gets the policy ID for an IP by index on the IP's policy list
function policyIdForIpAtIndex(address ipId, uint256 index) external view returns (uint256 policyId);
/// @notice Gets the policy for an IP by index on the IP's policy list
function policyForIpAtIndex(address ipId, uint256 index) external view returns (Licensing.Policy memory);
/// @notice Gets the index of a policy in an IP's policy list
function indexOfPolicyForIp(address ipId, uint256 policyId) external view returns (uint256 index);
/// @notice True if the license was added to the IP by linking (burning a license)
function isPolicyInherited(address ipId, uint256 policyId) external view returns (bool);
/// @notice True if holder is the licensee for the license (owner of the license NFT), or derivative IP owner if
/// the license was added to the IP by linking (burning a license)
function isLicensee(uint256 licenseId, address holder) external view returns (bool);
/// @notice IP ID of the licensor for the license (parent IP)
function licensorIpId(uint256 licenseId) external view returns (address);
/// @notice License data (licensor, policy...) for the license id
function license(uint256 licenseId) external view returns (Licensing.License memory);
/// @notice True if an IP is a derivative of another IP
function isParent(address parentIpId, address childIpId) external view returns (bool);
/// @notice Returns the parent IP IDs for an IP ID
function parentIpIds(address ipId) external view returns (address[] memory);
/// @notice Total number of parents for an IP ID
function totalParentsForIpId(address ipId) external view returns (uint256);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.19;
/// @title Errors Library
/// @notice Library for all Story Protocol contract errors.
library Errors {
////////////////////////////////////////////////////////////////////////////
// Governance //
////////////////////////////////////////////////////////////////////////////
error Governance__OnlyProtocolAdmin();
error Governance__ZeroAddress();
error Governance__ProtocolPaused();
error Governance__InconsistentState();
error Governance__NewStateIsTheSameWithOldState();
error Governance__UnsupportedInterface(string interfaceName);
////////////////////////////////////////////////////////////////////////////
// IPAccount //
////////////////////////////////////////////////////////////////////////////
error IPAccount__InvalidSigner();
error IPAccount__InvalidSignature();
error IPAccount__ExpiredSignature();
////////////////////////////////////////////////////////////////////////////
// Module //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not allowed to call the provided module.
error Module_Unauthorized();
////////////////////////////////////////////////////////////////////////////
// IPAccountRegistry //
////////////////////////////////////////////////////////////////////////////
error IPAccountRegistry_InvalidIpAccountImpl();
////////////////////////////////////////////////////////////////////////////
// IPAssetRegistry //
////////////////////////////////////////////////////////////////////////////
/// @notice The IP asset has already been registered.
error IPAssetRegistry__AlreadyRegistered();
/// @notice The IP account has already been created.
error IPAssetRegistry__IPAccountAlreadyCreated();
/// @notice The IP asset has not yet been registered.
error IPAssetRegistry__NotYetRegistered();
/// @notice The specified IP resolver is not valid.
error IPAssetRegistry__ResolverInvalid();
/// @notice Caller not authorized to perform the IP registry function call.
error IPAssetRegistry__Unauthorized();
/// @notice The deployed address of account doesn't match with IP ID.
error IPAssetRegistry__InvalidAccount();
/// @notice The metadata provider is not valid.
error IPAssetRegistry__InvalidMetadataProvider();
////////////////////////////////////////////////////////////////////////////
// IPResolver ///
////////////////////////////////////////////////////////////////////////////
/// @notice The targeted IP does not yet have an IP account.
error IPResolver_InvalidIP();
/// @notice Caller not authorized to perform the IP resolver function call.
error IPResolver_Unauthorized();
////////////////////////////////////////////////////////////////////////////
// Metadata Provider ///
////////////////////////////////////////////////////////////////////////////
/// @notice Provided hash metadata is not valid.
error MetadataProvider__HashInvalid();
/// @notice The caller is not the authorized IP asset owner.
error MetadataProvider__IPAssetOwnerInvalid();
/// @notice Provided hash metadata is not valid.
error MetadataProvider__NameInvalid();
/// @notice The new metadata provider is not compatible with the old provider.
error MetadataProvider__MetadataNotCompatible();
/// @notice Provided registrant metadata is not valid.
error MetadataProvider__RegistrantInvalid();
/// @notice Provided registration date is not valid.
error MetadataProvider__RegistrationDateInvalid();
/// @notice Caller does not access to set metadata storage for the provider.
error MetadataProvider__Unauthorized();
/// @notice A metadata provider upgrade is not currently available.
error MetadataProvider__UpgradeUnavailable();
/// @notice The upgrade provider is not valid.
error MetadataProvider__UpgradeProviderInvalid();
/// @notice Provided metadata URI is not valid.
error MetadataProvider__URIInvalid();
////////////////////////////////////////////////////////////////////////////
// LicenseRegistry //
////////////////////////////////////////////////////////////////////////////
error LicenseRegistry__PolicyAlreadySetForIpId();
error LicenseRegistry__FrameworkNotFound();
error LicenseRegistry__EmptyLicenseUrl();
error LicenseRegistry__InvalidPolicyFramework();
error LicenseRegistry__PolicyAlreadyAdded();
error LicenseRegistry__ParamVerifierLengthMismatch();
error LicenseRegistry__PolicyNotFound();
error LicenseRegistry__NotLicensee();
error LicenseRegistry__ParentIdEqualThanChild();
error LicenseRegistry__LicensorDoesntHaveThisPolicy();
error LicenseRegistry__MintLicenseParamFailed();
error LicenseRegistry__LinkParentParamFailed();
error LicenseRegistry__TransferParamFailed();
error LicenseRegistry__InvalidLicensor();
error LicenseRegistry__ParamVerifierAlreadySet();
error LicenseRegistry__CommercialTermInNonCommercialPolicy();
error LicenseRegistry__EmptyParamName();
error LicenseRegistry__UnregisteredFrameworkAddingPolicy();
error LicenseRegistry__UnauthorizedAccess();
error LicenseRegistry__LicensorNotRegistered();
error LicenseRegistry__CallerNotLicensorAndPolicyNotSet();
////////////////////////////////////////////////////////////////////////////
// LicenseRegistryAware //
////////////////////////////////////////////////////////////////////////////
error LicenseRegistryAware__CallerNotLicenseRegistry();
////////////////////////////////////////////////////////////////////////////
// PolicyFrameworkManager //
////////////////////////////////////////////////////////////////////////////
error PolicyFrameworkManager__GettingPolicyWrongFramework();
////////////////////////////////////////////////////////////////////////////
// LicensorApprovalChecker //
////////////////////////////////////////////////////////////////////////////
error LicensorApprovalChecker__Unauthorized();
////////////////////////////////////////////////////////////////////////////
// Dispute Module //
////////////////////////////////////////////////////////////////////////////
error DisputeModule__ZeroArbitrationPolicy();
error DisputeModule__ZeroArbitrationRelayer();
error DisputeModule__ZeroDisputeTag();
error DisputeModule__ZeroLinkToDisputeEvidence();
error DisputeModule__NotWhitelistedArbitrationPolicy();
error DisputeModule__NotWhitelistedDisputeTag();
error DisputeModule__NotWhitelistedArbitrationRelayer();
error DisputeModule__NotDisputeInitiator();
error DisputeModule__NotInDisputeState();
error DisputeModule__NotAbleToResolve();
error ArbitrationPolicySP__ZeroDisputeModule();
error ArbitrationPolicySP__ZeroPaymentToken();
error ArbitrationPolicySP__NotDisputeModule();
////////////////////////////////////////////////////////////////////////////
// Royalty Module //
////////////////////////////////////////////////////////////////////////////
error RoyaltyModule__ZeroRoyaltyPolicy();
error RoyaltyModule__NotWhitelistedRoyaltyPolicy();
error RoyaltyModule__AlreadySetRoyaltyPolicy();
error RoyaltyModule__ZeroRoyaltyToken();
error RoyaltyModule__NotWhitelistedRoyaltyToken();
error RoyaltyModule__NoRoyaltyPolicySet();
error RoyaltyModule__IncompatibleRoyaltyPolicy();
error RoyaltyPolicyLS__ZeroRoyaltyModule();
error RoyaltyPolicyLS__ZeroLiquidSplitFactory();
error RoyaltyPolicyLS__ZeroLiquidSplitMain();
error RoyaltyPolicyLS__NotRoyaltyModule();
error RoyaltyPolicyLS__TransferFailed();
error RoyaltyPolicyLS__InvalidMinRoyalty();
error RoyaltyPolicyLS__InvalidRoyaltyStack();
error RoyaltyPolicyLS__ZeroMinRoyalty();
error RoyaltyPolicyLS__ZeroLicenseRegistry();
error LSClaimer__InvalidPath();
error LSClaimer__InvalidPathFirstPosition();
error LSClaimer__InvalidPathLastPosition();
error LSClaimer__AlreadyClaimed();
error LSClaimer__ZeroRNFT();
error LSClaimer__RNFTAlreadySet();
error LSClaimer__ETHBalanceNotZero();
error LSClaimer__ERC20BalanceNotZero();
error LSClaimer__ZeroIpId();
error LSClaimer__ZeroLicenseRegistry();
error LSClaimer__ZeroRoyaltyPolicyLS();
error LSClaimer__NotRoyaltyPolicyLS();
////////////////////////////////////////////////////////////////////////////
// ModuleRegistry //
////////////////////////////////////////////////////////////////////////////
error ModuleRegistry__ModuleAddressZeroAddress();
error ModuleRegistry__ModuleAddressNotContract();
error ModuleRegistry__ModuleAlreadyRegistered();
error ModuleRegistry__NameEmptyString();
error ModuleRegistry__NameAlreadyRegistered();
error ModuleRegistry__NameDoesNotMatch();
error ModuleRegistry__ModuleNotRegistered();
////////////////////////////////////////////////////////////////////////////
// RegistrationModule //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not the owner of the root IP NFT.
error RegistrationModule__InvalidOwner();
////////////////////////////////////////////////////////////////////////////
// AccessController //
////////////////////////////////////////////////////////////////////////////
error AccessController__IPAccountIsZeroAddress();
error AccessController__IPAccountIsNotValid();
error AccessController__SignerIsZeroAddress();
error AccessController__CallerIsNotIPAccount();
error AccessController__PermissionIsNotValid();
////////////////////////////////////////////////////////////////////////////
// TaggingModule //
////////////////////////////////////////////////////////////////////////////
error TaggingModule__InvalidRelationTypeName();
error TaggingModule__RelationTypeAlreadyExists();
error TaggingModule__SrcIpIdDoesNotHaveSrcTag();
error TaggingModule__DstIpIdDoesNotHaveDstTag();
error TaggingModule__RelationTypeDoesNotExist();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import { IPolicyVerifier } from "../interfaces/licensing/IPolicyVerifier.sol";
import { Errors } from "./Errors.sol";
/// @title Licensing
/// @notice Types and constants used by the licensing related contracts
library Licensing {
/// @notice A particular configuration (flavor) of a Policy Framework, setting values for the licensing
/// terms (parameters) of the framework.
/// @param policyFramework address of the IPolicyFrameworkManager this policy is based on
/// @param data Encoded data for the policy, specific to the policy framework
struct Policy {
address policyFramework;
bytes data;
}
/// @notice Data that define a License Agreement NFT
/// @param policyId Id of the policy this license is based on, which will be set in the derivative
/// IP when the license is burnt
/// @param licensorIpId Id of the IP this license is for
struct License {
uint256 policyId;
address licensorIpId;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;
import { Licensing } from "contracts/lib/Licensing.sol";
import { IPolicyVerifier } from "contracts/interfaces/licensing/IPolicyVerifier.sol";
/// @title IPolicyFrameworkManager
/// @notice Interface to define a policy framework contract, that will
/// register itself into the LicenseRegistry to format policy into the LicenseRegistry
interface IPolicyFrameworkManager is IPolicyVerifier {
// TODO: move here the interfaces for verification and sunset IPolicyVerifier
/// @notice Name to be show in LNFT metadata
function name() external view returns(string memory);
/// @notice URL to the off chain legal agreement template text
function licenseTextUrl() external view returns(string memory);
/// @notice address of Story Protocol license registry
function licenseRegistry() external view returns (address);
/// @notice called by the LicenseRegistry uri(uint256) method.
/// Must return ERC1155 OpenSea standard compliant metadata
function policyToJson(bytes memory policyData) external view returns (string memory);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
interface IAccessController {
event PermissionSet(
address indexed ipAccount,
address indexed signer,
address indexed to,
bytes4 func,
uint8 permission
);
/// @notice Sets the permission for a specific function call
/// @dev Each policy is represented as a mapping from an IP account address to a signer address to a recipient
///// address to a function selector to a permission level.
///// The permission level can be 0 (ABSTAIN), 1 (ALLOW), or 2 (DENY).
/// @param ipAccount_ The account that owns the IP
/// @param signer_ The account that signs the transaction
/// @param to_ The recipient(modules) of the transaction
/// @param func_ The function selector
/// @param permission_ The permission level
function setPermission(address ipAccount_, address signer_, address to_, bytes4 func_, uint8 permission_) external;
/// @notice Sets the permission for all IPAccounts
/// @dev Only the protocol admin can set the global permission
/// @param signer_ The account that signs the transaction
/// @param to_ The recipient(modules) of the transaction
/// @param func_ The function selector
/// @param permission_ The permission level
function setGlobalPermission(address signer_, address to_, bytes4 func_, uint8 permission_) external;
/// @notice Gets the permission for a specific function call
/// @param ipAccount_ The account that owns the IP
/// @param signer_ The account that signs the transaction
/// @param to_ The recipient (modules) of the transaction
/// @param func_ The function selector
/// @return The current permission level for the function call
function getPermission(
address ipAccount_,
address signer_,
address to_,
bytes4 func_
) external view returns (uint8);
/// @notice Checks the permission for a specific function call
/// @dev This function checks the permission level for a specific function call.
/// If a specific permission is set, it overrides the general (wildcard) permission.
/// If the current level permission is ABSTAIN, the final permission is determined by the upper level.
/// @param ipAccount_ The account that owns the IP
/// @param signer_ The account that signs the transaction
/// @param to_ The recipient of the transaction
/// @param func_ The function selector
/// @return A boolean indicating whether the function call is allowed
function checkPermission(
address ipAccount_,
address signer_,
address to_,
bytes4 func_
) external view returns (bool);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
/// @title Interface for IP Account Registry
/// @notice This interface manages the registration and tracking of IP Accounts
interface IIPAccountRegistry {
/// @notice Event emitted when a new IP Account is created
/// @param account The address of the new IP Account
/// @param implementation The address of the IP Account implementation
/// @param chainId The chain ID where the token contract deployed
/// @param tokenContract The address of the token contract associated with the IP Account
/// @param tokenId The ID of the token associated with the IP Account
event IPAccountRegistered(
address indexed account,
address indexed implementation,
uint256 indexed chainId,
address tokenContract,
uint256 tokenId
);
/// @notice Deploys an IPAccount contract with the IPAccount implementation and returns the address of the new IP
/// @dev The IPAccount deployment deltegates to public ERC6551 Registry
/// @param chainId_ The chain ID where the token contract deployed
/// @param tokenContract_ The address of the token contract to be associated with the IP Account
/// @param tokenId_ The ID of the token to be associated with the IP Account
/// @return The address of the newly created IP Account
function registerIpAccount(
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) external returns (address);
/// @notice Returns the IPAccount address for the given NFT token
/// @param chainId_ The chain ID where the token contract deployed
/// @param tokenContract_ The address of the token contract associated with the IP Account
/// @param tokenId_ The ID of the token associated with the IP Account
/// @return The address of the IP Account associated with the given NFT token
function ipAccount(
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) external view returns (address);
/// @notice Returns the IPAccount implementation address
/// @return The address of the IPAccount implementation
function getIPAccountImpl() external view returns (address);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.21;
import { IIPAccountRegistry } from "contracts/interfaces/registries/IIPAccountRegistry.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { IERC6551Account } from "lib/reference/src/interfaces/IERC6551Account.sol";
import { IIPAccount } from "contracts/interfaces/IIPAccount.sol";
/// @title IPAccountChecker
/// @dev This library provides utility functions to check the registration and validity of IP Accounts.
/// It uses the ERC165 standard for contract introspection and the IIPAccountRegistry interface
/// for account registration checks.
library IPAccountChecker {
/// @notice Returns true if the IPAccount is registered.
/// @param chainId_ The chain ID where the IP Account is located.
/// @param tokenContract_ The address of the token contract associated with the IP Account.
/// @param tokenId_ The ID of the token associated with the IP Account.
/// @return True if the IP Account is registered, false otherwise.
function isRegistered(
IIPAccountRegistry ipAccountRegistry_,
uint256 chainId_,
address tokenContract_,
uint256 tokenId_
) external view returns (bool) {
return ipAccountRegistry_.ipAccount(chainId_, tokenContract_, tokenId_).code.length != 0;
}
/// @notice Checks if the given address is a valid IP Account.
/// @param ipAccountRegistry_ The IP Account registry contract.
/// @param ipAccountAddress_ The address to check.
/// @return True if the address is a valid IP Account, false otherwise.
function isIpAccount(
IIPAccountRegistry ipAccountRegistry_,
address ipAccountAddress_
) external view returns (bool) {
if (ipAccountAddress_ == address(0)) return false;
if (ipAccountAddress_.code.length == 0) return false;
if (!ERC165Checker.supportsERC165(ipAccountAddress_)) return false;
if (!ERC165Checker.supportsInterface(ipAccountAddress_, type(IERC6551Account).interfaceId)) return false;
if (!ERC165Checker.supportsInterface(ipAccountAddress_, type(IIPAccount).interfaceId)) return false;
(uint chainId, address tokenContract, uint tokenId) = IIPAccount(payable(ipAccountAddress_)).token();
return ipAccountAddress_ == ipAccountRegistry_.ipAccount(chainId, tokenContract, tokenId);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the value of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155Received} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.20;
import {IERC1155} from "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using StorageSlot for bytes32;
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* `array` is expected to be sorted in ascending order, and to contain no
* repeated elements.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @dev the ERC-165 identifier for this interface is `0x6faff5f1`
interface IERC6551Account {
/**
* @dev Allows the account to receive Ether.
*
* Accounts MUST implement a `receive` function.
*
* Accounts MAY perform arbitrary logic to restrict conditions
* under which Ether can be received.
*/
receive() external payable;
/**
* @dev Returns the identifier of the non-fungible token which owns the account.
*
* The return value of this function MUST be constant - it MUST NOT change over time.
*
* @return chainId The EIP-155 ID of the chain the token exists on
* @return tokenContract The contract address of the token
* @return tokenId The ID of the token
*/
function token()
external
view
returns (uint256 chainId, address tokenContract, uint256 tokenId);
/**
* @dev Returns a value that SHOULD be modified each time the account changes state.
*
* @return The current account state
*/
function state() external view returns (uint256);
/**
* @dev Returns a magic value indicating whether a given signer is authorized to act on behalf
* of the account.
*
* MUST return the bytes4 magic value 0x523e3260 if the given signer is valid.
*
* By default, the holder of the non-fungible token the account is bound to MUST be considered
* a valid signer.
*
* Accounts MAY implement additional authorization logic which invalidates the holder as a
* signer or grants signing permissions to other non-holder accounts.
*
* @param signer The address to check signing authorization for
* @param context Additional data used to determine whether the signer is valid
* @return magicValue Magic value indicating whether the signer is valid
*/
function isValidSigner(address signer, bytes calldata context)
external
view
returns (bytes4 magicValue);
}// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf
pragma solidity ^0.8.23;
import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import { IERC6551Account } from "lib/reference/src/interfaces/IERC6551Account.sol";
/// @title IIPAccount
/// @dev IPAccount is a token-bound account that adopts the EIP-6551 standard.
/// These accounts are deployed at deterministic addresses through the official 6551 account registry.
/// As a deployed smart contract, IPAccount can store IP-related information,
/// like ownership of other NFTs such as license NFT or Royalty NFT.
/// IPAccount can interact with modules by making calls as a normal transaction sender.
/// This allows for seamless operations on the state and data of IP.
/// IPAccount is core identity for all actions.
interface IIPAccount is IERC6551Account, IERC721Receiver, IERC1155Receiver {
/// @notice Emitted when a transaction is executed.
event Executed(address indexed to, uint256 value, bytes data, uint256 nonce);
/// @notice Emitted when a transaction is executed on behalf of the signer.
event ExecutedWithSig(
address indexed to,
uint256 value,
bytes data,
uint256 nonce,
uint256 deadline,
address indexed signer,
bytes signature
);
/// @notice Executes a transaction from the IP Account.
/// @param to_ The recipient of the transaction.
/// @param value_ The amount of Ether to send.
/// @param data_ The data to send along with the transaction.
/// @return The return data from the transaction.
function execute(address to_, uint256 value_, bytes calldata data_) external payable returns (bytes memory);
/// @notice Executes a transaction from the IP Account on behalf of the signer.
/// @param to The recipient of the transaction.
/// @param value The amount of Ether to send.
/// @param data The data to send along with the transaction.
/// @param signer The signer of the transaction.
/// @param deadline The deadline of the transaction signature.
/// @param signature The signature of the transaction, EIP-712 encoded.
function executeWithSig(
address to,
uint256 value,
bytes calldata data,
address signer,
uint256 deadline,
bytes calldata signature
) external payable returns (bytes memory);
/// @notice Returns the owner of the IP Account.
/// @return The address of the owner.
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}{
"remappings": [
"@openzeppelin/=node_modules/@openzeppelin/",
"base64-sol/=node_modules/base64-sol/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"openzeppelin-contracts/=lib/reference/lib/openzeppelin-contracts/",
"reference/=lib/reference/"
],
"optimizer": {
"enabled": true,
"runs": 20000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {
"contracts/lib/registries/IPAccountChecker.sol": {
"IPAccountChecker": "0x4687d14d30ea46a60499c2dcc07a56d2d1590fc3"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"accessController","type":"address"},{"internalType":"address","name":"ipAccountRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC1155InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC1155InvalidApprover","type":"error"},{"inputs":[{"internalType":"uint256","name":"idsLength","type":"uint256"},{"internalType":"uint256","name":"valuesLength","type":"uint256"}],"name":"ERC1155InvalidArrayLength","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC1155InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC1155InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC1155InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC1155MissingApprovalForAll","type":"error"},{"inputs":[],"name":"LicenseRegistry__CallerNotLicensorAndPolicyNotSet","type":"error"},{"inputs":[],"name":"LicenseRegistry__EmptyLicenseUrl","type":"error"},{"inputs":[],"name":"LicenseRegistry__FrameworkNotFound","type":"error"},{"inputs":[],"name":"LicenseRegistry__InvalidPolicyFramework","type":"error"},{"inputs":[],"name":"LicenseRegistry__LicensorNotRegistered","type":"error"},{"inputs":[],"name":"LicenseRegistry__LinkParentParamFailed","type":"error"},{"inputs":[],"name":"LicenseRegistry__MintLicenseParamFailed","type":"error"},{"inputs":[],"name":"LicenseRegistry__NotLicensee","type":"error"},{"inputs":[],"name":"LicenseRegistry__ParentIdEqualThanChild","type":"error"},{"inputs":[],"name":"LicenseRegistry__PolicyAlreadyAdded","type":"error"},{"inputs":[],"name":"LicenseRegistry__PolicyAlreadySetForIpId","type":"error"},{"inputs":[],"name":"LicenseRegistry__PolicyNotFound","type":"error"},{"inputs":[],"name":"LicenseRegistry__TransferParamFailed","type":"error"},{"inputs":[],"name":"LicenseRegistry__UnauthorizedAccess","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":true,"internalType":"address[]","name":"parentIpIds","type":"address[]"}],"name":"IpIdLinkedToParents","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"licenseId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint256","name":"policyId","type":"uint256"},{"internalType":"address","name":"licensorIpId","type":"address"}],"indexed":false,"internalType":"struct Licensing.License","name":"licenseData","type":"tuple"}],"name":"LicenseMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"ipId","type":"address"},{"indexed":true,"internalType":"uint256","name":"policyId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bool","name":"inheritedPolicy","type":"bool"}],"name":"PolicyAddedToIpId","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"framework","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"licenseTextUrl","type":"string"}],"name":"PolicyFrameworkRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"policyFrameworkManager","type":"address"},{"indexed":true,"internalType":"uint256","name":"policyId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"policy","type":"bytes"}],"name":"PolicyRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"ACCESS_CONTROLLER","outputs":[{"internalType":"contract IAccessController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IP_ACCOUNT_REGISTRY","outputs":[{"internalType":"contract IIPAccountRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"uint256","name":"polId","type":"uint256"}],"name":"addPolicyToIp","outputs":[{"internalType":"uint256","name":"indexOnIpId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"indexOfPolicyForIp","outputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"policyFramework","type":"address"}],"name":"isFrameworkRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"},{"internalType":"address","name":"holder","type":"address"}],"name":"isLicensee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"parentIpId","type":"address"},{"internalType":"address","name":"childIpId","type":"address"}],"name":"isParent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"isPolicyDefined","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"isPolicyIdSetForIp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"isPolicyInherited","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"}],"name":"license","outputs":[{"components":[{"internalType":"uint256","name":"policyId","type":"uint256"},{"internalType":"address","name":"licensorIpId","type":"address"}],"internalType":"struct Licensing.License","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"}],"name":"licensorIpId","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"licenseIds","type":"uint256[]"},{"internalType":"address","name":"childIpId","type":"address"},{"internalType":"address","name":"holder","type":"address"}],"name":"linkIpToParents","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"policyId","type":"uint256"},{"internalType":"address","name":"licensorIp","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mintLicense","outputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"}],"name":"parentIpIds","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"policyId","type":"uint256"}],"name":"policy","outputs":[{"components":[{"internalType":"address","name":"policyFramework","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Licensing.Policy","name":"pol","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"policyForIpAtIndex","outputs":[{"components":[{"internalType":"address","name":"policyFramework","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Licensing.Policy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"}],"name":"policyForLicense","outputs":[{"components":[{"internalType":"address","name":"policyFramework","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Licensing.Policy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"policyIdForIpAtIndex","outputs":[{"internalType":"uint256","name":"policyId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"licenseId","type":"uint256"}],"name":"policyIdForLicense","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"}],"name":"policyIdsForIp","outputs":[{"internalType":"uint256[]","name":"policyIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"registerPolicy","outputs":[{"internalType":"uint256","name":"policyId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"registerPolicyFrameworkManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"}],"name":"totalParentsForIpId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPolicies","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"ipId","type":"address"}],"name":"totalPoliciesForIp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b5060405162003b5338038062003b53833981016040819052620000349162000096565b6040805160208101909152600081526200004e8162000067565b506001600160a01b039182166080521660a05262000241565b600262000075828262000175565b5050565b80516001600160a01b03811681146200009157600080fd5b919050565b60008060408385031215620000aa57600080fd5b620000b58362000079565b9150620000c56020840162000079565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620000f957607f821691505b6020821081036200011a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000170576000816000526020600020601f850160051c810160208610156200014b5750805b601f850160051c820191505b818110156200016c5782815560010162000157565b5050505b505050565b81516001600160401b03811115620001915762000191620000ce565b620001a981620001a28454620000e4565b8462000120565b602080601f831160018114620001e15760008415620001c85750858301515b600019600386901b1c1916600185901b1785556200016c565b600085815260208120601f198616915b828110156200021257888601518255948401946001909101908401620001f1565b5085821015620002315787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a0516138d0620002836000396000818161055201526108e501526000818161034a01528181610a4f015281816110f2015261193d01526138d06000f3fe608060405234801561001057600080fd5b50600436106102405760003560e01c80634a21d5fc11610145578063a22cb465116100bd578063ca0f8b071161008c578063e985e9c511610071578063e985e9c514610658578063f059d78e14610694578063f242432a1461069c57600080fd5b8063ca0f8b0714610632578063d18f8ba01461064557600080fd5b8063a22cb465146105c0578063a2ea1376146105d3578063a8206bae146105e6578063b754f2721461061257600080fd5b8063702acd851161011457806396d31616116100f957806396d3161614610587578063972fefb91461059a57806399a7776e146105ad57600080fd5b8063702acd851461054d5780637305424f1461057457600080fd5b80634a21d5fc146104b95780634e1273f4146104ef5780634e23932f1461050f57806352f326971461052257600080fd5b80632c546207116101d85780633799e406116101a75780633d3cc1bf1161018c5780633d3cc1bf1461047357806344523fdf1461049357806346648011146104a657600080fd5b80633799e406146104115780633cea51201461045357600080fd5b80632c546207146103aa5780632eb2c2d6146103bf57806332b0cbce146103d257806334d70eea146103e557600080fd5b8063178ed28411610214578063178ed284146102e35780631b8b10731461034557806321f75d9e146103845780632a5c2ce71461039757600080fd5b8062fdd58e1461024557806301ffc9a71461026b57806306fdde031461028e5780630e89341c146102d0575b600080fd5b610258610253366004612c8b565b6106af565b6040519081526020015b60405180910390f35b61027e610279366004612ce3565b6106d7565b6040519015158152602001610262565b60408051808201909152601081527f4c4943454e53455f52454749535452590000000000000000000000000000000060208201525b6040516102629190612d6e565b6102c36102de366004612d81565b6107ba565b6103386102f1366004612d81565b6040805180820190915260008082526020820152506000908152600b6020908152604091829020825180840190935280548352600101546001600160a01b03169082015290565b6040516102629190612d9a565b61036c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610262565b610258610392366004612dba565b6108b5565b6102586103a5366004612e00565b610d4c565b6103bd6103b8366004612e00565b610d6d565b005b6103bd6103cd366004612fc3565b610fd0565b6103bd6103e036600461306d565b611074565b61036c6103f3366004612d81565b6000908152600b60205260409020600101546001600160a01b031690565b61027e61041f366004612c8b565b6001600160a01b03919091166000908152600760209081526040808320938352929052206001015462010000900460ff1690565b610466610461366004612d81565b61158b565b60405161026291906130f7565b610486610481366004612e00565b61166d565b6040516102629190613125565b6104666104a1366004612c8b565b611691565b6104666104b4366004612d81565b611795565b6102586104c7366004612c8b565b6001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105026104fd366004613172565b6117c2565b604051610262919061326e565b61027e61051d366004613281565b6118a8565b61027e610530366004612d81565b6000908152600560205260409020546001600160a01b0316151590565b61036c7f000000000000000000000000000000000000000000000000000000000000000081565b610258610582366004612c8b565b6118bd565b610258610595366004612e00565b611a42565b6105026105a8366004612e00565b611a63565b6102586105bb366004612c8b565b611a87565b6103bd6105ce3660046132bb565b611aa9565b6102586105e13660046132f2565b611ab8565b61027e6105f4366004612e00565b6001600160a01b031660009081526003602052604090205460ff1690565b610258610620366004612d81565b6000908152600b602052604090205490565b61027e610640366004612c8b565b611bfe565b61027e610653366004613327565b611c20565b61027e610666366004613327565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b600654610258565b6103bd6106aa366004613351565b611c42565b6000818152602081815260408083206001600160a01b03861684529091529020545b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fd9b67a2600000000000000000000000000000000000000000000000000000000148061076a57507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e89341c00000000000000000000000000000000000000000000000000000000145b806106d157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146106d1565b6000818152600b60209081526040808320815180830190925280548083526001909101546001600160a01b03169282019290925260609290916107fc9061158b565b805160208201516040517feb6b33150000000000000000000000000000000000000000000000000000000081529293506001600160a01b039091169163eb6b33159161084a91600401612d6e565b600060405180830381865afa158015610867573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108ad91908101906133b6565b949350505050565b6040517f5a1c2dd70000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015284166024820152600090734687d14d30ea46a60499c2dcc07a56d2d1590fc390635a1c2dd790604401602060405180830381865af4158015610951573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610975919061342d565b6109ab576040517f998df7ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526008602052604090206109cd9086611cd9565b610af357336001600160a01b03851614801590610abc57506040517f7dfd0ddb0000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301523360248301523060448301527f21f75d9e0000000000000000000000000000000000000000000000000000000060648301527f00000000000000000000000000000000000000000000000000000000000000001690637dfd0ddb90608401602060405180830381865afa158015610a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aba919061342d565b155b15610af3576040517f3404d1f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610afe8661158b565b6001600160a01b03861660009081526007602090815260408083208a8452909152902060010154815191925062010000900460ff1690610b5e907fcd6f464d00000000000000000000000000000000000000000000000000000000611cf1565b15610c3257815160208301516040517fcd6f464d0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163cd6f464d91610bb991339186918c918b918d919060040161344a565b6020604051808303816000875af1158015610bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfc919061342d565b610c32576040517ff81f025100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060400160405280898152602001886001600160a01b031681525090506000610c8382604051602001610c6a9190612d9a565b604051602081830303815290604052600a600c54611d0d565b90955090508015610d2557600c8590556000858152600b60209081526040918290208451815590840151600190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039283161790559051869188169033907ffe73f59d33d83a61320621c23a68cc04b52cd8bd47cdf04a43d1365e8dd277ae90610d1c908c908890613498565b60405180910390a45b610d4086868960405180602001604052806000815250611d64565b50505050949350505050565b6001600160a01b03811660009081526008602052604081206106d190611dda565b610d97817fe835d3c800000000000000000000000000000000000000000000000000000000611cf1565b610dcd576040517fed12b51a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008190506000816001600160a01b031663c75e9a596040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e12573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e5891908101906133b6565b9050805160001480610e7f5750604080516020810190915260008152610e7f908290611de4565b15610eb6576040517fa327329a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0380841660008181526003602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580517f06fdde03000000000000000000000000000000000000000000000000000000008152905192937fbae121b7564f0ecf01ff015fde3faa4dd4d8923eb147bb844bee40815fa94b7693908716926306fdde0392600480820193918290030181865afa158015610f6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610fb491908101906133b6565b83604051610fc39291906134bf565b60405180910390a2505050565b336001600160a01b038616811480159061101057506001600160a01b0380871660009081526001602090815260408083209385168352929052205460ff16155b1561105f576040517fe237d9220000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152871660248201526044015b60405180910390fd5b61106c8686868686611e09565b505050505050565b336001600160a01b0383161480159061115f57506040517f7dfd0ddb0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301523360248301523060448301527f32b0cbce0000000000000000000000000000000000000000000000000000000060648301527f00000000000000000000000000000000000000000000000000000000000000001690637dfd0ddb90608401602060405180830381865afa158015611139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115d919061342d565b155b15611196576040517f3554b54000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260008167ffffffffffffffff8111156111b2576111b2612e1b565b6040519080825280602002602001820160405280156111db578160200160208202803683370190505b50905060008267ffffffffffffffff8111156111f9576111f9612e1b565b604051908082528060200260200182016040528015611222578160200160208202803683370190505b50905060005b838110156114f7576000888883818110611244576112446134e4565b90506020020135905061125786826106af565b600003611290576040517f784b513600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600b6020908152604091829020825180840190935280548352600101546001600160a01b031690820181905285518690859081106112d5576112d56134e4565b60200260200101906001600160a01b031690816001600160a01b031681525050876001600160a01b0316858481518110611311576113116134e4565b60200260200101516001600160a01b031603611359576040517f6b7a4bb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611368826000015161158b565b905061139881600001517ff02a311100000000000000000000000000000000000000000000000000000000611cf1565b1561146b5780600001516001600160a01b031663f02a311184338c8a89815181106113c5576113c56134e4565b602002602001015186602001516040518663ffffffff1660e01b81526004016113f2959493929190613513565b6020604051808303816000875af1158015611411573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611435919061342d565b61146b576040517fc9846cf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61147b8983600001516001611ea3565b506114cc868581518110611491576114916134e4565b6020026020010151600960008c6001600160a01b03166001600160a01b0316815260200190815260200160002061200f90919063ffffffff16565b5060018585815181106114e1576114e16134e4565b6020908102919091010152505050600101611228565b5081604051611506919061354d565b604051908190038120906001600160a01b0387169033907fd62a66bdb7d79aa53f9f9de9ebfa160d79778d07e68afe0a0c9c626243054b3c90600090a461158284888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250612024915050565b50505050505050565b604080518082019091526000815260606020820152600082815260056020908152604091829020825180840190935280546001600160a01b0316835260018101805491928401916115db9061358c565b80601f01602080910402602001604051908101604052809291908181526020018280546116079061358c565b80156116545780601f1061162957610100808354040283529160200191611654565b820191906000526020600020905b81548152906001019060200180831161163757829003601f168201915b505050505081525050905061166881612089565b919050565b6001600160a01b03811660009081526009602052604090206060906106d1906120cd565b6040805180820190915260008152606060208201526001600160a01b0383166000908152600860205260408120600591906116cc90856120da565b81526020808201929092526040908101600020815180830190925280546001600160a01b03168252600181018054929391929184019161170b9061358c565b80601f01602080910402602001604051908101604052809291908181526020018280546117379061358c565b80156117845780601f1061175957610100808354040283529160200191611784565b820191906000526020600020905b81548152906001019060200180831161176757829003601f168201915b505050505081525050905092915050565b6040805180820190915260008152606060208201526000828152600b60205260409020546106d19061158b565b6060815183511461180c57815183516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401611056565b6000835167ffffffffffffffff81111561182857611828612e1b565b604051908082528060200260200182016040528015611851578160200160208202803683370190505b50905060005b84518110156118a05760208082028601015161187b906020808402870101516106af565b82828151811061188d5761188d6134e4565b6020908102919091010152600101611857565b509392505050565b6000806118b583856106af565b119392505050565b6000336001600160a01b038416148015906119aa57506040517f7dfd0ddb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301523360248301523060448301527f7305424f0000000000000000000000000000000000000000000000000000000060648301527f00000000000000000000000000000000000000000000000000000000000000001690637dfd0ddb90608401602060405180830381865afa158015611984573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a8919061342d565b155b156119e1576040517f3554b54000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260409020546001600160a01b0316611a2f576040517f91d3a01500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a3b83836000611ea3565b9392505050565b6001600160a01b03811660009081526009602052604081206106d190611dda565b6001600160a01b03811660009081526008602052604090206060906106d1906120cd565b6001600160a01b0382166000908152600860205260408120611a3b90836120da565b611ab43383836120e6565b5050565b6000611ac3336121b4565b60006040518060400160405280336001600160a01b03168152602001848152509050600080611b1583604051602001611afc91906130f7565b6040516020818303038152906040526004600654611d0d565b9150915080611b50576040517f61f8a6ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068290556000828152600560209081526040909120845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155908401518491906001820190611bb09082613627565b5090505081336001600160a01b03167f65dec4527c3884529f23bafda109f3c50ac1829ca9256c5948c411c4b04dbadd87604051611bee9190612d6e565b60405180910390a3509392505050565b6001600160a01b0382166000908152600860205260408120611a3b9083611cd9565b6001600160a01b0381166000908152600960205260408120611a3b9084612206565b336001600160a01b0386168114801590611c8257506001600160a01b0380871660009081526001602090815260408083209385168352929052205460ff16155b15611ccc576040517fe237d9220000000000000000000000000000000000000000000000000000000081526001600160a01b03808316600483015287166024820152604401611056565b61106c8686868686612228565b60008181526001830160205260408120541515611a3b565b6000611cfc836122e0565b8015611a3b5750611a3b8383612344565b8251602080850191909120600081815291849052604082205491908215611d38575060009050611d5c565b611d43846001613770565b6000918252602086905260409091208190559150600190505b935093915050565b6001600160a01b038416611da7576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6040805160018082526020820186905281830190815260608201859052608082019092529061106c600087848487612432565b60006106d1825490565b600081518351148015611a3b5750508051602091820120825192909101919091201490565b6001600160a01b038416611e4c576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6001600160a01b038516611e8f576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b611e9c8585858585612432565b5050505050565b6001600160a01b0383166000908152600860205260408120611ec58185612485565b611efb576040517fee9ad94800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001611f0682611dda565b611f109190613783565b6001600160a01b0386166000908152600760209081526040808320888452909152902060018101549193509060ff1615611f76576040517fee9ad94800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82815560018101805485151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009091161761010117905560405185906001600160a01b0388169033907f254c6a515aa0fc04a771c691313394d3739445c4c7e97384ac0cc5a51049123590611ffe9088908a909182521515602082015260400190565b60405180910390a450509392505050565b6000611a3b836001600160a01b03841661248d565b6001600160a01b038316612067576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b612084836000848460405180602001604052806000815250612432565b505050565b80516001600160a01b03166120ca576040517f91d3a01500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b60606000611a3b836124dc565b6000611a3b8383612538565b6001600160a01b038216612129576040517fced3e10000000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b03811660009081526003602052604090205460ff166120ca576040517f872daf8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03811660009081526001830160205260408120541515611a3b565b6001600160a01b03841661226b576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6001600160a01b0385166122ae576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b604080516001808252602082018690528183019081526060820185905260808201909252906115828787848487612432565b600061230c827f01ffc9a700000000000000000000000000000000000000000000000000000000612344565b80156106d1575061233d827fffffffff00000000000000000000000000000000000000000000000000000000612344565b1592915050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561241b575060208210155b80156124275750600081115b979650505050505050565b61243e85858585612562565b6001600160a01b03841615611e9c57825133906001036124775760208481015190840151612470838989858589612706565b505061106c565b61106c8187878787876128c4565b6000611a3b83835b60008181526001830160205260408120546124d4575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106d1565b5060006106d1565b60608160000180548060200260200160405190810160405280929190818152602001828054801561252c57602002820191906000526020600020905b815481526020019060010190808311612518575b50505050509050919050565b600082600001828154811061254f5761254f6134e4565b9060005260206000200154905092915050565b6001600160a01b0384161580159061258257506001600160a01b03831615155b156126f45760005b82518110156126f25760006125cd600b60008685815181106125ae576125ae6134e4565b602002602001015181526020019081526020016000206000015461158b565b90506125fd81600001517f08faf7f300000000000000000000000000000000000000000000000000000000611cf1565b156126e95780600001516001600160a01b03166308faf7f3858481518110612627576126276134e4565b60200260200101518888878781518110612643576126436134e4565b602002602001015186602001516040518663ffffffff1660e01b8152600401612670959493929190613796565b6020604051808303816000875af115801561268f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b3919061342d565b6126e9576040517f9112adf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060010161258a565b505b61270084848484612a2e565b50505050565b6001600160a01b0384163b1561106c576040517ff23a6e610000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f23a6e619061276390899089908890889088906004016137ce565b6020604051808303816000875af19250505080156127bc575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526127b991810190613806565b60015b61283e573d8080156127ea576040519150601f19603f3d011682016040523d82523d6000602084013e6127ef565b606091505b508051600003612836576040517f57f447ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401611056565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167ff23a6e610000000000000000000000000000000000000000000000000000000014611582576040517f57f447ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401611056565b6001600160a01b0384163b1561106c576040517fbc197c810000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063bc197c81906129219089908990889088908890600401613823565b6020604051808303816000875af192505050801561297a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261297791810190613806565b60015b6129a8573d8080156127ea576040519150601f19603f3d011682016040523d82523d6000602084013e6127ef565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fbc197c810000000000000000000000000000000000000000000000000000000014611582576040517f57f447ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401611056565b8051825114612a7657815181516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401611056565b3360005b8351811015612b95576020818102858101820151908501909101516001600160a01b03881615612b46576000828152602081815260408083206001600160a01b038c16845290915290205481811015612b1f576040517f03dee4c50000000000000000000000000000000000000000000000000000000081526001600160a01b038a166004820152602481018290526044810183905260648101849052608401611056565b6000838152602081815260408083206001600160a01b038d16845290915290209082900390555b6001600160a01b03871615612b8b576000828152602081815260408083206001600160a01b038b16845290915281208054839290612b85908490613770565b90915550505b5050600101612a7a565b508251600103612c165760208301516000906020840151909150856001600160a01b0316876001600160a01b0316846001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051612c07929190918252602082015260400190565b60405180910390a45050611e9c565b836001600160a01b0316856001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051612c65929190613875565b60405180910390a45050505050565b80356001600160a01b038116811461166857600080fd5b60008060408385031215612c9e57600080fd5b612ca783612c74565b946020939093013593505050565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146120ca57600080fd5b600060208284031215612cf557600080fd5b8135611a3b81612cb5565b60005b83811015612d1b578181015183820152602001612d03565b50506000910152565b60008151808452612d3c816020860160208601612d00565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611a3b6020830184612d24565b600060208284031215612d9357600080fd5b5035919050565b815181526020808301516001600160a01b031690820152604081016106d1565b60008060008060808587031215612dd057600080fd5b84359350612de060208601612c74565b925060408501359150612df560608601612c74565b905092959194509250565b600060208284031215612e1257600080fd5b611a3b82612c74565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612e9157612e91612e1b565b604052919050565b600067ffffffffffffffff821115612eb357612eb3612e1b565b5060051b60200190565b600082601f830112612ece57600080fd5b81356020612ee3612ede83612e99565b612e4a565b8083825260208201915060208460051b870101935086841115612f0557600080fd5b602086015b84811015612f215780358352918301918301612f0a565b509695505050505050565b600067ffffffffffffffff821115612f4657612f46612e1b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112612f8357600080fd5b8135612f91612ede82612f2c565b818152846020838601011115612fa657600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612fdb57600080fd5b612fe486612c74565b9450612ff260208701612c74565b9350604086013567ffffffffffffffff8082111561300f57600080fd5b61301b89838a01612ebd565b9450606088013591508082111561303157600080fd5b61303d89838a01612ebd565b9350608088013591508082111561305357600080fd5b5061306088828901612f72565b9150509295509295909350565b6000806000806060858703121561308357600080fd5b843567ffffffffffffffff8082111561309b57600080fd5b818701915087601f8301126130af57600080fd5b8135818111156130be57600080fd5b8860208260051b85010111156130d357600080fd5b6020928301965094506130e99187019050612c74565b9150612df560408601612c74565b602081526001600160a01b038251166020820152600060208301516040808401526108ad6060840182612d24565b6020808252825182820181905260009190848201906040850190845b818110156131665783516001600160a01b031683529284019291840191600101613141565b50909695505050505050565b6000806040838503121561318557600080fd5b823567ffffffffffffffff8082111561319d57600080fd5b818501915085601f8301126131b157600080fd5b813560206131c1612ede83612e99565b82815260059290921b840181019181810190898411156131e057600080fd5b948201945b83861015613205576131f686612c74565b825294820194908201906131e5565b9650508601359250508082111561321b57600080fd5b5061322885828601612ebd565b9150509250929050565b60008151808452602080850194506020840160005b8381101561326357815187529582019590820190600101613247565b509495945050505050565b602081526000611a3b6020830184613232565b6000806040838503121561329457600080fd5b823591506132a460208401612c74565b90509250929050565b80151581146120ca57600080fd5b600080604083850312156132ce57600080fd5b6132d783612c74565b915060208301356132e7816132ad565b809150509250929050565b60006020828403121561330457600080fd5b813567ffffffffffffffff81111561331b57600080fd5b6108ad84828501612f72565b6000806040838503121561333a57600080fd5b61334383612c74565b91506132a460208401612c74565b600080600080600060a0868803121561336957600080fd5b61337286612c74565b945061338060208701612c74565b93506040860135925060608601359150608086013567ffffffffffffffff8111156133aa57600080fd5b61306088828901612f72565b6000602082840312156133c857600080fd5b815167ffffffffffffffff8111156133df57600080fd5b8201601f810184136133f057600080fd5b80516133fe612ede82612f2c565b81815285602083850101111561341357600080fd5b613424826020830160208601612d00565b95945050505050565b60006020828403121561343f57600080fd5b8151611a3b816132ad565b60006001600160a01b0380891683528715156020840152808716604084015280861660608401525083608083015260c060a083015261348c60c0830184612d24565b98975050505050505050565b82815260608101611a3b6020830184805182526020908101516001600160a01b0316910152565b6040815260006134d26040830185612d24565b82810360208401526134248185612d24565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b85815260006001600160a01b038087166020840152808616604084015280851660608401525060a0608083015261242760a0830184612d24565b815160009082906020808601845b838110156135805781516001600160a01b03168552938201939082019060010161355b565b50929695505050505050565b600181811c908216806135a057607f821691505b6020821081036135d9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115612084576000816000526020600020601f850160051c810160208610156136085750805b601f850160051c820191505b8181101561106c57828155600101613614565b815167ffffffffffffffff81111561364157613641612e1b565b6136558161364f845461358c565b846135df565b602080601f8311600181146136a857600084156136725750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561106c565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156136f5578886015182559484019460019091019084016136d6565b508582101561373157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156106d1576106d1613741565b818103818111156106d1576106d1613741565b85815260006001600160a01b03808716602084015280861660408401525083606083015260a0608083015261242760a0830184612d24565b60006001600160a01b03808816835280871660208401525084604083015283606083015260a0608083015261242760a0830184612d24565b60006020828403121561381857600080fd5b8151611a3b81612cb5565b60006001600160a01b03808816835280871660208401525060a0604083015261384f60a0830186613232565b82810360608401526138618186613232565b9050828103608084015261348c8185612d24565b6040815260006138886040830185613232565b8281036020840152613424818561323256fea2646970667358221220831d1cbaeee9367fcc32ef0cdbe5869d108c9bf292e3adf496e5d825c6ace5ea64736f6c63430008170033000000000000000000000000031400de2e7694898eab1936868e77e88e240de90000000000000000000000006087351f4d90fa2e5575d996314170cf1b4e9620
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102405760003560e01c80634a21d5fc11610145578063a22cb465116100bd578063ca0f8b071161008c578063e985e9c511610071578063e985e9c514610658578063f059d78e14610694578063f242432a1461069c57600080fd5b8063ca0f8b0714610632578063d18f8ba01461064557600080fd5b8063a22cb465146105c0578063a2ea1376146105d3578063a8206bae146105e6578063b754f2721461061257600080fd5b8063702acd851161011457806396d31616116100f957806396d3161614610587578063972fefb91461059a57806399a7776e146105ad57600080fd5b8063702acd851461054d5780637305424f1461057457600080fd5b80634a21d5fc146104b95780634e1273f4146104ef5780634e23932f1461050f57806352f326971461052257600080fd5b80632c546207116101d85780633799e406116101a75780633d3cc1bf1161018c5780633d3cc1bf1461047357806344523fdf1461049357806346648011146104a657600080fd5b80633799e406146104115780633cea51201461045357600080fd5b80632c546207146103aa5780632eb2c2d6146103bf57806332b0cbce146103d257806334d70eea146103e557600080fd5b8063178ed28411610214578063178ed284146102e35780631b8b10731461034557806321f75d9e146103845780632a5c2ce71461039757600080fd5b8062fdd58e1461024557806301ffc9a71461026b57806306fdde031461028e5780630e89341c146102d0575b600080fd5b610258610253366004612c8b565b6106af565b6040519081526020015b60405180910390f35b61027e610279366004612ce3565b6106d7565b6040519015158152602001610262565b60408051808201909152601081527f4c4943454e53455f52454749535452590000000000000000000000000000000060208201525b6040516102629190612d6e565b6102c36102de366004612d81565b6107ba565b6103386102f1366004612d81565b6040805180820190915260008082526020820152506000908152600b6020908152604091829020825180840190935280548352600101546001600160a01b03169082015290565b6040516102629190612d9a565b61036c7f000000000000000000000000031400de2e7694898eab1936868e77e88e240de981565b6040516001600160a01b039091168152602001610262565b610258610392366004612dba565b6108b5565b6102586103a5366004612e00565b610d4c565b6103bd6103b8366004612e00565b610d6d565b005b6103bd6103cd366004612fc3565b610fd0565b6103bd6103e036600461306d565b611074565b61036c6103f3366004612d81565b6000908152600b60205260409020600101546001600160a01b031690565b61027e61041f366004612c8b565b6001600160a01b03919091166000908152600760209081526040808320938352929052206001015462010000900460ff1690565b610466610461366004612d81565b61158b565b60405161026291906130f7565b610486610481366004612e00565b61166d565b6040516102629190613125565b6104666104a1366004612c8b565b611691565b6104666104b4366004612d81565b611795565b6102586104c7366004612c8b565b6001600160a01b03919091166000908152600760209081526040808320938352929052205490565b6105026104fd366004613172565b6117c2565b604051610262919061326e565b61027e61051d366004613281565b6118a8565b61027e610530366004612d81565b6000908152600560205260409020546001600160a01b0316151590565b61036c7f0000000000000000000000006087351f4d90fa2e5575d996314170cf1b4e962081565b610258610582366004612c8b565b6118bd565b610258610595366004612e00565b611a42565b6105026105a8366004612e00565b611a63565b6102586105bb366004612c8b565b611a87565b6103bd6105ce3660046132bb565b611aa9565b6102586105e13660046132f2565b611ab8565b61027e6105f4366004612e00565b6001600160a01b031660009081526003602052604090205460ff1690565b610258610620366004612d81565b6000908152600b602052604090205490565b61027e610640366004612c8b565b611bfe565b61027e610653366004613327565b611c20565b61027e610666366004613327565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b600654610258565b6103bd6106aa366004613351565b611c42565b6000818152602081815260408083206001600160a01b03861684529091529020545b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fd9b67a2600000000000000000000000000000000000000000000000000000000148061076a57507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e89341c00000000000000000000000000000000000000000000000000000000145b806106d157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146106d1565b6000818152600b60209081526040808320815180830190925280548083526001909101546001600160a01b03169282019290925260609290916107fc9061158b565b805160208201516040517feb6b33150000000000000000000000000000000000000000000000000000000081529293506001600160a01b039091169163eb6b33159161084a91600401612d6e565b600060405180830381865afa158015610867573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108ad91908101906133b6565b949350505050565b6040517f5a1c2dd70000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000006087351f4d90fa2e5575d996314170cf1b4e96208116600483015284166024820152600090734687d14d30ea46a60499c2dcc07a56d2d1590fc390635a1c2dd790604401602060405180830381865af4158015610951573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610975919061342d565b6109ab576040517f998df7ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526008602052604090206109cd9086611cd9565b610af357336001600160a01b03851614801590610abc57506040517f7dfd0ddb0000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301523360248301523060448301527f21f75d9e0000000000000000000000000000000000000000000000000000000060648301527f000000000000000000000000031400de2e7694898eab1936868e77e88e240de91690637dfd0ddb90608401602060405180830381865afa158015610a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aba919061342d565b155b15610af3576040517f3404d1f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610afe8661158b565b6001600160a01b03861660009081526007602090815260408083208a8452909152902060010154815191925062010000900460ff1690610b5e907fcd6f464d00000000000000000000000000000000000000000000000000000000611cf1565b15610c3257815160208301516040517fcd6f464d0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163cd6f464d91610bb991339186918c918b918d919060040161344a565b6020604051808303816000875af1158015610bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfc919061342d565b610c32576040517ff81f025100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518060400160405280898152602001886001600160a01b031681525090506000610c8382604051602001610c6a9190612d9a565b604051602081830303815290604052600a600c54611d0d565b90955090508015610d2557600c8590556000858152600b60209081526040918290208451815590840151600190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039283161790559051869188169033907ffe73f59d33d83a61320621c23a68cc04b52cd8bd47cdf04a43d1365e8dd277ae90610d1c908c908890613498565b60405180910390a45b610d4086868960405180602001604052806000815250611d64565b50505050949350505050565b6001600160a01b03811660009081526008602052604081206106d190611dda565b610d97817fe835d3c800000000000000000000000000000000000000000000000000000000611cf1565b610dcd576040517fed12b51a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008190506000816001600160a01b031663c75e9a596040518163ffffffff1660e01b8152600401600060405180830381865afa158015610e12573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e5891908101906133b6565b9050805160001480610e7f5750604080516020810190915260008152610e7f908290611de4565b15610eb6576040517fa327329a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0380841660008181526003602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580517f06fdde03000000000000000000000000000000000000000000000000000000008152905192937fbae121b7564f0ecf01ff015fde3faa4dd4d8923eb147bb844bee40815fa94b7693908716926306fdde0392600480820193918290030181865afa158015610f6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610fb491908101906133b6565b83604051610fc39291906134bf565b60405180910390a2505050565b336001600160a01b038616811480159061101057506001600160a01b0380871660009081526001602090815260408083209385168352929052205460ff16155b1561105f576040517fe237d9220000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830152871660248201526044015b60405180910390fd5b61106c8686868686611e09565b505050505050565b336001600160a01b0383161480159061115f57506040517f7dfd0ddb0000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301523360248301523060448301527f32b0cbce0000000000000000000000000000000000000000000000000000000060648301527f000000000000000000000000031400de2e7694898eab1936868e77e88e240de91690637dfd0ddb90608401602060405180830381865afa158015611139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115d919061342d565b155b15611196576040517f3554b54000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260008167ffffffffffffffff8111156111b2576111b2612e1b565b6040519080825280602002602001820160405280156111db578160200160208202803683370190505b50905060008267ffffffffffffffff8111156111f9576111f9612e1b565b604051908082528060200260200182016040528015611222578160200160208202803683370190505b50905060005b838110156114f7576000888883818110611244576112446134e4565b90506020020135905061125786826106af565b600003611290576040517f784b513600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600b6020908152604091829020825180840190935280548352600101546001600160a01b031690820181905285518690859081106112d5576112d56134e4565b60200260200101906001600160a01b031690816001600160a01b031681525050876001600160a01b0316858481518110611311576113116134e4565b60200260200101516001600160a01b031603611359576040517f6b7a4bb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611368826000015161158b565b905061139881600001517ff02a311100000000000000000000000000000000000000000000000000000000611cf1565b1561146b5780600001516001600160a01b031663f02a311184338c8a89815181106113c5576113c56134e4565b602002602001015186602001516040518663ffffffff1660e01b81526004016113f2959493929190613513565b6020604051808303816000875af1158015611411573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611435919061342d565b61146b576040517fc9846cf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61147b8983600001516001611ea3565b506114cc868581518110611491576114916134e4565b6020026020010151600960008c6001600160a01b03166001600160a01b0316815260200190815260200160002061200f90919063ffffffff16565b5060018585815181106114e1576114e16134e4565b6020908102919091010152505050600101611228565b5081604051611506919061354d565b604051908190038120906001600160a01b0387169033907fd62a66bdb7d79aa53f9f9de9ebfa160d79778d07e68afe0a0c9c626243054b3c90600090a461158284888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250612024915050565b50505050505050565b604080518082019091526000815260606020820152600082815260056020908152604091829020825180840190935280546001600160a01b0316835260018101805491928401916115db9061358c565b80601f01602080910402602001604051908101604052809291908181526020018280546116079061358c565b80156116545780601f1061162957610100808354040283529160200191611654565b820191906000526020600020905b81548152906001019060200180831161163757829003601f168201915b505050505081525050905061166881612089565b919050565b6001600160a01b03811660009081526009602052604090206060906106d1906120cd565b6040805180820190915260008152606060208201526001600160a01b0383166000908152600860205260408120600591906116cc90856120da565b81526020808201929092526040908101600020815180830190925280546001600160a01b03168252600181018054929391929184019161170b9061358c565b80601f01602080910402602001604051908101604052809291908181526020018280546117379061358c565b80156117845780601f1061175957610100808354040283529160200191611784565b820191906000526020600020905b81548152906001019060200180831161176757829003601f168201915b505050505081525050905092915050565b6040805180820190915260008152606060208201526000828152600b60205260409020546106d19061158b565b6060815183511461180c57815183516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401611056565b6000835167ffffffffffffffff81111561182857611828612e1b565b604051908082528060200260200182016040528015611851578160200160208202803683370190505b50905060005b84518110156118a05760208082028601015161187b906020808402870101516106af565b82828151811061188d5761188d6134e4565b6020908102919091010152600101611857565b509392505050565b6000806118b583856106af565b119392505050565b6000336001600160a01b038416148015906119aa57506040517f7dfd0ddb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301523360248301523060448301527f7305424f0000000000000000000000000000000000000000000000000000000060648301527f000000000000000000000000031400de2e7694898eab1936868e77e88e240de91690637dfd0ddb90608401602060405180830381865afa158015611984573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a8919061342d565b155b156119e1576040517f3554b54000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260409020546001600160a01b0316611a2f576040517f91d3a01500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a3b83836000611ea3565b9392505050565b6001600160a01b03811660009081526009602052604081206106d190611dda565b6001600160a01b03811660009081526008602052604090206060906106d1906120cd565b6001600160a01b0382166000908152600860205260408120611a3b90836120da565b611ab43383836120e6565b5050565b6000611ac3336121b4565b60006040518060400160405280336001600160a01b03168152602001848152509050600080611b1583604051602001611afc91906130f7565b6040516020818303038152906040526004600654611d0d565b9150915080611b50576040517f61f8a6ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068290556000828152600560209081526040909120845181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178155908401518491906001820190611bb09082613627565b5090505081336001600160a01b03167f65dec4527c3884529f23bafda109f3c50ac1829ca9256c5948c411c4b04dbadd87604051611bee9190612d6e565b60405180910390a3509392505050565b6001600160a01b0382166000908152600860205260408120611a3b9083611cd9565b6001600160a01b0381166000908152600960205260408120611a3b9084612206565b336001600160a01b0386168114801590611c8257506001600160a01b0380871660009081526001602090815260408083209385168352929052205460ff16155b15611ccc576040517fe237d9220000000000000000000000000000000000000000000000000000000081526001600160a01b03808316600483015287166024820152604401611056565b61106c8686868686612228565b60008181526001830160205260408120541515611a3b565b6000611cfc836122e0565b8015611a3b5750611a3b8383612344565b8251602080850191909120600081815291849052604082205491908215611d38575060009050611d5c565b611d43846001613770565b6000918252602086905260409091208190559150600190505b935093915050565b6001600160a01b038416611da7576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6040805160018082526020820186905281830190815260608201859052608082019092529061106c600087848487612432565b60006106d1825490565b600081518351148015611a3b5750508051602091820120825192909101919091201490565b6001600160a01b038416611e4c576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6001600160a01b038516611e8f576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b611e9c8585858585612432565b5050505050565b6001600160a01b0383166000908152600860205260408120611ec58185612485565b611efb576040517fee9ad94800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001611f0682611dda565b611f109190613783565b6001600160a01b0386166000908152600760209081526040808320888452909152902060018101549193509060ff1615611f76576040517fee9ad94800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82815560018101805485151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009091161761010117905560405185906001600160a01b0388169033907f254c6a515aa0fc04a771c691313394d3739445c4c7e97384ac0cc5a51049123590611ffe9088908a909182521515602082015260400190565b60405180910390a450509392505050565b6000611a3b836001600160a01b03841661248d565b6001600160a01b038316612067576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b612084836000848460405180602001604052806000815250612432565b505050565b80516001600160a01b03166120ca576040517f91d3a01500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b60606000611a3b836124dc565b6000611a3b8383612538565b6001600160a01b038216612129576040517fced3e10000000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b03811660009081526003602052604090205460ff166120ca576040517f872daf8c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03811660009081526001830160205260408120541515611a3b565b6001600160a01b03841661226b576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b6001600160a01b0385166122ae576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401611056565b604080516001808252602082018690528183019081526060820185905260808201909252906115828787848487612432565b600061230c827f01ffc9a700000000000000000000000000000000000000000000000000000000612344565b80156106d1575061233d827fffffffff00000000000000000000000000000000000000000000000000000000612344565b1592915050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561241b575060208210155b80156124275750600081115b979650505050505050565b61243e85858585612562565b6001600160a01b03841615611e9c57825133906001036124775760208481015190840151612470838989858589612706565b505061106c565b61106c8187878787876128c4565b6000611a3b83835b60008181526001830160205260408120546124d4575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106d1565b5060006106d1565b60608160000180548060200260200160405190810160405280929190818152602001828054801561252c57602002820191906000526020600020905b815481526020019060010190808311612518575b50505050509050919050565b600082600001828154811061254f5761254f6134e4565b9060005260206000200154905092915050565b6001600160a01b0384161580159061258257506001600160a01b03831615155b156126f45760005b82518110156126f25760006125cd600b60008685815181106125ae576125ae6134e4565b602002602001015181526020019081526020016000206000015461158b565b90506125fd81600001517f08faf7f300000000000000000000000000000000000000000000000000000000611cf1565b156126e95780600001516001600160a01b03166308faf7f3858481518110612627576126276134e4565b60200260200101518888878781518110612643576126436134e4565b602002602001015186602001516040518663ffffffff1660e01b8152600401612670959493929190613796565b6020604051808303816000875af115801561268f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b3919061342d565b6126e9576040517f9112adf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060010161258a565b505b61270084848484612a2e565b50505050565b6001600160a01b0384163b1561106c576040517ff23a6e610000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063f23a6e619061276390899089908890889088906004016137ce565b6020604051808303816000875af19250505080156127bc575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526127b991810190613806565b60015b61283e573d8080156127ea576040519150601f19603f3d011682016040523d82523d6000602084013e6127ef565b606091505b508051600003612836576040517f57f447ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401611056565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167ff23a6e610000000000000000000000000000000000000000000000000000000014611582576040517f57f447ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401611056565b6001600160a01b0384163b1561106c576040517fbc197c810000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063bc197c81906129219089908990889088908890600401613823565b6020604051808303816000875af192505050801561297a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261297791810190613806565b60015b6129a8573d8080156127ea576040519150601f19603f3d011682016040523d82523d6000602084013e6127ef565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fbc197c810000000000000000000000000000000000000000000000000000000014611582576040517f57f447ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401611056565b8051825114612a7657815181516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401611056565b3360005b8351811015612b95576020818102858101820151908501909101516001600160a01b03881615612b46576000828152602081815260408083206001600160a01b038c16845290915290205481811015612b1f576040517f03dee4c50000000000000000000000000000000000000000000000000000000081526001600160a01b038a166004820152602481018290526044810183905260648101849052608401611056565b6000838152602081815260408083206001600160a01b038d16845290915290209082900390555b6001600160a01b03871615612b8b576000828152602081815260408083206001600160a01b038b16845290915281208054839290612b85908490613770565b90915550505b5050600101612a7a565b508251600103612c165760208301516000906020840151909150856001600160a01b0316876001600160a01b0316846001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051612c07929190918252602082015260400190565b60405180910390a45050611e9c565b836001600160a01b0316856001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051612c65929190613875565b60405180910390a45050505050565b80356001600160a01b038116811461166857600080fd5b60008060408385031215612c9e57600080fd5b612ca783612c74565b946020939093013593505050565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146120ca57600080fd5b600060208284031215612cf557600080fd5b8135611a3b81612cb5565b60005b83811015612d1b578181015183820152602001612d03565b50506000910152565b60008151808452612d3c816020860160208601612d00565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611a3b6020830184612d24565b600060208284031215612d9357600080fd5b5035919050565b815181526020808301516001600160a01b031690820152604081016106d1565b60008060008060808587031215612dd057600080fd5b84359350612de060208601612c74565b925060408501359150612df560608601612c74565b905092959194509250565b600060208284031215612e1257600080fd5b611a3b82612c74565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612e9157612e91612e1b565b604052919050565b600067ffffffffffffffff821115612eb357612eb3612e1b565b5060051b60200190565b600082601f830112612ece57600080fd5b81356020612ee3612ede83612e99565b612e4a565b8083825260208201915060208460051b870101935086841115612f0557600080fd5b602086015b84811015612f215780358352918301918301612f0a565b509695505050505050565b600067ffffffffffffffff821115612f4657612f46612e1b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112612f8357600080fd5b8135612f91612ede82612f2c565b818152846020838601011115612fa657600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612fdb57600080fd5b612fe486612c74565b9450612ff260208701612c74565b9350604086013567ffffffffffffffff8082111561300f57600080fd5b61301b89838a01612ebd565b9450606088013591508082111561303157600080fd5b61303d89838a01612ebd565b9350608088013591508082111561305357600080fd5b5061306088828901612f72565b9150509295509295909350565b6000806000806060858703121561308357600080fd5b843567ffffffffffffffff8082111561309b57600080fd5b818701915087601f8301126130af57600080fd5b8135818111156130be57600080fd5b8860208260051b85010111156130d357600080fd5b6020928301965094506130e99187019050612c74565b9150612df560408601612c74565b602081526001600160a01b038251166020820152600060208301516040808401526108ad6060840182612d24565b6020808252825182820181905260009190848201906040850190845b818110156131665783516001600160a01b031683529284019291840191600101613141565b50909695505050505050565b6000806040838503121561318557600080fd5b823567ffffffffffffffff8082111561319d57600080fd5b818501915085601f8301126131b157600080fd5b813560206131c1612ede83612e99565b82815260059290921b840181019181810190898411156131e057600080fd5b948201945b83861015613205576131f686612c74565b825294820194908201906131e5565b9650508601359250508082111561321b57600080fd5b5061322885828601612ebd565b9150509250929050565b60008151808452602080850194506020840160005b8381101561326357815187529582019590820190600101613247565b509495945050505050565b602081526000611a3b6020830184613232565b6000806040838503121561329457600080fd5b823591506132a460208401612c74565b90509250929050565b80151581146120ca57600080fd5b600080604083850312156132ce57600080fd5b6132d783612c74565b915060208301356132e7816132ad565b809150509250929050565b60006020828403121561330457600080fd5b813567ffffffffffffffff81111561331b57600080fd5b6108ad84828501612f72565b6000806040838503121561333a57600080fd5b61334383612c74565b91506132a460208401612c74565b600080600080600060a0868803121561336957600080fd5b61337286612c74565b945061338060208701612c74565b93506040860135925060608601359150608086013567ffffffffffffffff8111156133aa57600080fd5b61306088828901612f72565b6000602082840312156133c857600080fd5b815167ffffffffffffffff8111156133df57600080fd5b8201601f810184136133f057600080fd5b80516133fe612ede82612f2c565b81815285602083850101111561341357600080fd5b613424826020830160208601612d00565b95945050505050565b60006020828403121561343f57600080fd5b8151611a3b816132ad565b60006001600160a01b0380891683528715156020840152808716604084015280861660608401525083608083015260c060a083015261348c60c0830184612d24565b98975050505050505050565b82815260608101611a3b6020830184805182526020908101516001600160a01b0316910152565b6040815260006134d26040830185612d24565b82810360208401526134248185612d24565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b85815260006001600160a01b038087166020840152808616604084015280851660608401525060a0608083015261242760a0830184612d24565b815160009082906020808601845b838110156135805781516001600160a01b03168552938201939082019060010161355b565b50929695505050505050565b600181811c908216806135a057607f821691505b6020821081036135d9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115612084576000816000526020600020601f850160051c810160208610156136085750805b601f850160051c820191505b8181101561106c57828155600101613614565b815167ffffffffffffffff81111561364157613641612e1b565b6136558161364f845461358c565b846135df565b602080601f8311600181146136a857600084156136725750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561106c565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156136f5578886015182559484019460019091019084016136d6565b508582101561373157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156106d1576106d1613741565b818103818111156106d1576106d1613741565b85815260006001600160a01b03808716602084015280861660408401525083606083015260a0608083015261242760a0830184612d24565b60006001600160a01b03808816835280871660208401525084604083015283606083015260a0608083015261242760a0830184612d24565b60006020828403121561381857600080fd5b8151611a3b81612cb5565b60006001600160a01b03808816835280871660208401525060a0604083015261384f60a0830186613232565b82810360608401526138618186613232565b9050828103608084015261348c8185612d24565b6040815260006138886040830185613232565b8281036020840152613424818561323256fea2646970667358221220831d1cbaeee9367fcc32ef0cdbe5869d108c9bf292e3adf496e5d825c6ace5ea64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000031400de2e7694898eab1936868e77e88e240de90000000000000000000000006087351f4d90fa2e5575d996314170cf1b4e9620
-----Decoded View---------------
Arg [0] : accessController (address): 0x031400de2e7694898eAB1936868e77E88e240DE9
Arg [1] : ipAccountRegistry (address): 0x6087351F4D90FA2E5575D996314170cf1b4e9620
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000031400de2e7694898eab1936868e77e88e240de9
Arg [1] : 0000000000000000000000006087351f4d90fa2e5575d996314170cf1b4e9620
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.