Token
Programmable IP License NFT (PILNFT)
ERC-1155
Overview
Max Total Supply
0 PILNFT
Holders
2,444
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Loading...
Loading
Loading...
Loading
Loading...
Loading
| # | Exchange | Pair | Price | 24H Volume | % Volume |
|---|
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: BUSL-1.1
pragma solidity 0.8.23;
import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IPolicyFrameworkManager } from "../interfaces/modules/licensing/IPolicyFrameworkManager.sol";
import { ILicenseRegistry } from "../interfaces/registries/ILicenseRegistry.sol";
import { ILicensingModule } from "../interfaces/modules/licensing/ILicensingModule.sol";
import { IDisputeModule } from "../interfaces/modules/dispute/IDisputeModule.sol";
import { Governable } from "../governance/Governable.sol";
import { Errors } from "../lib/Errors.sol";
import { Licensing } from "../lib/Licensing.sol";
import { DataUniqueness } from "../lib/DataUniqueness.sol";
/// @title LicenseRegistry aka LNFT
/// @notice Registry of License NFTs, which represent licenses granted by IP ID licensors to create derivative IPs.
contract LicenseRegistry is ILicenseRegistry, ERC1155, Governable {
using Strings for *;
/// @notice Emitted for metadata updates, per EIP-4906
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
/// @notice Name of the Programmable IP License NFT
string public name = "Programmable IP License NFT";
/// @notice Symbol of the Programmable IP License NFT
string public symbol = "PILNFT";
/// @notice URL of the Licensing Image
string public imageUrl;
// TODO: deploy with CREATE2 to make this immutable
/// @notice Returns the canonical protocol-wide LicensingModule
ILicensingModule public LICENSING_MODULE;
/// @notice Returns the canonical protocol-wide DisputeModule
IDisputeModule public DISPUTE_MODULE;
/// @dev Maps the hash of the license data to the licenseId
mapping(bytes32 licenseHash => uint256 licenseId) private _hashedLicenses;
/// @dev Maps the licenseId to the license data
mapping(uint256 licenseId => Licensing.License licenseData) private _licenses;
/// @dev Tracks the number of licenses registered in the protocol, it will not decrease when a license is burnt.
uint256 private _mintedLicenses;
/// @dev We have to implement this modifier instead of inheriting `LicensingModuleAware` because LicensingModule
/// constructor requires the licenseRegistry address, which would create a circular dependency. Thus, we use the
/// function `setLicensingModule` to set the licensing module address after deploying the module.
modifier onlyLicensingModule() {
if (msg.sender != address(LICENSING_MODULE)) {
revert Errors.LicenseRegistry__CallerNotLicensingModule();
}
_;
}
constructor(address governance, string memory url) ERC1155("") Governable(governance) {
imageUrl = url;
}
/// @dev Sets the DisputeModule address.
/// @dev Enforced to be only callable by the protocol admin
/// @param newDisputeModule The address of the DisputeModule
function setDisputeModule(address newDisputeModule) external onlyProtocolAdmin {
if (newDisputeModule == address(0)) {
revert Errors.LicenseRegistry__ZeroDisputeModule();
}
DISPUTE_MODULE = IDisputeModule(newDisputeModule);
}
/// @dev Sets the LicensingModule address.
/// @dev Enforced to be only callable by the protocol admin
/// @param newLicensingModule The address of the LicensingModule
function setLicensingModule(address newLicensingModule) external onlyProtocolAdmin {
if (newLicensingModule == address(0)) {
revert Errors.LicenseRegistry__ZeroLicensingModule();
}
LICENSING_MODULE = ILicensingModule(newLicensingModule);
}
/// @dev Sets the Licensing Image URL.
/// @dev Enforced to be only callable by the protocol admin
/// @param url The URL of the Licensing Image
function setLicensingImageUrl(string calldata url) external onlyProtocolAdmin {
imageUrl = url;
emit BatchMetadataUpdate(1, _mintedLicenses);
}
/// @notice 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. If not, the license is fungible and an id will be reused.
/// @dev Only callable by the licensing module.
/// @param policyId The ID of the policy to be minted
/// @param licensorIpId_ The ID of the IP granting the license (ie. licensor)
/// @param transferable True if the license is transferable
/// @param amount Number of licenses to mint. License NFT is fungible for same policy and same licensors
/// @param receiver Receiver address of the minted license NFT(s).
/// @return licenseId The ID of the minted license NFT(s).
function mintLicense(
uint256 policyId,
address licensorIpId_,
bool transferable,
uint256 amount, // mint amount
address receiver
) external onlyLicensingModule returns (uint256 licenseId) {
Licensing.License memory licenseData = Licensing.License({
policyId: policyId,
licensorIpId: licensorIpId_,
transferable: transferable
});
bool isNew;
(licenseId, isNew) = DataUniqueness.addIdOrGetExisting(
abi.encode(licenseData),
_hashedLicenses,
_mintedLicenses
);
if (isNew) {
_mintedLicenses = licenseId;
_licenses[licenseId] = licenseData;
emit LicenseMinted(msg.sender, receiver, licenseId, amount, licenseData);
}
_mint(receiver, licenseId, amount, "");
return licenseId;
}
function burnLicenses(address holder, uint256[] calldata licenseIds) external onlyLicensingModule {
uint256[] memory values = new uint256[](licenseIds.length);
for (uint256 i = 0; i < licenseIds.length; i++) {
values[i] = 1;
}
// Burn licenses
_burnBatch(holder, licenseIds, values);
}
/// @notice Returns the number of licenses registered in the protocol.
/// @dev Token ID counter total count.
/// @return mintedLicenses The number of minted licenses
function mintedLicenses() external view returns (uint256) {
return _mintedLicenses;
}
/// @notice Returns true if holder has positive balance for the given license ID.
/// @return isLicensee 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) {
return balanceOf(holder, licenseId) > 0;
}
/// @notice Returns the license data for the given license ID
/// @param licenseId The ID of the license
/// @return licenseData The license data
function license(uint256 licenseId) external view returns (Licensing.License memory) {
return _licenses[licenseId];
}
/// @notice Returns the ID of the IP asset that is the licensor of the given license ID
/// @param licenseId The ID of the license
/// @return licensorIpId The ID of the licensor
function licensorIpId(uint256 licenseId) external view returns (address) {
return _licenses[licenseId].licensorIpId;
}
/// @notice Returns the policy ID for the given license ID
/// @param licenseId The ID of the license
/// @return policyId The ID of the policy
function policyIdForLicense(uint256 licenseId) external view returns (uint256) {
return _licenses[licenseId].policyId;
}
/// @notice Returns true if the license has been revoked (licensor tagged after a dispute in
/// the dispute module). If the tag is removed, the license is not revoked anymore.
/// @param licenseId The id of the license to check
/// @return isRevoked True if the license is revoked
function isLicenseRevoked(uint256 licenseId) public view returns (bool) {
// For beta, any tag means revocation, for mainnet we need more context.
// TODO: signal metadata update when tag changes.
return DISPUTE_MODULE.isIpTagged(_licenses[licenseId].licensorIpId);
}
/// @notice ERC1155 OpenSea metadata JSON representation of the LNFT parameters
/// @dev Expect PFM.policyToJson to return {'trait_type: 'value'},{'trait_type': 'value'},...,{...}
/// (last attribute must not have a comma at the end)
function uri(uint256 id) public view virtual override returns (string memory) {
Licensing.License memory licenseData = _licenses[id];
Licensing.Policy memory pol = LICENSING_MODULE.policy(licenseData.policyId);
string memory licensorIpIdHex = licenseData.licensorIpId.toHexString();
/* solhint-disable */
// Follows the OpenSea standard for JSON metadata
// base json, open the attributes array
string memory json = string(
abi.encodePacked(
"{",
'"name": "Story Protocol License #',
id.toString(),
'",',
'"description": "License agreement stating the terms of a Story Protocol IPAsset",',
'"external_url": "https://protocol.storyprotocol.xyz/ipa/',
licensorIpIdHex,
'",',
// solhint-disable-next-line max-length
'"image": "',
imageUrl,
'",',
'"attributes": ['
)
);
// append the policy specific attributes (last attribute added by PFM should have a comma at the end)
// TODO: Safeguard mechanism to make sure the attributes added by PFM do NOT overlap with the common traits
// defined above. Currently, we add the common license attributes after adding the PFM attributes to override.
// But OpenSea might take the value of the first duplicate.
json = string(
abi.encodePacked(json, IPolicyFrameworkManager(pol.policyFramework).policyToJson(pol.frameworkData))
);
// append the common license attributes
json = string(
abi.encodePacked(
json,
'{"trait_type": "Licensor", "value": "',
licensorIpIdHex,
'"},',
'{"trait_type": "Policy Framework", "value": "',
pol.policyFramework.toHexString(),
'"},',
'{"trait_type": "Transferable", "value": "',
licenseData.transferable ? "true" : "false",
'"},',
'{"trait_type": "Revoked", "value": "',
isLicenseRevoked(id) ? "true" : "false",
'"}'
)
);
// close the attributes array and the json metadata object
json = string(abi.encodePacked(json, "]}"));
/* solhint-enable */
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(bytes(json))));
}
/// @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 in LicensingModule respectively
if (from != address(0) && to != address(0)) {
for (uint256 i = 0; i < ids.length; i++) {
Licensing.License memory lic = _licenses[ids[i]];
// TODO: Hook for verify transfer params
if (isLicenseRevoked(ids[i])) {
revert Errors.LicenseRegistry__RevokedLicense();
}
if (!lic.transferable) {
// True if from == licensor
if (from != lic.licensorIpId) {
revert Errors.LicenseRegistry__NotTransferable();
}
}
}
}
super._update(from, to, ids, values);
}
}// 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/Base64.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/
if (data.length == 0) return "";
// Loads the table into memory
string memory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
// and split into 4 numbers of 6 bits.
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
string memory result = new string(4 * ((data.length + 2) / 3));
/// @solidity memory-safe-assembly
assembly {
// Prepare the lookup table (skip the first "length" byte)
let tablePtr := add(table, 1)
// Prepare result pointer, jump over length
let resultPtr := add(result, 32)
// Run over the input, 3 bytes at a time
for {
let dataPtr := data
let endPtr := add(data, mload(data))
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 bytes (18 bits) chunk
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F which is the number of
// the previous character in the ASCII table prior to the Base64 Table
// The result is then added to the table to get the character to write,
// and finally write it in the result pointer but with a left shift
// of 256 (1 byte) - 8 (1 ASCII char) = 248 bits
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.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 IERC165 {
/// @notice Name to be show in LNFT metadata
function name() external view returns (string memory);
/// @notice Returns the URL to the off chain legal agreement template text
function licenseTextUrl() external view returns (string memory);
/// @notice Returns the stringified JSON policy data for the LicenseRegistry.uri(uint256) method.
/// @dev Must return ERC1155 OpenSea standard compliant metadata.
/// @param policyData The encoded licensing policy data to be decoded by the PFM
/// @return jsonString The OpenSea-compliant metadata URI of the policy
function policyToJson(bytes memory policyData) external view returns (string memory);
/// @notice Verify compatibility of one or more policies when inheriting them from one or more parent IPs.
/// @dev Enforced to be only callable by LicenseRegistry
/// @dev The assumption in this method is that we can add parents later on, hence the need
/// for an aggregator, if not we will do this when linking to parents directly with an
/// array of policies.
/// @param aggregator common state of the policies for the IP
/// @param policyId the ID of the policy being inherited
/// @param policy the policy to inherit
/// @return changedAgg true if the aggregator was changed
/// @return newAggregator the new aggregator
function processInheritedPolicies(
bytes memory aggregator,
uint256 policyId,
bytes memory policy
) external view returns (bool changedAgg, bytes memory newAggregator);
/// @notice Verify policy parameters for minting a license.
/// @dev Enforced to be only callable by LicenseRegistry
/// @param licensee the address that holds the license and is executing the mint
/// @param mintingFromADerivative true if we verify minting a license from a derivative IP ID
/// @param receiver the address receiving the license
/// @param licensorIpId the IP id of the licensor
/// @param mintAmount the amount of licenses to mint
/// @param policyData the encoded framework policy data to verify
/// @return verified True if the link is verified
function verifyMint(
address licensee,
bool mintingFromADerivative,
address licensorIpId,
address receiver,
uint256 mintAmount,
bytes memory policyData
) external returns (bool);
/// @notice Verify policy parameters for linking a child IP to a parent IP (licensor) by burning a license NFT.
/// @dev Enforced to be only callable by LicenseRegistry
/// @param licenseId the license id to burn
/// @param licensee the address that holds the license and is executing the link
/// @param ipId the IP id of the IP being linked
/// @param parentIpId the IP id of the parent IP
/// @param policyData the encoded framework policy data to verify
/// @return verified True if the link is verified
function verifyLink(
uint256 licenseId,
address licensee,
address ipId,
address parentIpId,
bytes calldata policyData
) external returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import { Licensing } from "../../lib/Licensing.sol";
import { IDisputeModule } from "../modules/dispute/IDisputeModule.sol";
import { ILicensingModule } from "../modules/licensing/ILicensingModule.sol";
/// @title ILicenseRegistry
interface ILicenseRegistry is IERC1155 {
/// @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 Returns the canonical protocol-wide LicensingModule
function LICENSING_MODULE() external view returns (ILicensingModule);
/// @notice Returns the canonical protocol-wide DisputeModule
function DISPUTE_MODULE() external view returns (IDisputeModule);
/// @notice 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. If not, the license is fungible and an id will be reused.
/// @dev Only callable by the licensing module.
/// @param policyId The ID of the policy to be minted
/// @param licensorIpId_ The ID of the IP granting the license (ie. licensor)
/// @param transferable True if the license is transferable
/// @param amount Number of licenses to mint. License NFT is fungible for same policy and same licensors
/// @param receiver Receiver address of the minted license NFT(s).
/// @return licenseId The ID of the minted license NFT(s).
function mintLicense(
uint256 policyId,
address licensorIpId_,
bool transferable,
uint256 amount,
address receiver
) external returns (uint256 licenseId);
/// @notice Burns licenses
/// @param holder The address that holds the licenses
/// @param licenseIds The ids of the licenses to burn
function burnLicenses(address holder, uint256[] calldata licenseIds) external;
///
/// Getters
///
/// @notice Returns the number of licenses registered in the protocol.
/// @dev Token ID counter total count.
/// @return mintedLicenses The number of minted licenses
function mintedLicenses() external view returns (uint256);
/// @notice Returns true if holder has positive balance for the given license ID.
/// @return isLicensee 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 Returns the license data for the given license ID
/// @param licenseId The ID of the license
/// @return licenseData The license data
function license(uint256 licenseId) external view returns (Licensing.License memory);
/// @notice Returns the ID of the IP asset that is the licensor of the given license ID
/// @param licenseId The ID of the license
/// @return licensorIpId The ID of the licensor
function licensorIpId(uint256 licenseId) external view returns (address);
/// @notice Returns the policy ID for the given license ID
/// @param licenseId The ID of the license
/// @return policyId The ID of the policy
function policyIdForLicense(uint256 licenseId) external view returns (uint256);
/// @notice Returns true if the license has been revoked (licensor tagged after a dispute in
/// the dispute module). If the tag is removed, the license is not revoked anymore.
/// @param licenseId The id of the license to check
/// @return isRevoked True if the license is revoked
function isLicenseRevoked(uint256 licenseId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { Licensing } from "../../../lib/Licensing.sol";
import { IModule } from "../base/IModule.sol";
import { RoyaltyModule } from "../../../modules/royalty/RoyaltyModule.sol";
import { ILicenseRegistry } from "../../registries/ILicenseRegistry.sol";
import { IDisputeModule } from "../dispute/IDisputeModule.sol";
/// @title ILicensingModule
interface ILicensingModule is IModule {
/// @notice Status of a policy on IP asset
/// @param index The local index of the policy in the IP asset
/// @param isSet True if the policy is set in the IP asset
/// @param active True if the policy is active
/// @param isInherited True if the policy is inherited from a parent IP asset
struct PolicySetup {
uint256 index;
bool isSet;
bool active;
bool isInherited;
}
/// @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 policyId The id of the policy
/// @param policyFrameworkManager The address of the policy framework manager
/// @param frameworkData The policy framework specific encoded data
/// @param royaltyPolicy The address of the royalty policy
/// @param royaltyData The royalty policy specific encoded data
/// @param mintingFee The fee to be paid when minting a license
/// @param mintingFeeToken The token to be used to pay the minting fee
event PolicyRegistered(
uint256 indexed policyId,
address indexed policyFrameworkManager,
bytes frameworkData,
address royaltyPolicy,
bytes royaltyData,
uint256 mintingFee,
address mintingFeeToken
);
/// @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 set
/// @param isInherited 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 isInherited
);
/// @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 IPs
event IpIdLinkedToParents(address indexed caller, address indexed ipId, address[] parentIpIds);
/// @notice Returns the canonical protocol-wide RoyaltyModule
function ROYALTY_MODULE() external view returns (RoyaltyModule);
/// @notice Returns the canonical protocol-wide LicenseRegistry
function LICENSE_REGISTRY() external view returns (ILicenseRegistry);
/// @notice Returns the canonical protocol-wide DisputeModule
function DISPUTE_MODULE() external view returns (IDisputeModule);
/// @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 pol The Licensing policy data. MUST have same policy framework as the caller address
/// @return policyId The id of the newly registered policy
function registerPolicy(Licensing.Policy memory pol) external returns (uint256 policyId);
/// @notice Adds a policy to the set of policies of an IP
/// @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 set
function addPolicyToIp(address ipId, uint256 polId) external returns (uint256 indexOnIpId);
/// @notice Mints a license to create derivative IP. License NFTs represent a policy granted by IPs (licensors).
/// Reverts if caller is not authorized by any of the licensors.
/// @dev 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.
/// @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
/// @param royaltyContext The context for the royalty module to process
/// @return licenseId The ID of the license NFT(s)
function mintLicense(
uint256 policyId,
address licensorIpId,
uint256 amount,
address receiver,
bytes calldata royaltyContext
) external returns (uint256 licenseId);
/// @notice Links an IP to the licensors listed in the license NFTs, if their policies allow it. Burns the license
/// NFTs in the proccess. The caller must be the owner of the IP asset and license NFTs.
/// @param licenseIds The id of the licenses to burn
/// @param childIpId The id of the child IP to be linked
/// @param royaltyContext The context for the royalty module to process
function linkIpToParents(uint256[] calldata licenseIds, address childIpId, bytes calldata royaltyContext) external;
///
/// Getters
///
/// @notice Returns if the framework address is registered in the LicensingModule.
/// @param policyFramework The address of the policy framework manager
/// @return isRegistered True if the framework is registered
function isFrameworkRegistered(address policyFramework) external view returns (bool);
/// @notice Returns amount of distinct licensing policies in the LicensingModule.
/// @return totalPolicies The amount of policies
function totalPolicies() external view returns (uint256);
/// @notice Returns the policy data for policyId, reverts if not found.
/// @param policyId The id of the policy
/// @return pol The policy data
function policy(uint256 policyId) external view returns (Licensing.Policy memory pol);
/// @notice Returns the policy id for the given policy data, or 0 if not found.
/// @param pol The policy data in Policy struct
/// @return policyId The id of the policy
function getPolicyId(Licensing.Policy calldata pol) external view returns (uint256 policyId);
/// @notice Returns the policy aggregator data for the given IP ID in the framework.
/// @param framework The address of the policy framework manager
/// @param ipId The id of the IP asset
/// @return data The encoded policy aggregator data to be decoded by the framework manager
function policyAggregatorData(address framework, address ipId) external view returns (bytes memory);
/// @notice Returns if policyId exists in the LicensingModule
/// @param policyId The id of the policy
/// @return isDefined True if the policy is defined
function isPolicyDefined(uint256 policyId) external view returns (bool);
/// @notice Returns the policy ids attached to an IP
/// @dev Potentially gas-intensive operation, use with care.
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset
/// @return policyIds The ids of policy ids for the IP
function policyIdsForIp(bool isInherited, address ipId) external view returns (uint256[] memory policyIds);
/// @notice Returns the total number of policies attached to an IP
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset
/// @return totalPolicies The total number of policies for the IP
function totalPoliciesForIp(bool isInherited, address ipId) external view returns (uint256);
/// @notice Returns if a given policyId is attached to an IP
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset
/// @param policyId The id of the policy
/// @return isSet True if the policy is set in the IP asset
function isPolicyIdSetForIp(bool isInherited, address ipId, uint256 policyId) external view returns (bool);
/// @notice Returns the policy ID for an IP by local index on the IP's policy set
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset to check
/// @param index The local index of a policy in the IP's policy set
/// @return policyId The id of the policy
function policyIdForIpAtIndex(
bool isInherited,
address ipId,
uint256 index
) external view returns (uint256 policyId);
/// @notice Returns the policy data for an IP by the policy's local index on the IP's policy set
/// @param isInherited True if the policy is inherited from a parent IP
/// @param ipId The id of the IP asset to check
/// @param index The local index of a policy in the IP's policy set
/// @return policy The policy data
function policyForIpAtIndex(
bool isInherited,
address ipId,
uint256 index
) external view returns (Licensing.Policy memory);
/// @notice Returns the status of a policy in an IP's policy set
/// @param ipId The id of the IP asset to check
/// @param policyId The id of the policy
/// @return index The local index of the policy in the IP's policy set
/// @return isInherited True if the policy is inherited from a parent IP
/// @return active True if the policy is active
function policyStatus(
address ipId,
uint256 policyId
) external view returns (uint256 index, bool isInherited, bool active);
/// @notice Returns if the given policy attached to the given IP is inherited from a parent IP.
/// @param ipId The id of the IP asset that has the policy attached
/// @param policyId The id of the policy to check if inherited
/// @return isInherited True if the policy is inherited from a parent IP
function isPolicyInherited(address ipId, uint256 policyId) external view returns (bool);
/// @notice Returns if an IP is a derivative of another IP
/// @param parentIpId The id of the parent IP asset to check
/// @param childIpId The id of the child IP asset to check
/// @return isParent True if the child IP is a derivative of the parent IP
function isParent(address parentIpId, address childIpId) external view returns (bool);
/// @notice Returns the list of parent IP assets for a given child IP asset
/// @param ipId The id of the child IP asset to check
/// @return parentIpIds The ids of the parent IP assets
function parentIpIds(address ipId) external view returns (address[] memory);
/// @notice Returns the total number of parents for an IP asset
/// @param ipId The id of the IP asset to check
/// @return totalParents The total number of parent IP assets
function totalParentsForIpId(address ipId) external view returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Dispute Module Interface
interface IDisputeModule {
/// @notice Dispute struct
/// @param targetIpId The ipId that is the target of the dispute
/// @param disputeInitiator The address of the dispute initiator
/// @param arbitrationPolicy The address of the arbitration policy
/// @param linkToDisputeEvidence The link of the dispute evidence
/// @param targetTag The target tag of the dispute
/// @param currentTag The current tag of the dispute
struct Dispute {
address targetIpId;
address disputeInitiator;
address arbitrationPolicy;
bytes32 linkToDisputeEvidence;
bytes32 targetTag;
bytes32 currentTag;
}
/// @notice Event emitted when a dispute tag whitelist status is updated
/// @param tag The dispute tag
/// @param allowed Indicates if the dispute tag is whitelisted
event TagWhitelistUpdated(bytes32 tag, bool allowed);
/// @notice Event emitted when an arbitration policy whitelist status is updated
/// @param arbitrationPolicy The address of the arbitration policy
/// @param allowed Indicates if the arbitration policy is whitelisted
event ArbitrationPolicyWhitelistUpdated(address arbitrationPolicy, bool allowed);
/// @notice Event emitted when an arbitration relayer whitelist status is updated
/// @param arbitrationPolicy The address of the arbitration policy
/// @param arbitrationRelayer The address of the arbitration relayer
/// @param allowed Indicates if the arbitration relayer is whitelisted
event ArbitrationRelayerWhitelistUpdated(address arbitrationPolicy, address arbitrationRelayer, bool allowed);
/// @notice Event emitted when the base arbitration policy is set
/// @param arbitrationPolicy The address of the arbitration policy
event DefaultArbitrationPolicyUpdated(address arbitrationPolicy);
/// @notice Event emitted when an arbitration policy is set for an ipId
/// @param ipId The ipId address
/// @param arbitrationPolicy The address of the arbitration policy
event ArbitrationPolicySet(address ipId, address arbitrationPolicy);
/// @notice Event emitted when a dispute is raised
/// @param disputeId The dispute id
/// @param targetIpId The ipId that is the target of the dispute
/// @param disputeInitiator The address of the dispute initiator
/// @param arbitrationPolicy The address of the arbitration policy
/// @param linkToDisputeEvidence The link of the dispute evidence
/// @param targetTag The target tag of the dispute
/// @param data Custom data adjusted to each policy
event DisputeRaised(
uint256 disputeId,
address targetIpId,
address disputeInitiator,
address arbitrationPolicy,
bytes32 linkToDisputeEvidence,
bytes32 targetTag,
bytes data
);
/// @notice Event emitted when a dispute judgement is set
/// @param disputeId The dispute id
/// @param decision The decision of the dispute
/// @param data Custom data adjusted to each policy
event DisputeJudgementSet(uint256 disputeId, bool decision, bytes data);
/// @notice Event emitted when a dispute is cancelled
/// @param disputeId The dispute id
/// @param data Custom data adjusted to each policy
event DisputeCancelled(uint256 disputeId, bytes data);
/// @notice Event emitted when a dispute is resolved
/// @param disputeId The dispute id
event DisputeResolved(uint256 disputeId);
/// @notice Tag to represent the dispute is in dispute state waiting for judgement
function IN_DISPUTE() external view returns (bytes32);
/// @notice Dispute ID counter
function disputeCounter() external view returns (uint256);
/// @notice The address of the base arbitration policy
function baseArbitrationPolicy() external view returns (address);
/// @notice Returns the dispute information for a given dispute id
/// @param disputeId The dispute id
/// @return targetIpId The ipId that is the target of the dispute
/// @return disputeInitiator The address of the dispute initiator
/// @return arbitrationPolicy The address of the arbitration policy
/// @return linkToDisputeEvidence The link of the dispute summary
/// @return targetTag The target tag of the dispute
/// @return currentTag The current tag of the dispute
function disputes(
uint256 disputeId
)
external
view
returns (
address targetIpId,
address disputeInitiator,
address arbitrationPolicy,
bytes32 linkToDisputeEvidence,
bytes32 targetTag,
bytes32 currentTag
);
/// @notice Indicates if a dispute tag is whitelisted
/// @param tag The dispute tag
/// @return allowed Indicates if the dispute tag is whitelisted
function isWhitelistedDisputeTag(bytes32 tag) external view returns (bool allowed);
/// @notice Indicates if an arbitration policy is whitelisted
/// @param arbitrationPolicy The address of the arbitration policy
/// @return allowed Indicates if the arbitration policy is whitelisted
function isWhitelistedArbitrationPolicy(address arbitrationPolicy) external view returns (bool allowed);
/// @notice Indicates if an arbitration relayer is whitelisted for a given arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
/// @param arbitrationRelayer The address of the arbitration relayer
/// @return allowed Indicates if the arbitration relayer is whitelisted
function isWhitelistedArbitrationRelayer(
address arbitrationPolicy,
address arbitrationRelayer
) external view returns (bool allowed);
/// @notice Arbitration policy for a given ipId
/// @param ipId The ipId
/// @return policy The address of the arbitration policy
function arbitrationPolicies(address ipId) external view returns (address policy);
/// @notice Whitelists a dispute tag
/// @param tag The dispute tag
/// @param allowed Indicates if the dispute tag is whitelisted or not
function whitelistDisputeTag(bytes32 tag, bool allowed) external;
/// @notice Whitelists an arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
/// @param allowed Indicates if the arbitration policy is whitelisted or not
function whitelistArbitrationPolicy(address arbitrationPolicy, bool allowed) external;
/// @notice Whitelists an arbitration relayer for a given arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
/// @param arbPolicyRelayer The address of the arbitration relayer
/// @param allowed Indicates if the arbitration relayer is whitelisted or not
function whitelistArbitrationRelayer(address arbitrationPolicy, address arbPolicyRelayer, bool allowed) external;
/// @notice Sets the base arbitration policy
/// @param arbitrationPolicy The address of the arbitration policy
function setBaseArbitrationPolicy(address arbitrationPolicy) external;
/// @notice Sets the arbitration policy for an ipId
/// @param ipId The ipId
/// @param arbitrationPolicy The address of the arbitration policy
function setArbitrationPolicy(address ipId, address arbitrationPolicy) external;
/// @notice Raises a dispute on a given ipId
/// @param targetIpId The ipId that is the target of the dispute
/// @param linkToDisputeEvidence The link of the dispute evidence
/// @param targetTag The target tag of the dispute
/// @param data The data to initialize the policy
/// @return disputeId The id of the newly raised dispute
function raiseDispute(
address targetIpId,
string memory linkToDisputeEvidence,
bytes32 targetTag,
bytes calldata data
) external returns (uint256 disputeId);
/// @notice Sets the dispute judgement on a given dispute. Only whitelisted arbitration relayers can call to judge.
/// @param disputeId The dispute id
/// @param decision The decision of the dispute
/// @param data The data to set the dispute judgement
function setDisputeJudgement(uint256 disputeId, bool decision, bytes calldata data) external;
/// @notice Cancels an ongoing dispute
/// @param disputeId The dispute id
/// @param data The data to cancel the dispute
function cancelDispute(uint256 disputeId, bytes calldata data) external;
/// @notice Resolves a dispute after it has been judged
/// @param disputeId The dispute id
function resolveDispute(uint256 disputeId) external;
/// @notice Returns true if the ipId is tagged with any tag (meaning at least one dispute went through)
/// @param ipId The ipId
/// @return isTagged True if the ipId is tagged
function isIpTagged(address ipId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { Errors } from "../lib/Errors.sol";
import { IGovernance } from "../interfaces/governance/IGovernance.sol";
import { IGovernable } from "../interfaces/governance/IGovernable.sol";
import { GovernanceLib } from "../lib/GovernanceLib.sol";
/// @title Governable
/// @dev All contracts managed by governance should inherit from this contract.
abstract contract Governable is IGovernable {
/// @notice The address of the governance.
address public governance;
/// @dev Ensures that the function is called by the protocol admin.
modifier onlyProtocolAdmin() {
if (!IGovernance(governance).hasRole(GovernanceLib.PROTOCOL_ADMIN, msg.sender)) {
revert Errors.Governance__OnlyProtocolAdmin();
}
_;
}
modifier whenNotPaused() {
if (IGovernance(governance).getState() == GovernanceLib.ProtocolState.Paused) {
revert Errors.Governance__ProtocolPaused();
}
_;
}
/// @notice Constructs a new Governable contract.
/// @param governance_ The address of the governance.
constructor(address governance_) {
if (governance_ == address(0)) revert Errors.Governance__ZeroAddress();
governance = governance_;
emit GovernanceUpdated(governance);
}
/// @notice Sets a new governance address.
/// @param newGovernance The address of the new governance.
function setGovernance(address newGovernance) external onlyProtocolAdmin {
if (newGovernance == address(0)) revert Errors.Governance__ZeroAddress();
if (!ERC165Checker.supportsInterface(newGovernance, type(IGovernance).interfaceId))
revert Errors.Governance__UnsupportedInterface("IGovernance");
if (IGovernance(newGovernance).getState() != IGovernance(governance).getState())
revert Errors.Governance__InconsistentState();
governance = newGovernance;
emit GovernanceUpdated(newGovernance);
}
/// @notice Returns the current governance address.
/// @return governance The address of the current governance.
function getGovernance() external view returns (address) {
return governance;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Errors Library
/// @notice Library for all Story Protocol contract errors.
library Errors {
////////////////////////////////////////////////////////////////////////////
// Governance //
////////////////////////////////////////////////////////////////////////////
error Governance__OnlyProtocolAdmin();
error Governance__ZeroAddress();
error Governance__ProtocolPaused();
error Governance__InconsistentState();
error Governance__NewStateIsTheSameWithOldState();
error Governance__UnsupportedInterface(string interfaceName);
////////////////////////////////////////////////////////////////////////////
// IPAccount //
////////////////////////////////////////////////////////////////////////////
error IPAccount__InvalidSigner();
error IPAccount__InvalidSignature();
error IPAccount__ExpiredSignature();
error IPAccount__InvalidCalldata();
error IPAccount__InvalidAccessController();
////////////////////////////////////////////////////////////////////////////
// Module //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not allowed to call the provided module.
error Module_Unauthorized();
////////////////////////////////////////////////////////////////////////////
// IPAccountRegistry //
////////////////////////////////////////////////////////////////////////////
error IPAccountRegistry_InvalidIpAccountImpl();
////////////////////////////////////////////////////////////////////////////
// IPAssetRegistry //
////////////////////////////////////////////////////////////////////////////
/// @notice The IP asset has already been registered.
error IPAssetRegistry__AlreadyRegistered();
/// @notice The IP account has already been created.
error IPAssetRegistry__IPAccountAlreadyCreated();
/// @notice The IP asset has not yet been registered.
error IPAssetRegistry__NotYetRegistered();
/// @notice The IP asset registrant is not authorized.
error IPAssetRegistry__RegistrantUnauthorized();
/// @notice The specified IP resolver is not valid.
error IPAssetRegistry__ResolverInvalid();
/// @notice Caller not authorized to perform the IP registry function call.
error IPAssetRegistry__Unauthorized();
/// @notice The deployed address of account doesn't match with IP ID.
error IPAssetRegistry__InvalidAccount();
/// @notice The metadata provider is not valid.
error IPAssetRegistry__InvalidMetadataProvider();
////////////////////////////////////////////////////////////////////////////
// IPResolver ///
////////////////////////////////////////////////////////////////////////////
/// @notice The targeted IP does not yet have an IP account.
error IPResolver_InvalidIP();
/// @notice Caller not authorized to perform the IP resolver function call.
error IPResolver_Unauthorized();
////////////////////////////////////////////////////////////////////////////
// Metadata Provider ///
////////////////////////////////////////////////////////////////////////////
/// @notice Provided hash metadata is not valid.
error MetadataProvider__HashInvalid();
/// @notice The caller is not the authorized IP asset owner.
error MetadataProvider__IPAssetOwnerInvalid();
/// @notice Provided hash metadata is not valid.
error MetadataProvider__NameInvalid();
/// @notice The new metadata provider is not compatible with the old provider.
error MetadataProvider__MetadataNotCompatible();
/// @notice Provided registrant metadata is not valid.
error MetadataProvider__RegistrantInvalid();
/// @notice Provided registration date is not valid.
error MetadataProvider__RegistrationDateInvalid();
/// @notice Caller does not access to set metadata storage for the provider.
error MetadataProvider__Unauthorized();
/// @notice A metadata provider upgrade is not currently available.
error MetadataProvider__UpgradeUnavailable();
/// @notice The upgrade provider is not valid.
error MetadataProvider__UpgradeProviderInvalid();
/// @notice Provided metadata URI is not valid.
error MetadataProvider__URIInvalid();
////////////////////////////////////////////////////////////////////////////
// LicenseRegistry //
////////////////////////////////////////////////////////////////////////////
error LicenseRegistry__CallerNotLicensingModule();
error LicenseRegistry__ZeroLicensingModule();
error LicensingModule__CallerNotLicenseRegistry();
error LicenseRegistry__RevokedLicense();
/// @notice emitted when trying to transfer a license that is not transferable (by policy)
error LicenseRegistry__NotTransferable();
/// @notice emitted on constructor if dispute module is not set
error LicenseRegistry__ZeroDisputeModule();
////////////////////////////////////////////////////////////////////////////
// LicensingModule //
////////////////////////////////////////////////////////////////////////////
error LicensingModule__PolicyAlreadySetForIpId();
error LicensingModule__FrameworkNotFound();
error LicensingModule__EmptyLicenseUrl();
error LicensingModule__InvalidPolicyFramework();
error LicensingModule__ParamVerifierLengthMismatch();
error LicensingModule__PolicyNotFound();
error LicensingModule__NotLicensee();
error LicensingModule__ParentIdEqualThanChild();
error LicensingModule__LicensorDoesntHaveThisPolicy();
error LicensingModule__MintLicenseParamFailed();
error LicensingModule__LinkParentParamFailed();
error LicensingModule__TransferParamFailed();
error LicensingModule__InvalidLicensor();
error LicensingModule__ParamVerifierAlreadySet();
error LicensingModule__CommercialTermInNonCommercialPolicy();
error LicensingModule__EmptyParamName();
error LicensingModule__UnregisteredFrameworkAddingPolicy();
error LicensingModule__UnauthorizedAccess();
error LicensingModule__LicensorNotRegistered();
error LicensingModule__CallerNotLicensorAndPolicyNotSet();
error LicensingModule__DerivativesCannotAddPolicy();
error LicensingModule__IncompatibleRoyaltyPolicyAddress();
error LicensingModule__IncompatibleRoyaltyPolicyDerivativeRevShare();
error LicensingModule__IncompatibleLicensorCommercialPolicy();
error LicensingModule__IncompatibleLicensorRoyaltyDerivativeRevShare();
error LicensingModule__DerivativeRevShareSumExceedsMaxRNFTSupply();
error LicensingModule__MismatchBetweenRoyaltyPolicy();
error LicensingModule__RegisterPolicyFrameworkMismatch();
error LicensingModule__RoyaltyPolicyNotWhitelisted();
error LicensingModule__MintingFeeTokenNotWhitelisted();
error LicensingModule__ReceiverZeroAddress();
error LicensingModule__MintAmountZero();
/// @notice emitted when trying to interact with an IP that has been disputed in the DisputeModule
error LicensingModule__DisputedIpId();
/// @notice emitted when linking a license from a licensor that has been disputed in the DisputeModule
error LicensingModule__LinkingRevokedLicense();
////////////////////////////////////////////////////////////////////////////
// LicensingModuleAware //
////////////////////////////////////////////////////////////////////////////
error LicensingModuleAware__CallerNotLicensingModule();
////////////////////////////////////////////////////////////////////////////
// PolicyFrameworkManager //
////////////////////////////////////////////////////////////////////////////
error PolicyFrameworkManager__GettingPolicyWrongFramework();
error PolicyFrameworkManager__CommercializerCheckerDoesNotSupportHook(address commercializer);
////////////////////////////////////////////////////////////////////////////
// LicensorApprovalChecker //
////////////////////////////////////////////////////////////////////////////
error LicensorApprovalChecker__Unauthorized();
////////////////////////////////////////////////////////////////////////////
// Dispute Module //
////////////////////////////////////////////////////////////////////////////
error DisputeModule__ZeroArbitrationPolicy();
error DisputeModule__ZeroArbitrationRelayer();
error DisputeModule__ZeroDisputeTag();
error DisputeModule__ZeroLinkToDisputeEvidence();
error DisputeModule__NotWhitelistedArbitrationPolicy();
error DisputeModule__NotWhitelistedDisputeTag();
error DisputeModule__NotWhitelistedArbitrationRelayer();
error DisputeModule__NotDisputeInitiator();
error DisputeModule__NotInDisputeState();
error DisputeModule__NotAbleToResolve();
error DisputeModule__NotRegisteredIpId();
error DisputeModule__UnauthorizedAccess();
error ArbitrationPolicySP__ZeroDisputeModule();
error ArbitrationPolicySP__ZeroPaymentToken();
error ArbitrationPolicySP__NotDisputeModule();
////////////////////////////////////////////////////////////////////////////
// Royalty Module //
////////////////////////////////////////////////////////////////////////////
error RoyaltyModule__ZeroRoyaltyPolicy();
error RoyaltyModule__NotWhitelistedRoyaltyPolicy();
error RoyaltyModule__ZeroRoyaltyToken();
error RoyaltyModule__NotWhitelistedRoyaltyToken();
error RoyaltyModule__NoRoyaltyPolicySet();
error RoyaltyModule__IncompatibleRoyaltyPolicy();
error RoyaltyModule__NotAllowedCaller();
error RoyaltyModule__ZeroLicensingModule();
error RoyaltyModule__CanOnlyMintSelectedPolicy();
error RoyaltyModule__NoParentsOnLinking();
error RoyaltyModule__NotRegisteredIpId();
error RoyaltyPolicyLAP__ZeroRoyaltyModule();
error RoyaltyPolicyLAP__ZeroLiquidSplitFactory();
error RoyaltyPolicyLAP__ZeroLiquidSplitMain();
error RoyaltyPolicyLAP__NotRoyaltyModule();
error RoyaltyPolicyLAP__ZeroLicensingModule();
error RoyaltyPolicyLAP__AboveParentLimit();
error RoyaltyPolicyLAP__AboveAncestorsLimit();
error RoyaltyPolicyLAP__AboveRoyaltyStackLimit();
error RoyaltyPolicyLAP__InvalidAncestorsLength();
error RoyaltyPolicyLAP__InvalidAncestors();
error RoyaltyPolicyLAP__InvalidRoyaltyAmountLength();
error RoyaltyPolicyLAP__InvalidAncestorsHash();
error RoyaltyPolicyLAP__InvalidParentRoyaltiesLength();
error RoyaltyPolicyLAP__InvalidAncestorsRoyalty();
error RoyaltyPolicyLAP__ImplementationAlreadySet();
error RoyaltyPolicyLAP__ZeroAncestorsVaultImpl();
error RoyaltyPolicyLAP__NotFullOwnership();
error RoyaltyPolicyLAP__UnlinkableToParents();
error RoyaltyPolicyLAP__TransferFailed();
error RoyaltyPolicyLAP__LastPositionNotAbleToMintLicense();
error AncestorsVaultLAP__ZeroRoyaltyPolicyLAP();
error AncestorsVaultLAP__AlreadyClaimed();
error AncestorsVaultLAP__InvalidAncestorsHash();
error AncestorsVaultLAP__InvalidClaimer();
error AncestorsVaultLAP__ClaimerNotAnAncestor();
error AncestorsVaultLAP__ETHBalanceNotZero();
error AncestorsVaultLAP__ERC20BalanceNotZero();
error AncestorsVaultLAP__TransferFailed();
////////////////////////////////////////////////////////////////////////////
// ModuleRegistry //
////////////////////////////////////////////////////////////////////////////
error ModuleRegistry__ModuleAddressZeroAddress();
error ModuleRegistry__ModuleAddressNotContract();
error ModuleRegistry__ModuleAlreadyRegistered();
error ModuleRegistry__NameEmptyString();
error ModuleRegistry__NameAlreadyRegistered();
error ModuleRegistry__NameDoesNotMatch();
error ModuleRegistry__ModuleNotRegistered();
error ModuleRegistry__InterfaceIdZero();
error ModuleRegistry__ModuleTypeAlreadyRegistered();
error ModuleRegistry__ModuleTypeNotRegistered();
error ModuleRegistry__ModuleNotSupportExpectedModuleTypeInterfaceId();
error ModuleRegistry__ModuleTypeEmptyString();
////////////////////////////////////////////////////////////////////////////
// RegistrationModule //
////////////////////////////////////////////////////////////////////////////
/// @notice The caller is not the owner of the root IP NFT.
error RegistrationModule__InvalidOwner();
////////////////////////////////////////////////////////////////////////////
// AccessController //
////////////////////////////////////////////////////////////////////////////
error AccessController__IPAccountIsZeroAddress();
error AccessController__IPAccountIsNotValid(address ipAccount);
error AccessController__SignerIsZeroAddress();
error AccessController__CallerIsNotIPAccount();
error AccessController__PermissionIsNotValid();
error AccessController__BothCallerAndRecipientAreNotRegisteredModule(address signer, address to);
error AccessController__PermissionDenied(address ipAccount, address signer, address to, bytes4 func);
////////////////////////////////////////////////////////////////////////////
// AccessControlled //
////////////////////////////////////////////////////////////////////////////
error AccessControlled__ZeroAddress();
error AccessControlled__NotIpAccount(address ipAccount);
error AccessControlled__CallerIsNotIpAccount(address caller);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @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 isLicenseTransferable Whether or not the license is transferable
/// @param policyFramework address of the IPolicyFrameworkManager this policy is based on
/// @param frameworkData Data to be used by the policy framework to verify minting and linking
/// @param royaltyPolicy address of the royalty policy to be used by the policy framework, if any
/// @param royaltyData Data to be used by the royalty policy (for example, encoding of the royalty percentage)
/// @param mintingFee Fee to be paid when minting a license
/// @param mintingFeeToken Token to be used to pay the minting fee
struct Policy {
bool isLicenseTransferable;
address policyFramework;
bytes frameworkData;
address royaltyPolicy;
bytes royaltyData;
uint256 mintingFee;
address mintingFeeToken;
}
/// @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 for linking
/// @param licensorIpId Id of the IP this license is for
/// @param transferable Whether or not the license is transferable
struct License {
uint256 policyId;
address licensorIpId;
bool transferable;
// TODO: support for transfer hooks
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title DataUniqueness
/// @notice Library to store data without repetition, assigning an id to it if new or reusing existing one
/// if already stored
library DataUniqueness {
/// 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
) internal returns (uint256 id, bool isNew) {
// We could just use the hash 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 a counter if we need to.
bytes32 hash = keccak256(data);
id = _hashToIds[hash];
if (id != 0) {
return (id, false);
}
id = existingIds + 1;
_hashToIds[hash] = id;
return (id, true);
}
}// 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) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/// @notice Module Interface
interface IModule is IERC165 {
/// @notice Returns the string identifier associated with the module.
function name() external returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { BaseModule } from "../BaseModule.sol";
import { Governable } from "../../governance/Governable.sol";
import { IRoyaltyModule } from "../../interfaces/modules/royalty/IRoyaltyModule.sol";
import { IRoyaltyPolicy } from "../../interfaces/modules/royalty/policies/IRoyaltyPolicy.sol";
import { Errors } from "../../lib/Errors.sol";
import { ROYALTY_MODULE_KEY } from "../../lib/modules/Module.sol";
import { BaseModule } from "../BaseModule.sol";
/// @title Story Protocol Royalty Module
/// @notice The Story Protocol royalty module allows to set royalty policies an IP asset and pay royalties as a
/// derivative IP.
contract RoyaltyModule is IRoyaltyModule, Governable, ReentrancyGuard, BaseModule {
using ERC165Checker for address;
string public constant override name = ROYALTY_MODULE_KEY;
/// @notice Returns the licensing module address
address public LICENSING_MODULE;
/// @notice Indicates if a royalty policy is whitelisted
mapping(address royaltyPolicy => bool isWhitelisted) public isWhitelistedRoyaltyPolicy;
/// @notice Indicates if a royalty token is whitelisted
mapping(address token => bool) public isWhitelistedRoyaltyToken;
/// @notice Indicates the royalty policy for a given IP asset
mapping(address ipId => address royaltyPolicy) public royaltyPolicies;
constructor(address governance) Governable(governance) {}
/// @notice Modifier to enforce that the caller is the licensing module
modifier onlyLicensingModule() {
if (msg.sender != LICENSING_MODULE) revert Errors.RoyaltyModule__NotAllowedCaller();
_;
}
/// @notice Sets the license registry
/// @dev Enforced to be only callable by the protocol admin
/// @param licensingModule The address of the license registry
function setLicensingModule(address licensingModule) external onlyProtocolAdmin {
if (licensingModule == address(0)) revert Errors.RoyaltyModule__ZeroLicensingModule();
LICENSING_MODULE = licensingModule;
}
/// @notice Whitelist a royalty policy
/// @dev Enforced to be only callable by the protocol admin
/// @param royaltyPolicy The address of the royalty policy
/// @param allowed Indicates if the royalty policy is whitelisted or not
function whitelistRoyaltyPolicy(address royaltyPolicy, bool allowed) external onlyProtocolAdmin {
if (royaltyPolicy == address(0)) revert Errors.RoyaltyModule__ZeroRoyaltyPolicy();
isWhitelistedRoyaltyPolicy[royaltyPolicy] = allowed;
emit RoyaltyPolicyWhitelistUpdated(royaltyPolicy, allowed);
}
/// @notice Whitelist a royalty token
/// @dev Enforced to be only callable by the protocol admin
/// @param token The token address
/// @param allowed Indicates if the token is whitelisted or not
function whitelistRoyaltyToken(address token, bool allowed) external onlyProtocolAdmin {
if (token == address(0)) revert Errors.RoyaltyModule__ZeroRoyaltyToken();
isWhitelistedRoyaltyToken[token] = allowed;
emit RoyaltyTokenWhitelistUpdated(token, allowed);
}
/// @notice Executes royalty related logic on license minting
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The ipId whose license is being minted (licensor)
/// @param royaltyPolicy The royalty policy address of the license being minted
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLicenseMinting(
address ipId,
address royaltyPolicy,
bytes calldata licenseData,
bytes calldata externalData
) external nonReentrant onlyLicensingModule {
if (!isWhitelistedRoyaltyPolicy[royaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
address royaltyPolicyIpId = royaltyPolicies[ipId];
// if the node is a root node, then royaltyPolicyIpId will be address(0) and any type of royalty type can be
// selected to mint a license if the node is a derivative node, then the any minted licenses by the derivative
// node should have the same royalty policy as the parent node a derivative node set its royalty policy
// immutably in onLinkToParents() function below
if (royaltyPolicyIpId != royaltyPolicy && royaltyPolicyIpId != address(0))
revert Errors.RoyaltyModule__CanOnlyMintSelectedPolicy();
IRoyaltyPolicy(royaltyPolicy).onLicenseMinting(ipId, licenseData, externalData);
}
/// @notice Executes royalty related logic on linking to parents
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The children ipId that is being linked to parents
/// @param royaltyPolicy The common royalty policy address of all the licenses being burned
/// @param parentIpIds The parent ipIds that the children ipId is being linked to
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLinkToParents(
address ipId,
address royaltyPolicy,
address[] calldata parentIpIds,
bytes[] memory licenseData,
bytes calldata externalData
) external nonReentrant onlyLicensingModule {
if (!isWhitelistedRoyaltyPolicy[royaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
if (parentIpIds.length == 0) revert Errors.RoyaltyModule__NoParentsOnLinking();
for (uint32 i = 0; i < parentIpIds.length; i++) {
address parentRoyaltyPolicy = royaltyPolicies[parentIpIds[i]];
// if the parent node has a royalty policy set, then the derivative node should have the same royalty
// policy if the parent node does not have a royalty policy set, then the derivative node can set any type
// of royalty policy as long as the children ip obtained and is burning all licenses with that royalty type
// from each parent (was checked in licensing module before calling this function)
if (parentRoyaltyPolicy != royaltyPolicy && parentRoyaltyPolicy != address(0))
revert Errors.RoyaltyModule__IncompatibleRoyaltyPolicy();
}
royaltyPolicies[ipId] = royaltyPolicy;
IRoyaltyPolicy(royaltyPolicy).onLinkToParents(ipId, parentIpIds, licenseData, externalData);
}
/// @notice Allows the function caller to pay royalties to the receiver IP asset on behalf of the payer IP asset.
/// @param receiverIpId The ipId that receives the royalties
/// @param payerIpId The ipId that pays the royalties
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payRoyaltyOnBehalf(
address receiverIpId,
address payerIpId,
address token,
uint256 amount
) external nonReentrant {
if (!isWhitelistedRoyaltyToken[token]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyToken();
address payerRoyaltyPolicy = royaltyPolicies[payerIpId];
// if the payer does not have a royalty policy set, then the payer is not a derivative ip and does not pay
// royalties the receiver ip can have a zero royalty policy since that could mean it is an ip a root
if (payerRoyaltyPolicy == address(0)) revert Errors.RoyaltyModule__NoRoyaltyPolicySet();
if (!isWhitelistedRoyaltyPolicy[payerRoyaltyPolicy]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
IRoyaltyPolicy(payerRoyaltyPolicy).onRoyaltyPayment(msg.sender, receiverIpId, token, amount);
emit RoyaltyPaid(receiverIpId, payerIpId, msg.sender, token, amount);
}
/// @notice Allows to pay the minting fee for a license
/// @param receiverIpId The ipId that receives the royalties
/// @param payerAddress The address that pays the royalties
/// @param licenseRoyaltyPolicy The royalty policy of the license being minted
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payLicenseMintingFee(
address receiverIpId,
address payerAddress,
address licenseRoyaltyPolicy,
address token,
uint256 amount
) external onlyLicensingModule {
if (!isWhitelistedRoyaltyToken[token]) revert Errors.RoyaltyModule__NotWhitelistedRoyaltyToken();
if (licenseRoyaltyPolicy == address(0)) revert Errors.RoyaltyModule__NoRoyaltyPolicySet();
if (!isWhitelistedRoyaltyPolicy[licenseRoyaltyPolicy])
revert Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy();
IRoyaltyPolicy(licenseRoyaltyPolicy).onRoyaltyPayment(payerAddress, receiverIpId, token, amount);
emit LicenseMintingFeePaid(receiverIpId, payerAddress, token, amount);
}
/// @notice IERC165 interface support.
function supportsInterface(bytes4 interfaceId) public view virtual override(BaseModule, IERC165) returns (bool) {
return interfaceId == type(IRoyaltyModule).interfaceId || super.supportsInterface(interfaceId);
}
}// 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: BUSL-1.1
pragma solidity 0.8.23;
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
import { GovernanceLib } from "../../lib/GovernanceLib.sol";
/// @title IGovernance
/// @dev This interface defines the governance functionality for the protocol.
interface IGovernance is IAccessControl {
/// @notice Emitted when the protocol state is set
/// @param account The address that triggered the state change
/// @param prevState The previous state of the protocol
/// @param newState The new state of the protocol
/// @param timestamp The time when the state change occurred
event StateSet(
address indexed account,
GovernanceLib.ProtocolState prevState,
GovernanceLib.ProtocolState newState,
uint256 timestamp
);
/// @notice Sets the state of the protocol
/// @dev This function can only be called by an account with the appropriate role
/// @param newState The new state to set for the protocol
function setState(GovernanceLib.ProtocolState newState) external;
/// @notice Returns the current state of the protocol
/// @return state The current state of the protocol
function getState() external view returns (GovernanceLib.ProtocolState);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title IGovernable
/// @notice This is the interface for the Lens Protocol main governance functions.
interface IGovernable {
/// @notice Emitted when the governance is updated
/// @param newGovernance The address of the new governance
event GovernanceUpdated(address indexed newGovernance);
/// @notice Sets the governance address
/// @param newGovernance The address of the new governance
function setGovernance(address newGovernance) external;
/// @notice Returns the current governance address
/// @return The address of the current governance
function getGovernance() external view returns (address);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title Governance
/// @dev This library provides types for Story Protocol Governance.
library GovernanceLib {
bytes32 public constant PROTOCOL_ADMIN = bytes32(0);
/// @notice An enum containing the different states the protocol can be in.
/// @param Unpaused The unpaused state.
/// @param Paused The paused state.
enum ProtocolState {
Unpaused,
Paused
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/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/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IModule } from "../interfaces/modules/base/IModule.sol";
/// @title BaseModule
/// @notice Base implementation for all modules in Story Protocol.
abstract contract BaseModule is ERC165, IModule {
/// @notice IERC165 interface support.
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IModule).interfaceId || super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
import { IModule } from "../../modules/base/IModule.sol";
/// @title RoyaltyModule interface
interface IRoyaltyModule is IModule {
/// @notice Event emitted when a royalty policy is whitelisted
/// @param royaltyPolicy The address of the royalty policy
/// @param allowed Indicates if the royalty policy is whitelisted or not
event RoyaltyPolicyWhitelistUpdated(address royaltyPolicy, bool allowed);
/// @notice Event emitted when a royalty token is whitelisted
/// @param token The address of the royalty token
/// @param allowed Indicates if the royalty token is whitelisted or not
event RoyaltyTokenWhitelistUpdated(address token, bool allowed);
/// @notice Event emitted when royalties are paid
/// @param receiverIpId The ID of IP asset that receives the royalties
/// @param payerIpId The ID of IP asset that pays the royalties
/// @param sender The address that pays the royalties on behalf of the payer ID of IP asset
/// @param token The token that is used to pay the royalties
/// @param amount The amount that is paid
event RoyaltyPaid(address receiverIpId, address payerIpId, address sender, address token, uint256 amount);
/// @notice Event emitted when the license minting fee is paid
/// @param receiverIpId The ipId that receives the royalties
/// @param payerAddress The address that pays the royalties
/// @param token The token that is used to pay the royalties
/// @param amount The amount paid
event LicenseMintingFeePaid(address receiverIpId, address payerAddress, address token, uint256 amount);
/// @notice Returns the licensing module address
function LICENSING_MODULE() external view returns (address);
/// @notice Indicates if a royalty policy is whitelisted
/// @param royaltyPolicy The address of the royalty policy
/// @return isWhitelisted True if the royalty policy is whitelisted
function isWhitelistedRoyaltyPolicy(address royaltyPolicy) external view returns (bool);
/// @notice Indicates if a royalty token is whitelisted
/// @param token The address of the royalty token
/// @return isWhitelisted True if the royalty token is whitelisted
function isWhitelistedRoyaltyToken(address token) external view returns (bool);
/// @notice Indicates the royalty policy for a given IP asset
/// @param ipId The ID of IP asset
/// @return royaltyPolicy The address of the royalty policy
function royaltyPolicies(address ipId) external view returns (address);
/// @notice Whitelist a royalty policy
/// @dev Enforced to be only callable by the protocol admin
/// @param royaltyPolicy The address of the royalty policy
/// @param allowed Indicates if the royalty policy is whitelisted or not
function whitelistRoyaltyPolicy(address royaltyPolicy, bool allowed) external;
/// @notice Whitelist a royalty token
/// @dev Enforced to be only callable by the protocol admin
/// @param token The token address
/// @param allowed Indicates if the token is whitelisted or not
function whitelistRoyaltyToken(address token, bool allowed) external;
/// @notice Executes royalty related logic on license minting
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The ipId whose license is being minted (licensor)
/// @param royaltyPolicy The royalty policy address of the license being minted
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLicenseMinting(
address ipId,
address royaltyPolicy,
bytes calldata licenseData,
bytes calldata externalData
) external;
/// @notice Executes royalty related logic on linking to parents
/// @dev Enforced to be only callable by LicensingModule
/// @param ipId The children ipId that is being linked to parents
/// @param royaltyPolicy The common royalty policy address of all the licenses being burned
/// @param parentIpIds The parent ipIds that the children ipId is being linked to
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLinkToParents(
address ipId,
address royaltyPolicy,
address[] calldata parentIpIds,
bytes[] memory licenseData,
bytes calldata externalData
) external;
/// @notice Allows the function caller to pay royalties to the receiver IP asset on behalf of the payer IP asset.
/// @param receiverIpId The ID of the IP asset that receives the royalties
/// @param payerIpId The ID of the IP asset that pays the royalties
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payRoyaltyOnBehalf(address receiverIpId, address payerIpId, address token, uint256 amount) external;
/// @notice Allows to pay the minting fee for a license
/// @param receiverIpId The ipId that receives the royalties
/// @param payerAddress The address that pays the royalties
/// @param licenseRoyaltyPolicy The royalty policy of the license being minted
/// @param token The token to use to pay the royalties
/// @param amount The amount to pay
function payLicenseMintingFee(
address receiverIpId,
address payerAddress,
address licenseRoyaltyPolicy,
address token,
uint256 amount
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;
/// @title RoyaltyPolicy interface
interface IRoyaltyPolicy {
/// @notice Executes royalty related logic on minting a license
/// @dev Enforced to be only callable by RoyaltyModule
/// @param ipId The ipId whose license is being minted (licensor)
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLicenseMinting(address ipId, bytes calldata licenseData, bytes calldata externalData) external;
/// @notice Executes royalty related logic on linking to parents
/// @dev Enforced to be only callable by RoyaltyModule
/// @param ipId The children ipId that is being linked to parents
/// @param parentIpIds The parent ipIds that the children ipId is being linked to
/// @param licenseData The license data custom to each the royalty policy
/// @param externalData The external data custom to each the royalty policy
function onLinkToParents(
address ipId,
address[] calldata parentIpIds,
bytes[] memory licenseData,
bytes calldata externalData
) external;
/// @notice Allows the caller to pay royalties to the given IP asset
/// @param caller The caller is the address from which funds will transferred from
/// @param ipId The ipId of the receiver of the royalties
/// @param token The token to pay
/// @param amount The amount to pay
function onRoyaltyPayment(address caller, address ipId, address token, uint256 amount) external;
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.23; // Default Module Type, all modules in this type by default string constant MODULE_TYPE_DEFAULT = "MODULE"; string constant MODULE_TYPE_HOOK = "HOOK_MODULE"; // String values for core protocol modules. string constant IP_RESOLVER_MODULE_KEY = "IP_RESOLVER_MODULE"; // String values for core protocol modules. string constant REGISTRATION_MODULE_KEY = "REGISTRATION_MODULE"; // String values for core protocol modules. string constant LICENSING_MODULE_KEY = "LICENSING_MODULE"; // String values for core protocol modules. string constant DISPUTE_MODULE_KEY = "DISPUTE_MODULE"; string constant ROYALTY_MODULE_KEY = "ROYALTY_MODULE"; string constant TOKEN_WITHDRAWAL_MODULE_KEY = "TOKEN_MANAGEMENT_MODULE";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}{
"remappings": [
"@ethereum-waffle/=node_modules/@ethereum-waffle/",
"@openzeppelin/=node_modules/@openzeppelin/",
"forge-std/=node_modules/forge-std/src/",
"ds-test/=node_modules/ds-test/src/",
"base64-sol/=node_modules/base64-sol/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"erc6551/=node_modules/erc6551/",
"openzeppelin-contracts/=lib/reference/lib/openzeppelin-contracts/",
"reference/=lib/reference/"
],
"optimizer": {
"enabled": true,
"runs": 20000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {
"contracts/lib/registries/IPAccountChecker.sol": {
"IPAccountChecker": "0x36e93affeca875ebcef53e922a4b716ad2a508a9"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"governance","type":"address"},{"internalType":"string","name":"url","type":"string"}],"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":"Governance__InconsistentState","type":"error"},{"inputs":[],"name":"Governance__OnlyProtocolAdmin","type":"error"},{"inputs":[{"internalType":"string","name":"interfaceName","type":"string"}],"name":"Governance__UnsupportedInterface","type":"error"},{"inputs":[],"name":"Governance__ZeroAddress","type":"error"},{"inputs":[],"name":"LicenseRegistry__CallerNotLicensingModule","type":"error"},{"inputs":[],"name":"LicenseRegistry__NotTransferable","type":"error"},{"inputs":[],"name":"LicenseRegistry__RevokedLicense","type":"error"},{"inputs":[],"name":"LicenseRegistry__ZeroDisputeModule","type":"error"},{"inputs":[],"name":"LicenseRegistry__ZeroLicensingModule","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"StringsInsufficientHexLength","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":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceUpdated","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"},{"internalType":"bool","name":"transferable","type":"bool"}],"indexed":false,"internalType":"struct Licensing.License","name":"licenseData","type":"tuple"}],"name":"LicenseMinted","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":"DISPUTE_MODULE","outputs":[{"internalType":"contract IDisputeModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LICENSING_MODULE","outputs":[{"internalType":"contract ILicensingModule","name":"","type":"address"}],"stateMutability":"view","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":"holder","type":"address"},{"internalType":"uint256[]","name":"licenseIds","type":"uint256[]"}],"name":"burnLicenses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getGovernance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"imageUrl","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"uint256","name":"licenseId","type":"uint256"}],"name":"isLicenseRevoked","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":"uint256","name":"licenseId","type":"uint256"}],"name":"license","outputs":[{"components":[{"internalType":"uint256","name":"policyId","type":"uint256"},{"internalType":"address","name":"licensorIpId","type":"address"},{"internalType":"bool","name":"transferable","type":"bool"}],"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":"policyId","type":"uint256"},{"internalType":"address","name":"licensorIpId_","type":"address"},{"internalType":"bool","name":"transferable","type":"bool"},{"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":"mintedLicenses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"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":"address","name":"newDisputeModule","type":"address"}],"name":"setDisputeModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernance","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"url","type":"string"}],"name":"setLicensingImageUrl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newLicensingModule","type":"address"}],"name":"setLicensingModule","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":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"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
60c0604052601b60809081527f50726f6772616d6d61626c65204950204c6963656e7365204e4654000000000060a0526004906200003e9082620001f9565b5060408051808201909152600681526514125313919560d21b60208201526005906200006b9082620001f9565b503480156200007957600080fd5b50604051620041fb380380620041fb8339810160408190526200009c91620002c5565b6040805160208101909152600081528290620000b88162000140565b506001600160a01b038116620000e15760405163239261b360e11b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040517f9d3e522e1e47a2f6009739342b9cc7b252a1888154e843ab55ee1c81745795ab90600090a2506006620001378282620001f9565b505050620003bb565b60026200014e8282620001f9565b5050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200017d57607f821691505b6020821081036200019e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001f4576000816000526020600020601f850160051c81016020861015620001cf5750805b601f850160051c820191505b81811015620001f057828155600101620001db565b5050505b505050565b81516001600160401b0381111562000215576200021562000152565b6200022d8162000226845462000168565b84620001a4565b602080601f8311600181146200026557600084156200024c5750858301515b600019600386901b1c1916600185901b178555620001f0565b600085815260208120601f198616915b82811015620002965788860151825594840194600190910190840162000275565b5085821015620002b55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008060408385031215620002d957600080fd5b82516001600160a01b0381168114620002f157600080fd5b602084810151919350906001600160401b03808211156200031157600080fd5b818601915086601f8301126200032657600080fd5b8151818111156200033b576200033b62000152565b604051601f8201601f19908116603f0116810190838211818310171562000366576200036662000152565b8160405282815289868487010111156200037f57600080fd5b600093505b82841015620003a3578484018601518185018701529285019262000384565b60008684830101528096505050505050509250929050565b613e3080620003cb6000396000f3fe608060405234801561001057600080fd5b50600436106101b85760003560e01c80635aa6e675116100f9578063b24387df11610097578063daa34fd011610071578063daa34fd014610480578063e985e9c514610493578063f242432a146104dc578063f943f090146104ef57600080fd5b8063b24387df14610445578063b754f2721461044d578063cc5b60841461046d57600080fd5b8063a22cb465116100d3578063a22cb46514610404578063a36a3f0514610417578063ab033ea91461042a578063aba831501461043d57600080fd5b80635aa6e675146103bc57806365165aa5146103dc57806395d89b41146103fc57600080fd5b80632de90676116101665780633a5384cb116101405780633a5384cb146103635780634e1273f4146103765780634e23932f1461039657806359784cad146103a957600080fd5b80632de90676146103025780632eb2c2d61461031757806334d70eea1461032a57600080fd5b80630e89341c116101975780630e89341c1461021b578063178ed2841461022e578063289b3c0d146102c357600080fd5b8062fdd58e146101bd57806301ffc9a7146101e357806306fdde0314610206575b600080fd5b6101d06101cb366004612af9565b61050f565b6040519081526020015b60405180910390f35b6101f66101f1366004612b53565b610544565b60405190151581526020016101da565b61020e610627565b6040516101da9190612bde565b61020e610229366004612bf1565b6106b5565b6102b661023c366004612bf1565b604080516060808201835260008083526020808401829052928401819052938452600a82529282902082519384018352805484526001015473ffffffffffffffffffffffffffffffffffffffff81169184019190915274010000000000000000000000000000000000000000900460ff1615159082015290565b6040516101da9190612c0a565b60035473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101da565b610315610310366004612c43565b610a77565b005b610315610325366004612e86565b610b96565b6102dd610338366004612bf1565b6000908152600a602052604090206001015473ffffffffffffffffffffffffffffffffffffffff1690565b6101f6610371366004612bf1565b610c61565b610389610384366004612f34565b610d07565b6040516101da9190613032565b6101f66103a4366004613045565b610ded565b6101d06103b7366004613083565b610e02565b6003546102dd9073ffffffffffffffffffffffffffffffffffffffff1681565b6007546102dd9073ffffffffffffffffffffffffffffffffffffffff1681565b61020e610fb1565b6103156104123660046130e2565b610fbe565b610315610425366004613110565b610fcd565b610315610438366004613110565b611130565b61020e6114a3565b600b546101d0565b6101d061045b366004612bf1565b6000908152600a602052604090205490565b61031561047b366004613110565b6114b0565b61031561048e36600461312d565b611613565b6101f66104a13660046131b5565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205460ff1690565b6103156104ea3660046131e3565b611723565b6008546102dd9073ffffffffffffffffffffffffffffffffffffffff1681565b60008181526020818152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091529020545b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fd9b67a260000000000000000000000000000000000000000000000000000000014806105d757507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e89341c00000000000000000000000000000000000000000000000000000000145b8061053e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461053e565b600480546106349061324c565b80601f01602080910402602001604051908101604052809291908181526020018280546106609061324c565b80156106ad5780601f10610682576101008083540402835291602001916106ad565b820191906000526020600020905b81548152906001019060200180831161069057829003601f168201915b505050505081565b6000818152600a60209081526040808320815160608082018452825480835260019093015473ffffffffffffffffffffffffffffffffffffffff8082169684019690965274010000000000000000000000000000000000000000900460ff1615158285015260075493517f3cea5120000000000000000000000000000000000000000000000000000000008152600481019390935294909390921690633cea512090602401600060405180830381865afa158015610777573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107bd919081019061330a565b905060006107e4836020015173ffffffffffffffffffffffffffffffffffffffff166117e1565b905060006107f186611804565b82600660405160200161080693929190613496565b604051602081830303815290604052905080836020015173ffffffffffffffffffffffffffffffffffffffff1663eb6b331585604001516040518263ffffffff1660e01b81526004016108599190612bde565b600060405180830381865afa158015610876573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108bc91908101906136a7565b6040516020016108cd9291906136f0565b60405160208183030381529060405290508082610903856020015173ffffffffffffffffffffffffffffffffffffffff166117e1565b8660400151610947576040518060400160405280600581526020017f66616c736500000000000000000000000000000000000000000000000000000081525061097e565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b6109878a610c61565b6109c6576040518060400160405280600581526020017f66616c73650000000000000000000000000000000000000000000000000000008152506109fd565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b604051602001610a1195949392919061371f565b604051602081830303815290604052905080604051602001610a33919061393e565b6040516020818303038152906040529050610a4d816118c2565b604051602001610a5d919061397f565b604051602081830303815290604052945050505050919050565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa158015610aec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1091906139c4565b610b46576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006610b53828483613a29565b50600b54604080516001815260208101929092527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a15050565b3373ffffffffffffffffffffffffffffffffffffffff86168114801590610bf0575073ffffffffffffffffffffffffffffffffffffffff80871660009081526001602090815260408083209385168352929052205460ff16155b15610c4c576040517fe237d92200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8083166004830152871660248201526044015b60405180910390fd5b610c598686868686611a15565b505050505050565b6008546000828152600a60205260408082206001015490517f13f46c4200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152919216906313f46c4290602401602060405180830381865afa158015610ce3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053e91906139c4565b60608151835114610d5157815183516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610c43565b6000835167ffffffffffffffff811115610d6d57610d6d612cb5565b604051908082528060200260200182016040528015610d96578160200160208202803683370190505b50905060005b8451811015610de557602080820286010151610dc09060208084028701015161050f565b828281518110610dd257610dd2613b43565b6020908102919091010152600101610d9c565b509392505050565b600080610dfa838561050f565b119392505050565b60075460009073ffffffffffffffffffffffffffffffffffffffff163314610e56576040517f6b9c60a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060405180606001604052808881526020018773ffffffffffffffffffffffffffffffffffffffff16815260200186151581525090506000610ebc82604051602001610ea39190612c0a565b6040516020818303038152906040526009600b54611ac9565b90935090508015610f8b57600b8390556000838152600a602090815260409182902084518155908401516001909101805483860151151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00000000000000000000000000000000000000000090911673ffffffffffffffffffffffffffffffffffffffff938416171790559051849186169033907f08f994adef75dc0c809636b2fb0004553e15a247a89664f0b038034801c719a190610f82908a908890613b72565b60405180910390a45b610fa684848760405180602001604052806000815250611b20565b505095945050505050565b600580546106349061324c565b610fc9338383611ba3565b5050565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa158015611042573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106691906139c4565b61109c576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166110e9576040517ff9699b4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa1580156111a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c991906139c4565b6111ff576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661124c576040517f4724c36600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611276817f4ebb53a600000000000000000000000000000000000000000000000000000000611c8b565b6112db576040517ea73c8d00000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f49476f7665726e616e63650000000000000000000000000000000000000000006044820152606401610c43565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631865c57d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611348573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136c9190613bb2565b600181111561137d5761137d613bd3565b8173ffffffffffffffffffffffffffffffffffffffff16631865c57d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ec9190613bb2565b60018111156113fd576113fd613bd3565b14611434576040517f649cdd9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f9d3e522e1e47a2f6009739342b9cc7b252a1888154e843ab55ee1c81745795ab90600090a250565b600680546106349061324c565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa158015611525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154991906139c4565b61157f576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166115cc576040517fb028818e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60075473ffffffffffffffffffffffffffffffffffffffff163314611664576040517f6b9c60a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561167f5761167f612cb5565b6040519080825280602002602001820160405280156116a8578160200160208202803683370190505b50905060005b828110156116dd5760018282815181106116ca576116ca613b43565b60209081029190910101526001016116ae565b5061171d84848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250611cae915050565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff8616811480159061177d575073ffffffffffffffffffffffffffffffffffffffff80871660009081526001602090815260408083209385168352929052205460ff16155b156117d4576040517fe237d92200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808316600483015287166024820152604401610c43565b610c598686868686611d20565b606061053e73ffffffffffffffffffffffffffffffffffffffff83166014611dfb565b6060600061181183612021565b600101905060008167ffffffffffffffff81111561183157611831612cb5565b6040519080825280601f01601f19166020018201604052801561185b576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461186557509392505050565b606081516000036118e157505060408051602081019091526000815290565b6000604051806060016040528060408152602001613dbb60409139905060006003845160026119109190613c31565b61191a9190613c44565b611925906004613c7f565b67ffffffffffffffff81111561193d5761193d612cb5565b6040519080825280601f01601f191660200182016040528015611967576020820181803683370190505b509050600182016020820185865187015b808210156119d3576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250611978565b50506003865106600181146119ef5760028114611a0257611a0a565b603d6001830353603d6002830353611a0a565b603d60018303535b509195945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416611a65576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff8516611ab5576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b611ac28585858585612103565b5050505050565b8251602080850191909120600081815291849052604082205491908215611af4575060009050611b18565b611aff846001613c31565b6000918252602086905260409091208190559150600190505b935093915050565b73ffffffffffffffffffffffffffffffffffffffff8416611b70576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b60408051600180825260208201869052818301908152606082018590526080820190925290610c59600087848487612103565b73ffffffffffffffffffffffffffffffffffffffff8216611bf3576040517fced3e10000000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000611c9683612163565b8015611ca75750611ca783836121c7565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8316611cfe576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b611d1b836000848460405180602001604052806000815250612103565b505050565b73ffffffffffffffffffffffffffffffffffffffff8416611d70576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff8516611dc0576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b60408051600180825260208201869052818301908152606082018590526080820190925290611df28787848487612103565b50505050505050565b6060826000611e0b846002613c7f565b611e16906002613c31565b67ffffffffffffffff811115611e2e57611e2e612cb5565b6040519080825280601f01601f191660200182016040528015611e58576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611e8f57611e8f613b43565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611ef257611ef2613b43565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000611f2e856002613c7f565b611f39906001613c31565b90505b6001811115611fd6577f303132333435363738396162636465660000000000000000000000000000000083600f1660108110611f7a57611f7a613b43565b1a60f81b828281518110611f9057611f90613b43565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049290921c91611fcf81613c96565b9050611f3c565b508115612019576040517fe22e27eb0000000000000000000000000000000000000000000000000000000081526004810186905260248101859052604401610c43565b949350505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061206a577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310612096576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106120b457662386f26fc10000830492506010015b6305f5e10083106120cc576305f5e100830492506008015b61271083106120e057612710830492506004015b606483106120f2576064830492506002015b600a831061053e5760010192915050565b61210f858585856122b5565b73ffffffffffffffffffffffffffffffffffffffff841615611ac25782513390600103612155576020848101519084015161214e83898985858961246f565b5050610c59565b610c59818787878787612661565b600061218f827f01ffc9a7000000000000000000000000000000000000000000000000000000006121c7565b801561053e57506121c0827fffffffff000000000000000000000000000000000000000000000000000000006121c7565b1592915050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561229e575060208210155b80156122aa5750600081115b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416158015906122ef575073ffffffffffffffffffffffffffffffffffffffff831615155b156124635760005b8251811015612461576000600a600085848151811061231857612318613b43565b602090810291909101810151825281810192909252604090810160002081516060810183528154815260019091015473ffffffffffffffffffffffffffffffffffffffff8116938201939093527401000000000000000000000000000000000000000090920460ff1615159082015284519091506123af908590849081106123a2576123a2613b43565b6020026020010151610c61565b156123e6576040517fdf1d1ad200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015161245857806020015173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614612458576040517ffa45c60e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016122f7565b505b61171d848484846127f2565b73ffffffffffffffffffffffffffffffffffffffff84163b15610c59576040517ff23a6e6100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063f23a6e61906124e69089908990889088908890600401613ccb565b6020604051808303816000875af192505050801561253f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261253c91810190613d10565b60015b6125ce573d80801561256d576040519150601f19603f3d011682016040523d82523d6000602084013e612572565b606091505b5080516000036125c6576040517f57f447ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610c43565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167ff23a6e610000000000000000000000000000000000000000000000000000000014611df2576040517f57f447ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff84163b15610c59576040517fbc197c8100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063bc197c81906126d89089908990889088908890600401613d2d565b6020604051808303816000875af1925050508015612731575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261272e91810190613d10565b60015b61275f573d80801561256d576040519150601f19603f3d011682016040523d82523d6000602084013e612572565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fbc197c810000000000000000000000000000000000000000000000000000000014611df2576040517f57f447ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610c43565b805182511461283a57815181516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610c43565b3360005b83518110156129a75760208181028581018201519085019091015173ffffffffffffffffffffffffffffffffffffffff88161561293e5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8c1684529091529020548181101561290a576040517f03dee4c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a166004820152602481018290526044810183905260648101849052608401610c43565b60008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8d16845290915290209082900390555b73ffffffffffffffffffffffffffffffffffffffff87161561299d5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8b16845290915281208054839290612997908490613c31565b90915550505b505060010161283e565b508251600103612a4f57602083015160009060208401519091508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051612a40929190918252602082015260400190565b60405180910390a45050611ac2565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051612ac5929190613d8c565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612af657600080fd5b50565b60008060408385031215612b0c57600080fd5b8235612b1781612ad4565b946020939093013593505050565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114612af657600080fd5b600060208284031215612b6557600080fd5b8135611ca781612b25565b60005b83811015612b8b578181015183820152602001612b73565b50506000910152565b60008151808452612bac816020860160208601612b70565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611ca76020830184612b94565b600060208284031215612c0357600080fd5b5035919050565b8151815260208083015173ffffffffffffffffffffffffffffffffffffffff16908201526040808301511515908201526060810161053e565b60008060208385031215612c5657600080fd5b823567ffffffffffffffff80821115612c6e57600080fd5b818501915085601f830112612c8257600080fd5b813581811115612c9157600080fd5b866020828501011115612ca357600080fd5b60209290920196919550909350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715612d0757612d07612cb5565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612d5457612d54612cb5565b604052919050565b600067ffffffffffffffff821115612d7657612d76612cb5565b5060051b60200190565b600082601f830112612d9157600080fd5b81356020612da6612da183612d5c565b612d0d565b8083825260208201915060208460051b870101935086841115612dc857600080fd5b602086015b84811015612de45780358352918301918301612dcd565b509695505050505050565b600067ffffffffffffffff821115612e0957612e09612cb5565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112612e4657600080fd5b8135612e54612da182612def565b818152846020838601011115612e6957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612e9e57600080fd5b8535612ea981612ad4565b94506020860135612eb981612ad4565b9350604086013567ffffffffffffffff80821115612ed657600080fd5b612ee289838a01612d80565b94506060880135915080821115612ef857600080fd5b612f0489838a01612d80565b93506080880135915080821115612f1a57600080fd5b50612f2788828901612e35565b9150509295509295909350565b60008060408385031215612f4757600080fd5b823567ffffffffffffffff80821115612f5f57600080fd5b818501915085601f830112612f7357600080fd5b81356020612f83612da183612d5c565b82815260059290921b84018101918181019089841115612fa257600080fd5b948201945b83861015612fc9578535612fba81612ad4565b82529482019490820190612fa7565b96505086013592505080821115612fdf57600080fd5b50612fec85828601612d80565b9150509250929050565b60008151808452602080850194506020840160005b838110156130275781518752958201959082019060010161300b565b509495945050505050565b602081526000611ca76020830184612ff6565b6000806040838503121561305857600080fd5b82359150602083013561306a81612ad4565b809150509250929050565b8015158114612af657600080fd5b600080600080600060a0868803121561309b57600080fd5b8535945060208601356130ad81612ad4565b935060408601356130bd81613075565b92506060860135915060808601356130d481612ad4565b809150509295509295909350565b600080604083850312156130f557600080fd5b823561310081612ad4565b9150602083013561306a81613075565b60006020828403121561312257600080fd5b8135611ca781612ad4565b60008060006040848603121561314257600080fd5b833561314d81612ad4565b9250602084013567ffffffffffffffff8082111561316a57600080fd5b818601915086601f83011261317e57600080fd5b81358181111561318d57600080fd5b8760208260051b85010111156131a257600080fd5b6020830194508093505050509250925092565b600080604083850312156131c857600080fd5b82356131d381612ad4565b9150602083013561306a81612ad4565b600080600080600060a086880312156131fb57600080fd5b853561320681612ad4565b9450602086013561321681612ad4565b93506040860135925060608601359150608086013567ffffffffffffffff81111561324057600080fd5b612f2788828901612e35565b600181811c9082168061326057607f821691505b602082108103613299577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b80516132aa81613075565b919050565b80516132aa81612ad4565b60006132c8612da184612def565b90508281528383830111156132dc57600080fd5b611ca7836020830184612b70565b600082601f8301126132fb57600080fd5b611ca7838351602085016132ba565b60006020828403121561331c57600080fd5b815167ffffffffffffffff8082111561333457600080fd5b9083019060e0828603121561334857600080fd5b613350612ce4565b6133598361329f565b8152613367602084016132af565b602082015260408301518281111561337e57600080fd5b61338a878286016132ea565b60408301525061339c606084016132af565b60608201526080830151828111156133b357600080fd5b6133bf878286016132ea565b60808301525060a083015160a08201526133db60c084016132af565b60c082015295945050505050565b600081516133fb818560208601612b70565b9290920192915050565b600081546134128161324c565b6001828116801561342a576001811461345d5761348c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008416875282151583028701945061348c565b8560005260208060002060005b858110156134835781548a82015290840190820161346a565b50505082870194505b5050505092915050565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a202253746f72792050726f746f636f6c204c6963656e73652060018201527f230000000000000000000000000000000000000000000000000000000000000060218201526000845161351a816022850160208901612b70565b7f222c0000000000000000000000000000000000000000000000000000000000006022918401918201527f226465736372697074696f6e223a20224c6963656e73652061677265656d656e60248201527f742073746174696e6720746865207465726d73206f6620612053746f7279205060448201527f726f746f636f6c2049504173736574222c00000000000000000000000000000060648201527f2265787465726e616c5f75726c223a202268747470733a2f2f70726f746f636f60758201527f6c2e73746f727970726f746f636f6c2e78797a2f6970612f0000000000000000609582015261369d61367461361c61366e6136458260ad87018b6133e9565b7f222c000000000000000000000000000000000000000000000000000000000000815260020190565b7f22696d616765223a2022000000000000000000000000000000000000000000008152600a0190565b87613405565b7f2261747472696275746573223a205b00000000000000000000000000000000008152600f0190565b9695505050505050565b6000602082840312156136b957600080fd5b815167ffffffffffffffff8111156136d057600080fd5b8201601f810184136136e157600080fd5b612019848251602084016132ba565b60008351613702818460208801612b70565b835190830190613716818360208801612b70565b01949350505050565b60008651613731818460208b01612b70565b80830190507f7b2274726169745f74797065223a20224c6963656e736f72222c202276616c7581527f65223a202200000000000000000000000000000000000000000000000000000060208201528651613792816025840160208b01612b70565b8082019150507f227d2c00000000000000000000000000000000000000000000000000000000008060258301527f7b2274726169745f74797065223a2022506f6c696379204672616d65776f726b60288301527f222c202276616c7565223a2022000000000000000000000000000000000000006048830152865161381e816055850160208b01612b70565b60559201918201527f7b2274726169745f74797065223a20225472616e7366657261626c65222c202260588201527f76616c7565223a2022000000000000000000000000000000000000000000000060788201526139326139096139036138b461388b608186018a6133e9565b7f227d2c0000000000000000000000000000000000000000000000000000000000815260030190565b7f7b2274726169745f74797065223a20225265766f6b6564222c202276616c756581527f223a202200000000000000000000000000000000000000000000000000000000602082015260240190565b866133e9565b7f227d000000000000000000000000000000000000000000000000000000000000815260020190565b98975050505050505050565b60008251613950818460208701612b70565b7f5d7d000000000000000000000000000000000000000000000000000000000000920191825250600201919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516139b781601d850160208701612b70565b91909101601d0192915050565b6000602082840312156139d657600080fd5b8151611ca781613075565b601f821115611d1b576000816000526020600020601f850160051c81016020861015613a0a5750805b601f850160051c820191505b81811015610c5957828155600101613a16565b67ffffffffffffffff831115613a4157613a41612cb5565b613a5583613a4f835461324c565b836139e1565b6000601f841160018114613aa75760008515613a715750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611ac2565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015613af65786850135825560209485019460019092019101613ad6565b5086821015613b31577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b82815260808101611ca760208301848051825260208082015173ffffffffffffffffffffffffffffffffffffffff16908301526040908101511515910152565b600060208284031215613bc457600080fd5b815160028110611ca757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561053e5761053e613c02565b600082613c7a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b808202811582820484141761053e5761053e613c02565b600081613ca557613ca5613c02565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a060808301526122aa60a0830184612b94565b600060208284031215613d2257600080fd5b8151611ca781612b25565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a06040830152613d6660a0830186612ff6565b8281036060840152613d788186612ff6565b905082810360808401526139328185612b94565b604081526000613d9f6040830185612ff6565b8281036020840152613db18185612ff6565b9594505050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122046f1e0db503cdae72a099ccd5a4216451f9e1b9182fa82aa1fa3e395794f5a8664736f6c63430008170033000000000000000000000000c5cdbb3359143c2449d03342d2f13f2f0e58c1b80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005168747470733a2f2f6769746875622e636f6d2f73746f727970726f746f636f6c2f70726f746f636f6c2d636f72652f626c6f622f6d61696e2f6173736574732f6c6963656e73652d696d6167652e676966000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101b85760003560e01c80635aa6e675116100f9578063b24387df11610097578063daa34fd011610071578063daa34fd014610480578063e985e9c514610493578063f242432a146104dc578063f943f090146104ef57600080fd5b8063b24387df14610445578063b754f2721461044d578063cc5b60841461046d57600080fd5b8063a22cb465116100d3578063a22cb46514610404578063a36a3f0514610417578063ab033ea91461042a578063aba831501461043d57600080fd5b80635aa6e675146103bc57806365165aa5146103dc57806395d89b41146103fc57600080fd5b80632de90676116101665780633a5384cb116101405780633a5384cb146103635780634e1273f4146103765780634e23932f1461039657806359784cad146103a957600080fd5b80632de90676146103025780632eb2c2d61461031757806334d70eea1461032a57600080fd5b80630e89341c116101975780630e89341c1461021b578063178ed2841461022e578063289b3c0d146102c357600080fd5b8062fdd58e146101bd57806301ffc9a7146101e357806306fdde0314610206575b600080fd5b6101d06101cb366004612af9565b61050f565b6040519081526020015b60405180910390f35b6101f66101f1366004612b53565b610544565b60405190151581526020016101da565b61020e610627565b6040516101da9190612bde565b61020e610229366004612bf1565b6106b5565b6102b661023c366004612bf1565b604080516060808201835260008083526020808401829052928401819052938452600a82529282902082519384018352805484526001015473ffffffffffffffffffffffffffffffffffffffff81169184019190915274010000000000000000000000000000000000000000900460ff1615159082015290565b6040516101da9190612c0a565b60035473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101da565b610315610310366004612c43565b610a77565b005b610315610325366004612e86565b610b96565b6102dd610338366004612bf1565b6000908152600a602052604090206001015473ffffffffffffffffffffffffffffffffffffffff1690565b6101f6610371366004612bf1565b610c61565b610389610384366004612f34565b610d07565b6040516101da9190613032565b6101f66103a4366004613045565b610ded565b6101d06103b7366004613083565b610e02565b6003546102dd9073ffffffffffffffffffffffffffffffffffffffff1681565b6007546102dd9073ffffffffffffffffffffffffffffffffffffffff1681565b61020e610fb1565b6103156104123660046130e2565b610fbe565b610315610425366004613110565b610fcd565b610315610438366004613110565b611130565b61020e6114a3565b600b546101d0565b6101d061045b366004612bf1565b6000908152600a602052604090205490565b61031561047b366004613110565b6114b0565b61031561048e36600461312d565b611613565b6101f66104a13660046131b5565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205460ff1690565b6103156104ea3660046131e3565b611723565b6008546102dd9073ffffffffffffffffffffffffffffffffffffffff1681565b60008181526020818152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091529020545b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fd9b67a260000000000000000000000000000000000000000000000000000000014806105d757507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e89341c00000000000000000000000000000000000000000000000000000000145b8061053e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461053e565b600480546106349061324c565b80601f01602080910402602001604051908101604052809291908181526020018280546106609061324c565b80156106ad5780601f10610682576101008083540402835291602001916106ad565b820191906000526020600020905b81548152906001019060200180831161069057829003601f168201915b505050505081565b6000818152600a60209081526040808320815160608082018452825480835260019093015473ffffffffffffffffffffffffffffffffffffffff8082169684019690965274010000000000000000000000000000000000000000900460ff1615158285015260075493517f3cea5120000000000000000000000000000000000000000000000000000000008152600481019390935294909390921690633cea512090602401600060405180830381865afa158015610777573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526107bd919081019061330a565b905060006107e4836020015173ffffffffffffffffffffffffffffffffffffffff166117e1565b905060006107f186611804565b82600660405160200161080693929190613496565b604051602081830303815290604052905080836020015173ffffffffffffffffffffffffffffffffffffffff1663eb6b331585604001516040518263ffffffff1660e01b81526004016108599190612bde565b600060405180830381865afa158015610876573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526108bc91908101906136a7565b6040516020016108cd9291906136f0565b60405160208183030381529060405290508082610903856020015173ffffffffffffffffffffffffffffffffffffffff166117e1565b8660400151610947576040518060400160405280600581526020017f66616c736500000000000000000000000000000000000000000000000000000081525061097e565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b6109878a610c61565b6109c6576040518060400160405280600581526020017f66616c73650000000000000000000000000000000000000000000000000000008152506109fd565b6040518060400160405280600481526020017f74727565000000000000000000000000000000000000000000000000000000008152505b604051602001610a1195949392919061371f565b604051602081830303815290604052905080604051602001610a33919061393e565b6040516020818303038152906040529050610a4d816118c2565b604051602001610a5d919061397f565b604051602081830303815290604052945050505050919050565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa158015610aec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1091906139c4565b610b46576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006610b53828483613a29565b50600b54604080516001815260208101929092527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a15050565b3373ffffffffffffffffffffffffffffffffffffffff86168114801590610bf0575073ffffffffffffffffffffffffffffffffffffffff80871660009081526001602090815260408083209385168352929052205460ff16155b15610c4c576040517fe237d92200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8083166004830152871660248201526044015b60405180910390fd5b610c598686868686611a15565b505050505050565b6008546000828152600a60205260408082206001015490517f13f46c4200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152919216906313f46c4290602401602060405180830381865afa158015610ce3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053e91906139c4565b60608151835114610d5157815183516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610c43565b6000835167ffffffffffffffff811115610d6d57610d6d612cb5565b604051908082528060200260200182016040528015610d96578160200160208202803683370190505b50905060005b8451811015610de557602080820286010151610dc09060208084028701015161050f565b828281518110610dd257610dd2613b43565b6020908102919091010152600101610d9c565b509392505050565b600080610dfa838561050f565b119392505050565b60075460009073ffffffffffffffffffffffffffffffffffffffff163314610e56576040517f6b9c60a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060405180606001604052808881526020018773ffffffffffffffffffffffffffffffffffffffff16815260200186151581525090506000610ebc82604051602001610ea39190612c0a565b6040516020818303038152906040526009600b54611ac9565b90935090508015610f8b57600b8390556000838152600a602090815260409182902084518155908401516001909101805483860151151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00000000000000000000000000000000000000000090911673ffffffffffffffffffffffffffffffffffffffff938416171790559051849186169033907f08f994adef75dc0c809636b2fb0004553e15a247a89664f0b038034801c719a190610f82908a908890613b72565b60405180910390a45b610fa684848760405180602001604052806000815250611b20565b505095945050505050565b600580546106349061324c565b610fc9338383611ba3565b5050565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa158015611042573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106691906139c4565b61109c576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166110e9576040517ff9699b4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa1580156111a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c991906139c4565b6111ff576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661124c576040517f4724c36600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611276817f4ebb53a600000000000000000000000000000000000000000000000000000000611c8b565b6112db576040517ea73c8d00000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f49476f7665726e616e63650000000000000000000000000000000000000000006044820152606401610c43565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631865c57d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611348573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136c9190613bb2565b600181111561137d5761137d613bd3565b8173ffffffffffffffffffffffffffffffffffffffff16631865c57d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ec9190613bb2565b60018111156113fd576113fd613bd3565b14611434576040517f649cdd9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f9d3e522e1e47a2f6009739342b9cc7b252a1888154e843ab55ee1c81745795ab90600090a250565b600680546106349061324c565b6003546040517f91d148540000000000000000000000000000000000000000000000000000000081526000600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116906391d1485490604401602060405180830381865afa158015611525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154991906139c4565b61157f576040517f59a8f42a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166115cc576040517fb028818e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60075473ffffffffffffffffffffffffffffffffffffffff163314611664576040517f6b9c60a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561167f5761167f612cb5565b6040519080825280602002602001820160405280156116a8578160200160208202803683370190505b50905060005b828110156116dd5760018282815181106116ca576116ca613b43565b60209081029190910101526001016116ae565b5061171d84848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250611cae915050565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff8616811480159061177d575073ffffffffffffffffffffffffffffffffffffffff80871660009081526001602090815260408083209385168352929052205460ff16155b156117d4576040517fe237d92200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808316600483015287166024820152604401610c43565b610c598686868686611d20565b606061053e73ffffffffffffffffffffffffffffffffffffffff83166014611dfb565b6060600061181183612021565b600101905060008167ffffffffffffffff81111561183157611831612cb5565b6040519080825280601f01601f19166020018201604052801561185b576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461186557509392505050565b606081516000036118e157505060408051602081019091526000815290565b6000604051806060016040528060408152602001613dbb60409139905060006003845160026119109190613c31565b61191a9190613c44565b611925906004613c7f565b67ffffffffffffffff81111561193d5761193d612cb5565b6040519080825280601f01601f191660200182016040528015611967576020820181803683370190505b509050600182016020820185865187015b808210156119d3576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250611978565b50506003865106600181146119ef5760028114611a0257611a0a565b603d6001830353603d6002830353611a0a565b603d60018303535b509195945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416611a65576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff8516611ab5576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b611ac28585858585612103565b5050505050565b8251602080850191909120600081815291849052604082205491908215611af4575060009050611b18565b611aff846001613c31565b6000918252602086905260409091208190559150600190505b935093915050565b73ffffffffffffffffffffffffffffffffffffffff8416611b70576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b60408051600180825260208201869052818301908152606082018590526080820190925290610c59600087848487612103565b73ffffffffffffffffffffffffffffffffffffffff8216611bf3576040517fced3e10000000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000611c9683612163565b8015611ca75750611ca783836121c7565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8316611cfe576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b611d1b836000848460405180602001604052806000815250612103565b505050565b73ffffffffffffffffffffffffffffffffffffffff8416611d70576040517f57f447ce00000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff8516611dc0576040517f01a8351400000000000000000000000000000000000000000000000000000000815260006004820152602401610c43565b60408051600180825260208201869052818301908152606082018590526080820190925290611df28787848487612103565b50505050505050565b6060826000611e0b846002613c7f565b611e16906002613c31565b67ffffffffffffffff811115611e2e57611e2e612cb5565b6040519080825280601f01601f191660200182016040528015611e58576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611e8f57611e8f613b43565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611ef257611ef2613b43565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000611f2e856002613c7f565b611f39906001613c31565b90505b6001811115611fd6577f303132333435363738396162636465660000000000000000000000000000000083600f1660108110611f7a57611f7a613b43565b1a60f81b828281518110611f9057611f90613b43565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049290921c91611fcf81613c96565b9050611f3c565b508115612019576040517fe22e27eb0000000000000000000000000000000000000000000000000000000081526004810186905260248101859052604401610c43565b949350505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061206a577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310612096576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106120b457662386f26fc10000830492506010015b6305f5e10083106120cc576305f5e100830492506008015b61271083106120e057612710830492506004015b606483106120f2576064830492506002015b600a831061053e5760010192915050565b61210f858585856122b5565b73ffffffffffffffffffffffffffffffffffffffff841615611ac25782513390600103612155576020848101519084015161214e83898985858961246f565b5050610c59565b610c59818787878787612661565b600061218f827f01ffc9a7000000000000000000000000000000000000000000000000000000006121c7565b801561053e57506121c0827fffffffff000000000000000000000000000000000000000000000000000000006121c7565b1592915050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000821660248201526000908190604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d9150600051905082801561229e575060208210155b80156122aa5750600081115b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416158015906122ef575073ffffffffffffffffffffffffffffffffffffffff831615155b156124635760005b8251811015612461576000600a600085848151811061231857612318613b43565b602090810291909101810151825281810192909252604090810160002081516060810183528154815260019091015473ffffffffffffffffffffffffffffffffffffffff8116938201939093527401000000000000000000000000000000000000000090920460ff1615159082015284519091506123af908590849081106123a2576123a2613b43565b6020026020010151610c61565b156123e6576040517fdf1d1ad200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015161245857806020015173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614612458576040517ffa45c60e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506001016122f7565b505b61171d848484846127f2565b73ffffffffffffffffffffffffffffffffffffffff84163b15610c59576040517ff23a6e6100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063f23a6e61906124e69089908990889088908890600401613ccb565b6020604051808303816000875af192505050801561253f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261253c91810190613d10565b60015b6125ce573d80801561256d576040519150601f19603f3d011682016040523d82523d6000602084013e612572565b606091505b5080516000036125c6576040517f57f447ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610c43565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167ff23a6e610000000000000000000000000000000000000000000000000000000014611df2576040517f57f447ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610c43565b73ffffffffffffffffffffffffffffffffffffffff84163b15610c59576040517fbc197c8100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063bc197c81906126d89089908990889088908890600401613d2d565b6020604051808303816000875af1925050508015612731575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261272e91810190613d10565b60015b61275f573d80801561256d576040519150601f19603f3d011682016040523d82523d6000602084013e612572565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fbc197c810000000000000000000000000000000000000000000000000000000014611df2576040517f57f447ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610c43565b805182511461283a57815181516040517f5b05999100000000000000000000000000000000000000000000000000000000815260048101929092526024820152604401610c43565b3360005b83518110156129a75760208181028581018201519085019091015173ffffffffffffffffffffffffffffffffffffffff88161561293e5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8c1684529091529020548181101561290a576040517f03dee4c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a166004820152602481018290526044810183905260648101849052608401610c43565b60008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8d16845290915290209082900390555b73ffffffffffffffffffffffffffffffffffffffff87161561299d5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8b16845290915281208054839290612997908490613c31565b90915550505b505060010161283e565b508251600103612a4f57602083015160009060208401519091508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051612a40929190918252602082015260400190565b60405180910390a45050611ac2565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051612ac5929190613d8c565b60405180910390a45050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612af657600080fd5b50565b60008060408385031215612b0c57600080fd5b8235612b1781612ad4565b946020939093013593505050565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114612af657600080fd5b600060208284031215612b6557600080fd5b8135611ca781612b25565b60005b83811015612b8b578181015183820152602001612b73565b50506000910152565b60008151808452612bac816020860160208601612b70565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611ca76020830184612b94565b600060208284031215612c0357600080fd5b5035919050565b8151815260208083015173ffffffffffffffffffffffffffffffffffffffff16908201526040808301511515908201526060810161053e565b60008060208385031215612c5657600080fd5b823567ffffffffffffffff80821115612c6e57600080fd5b818501915085601f830112612c8257600080fd5b813581811115612c9157600080fd5b866020828501011115612ca357600080fd5b60209290920196919550909350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715612d0757612d07612cb5565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612d5457612d54612cb5565b604052919050565b600067ffffffffffffffff821115612d7657612d76612cb5565b5060051b60200190565b600082601f830112612d9157600080fd5b81356020612da6612da183612d5c565b612d0d565b8083825260208201915060208460051b870101935086841115612dc857600080fd5b602086015b84811015612de45780358352918301918301612dcd565b509695505050505050565b600067ffffffffffffffff821115612e0957612e09612cb5565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112612e4657600080fd5b8135612e54612da182612def565b818152846020838601011115612e6957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612e9e57600080fd5b8535612ea981612ad4565b94506020860135612eb981612ad4565b9350604086013567ffffffffffffffff80821115612ed657600080fd5b612ee289838a01612d80565b94506060880135915080821115612ef857600080fd5b612f0489838a01612d80565b93506080880135915080821115612f1a57600080fd5b50612f2788828901612e35565b9150509295509295909350565b60008060408385031215612f4757600080fd5b823567ffffffffffffffff80821115612f5f57600080fd5b818501915085601f830112612f7357600080fd5b81356020612f83612da183612d5c565b82815260059290921b84018101918181019089841115612fa257600080fd5b948201945b83861015612fc9578535612fba81612ad4565b82529482019490820190612fa7565b96505086013592505080821115612fdf57600080fd5b50612fec85828601612d80565b9150509250929050565b60008151808452602080850194506020840160005b838110156130275781518752958201959082019060010161300b565b509495945050505050565b602081526000611ca76020830184612ff6565b6000806040838503121561305857600080fd5b82359150602083013561306a81612ad4565b809150509250929050565b8015158114612af657600080fd5b600080600080600060a0868803121561309b57600080fd5b8535945060208601356130ad81612ad4565b935060408601356130bd81613075565b92506060860135915060808601356130d481612ad4565b809150509295509295909350565b600080604083850312156130f557600080fd5b823561310081612ad4565b9150602083013561306a81613075565b60006020828403121561312257600080fd5b8135611ca781612ad4565b60008060006040848603121561314257600080fd5b833561314d81612ad4565b9250602084013567ffffffffffffffff8082111561316a57600080fd5b818601915086601f83011261317e57600080fd5b81358181111561318d57600080fd5b8760208260051b85010111156131a257600080fd5b6020830194508093505050509250925092565b600080604083850312156131c857600080fd5b82356131d381612ad4565b9150602083013561306a81612ad4565b600080600080600060a086880312156131fb57600080fd5b853561320681612ad4565b9450602086013561321681612ad4565b93506040860135925060608601359150608086013567ffffffffffffffff81111561324057600080fd5b612f2788828901612e35565b600181811c9082168061326057607f821691505b602082108103613299577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b80516132aa81613075565b919050565b80516132aa81612ad4565b60006132c8612da184612def565b90508281528383830111156132dc57600080fd5b611ca7836020830184612b70565b600082601f8301126132fb57600080fd5b611ca7838351602085016132ba565b60006020828403121561331c57600080fd5b815167ffffffffffffffff8082111561333457600080fd5b9083019060e0828603121561334857600080fd5b613350612ce4565b6133598361329f565b8152613367602084016132af565b602082015260408301518281111561337e57600080fd5b61338a878286016132ea565b60408301525061339c606084016132af565b60608201526080830151828111156133b357600080fd5b6133bf878286016132ea565b60808301525060a083015160a08201526133db60c084016132af565b60c082015295945050505050565b600081516133fb818560208601612b70565b9290920192915050565b600081546134128161324c565b6001828116801561342a576001811461345d5761348c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008416875282151583028701945061348c565b8560005260208060002060005b858110156134835781548a82015290840190820161346a565b50505082870194505b5050505092915050565b7f7b0000000000000000000000000000000000000000000000000000000000000081527f226e616d65223a202253746f72792050726f746f636f6c204c6963656e73652060018201527f230000000000000000000000000000000000000000000000000000000000000060218201526000845161351a816022850160208901612b70565b7f222c0000000000000000000000000000000000000000000000000000000000006022918401918201527f226465736372697074696f6e223a20224c6963656e73652061677265656d656e60248201527f742073746174696e6720746865207465726d73206f6620612053746f7279205060448201527f726f746f636f6c2049504173736574222c00000000000000000000000000000060648201527f2265787465726e616c5f75726c223a202268747470733a2f2f70726f746f636f60758201527f6c2e73746f727970726f746f636f6c2e78797a2f6970612f0000000000000000609582015261369d61367461361c61366e6136458260ad87018b6133e9565b7f222c000000000000000000000000000000000000000000000000000000000000815260020190565b7f22696d616765223a2022000000000000000000000000000000000000000000008152600a0190565b87613405565b7f2261747472696275746573223a205b00000000000000000000000000000000008152600f0190565b9695505050505050565b6000602082840312156136b957600080fd5b815167ffffffffffffffff8111156136d057600080fd5b8201601f810184136136e157600080fd5b612019848251602084016132ba565b60008351613702818460208801612b70565b835190830190613716818360208801612b70565b01949350505050565b60008651613731818460208b01612b70565b80830190507f7b2274726169745f74797065223a20224c6963656e736f72222c202276616c7581527f65223a202200000000000000000000000000000000000000000000000000000060208201528651613792816025840160208b01612b70565b8082019150507f227d2c00000000000000000000000000000000000000000000000000000000008060258301527f7b2274726169745f74797065223a2022506f6c696379204672616d65776f726b60288301527f222c202276616c7565223a2022000000000000000000000000000000000000006048830152865161381e816055850160208b01612b70565b60559201918201527f7b2274726169745f74797065223a20225472616e7366657261626c65222c202260588201527f76616c7565223a2022000000000000000000000000000000000000000000000060788201526139326139096139036138b461388b608186018a6133e9565b7f227d2c0000000000000000000000000000000000000000000000000000000000815260030190565b7f7b2274726169745f74797065223a20225265766f6b6564222c202276616c756581527f223a202200000000000000000000000000000000000000000000000000000000602082015260240190565b866133e9565b7f227d000000000000000000000000000000000000000000000000000000000000815260020190565b98975050505050505050565b60008251613950818460208701612b70565b7f5d7d000000000000000000000000000000000000000000000000000000000000920191825250600201919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516139b781601d850160208701612b70565b91909101601d0192915050565b6000602082840312156139d657600080fd5b8151611ca781613075565b601f821115611d1b576000816000526020600020601f850160051c81016020861015613a0a5750805b601f850160051c820191505b81811015610c5957828155600101613a16565b67ffffffffffffffff831115613a4157613a41612cb5565b613a5583613a4f835461324c565b836139e1565b6000601f841160018114613aa75760008515613a715750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611ac2565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015613af65786850135825560209485019460019092019101613ad6565b5086821015613b31577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b82815260808101611ca760208301848051825260208082015173ffffffffffffffffffffffffffffffffffffffff16908301526040908101511515910152565b600060208284031215613bc457600080fd5b815160028110611ca757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561053e5761053e613c02565b600082613c7a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b808202811582820484141761053e5761053e613c02565b600081613ca557613ca5613c02565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a060808301526122aa60a0830184612b94565b600060208284031215613d2257600080fd5b8151611ca781612b25565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a06040830152613d6660a0830186612ff6565b8281036060840152613d788186612ff6565b905082810360808401526139328185612b94565b604081526000613d9f6040830185612ff6565b8281036020840152613db18185612ff6565b9594505050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122046f1e0db503cdae72a099ccd5a4216451f9e1b9182fa82aa1fa3e395794f5a8664736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c5cdbb3359143c2449d03342d2f13f2f0e58c1b80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005168747470733a2f2f6769746875622e636f6d2f73746f727970726f746f636f6c2f70726f746f636f6c2d636f72652f626c6f622f6d61696e2f6173736574732f6c6963656e73652d696d6167652e676966000000000000000000000000000000
-----Decoded View---------------
Arg [0] : governance (address): 0xc5Cdbb3359143C2449D03342D2F13F2F0e58c1b8
Arg [1] : url (string): https://github.com/storyprotocol/protocol-core/blob/main/assets/license-image.gif
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000c5cdbb3359143c2449d03342d2f13f2f0e58c1b8
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000051
Arg [3] : 68747470733a2f2f6769746875622e636f6d2f73746f727970726f746f636f6c
Arg [4] : 2f70726f746f636f6c2d636f72652f626c6f622f6d61696e2f6173736574732f
Arg [5] : 6c6963656e73652d696d6167652e676966000000000000000000000000000000
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.