// Sources flattened with hardhat v2.12.3 https://hardhat.org
// File @openzeppelin/contracts/utils/introspection/IERC165.sol@v4.9.2
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @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);
}
// File @solvprotocol/erc-3525/IERC721.sol@v1.3.0
//
pragma solidity ^0.8.1;
/**
* @title ERC-721 Non-Fungible Token Standard
* @dev See https://eips.ethereum.org/EIPS/eip-721
* Note: the ERC-165 identifier for this interface is 0x80ac58cd.
*/
interface IERC721 is IERC165 {
/**
* @dev This emits when ownership of any NFT changes by any mechanism.
* This event emits when NFTs are created (`from` == 0) and destroyed
* (`to` == 0). Exception: during contract creation, any number of NFTs
* may be created and assigned without emitting Transfer. At the time of
* any transfer, the approved address for that NFT (if any) is reset to none.
*/
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
/**
* @dev This emits when the approved address for an NFT is changed or
* reaffirmed. The zero address indicates there is no approved address.
* When a Transfer event emits, this also indicates that the approved
* address for that NFT (if any) is reset to none.
*/
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
/**
* @dev This emits when an operator is enabled or disabled for an owner.
* The operator can manage all NFTs of the owner.
*/
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
/**
* @notice Count all NFTs assigned to an owner
* @dev NFTs assigned to the zero address are considered invalid, and this
* function throws for queries about the zero address.
* @param _owner An address for whom to query the balance
* @return The number of NFTs owned by `_owner`, possibly zero
*/
function balanceOf(address _owner) external view returns (uint256);
/**
* @notice Find the owner of an NFT
* @dev NFTs assigned to zero address are considered invalid, and queries
* about them do throw.
* @param _tokenId The identifier for an NFT
* @return The address of the owner of the NFT
*/
function ownerOf(uint256 _tokenId) external view returns (address);
/**
* @notice Transfers the ownership of an NFT from one address to another address
* @dev Throws unless `msg.sender` is the current owner, an authorized
* operator, or the approved address for this NFT. Throws if `_from` is
* not the current owner. Throws if `_to` is the zero address. Throws if
* `_tokenId` is not a valid NFT. When transfer is complete, this function
* checks if `_to` is a smart contract (code size > 0). If so, it calls
* `onERC721Received` on `_to` and throws if the return value is not
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
* @param _from The current owner of the NFT
* @param _to The new owner
* @param _tokenId The NFT to transfer
* @param data Additional data with no specified format, sent in call to `_to`
*/
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable;
/**
* @notice Transfers the ownership of an NFT from one address to another address
* @dev This works identically to the other function with an extra data parameter,
* except this function just sets data to "".
* @param _from The current owner of the NFT
* @param _to The new owner
* @param _tokenId The NFT to transfer
*/
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
/**
* @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
* TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
* THEY MAY BE PERMANENTLY LOST
* @dev Throws unless `msg.sender` is the current owner, an authorized
* operator, or the approved address for this NFT. Throws if `_from` is
* not the current owner. Throws if `_to` is the zero address. Throws if
* `_tokenId` is not a valid NFT.
* @param _from The current owner of the NFT
* @param _to The new owner
* @param _tokenId The NFT to transfer
*/
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
/**
* @notice Change or reaffirm the approved address for an NFT
* @dev The zero address indicates there is no approved address.
* Throws unless `msg.sender` is the current NFT owner, or an authorized
* operator of the current owner.
* @param _approved The new approved NFT controller
* @param _tokenId The NFT to approve
*/
function approve(address _approved, uint256 _tokenId) external payable;
/**
* @notice Enable or disable approval for a third party ("operator") to manage
* all of `msg.sender`'s assets
* @dev Emits the ApprovalForAll event. The contract MUST allow
* multiple operators per owner.
* @param _operator Address to add to the set of authorized operators
* @param _approved True if the operator is approved, false to revoke approval
*/
function setApprovalForAll(address _operator, bool _approved) external;
/**
* @notice Get the approved address for a single NFT
* @dev Throws if `_tokenId` is not a valid NFT.
* @param _tokenId The NFT to find the approved address for
* @return The approved address for this NFT, or the zero address if there is none
*/
function getApproved(uint256 _tokenId) external view returns (address);
/**
* @notice Query if an address is an authorized operator for another address
* @param _owner The address that owns the NFTs
* @param _operator The address that acts on behalf of the owner
* @return True if `_operator` is an approved operator for `_owner`, false otherwise
*/
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
// File @solvprotocol/erc-3525/IERC3525.sol@v1.3.0
//
pragma solidity ^0.8.0;
/**
* @title ERC-3525 Semi-Fungible Token Standard
* @dev See https://eips.ethereum.org/EIPS/eip-3525
* Note: the ERC-165 identifier for this interface is 0xd5358140.
*/
interface IERC3525 is IERC165, IERC721 {
/**
* @dev MUST emit when value of a token is transferred to another token with the same slot,
* including zero value transfers (_value == 0) as well as transfers when tokens are created
* (`_fromTokenId` == 0) or destroyed (`_toTokenId` == 0).
* @param _fromTokenId The token id to transfer value from
* @param _toTokenId The token id to transfer value to
* @param _value The transferred value
*/
event TransferValue(uint256 indexed _fromTokenId, uint256 indexed _toTokenId, uint256 _value);
/**
* @dev MUST emits when the approval value of a token is set or changed.
* @param _tokenId The token to approve
* @param _operator The operator to approve for
* @param _value The maximum value that `_operator` is allowed to manage
*/
event ApprovalValue(uint256 indexed _tokenId, address indexed _operator, uint256 _value);
/**
* @dev MUST emit when the slot of a token is set or changed.
* @param _tokenId The token of which slot is set or changed
* @param _oldSlot The previous slot of the token
* @param _newSlot The updated slot of the token
*/
event SlotChanged(uint256 indexed _tokenId, uint256 indexed _oldSlot, uint256 indexed _newSlot);
/**
* @notice Get the number of decimals the token uses for value - e.g. 6, means the user
* representation of the value of a token can be calculated by dividing it by 1,000,000.
* Considering the compatibility with third-party wallets, this function is defined as
* `valueDecimals()` instead of `decimals()` to avoid conflict with ERC20 tokens.
* @return The number of decimals for value
*/
function valueDecimals() external view returns (uint8);
/**
* @notice Get the value of a token.
* @param _tokenId The token for which to query the balance
* @return The value of `_tokenId`
*/
function balanceOf(uint256 _tokenId) external view returns (uint256);
/**
* @notice Get the slot of a token.
* @param _tokenId The identifier for a token
* @return The slot of the token
*/
function slotOf(uint256 _tokenId) external view returns (uint256);
/**
* @notice Allow an operator to manage the value of a token, up to the `_value` amount.
* @dev MUST revert unless caller is the current owner, an authorized operator, or the approved
* address for `_tokenId`.
* MUST emit ApprovalValue event.
* @param _tokenId The token to approve
* @param _operator The operator to be approved
* @param _value The maximum value of `_toTokenId` that `_operator` is allowed to manage
*/
function approve(
uint256 _tokenId,
address _operator,
uint256 _value
) external payable;
/**
* @notice Get the maximum value of a token that an operator is allowed to manage.
* @param _tokenId The token for which to query the allowance
* @param _operator The address of an operator
* @return The current approval value of `_tokenId` that `_operator` is allowed to manage
*/
function allowance(uint256 _tokenId, address _operator) external view returns (uint256);
/**
* @notice Transfer value from a specified token to another specified token with the same slot.
* @dev Caller MUST be the current owner, an authorized operator or an operator who has been
* approved the whole `_fromTokenId` or part of it.
* MUST revert if `_fromTokenId` or `_toTokenId` is zero token id or does not exist.
* MUST revert if slots of `_fromTokenId` and `_toTokenId` do not match.
* MUST revert if `_value` exceeds the balance of `_fromTokenId` or its allowance to the
* operator.
* MUST emit `TransferValue` event.
* @param _fromTokenId The token to transfer value from
* @param _toTokenId The token to transfer value to
* @param _value The transferred value
*/
function transferFrom(
uint256 _fromTokenId,
uint256 _toTokenId,
uint256 _value
) external payable;
/**
* @notice Transfer value from a specified token to an address. The caller should confirm that
* `_to` is capable of receiving ERC3525 tokens.
* @dev This function MUST create a new ERC3525 token with the same slot for `_to` to receive
* the transferred value.
* MUST revert if `_fromTokenId` is zero token id or does not exist.
* MUST revert if `_to` is zero address.
* MUST revert if `_value` exceeds the balance of `_fromTokenId` or its allowance to the
* operator.
* MUST emit `Transfer` and `TransferValue` events.
* @param _fromTokenId The token to transfer value from
* @param _to The address to transfer value to
* @param _value The transferred value
* @return ID of the new token created for `_to` which receives the transferred value
*/
function transferFrom(
uint256 _fromTokenId,
address _to,
uint256 _value
) external payable returns (uint256);
}
// File @solvprotocol/erc-3525/IERC3525Receiver.sol@v1.3.0
//
pragma solidity ^0.8.1;
/**
* @title EIP-3525 token receiver interface
* @dev Interface for a smart contract that wants to be informed by EIP-3525 contracts when
* receiving values from ANY addresses or EIP-3525 tokens.
* Note: the EIP-165 identifier for this interface is 0x009ce20b.
*/
interface IERC3525Receiver {
/**
* @notice Handle the receipt of an EIP-3525 token value.
* @dev An EIP-3525 smart contract MUST check whether this function is implemented by the
* recipient contract, if the recipient contract implements this function, the EIP-3525
* contract MUST call this function after a value transfer (i.e. `transferFrom(uint256,
* uint256,uint256,bytes)`).
* MUST return 0x009ce20b (i.e. `bytes4(keccak256('onERC3525Received(address,uint256,uint256,
* uint256,bytes)'))`) if the transfer is accepted.
* MUST revert or return any value other than 0x009ce20b if the transfer is rejected.
* @param _operator The address which triggered the transfer
* @param _fromTokenId The token id to transfer value from
* @param _toTokenId The token id to transfer value to
* @param _value The transferred value
* @param _data Additional data with no specified format
* @return `bytes4(keccak256('onERC3525Received(address,uint256,uint256,uint256,bytes)'))`
* unless the transfer is rejected.
*/
function onERC3525Received(address _operator, uint256 _fromTokenId, uint256 _toTokenId, uint256 _value, bytes calldata _data) external returns (bytes4);
}
// File @solvprotocol/erc-3525/IERC721Receiver.sol@v1.3.0
//
pragma solidity ^0.8.1;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers from ERC721 asset contracts.
* Note: the ERC-165 identifier for this interface is 0x150b7a02.
*/
interface IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `transfer`. This function MAY throw to revert and reject the
* transfer. Return of other than the magic value MUST result in the
* transaction being reverted.
* Note: the contract address is always the message sender.
* @param _operator The address which called `safeTransferFrom` function
* @param _from The address which previously owned the token
* @param _tokenId The NFT identifier which is being transferred
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
* unless throwing
*/
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes calldata _data
) external returns(bytes4);
}
// File @openzeppelin/contracts/utils/Context.sol@v4.9.2
//
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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;
}
}
// File @openzeppelin/contracts/utils/math/SignedMath.sol@v4.9.2
//
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @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);
}
}
}
// File @openzeppelin/contracts/utils/math/Math.sol@v4.9.2
//
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
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.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
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 (rounding == Rounding.Up && 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 down.
*
* 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
// File @openzeppelin/contracts/utils/Strings.sol@v4.9.2
//
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @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), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(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) {
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] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
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 keccak256(bytes(a)) == keccak256(bytes(b));
}
}
// File @openzeppelin/contracts/utils/Counters.sol@v4.9.2
//
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
pragma solidity ^0.8.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library Counters {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
// File @solvprotocol/erc-3525/extensions/IERC721Enumerable.sol@v1.3.0
//
pragma solidity ^0.8.1;
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
* Note: the ERC-165 identifier for this interface is 0x780e9d63.
*/
interface IERC721Enumerable is IERC721 {
/**
* @notice Count NFTs tracked by this contract
* @return A count of valid NFTs tracked by this contract, where each one of
* them has an assigned and queryable owner not equal to the zero address
*/
function totalSupply() external view returns (uint256);
/**
* @notice Enumerate valid NFTs
* @dev Throws if `_index` >= `totalSupply()`.
* @param _index A counter less than `totalSupply()`
* @return The token identifier for the `_index`th NFT,
* (sort order not specified)
*/
function tokenByIndex(uint256 _index) external view returns (uint256);
/**
* @notice Enumerate NFTs assigned to an owner
* @dev Throws if `_index` >= `balanceOf(_owner)` or if
* `_owner` is the zero address, representing invalid NFTs.
* @param _owner An address where we are interested in NFTs owned by them
* @param _index A counter less than `balanceOf(_owner)`
* @return The token identifier for the `_index`th NFT assigned to `_owner`,
* (sort order not specified)
*/
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
// File @solvprotocol/erc-3525/extensions/IERC721Metadata.sol@v1.3.0
//
pragma solidity ^0.8.1;
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
* Note: the ERC-165 identifier for this interface is 0x5b5e139f.
*/
interface IERC721Metadata is IERC721 {
/**
* @notice A descriptive name for a collection of NFTs in this contract
*/
function name() external view returns (string memory);
/**
* @notice An abbreviated name for NFTs in this contract
*/
function symbol() external view returns (string memory);
/**
* @notice A distinct Uniform Resource Identifier (URI) for a given asset.
* @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
* 3986. The URI may point to a JSON file that conforms to the "ERC721
* Metadata JSON Schema".
*/
function tokenURI(uint256 _tokenId) external view returns (string memory);
}
// File @openzeppelin/contracts/utils/Address.sol@v4.9.2
//
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// File @solvprotocol/erc-3525/extensions/IERC3525Metadata.sol@v1.3.0
//
pragma solidity ^0.8.1;
/**
* @title ERC-3525 Semi-Fungible Token Standard, optional extension for metadata
* @dev Interfaces for any contract that wants to support query of the Uniform Resource Identifier
* (URI) for the ERC3525 contract as well as a specified slot.
* Because of the higher reliability of data stored in smart contracts compared to data stored in
* centralized systems, it is recommended that metadata, including `contractURI`, `slotURI` and
* `tokenURI`, be directly returned in JSON format, instead of being returned with a url pointing
* to any resource stored in a centralized system.
* See https://eips.ethereum.org/EIPS/eip-3525
* Note: the ERC-165 identifier for this interface is 0xe1600902.
*/
interface IERC3525Metadata is IERC3525, IERC721Metadata {
/**
* @notice Returns the Uniform Resource Identifier (URI) for the current ERC3525 contract.
* @dev This function SHOULD return the URI for this contract in JSON format, starting with
* header `data:application/json;`.
* See https://eips.ethereum.org/EIPS/eip-3525 for the JSON schema for contract URI.
* @return The JSON formatted URI of the current ERC3525 contract
*/
function contractURI() external view returns (string memory);
/**
* @notice Returns the Uniform Resource Identifier (URI) for the specified slot.
* @dev This function SHOULD return the URI for `_slot` in JSON format, starting with header
* `data:application/json;`.
* See https://eips.ethereum.org/EIPS/eip-3525 for the JSON schema for slot URI.
* @return The JSON formatted URI of `_slot`
*/
function slotURI(uint256 _slot) external view returns (string memory);
}
// File @solvprotocol/erc-3525/periphery/interface/IERC3525MetadataDescriptor.sol@v1.3.0
//
pragma solidity ^0.8.0;
interface IERC3525MetadataDescriptor {
function constructContractURI() external view returns (string memory);
function constructSlotURI(uint256 slot) external view returns (string memory);
function constructTokenURI(uint256 tokenId) external view returns (string memory);
}
// File @solvprotocol/erc-3525/ERC3525.sol@v1.3.0
//
pragma solidity ^0.8.0;
contract ERC3525 is Context, IERC3525Metadata, IERC721Enumerable {
using Strings for address;
using Strings for uint256;
using Address for address;
using Counters for Counters.Counter;
event SetMetadataDescriptor(address indexed metadataDescriptor);
struct TokenData {
uint256 id;
uint256 slot;
uint256 balance;
address owner;
address approved;
address[] valueApprovals;
}
struct AddressData {
uint256[] ownedTokens;
mapping(uint256 => uint256) ownedTokensIndex;
mapping(address => bool) approvals;
}
string private _name;
string private _symbol;
uint8 private _decimals;
Counters.Counter private _tokenIdGenerator;
// id => (approval => allowance)
// @dev _approvedValues cannot be defined within TokenData, cause struct containing mappings cannot be constructed.
mapping(uint256 => mapping(address => uint256)) private _approvedValues;
TokenData[] private _allTokens;
// key: id
mapping(uint256 => uint256) private _allTokensIndex;
mapping(address => AddressData) private _addressData;
IERC3525MetadataDescriptor public metadataDescriptor;
constructor(string memory name_, string memory symbol_, uint8 decimals_) {
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(IERC165).interfaceId ||
interfaceId == type(IERC3525).interfaceId ||
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC3525Metadata).interfaceId ||
interfaceId == type(IERC721Enumerable).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId;
}
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals the token uses for value.
*/
function valueDecimals() public view virtual override returns (uint8) {
return _decimals;
}
function balanceOf(uint256 tokenId_) public view virtual override returns (uint256) {
_requireMinted(tokenId_);
return _allTokens[_allTokensIndex[tokenId_]].balance;
}
function ownerOf(uint256 tokenId_) public view virtual override returns (address owner_) {
_requireMinted(tokenId_);
owner_ = _allTokens[_allTokensIndex[tokenId_]].owner;
require(owner_ != address(0), "ERC3525: invalid token ID");
}
function slotOf(uint256 tokenId_) public view virtual override returns (uint256) {
_requireMinted(tokenId_);
return _allTokens[_allTokensIndex[tokenId_]].slot;
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function contractURI() public view virtual override returns (string memory) {
string memory baseURI = _baseURI();
return
address(metadataDescriptor) != address(0) ?
metadataDescriptor.constructContractURI() :
bytes(baseURI).length > 0 ?
string(abi.encodePacked(baseURI, "contract/", Strings.toHexString(address(this)))) :
"";
}
function slotURI(uint256 slot_) public view virtual override returns (string memory) {
string memory baseURI = _baseURI();
return
address(metadataDescriptor) != address(0) ?
metadataDescriptor.constructSlotURI(slot_) :
bytes(baseURI).length > 0 ?
string(abi.encodePacked(baseURI, "slot/", slot_.toString())) :
"";
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId_) public view virtual override returns (string memory) {
_requireMinted(tokenId_);
string memory baseURI = _baseURI();
return
address(metadataDescriptor) != address(0) ?
metadataDescriptor.constructTokenURI(tokenId_) :
bytes(baseURI).length > 0 ?
string(abi.encodePacked(baseURI, tokenId_.toString())) :
"";
}
function approve(uint256 tokenId_, address to_, uint256 value_) public payable virtual override {
address owner = ERC3525.ownerOf(tokenId_);
require(to_ != owner, "ERC3525: approval to current owner");
require(_isApprovedOrOwner(_msgSender(), tokenId_), "ERC3525: approve caller is not owner nor approved");
_approveValue(tokenId_, to_, value_);
}
function allowance(uint256 tokenId_, address operator_) public view virtual override returns (uint256) {
_requireMinted(tokenId_);
return _approvedValues[tokenId_][operator_];
}
function transferFrom(
uint256 fromTokenId_,
address to_,
uint256 value_
) public payable virtual override returns (uint256 newTokenId) {
_spendAllowance(_msgSender(), fromTokenId_, value_);
newTokenId = _createDerivedTokenId(fromTokenId_);
_mint(to_, newTokenId, ERC3525.slotOf(fromTokenId_), 0);
_transferValue(fromTokenId_, newTokenId, value_);
}
function transferFrom(
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 value_
) public payable virtual override {
_spendAllowance(_msgSender(), fromTokenId_, value_);
_transferValue(fromTokenId_, toTokenId_, value_);
}
function balanceOf(address owner_) public view virtual override returns (uint256 balance) {
require(owner_ != address(0), "ERC3525: balance query for the zero address");
return _addressData[owner_].ownedTokens.length;
}
function transferFrom(
address from_,
address to_,
uint256 tokenId_
) public payable virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId_), "ERC3525: transfer caller is not owner nor approved");
_transferTokenId(from_, to_, tokenId_);
}
function safeTransferFrom(
address from_,
address to_,
uint256 tokenId_,
bytes memory data_
) public payable virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId_), "ERC3525: transfer caller is not owner nor approved");
_safeTransferTokenId(from_, to_, tokenId_, data_);
}
function safeTransferFrom(
address from_,
address to_,
uint256 tokenId_
) public payable virtual override {
safeTransferFrom(from_, to_, tokenId_, "");
}
function approve(address to_, uint256 tokenId_) public payable virtual override {
address owner = ERC3525.ownerOf(tokenId_);
require(to_ != owner, "ERC3525: approval to current owner");
require(
_msgSender() == owner || ERC3525.isApprovedForAll(owner, _msgSender()),
"ERC3525: approve caller is not owner nor approved for all"
);
_approve(to_, tokenId_);
}
function getApproved(uint256 tokenId_) public view virtual override returns (address) {
_requireMinted(tokenId_);
return _allTokens[_allTokensIndex[tokenId_]].approved;
}
function setApprovalForAll(address operator_, bool approved_) public virtual override {
_setApprovalForAll(_msgSender(), operator_, approved_);
}
function isApprovedForAll(address owner_, address operator_) public view virtual override returns (bool) {
return _addressData[owner_].approvals[operator_];
}
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
function tokenByIndex(uint256 index_) public view virtual override returns (uint256) {
require(index_ < ERC3525.totalSupply(), "ERC3525: global index out of bounds");
return _allTokens[index_].id;
}
function tokenOfOwnerByIndex(address owner_, uint256 index_) public view virtual override returns (uint256) {
require(index_ < ERC3525.balanceOf(owner_), "ERC3525: owner index out of bounds");
return _addressData[owner_].ownedTokens[index_];
}
function _setApprovalForAll(
address owner_,
address operator_,
bool approved_
) internal virtual {
require(owner_ != operator_, "ERC3525: approve to caller");
_addressData[owner_].approvals[operator_] = approved_;
emit ApprovalForAll(owner_, operator_, approved_);
}
function _isApprovedOrOwner(address operator_, uint256 tokenId_) internal view virtual returns (bool) {
address owner = ERC3525.ownerOf(tokenId_);
return (
operator_ == owner ||
ERC3525.isApprovedForAll(owner, operator_) ||
ERC3525.getApproved(tokenId_) == operator_
);
}
function _spendAllowance(address operator_, uint256 tokenId_, uint256 value_) internal virtual {
uint256 currentAllowance = ERC3525.allowance(tokenId_, operator_);
if (!_isApprovedOrOwner(operator_, tokenId_) && currentAllowance != type(uint256).max) {
require(currentAllowance >= value_, "ERC3525: insufficient allowance");
_approveValue(tokenId_, operator_, currentAllowance - value_);
}
}
function _exists(uint256 tokenId_) internal view virtual returns (bool) {
return _allTokens.length != 0 && _allTokens[_allTokensIndex[tokenId_]].id == tokenId_;
}
function _requireMinted(uint256 tokenId_) internal view virtual {
require(_exists(tokenId_), "ERC3525: invalid token ID");
}
function _mint(address to_, uint256 slot_, uint256 value_) internal virtual returns (uint256 tokenId) {
tokenId = _createOriginalTokenId();
_mint(to_, tokenId, slot_, value_);
}
function _mint(address to_, uint256 tokenId_, uint256 slot_, uint256 value_) internal virtual {
require(to_ != address(0), "ERC3525: mint to the zero address");
require(tokenId_ != 0, "ERC3525: cannot mint zero tokenId");
require(!_exists(tokenId_), "ERC3525: token already minted");
_beforeValueTransfer(address(0), to_, 0, tokenId_, slot_, value_);
__mintToken(to_, tokenId_, slot_);
__mintValue(tokenId_, value_);
_afterValueTransfer(address(0), to_, 0, tokenId_, slot_, value_);
}
function _mintValue(uint256 tokenId_, uint256 value_) internal virtual {
address owner = ERC3525.ownerOf(tokenId_);
uint256 slot = ERC3525.slotOf(tokenId_);
_beforeValueTransfer(address(0), owner, 0, tokenId_, slot, value_);
__mintValue(tokenId_, value_);
_afterValueTransfer(address(0), owner, 0, tokenId_, slot, value_);
}
function __mintValue(uint256 tokenId_, uint256 value_) private {
_allTokens[_allTokensIndex[tokenId_]].balance += value_;
emit TransferValue(0, tokenId_, value_);
}
function __mintToken(address to_, uint256 tokenId_, uint256 slot_) private {
TokenData memory tokenData = TokenData({
id: tokenId_,
slot: slot_,
balance: 0,
owner: to_,
approved: address(0),
valueApprovals: new address[](0)
});
_addTokenToAllTokensEnumeration(tokenData);
_addTokenToOwnerEnumeration(to_, tokenId_);
emit Transfer(address(0), to_, tokenId_);
emit SlotChanged(tokenId_, 0, slot_);
}
function _burn(uint256 tokenId_) internal virtual {
_requireMinted(tokenId_);
TokenData storage tokenData = _allTokens[_allTokensIndex[tokenId_]];
address owner = tokenData.owner;
uint256 slot = tokenData.slot;
uint256 value = tokenData.balance;
_beforeValueTransfer(owner, address(0), tokenId_, 0, slot, value);
_clearApprovedValues(tokenId_);
_removeTokenFromOwnerEnumeration(owner, tokenId_);
_removeTokenFromAllTokensEnumeration(tokenId_);
emit TransferValue(tokenId_, 0, value);
emit SlotChanged(tokenId_, slot, 0);
emit Transfer(owner, address(0), tokenId_);
_afterValueTransfer(owner, address(0), tokenId_, 0, slot, value);
}
function _burnValue(uint256 tokenId_, uint256 burnValue_) internal virtual {
_requireMinted(tokenId_);
TokenData storage tokenData = _allTokens[_allTokensIndex[tokenId_]];
address owner = tokenData.owner;
uint256 slot = tokenData.slot;
uint256 value = tokenData.balance;
require(value >= burnValue_, "ERC3525: burn value exceeds balance");
_beforeValueTransfer(owner, address(0), tokenId_, 0, slot, burnValue_);
tokenData.balance -= burnValue_;
emit TransferValue(tokenId_, 0, burnValue_);
_afterValueTransfer(owner, address(0), tokenId_, 0, slot, burnValue_);
}
function _addTokenToOwnerEnumeration(address to_, uint256 tokenId_) private {
_allTokens[_allTokensIndex[tokenId_]].owner = to_;
_addressData[to_].ownedTokensIndex[tokenId_] = _addressData[to_].ownedTokens.length;
_addressData[to_].ownedTokens.push(tokenId_);
}
function _removeTokenFromOwnerEnumeration(address from_, uint256 tokenId_) private {
_allTokens[_allTokensIndex[tokenId_]].owner = address(0);
AddressData storage ownerData = _addressData[from_];
uint256 lastTokenIndex = ownerData.ownedTokens.length - 1;
uint256 lastTokenId = ownerData.ownedTokens[lastTokenIndex];
uint256 tokenIndex = ownerData.ownedTokensIndex[tokenId_];
ownerData.ownedTokens[tokenIndex] = lastTokenId;
ownerData.ownedTokensIndex[lastTokenId] = tokenIndex;
delete ownerData.ownedTokensIndex[tokenId_];
ownerData.ownedTokens.pop();
}
function _addTokenToAllTokensEnumeration(TokenData memory tokenData_) private {
_allTokensIndex[tokenData_.id] = _allTokens.length;
_allTokens.push(tokenData_);
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId_) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId_];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
TokenData memory lastTokenData = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenData; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenData.id] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete _allTokensIndex[tokenId_];
_allTokens.pop();
}
function _approve(address to_, uint256 tokenId_) internal virtual {
_allTokens[_allTokensIndex[tokenId_]].approved = to_;
emit Approval(ERC3525.ownerOf(tokenId_), to_, tokenId_);
}
function _approveValue(
uint256 tokenId_,
address to_,
uint256 value_
) internal virtual {
require(to_ != address(0), "ERC3525: approve value to the zero address");
if (!_existApproveValue(to_, tokenId_)) {
_allTokens[_allTokensIndex[tokenId_]].valueApprovals.push(to_);
}
_approvedValues[tokenId_][to_] = value_;
emit ApprovalValue(tokenId_, to_, value_);
}
function _clearApprovedValues(uint256 tokenId_) internal virtual {
TokenData storage tokenData = _allTokens[_allTokensIndex[tokenId_]];
uint256 length = tokenData.valueApprovals.length;
for (uint256 i = 0; i < length; i++) {
address approval = tokenData.valueApprovals[i];
delete _approvedValues[tokenId_][approval];
}
delete tokenData.valueApprovals;
}
function _existApproveValue(address to_, uint256 tokenId_) internal view virtual returns (bool) {
uint256 length = _allTokens[_allTokensIndex[tokenId_]].valueApprovals.length;
for (uint256 i = 0; i < length; i++) {
if (_allTokens[_allTokensIndex[tokenId_]].valueApprovals[i] == to_) {
return true;
}
}
return false;
}
function _transferValue(
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 value_
) internal virtual {
require(_exists(fromTokenId_), "ERC3525: transfer from invalid token ID");
require(_exists(toTokenId_), "ERC3525: transfer to invalid token ID");
TokenData storage fromTokenData = _allTokens[_allTokensIndex[fromTokenId_]];
TokenData storage toTokenData = _allTokens[_allTokensIndex[toTokenId_]];
require(fromTokenData.balance >= value_, "ERC3525: insufficient balance for transfer");
require(fromTokenData.slot == toTokenData.slot, "ERC3525: transfer to token with different slot");
_beforeValueTransfer(
fromTokenData.owner,
toTokenData.owner,
fromTokenId_,
toTokenId_,
fromTokenData.slot,
value_
);
fromTokenData.balance -= value_;
toTokenData.balance += value_;
emit TransferValue(fromTokenId_, toTokenId_, value_);
_afterValueTransfer(
fromTokenData.owner,
toTokenData.owner,
fromTokenId_,
toTokenId_,
fromTokenData.slot,
value_
);
require(
_checkOnERC3525Received(fromTokenId_, toTokenId_, value_, ""),
"ERC3525: transfer rejected by ERC3525Receiver"
);
}
function _transferTokenId(
address from_,
address to_,
uint256 tokenId_
) internal virtual {
require(ERC3525.ownerOf(tokenId_) == from_, "ERC3525: transfer from invalid owner");
require(to_ != address(0), "ERC3525: transfer to the zero address");
uint256 slot = ERC3525.slotOf(tokenId_);
uint256 value = ERC3525.balanceOf(tokenId_);
_beforeValueTransfer(from_, to_, tokenId_, tokenId_, slot, value);
_approve(address(0), tokenId_);
_clearApprovedValues(tokenId_);
_removeTokenFromOwnerEnumeration(from_, tokenId_);
_addTokenToOwnerEnumeration(to_, tokenId_);
emit Transfer(from_, to_, tokenId_);
_afterValueTransfer(from_, to_, tokenId_, tokenId_, slot, value);
}
function _safeTransferTokenId(
address from_,
address to_,
uint256 tokenId_,
bytes memory data_
) internal virtual {
_transferTokenId(from_, to_, tokenId_);
require(
_checkOnERC721Received(from_, to_, tokenId_, data_),
"ERC3525: transfer to non ERC721Receiver"
);
}
function _checkOnERC3525Received(
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 value_,
bytes memory data_
) private returns (bool) {
address to = ERC3525.ownerOf(toTokenId_);
if (to.isContract() && IERC165(to).supportsInterface(type(IERC3525Receiver).interfaceId)) {
bytes4 retval = IERC3525Receiver(to).onERC3525Received(_msgSender(), fromTokenId_, toTokenId_, value_, data_);
return retval == IERC3525Receiver.onERC3525Received.selector;
} else {
return true;
}
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from_ address representing the previous owner of the given token ID
* @param to_ target address that will receive the tokens
* @param tokenId_ uint256 ID of the token to be transferred
* @param data_ bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(
address from_,
address to_,
uint256 tokenId_,
bytes memory data_
) private returns (bool) {
if (to_.isContract()) {
try
IERC721Receiver(to_).onERC721Received(_msgSender(), from_, tokenId_, data_) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
/* solhint-disable */
function _beforeValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual {}
function _afterValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual {}
/* solhint-enable */
function _setMetadataDescriptor(address metadataDescriptor_) internal virtual {
metadataDescriptor = IERC3525MetadataDescriptor(metadataDescriptor_);
emit SetMetadataDescriptor(metadataDescriptor_);
}
function _createOriginalTokenId() internal virtual returns (uint256) {
_tokenIdGenerator.increment();
return _tokenIdGenerator.current();
}
function _createDerivedTokenId(uint256 fromTokenId_) internal virtual returns (uint256) {
fromTokenId_;
return _createOriginalTokenId();
}
}
// File @openzeppelin/contracts/access/Ownable.sol@v4.9.2
//
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File @openzeppelin/contracts/security/ReentrancyGuard.sol@v4.9.2
//
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @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;
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
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// 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;
}
}
// File contracts/HomelessCard.sol
//
pragma solidity ^0.8.9;
contract HomelessCard is ERC3525, Ownable, ReentrancyGuard {
address public homelessDog;
uint256 public totalShare;
uint256 public constant SLOT = 0;
modifier onlyHomeless() {
require(msg.sender == homelessDog, "Not granted");
_;
}
constructor(address homelessDog_) ERC3525("HomelessCard", "HomelessCard", 18) {
homelessDog = homelessDog_;
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
ownerOf(tokenId);
return "https://homelessdog.infura-ipfs.io/ipfs/Qmaq8XCfs9xPdnmG2mbvpWE7hMQ4NpSZd5GqZYnkUgiuVU";
}
function mint(address to, uint256 value) external payable onlyHomeless {
totalShare += value;
uint256 tokenId;
if (balanceOf(to) > 0) {
tokenId = tokenOfOwnerByIndex(to, 0);
ERC3525._mintValue(tokenId, value);
} else {
tokenId = _createOriginalTokenId();
ERC3525._mint(to, tokenId, SLOT, value);
}
}
function burnValue(uint256 tokenId_, uint256 burnValue_) external nonReentrant {
require(_isApprovedOrOwner(_msgSender(), tokenId_), "ERC3525: caller is not token owner nor approved");
require(burnValue_ > 0, "burnValue is zero");
ERC3525._burnValue(tokenId_, burnValue_);
uint256 ethAmount = (address(this).balance * burnValue_) / totalShare;
totalShare -= burnValue_;
(bool success, ) = _msgSender().call{value: ethAmount}("");
require(success, "Unable to send value");
}
}
{
"compilationTarget": {
"HomelessCard.sol": "HomelessCard"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"homelessDog_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":false,"internalType":"bool","name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"ApprovalValue","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"metadataDescriptor","type":"address"}],"name":"SetMetadataDescriptor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_oldSlot","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_newSlot","type":"uint256"}],"name":"SlotChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_toTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"TransferValue","type":"event"},{"inputs":[],"name":"SLOT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"address","name":"operator_","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"burnValue_","type":"uint256"}],"name":"burnValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"homelessDog","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"operator_","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataDescriptor","outputs":[{"internalType":"contract IERC3525MetadataDescriptor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"slotOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"slotURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index_","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint256","name":"index_","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTokenId_","type":"uint256"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"uint256","name":"newTokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTokenId_","type":"uint256"},{"internalType":"uint256","name":"toTokenId_","type":"uint256"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"valueDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]