Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
OpenFundShareConcrete
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@solvprotocol/contracts-v3-sft-earn/contracts/EarnConcrete.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/value-issuable/SFTValueIssuableConcrete.sol";
import "./IOpenFundShareConcrete.sol";
error BurnNotAllowed();
contract OpenFundShareConcrete is IOpenFundShareConcrete, EarnConcrete, SFTValueIssuableConcrete {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function _burn(uint256 tokenId_, uint256 burnValue_) internal virtual override {
uint256 slot = IERC3525Upgradeable(delegate()).slotOf(tokenId_);
SlotExtInfo storage slotExtInfo = _slotExtInfos[slot];
if (slotExtInfo.isInterestRateSet) {
revert BurnNotAllowed();
}
if (burnValue_ > 0) {
uint256 tokenBalance = IERC3525Upgradeable(delegate()).balanceOf(tokenId_);
uint256 burnTokenInitialValue = burnValue_ * _tokenRepayInfo[tokenId_].initialValue / tokenBalance;
_tokenRepayInfo[tokenId_].initialValue -= burnTokenInitialValue;
_slotRepayInfo[slot].initialValue -= burnTokenInitialValue;
_slotRepayInfo[slot].totalValue -= burnValue_;
}
}
function _beforeMint(uint256 /** tokenId_ */, uint256 /** slot_ */, uint256 /** mintValue_ */) internal virtual override {
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @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 ReentrancyGuardUpgradeable is Initializable {
// 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;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_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 This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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
* ====
*
* [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://diligence.consensys.net/posts/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.5.11/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 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);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// 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 CountersUpgradeable {
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;
}
}// 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 IERC165Upgradeable {
/**
* @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 v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
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) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 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 10, 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 * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
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 = MathUpgradeable.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 `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*
* _Available since v4.5._
*/
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 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;
}
}// 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 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 10, 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 * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @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 `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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAddressResolver {
function getAddress(bytes32 name) external view returns (address);
function getRequiredAddress(bytes32 name, string calldata reason) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./IAddressResolver.sol";
abstract contract ResolverCache is Initializable {
IAddressResolver public resolver;
mapping(bytes32 => address) private _addressCache;
function __ResolverCache_init(address resolver_) internal onlyInitializing {
resolver = IAddressResolver(resolver_);
}
function getAddress(bytes32 name_) public view returns (address) {
return _addressCache[name_];
}
function getRequiredAddress(bytes32 name_, string memory reason_) public view returns (address) {
address addr = getAddress(name_);
require(addr != address(0), reason_);
return addr;
}
function rebuildCache() public virtual {
bytes32[] memory requiredAddresses = _resolverAddressesRequired();
for (uint256 i = 0; i < requiredAddresses.length; i++) {
bytes32 name = requiredAddresses[i];
address addr = resolver.getRequiredAddress(name, "AddressCache: address not found");
_addressCache[name] = addr;
}
}
function isResolverCached() external view returns (bool) {
bytes32[] memory requiredAddresses = _resolverAddressesRequired();
for (uint256 i = 0; i < requiredAddresses.length; i++) {
bytes32 name = requiredAddresses[i];
// false if our cache is invalid or if the resolver doesn't have the required address
if (resolver.getAddress(name) != _addressCache[name] || _addressCache[name] == address(0)) {
return false;
}
}
return true;
}
function _combineArrays(bytes32[] memory first, bytes32[] memory second)
internal
pure
returns (bytes32[] memory combination)
{
combination = new bytes32[](first.length + second.length);
for (uint i = 0; i < first.length; i++) {
combination[i] = first[i];
}
for (uint j = 0; j < second.length; j++) {
combination[first.length + j] = second[j];
}
}
function _resolverAddressesRequired() internal view virtual returns (bytes32[] memory addresses) {}
uint256[48] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOpenFundMarketStorage {
struct SFTInfo {
address manager;
bool isValid;
}
struct SubscribeLimitInfo {
uint256 hardCap;
uint256 subscribeMin;
uint256 subscribeMax;
uint64 fundraisingStartTime;
uint64 fundraisingEndTime;
}
struct PoolSFTInfo {
address openFundShare;
address openFundRedemption;
uint256 openFundShareSlot;
uint256 latestRedeemSlot;
}
struct PoolFeeInfo {
uint16 carryRate;
address carryCollector;
uint64 latestProtocolFeeSettleTime;
}
struct ManagerInfo {
address poolManager;
address subscribeNavManager;
address redeemNavManager;
}
struct PoolInfo {
PoolSFTInfo poolSFTInfo;
PoolFeeInfo poolFeeInfo;
ManagerInfo managerInfo;
SubscribeLimitInfo subscribeLimitInfo;
address vault;
address currency;
address navOracle;
uint64 valueDate;
bool permissionless;
uint256 fundraisingAmount;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/GovernorControl.sol";
import "./IOpenFundMarketStorage.sol";
contract OpenFundMarketStorage is IOpenFundMarketStorage, GovernorControl {
// keccak256(openFundSFT, openFundSlot)
mapping(bytes32 => PoolInfo) public poolInfos;
// keccak256(openFundSFT, openFundSlot) => buyer => purchased amount
mapping(bytes32 => mapping(address => uint256)) public purchasedRecords;
// redeemSlot => close time
mapping(uint256 => uint256) public poolRedeemSlotCloseTime;
// redeemSlot => openFundTokenId
mapping(uint256 => uint256) internal _poolRedeemTokenId;
mapping(address => bool) public currencies;
mapping(address => SFTInfo) public sftInfos;
uint256 public protocolFeeRate;
address public protocolFeeCollector;
mapping(bytes32 => uint256) public previousRedeemSlot;
uint256[42] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface INavOracle {
event SetSubscribeNav(bytes32 indexed poolId, uint256 indexed time, uint256 nav);
event UpdateAllTimeHighRedeemNav(bytes32 indexed poolId, uint256 oldNav, uint256 newNav);
function setSubscribeNavOnlyMarket(bytes32 poolId_, uint256 time_, uint256 nav_) external;
function updateAllTimeHighRedeemNavOnlyMarket(bytes32 poolId_, uint256 nav_) external;
function getSubscribeNav(bytes32 poolId_, uint256 time_) external view returns (uint256 nav_, uint256 navTime_);
function getAllTimeHighRedeemNav(bytes32 poolId_) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Constants.sol";
import "@solvprotocol/erc-3525/ERC3525Upgradeable.sol";
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTConcreteUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./IFCFSMultiRepayableConcrete.sol";
abstract contract FCFSMultiRepayableConcrete is IFCFSMultiRepayableConcrete, BaseSFTConcreteUpgradeable {
mapping(uint256 => SlotRepayInfo) internal _slotRepayInfo;
mapping(address => uint256) public allocatedCurrencyBalance;
uint32 internal constant REPAY_RATE_SCALAR = 1e8;
mapping(uint256 => SlotValueInfo) internal _slotValueInfo;
function repayOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override onlyDelegate {
_beforeRepay(txSender_, slot_, currency_, repayCurrencyAmount_);
_slotRepayInfo[slot_].repaidCurrencyAmount += repayCurrencyAmount_;
_slotRepayInfo[slot_].currencyBalance += repayCurrencyAmount_;
allocatedCurrencyBalance[currency_] += repayCurrencyAmount_;
}
function repayWithBalanceOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override onlyDelegate {
_beforeRepayWithBalance(txSender_, slot_, currency_, repayCurrencyAmount_);
uint256 balance = ERC20(currency_).balanceOf(delegate());
require(repayCurrencyAmount_ <= balance - allocatedCurrencyBalance[currency_], "MultiRepayableConcrete: insufficient unallocated balance");
_slotRepayInfo[slot_].repaidCurrencyAmount += repayCurrencyAmount_;
_slotRepayInfo[slot_].currencyBalance += repayCurrencyAmount_;
allocatedCurrencyBalance[currency_] += repayCurrencyAmount_;
}
function mintOnlyDelegate(uint256 /** tokenId_ */, uint256 slot_, uint256 mintValue_) external virtual override onlyDelegate {
_slotValueInfo[slot_].slotInitialValue += mintValue_;
_slotValueInfo[slot_].slotTotalValue += mintValue_;
}
function claimOnlyDelegate(uint256 tokenId_, uint256 slot_, address currency_, uint256 claimValue_) external virtual override onlyDelegate returns (uint256 claimCurrencyAmount_) {
_beforeClaim(tokenId_, slot_, currency_, claimValue_);
require(claimValue_ <= claimableValue(tokenId_), "MR: insufficient claimable value");
_slotValueInfo[slot_].slotTotalValue -= claimValue_;
uint8 valueDecimals = ERC3525Upgradeable(delegate()).valueDecimals();
claimCurrencyAmount_ = claimValue_ * _repayRate(slot_) / (10 ** valueDecimals);
require(claimCurrencyAmount_ <= _slotRepayInfo[slot_].currencyBalance, "MR: insufficient repaid currency amount");
allocatedCurrencyBalance[currency_] -= claimCurrencyAmount_;
_slotRepayInfo[slot_].currencyBalance -= claimCurrencyAmount_;
}
function transferOnlyDelegate(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromTokenBalance_, uint256 transferValue_) external virtual override onlyDelegate {
_beforeTransfer(fromTokenId_, toTokenId_, fromTokenBalance_, transferValue_);
}
function claimableValue(uint256 tokenId_) public view virtual override returns (uint256) {
uint256 slot = ERC3525Upgradeable(delegate()).slotOf(tokenId_);
uint256 balance = ERC3525Upgradeable(delegate()).balanceOf(tokenId_);
uint8 valueDecimals = ERC3525Upgradeable(delegate()).valueDecimals();
uint256 dueAmount = balance * _repayRate(slot) / (10 ** valueDecimals);
return dueAmount < _slotRepayInfo[slot].currencyBalance ? balance :
_slotRepayInfo[slot].currencyBalance * (10 ** valueDecimals) / _repayRate(slot);
}
function slotRepaidCurrencyAmount(uint256 slot_) public view virtual override returns (uint256) {
return _slotRepayInfo[slot_].repaidCurrencyAmount;
}
function slotCurrencyBalance(uint256 slot_) public view virtual override returns (uint256) {
return _slotRepayInfo[slot_].currencyBalance;
}
function slotInitialValue(uint256 slot_) public view virtual override returns (uint256) {
return _slotValueInfo[slot_].slotInitialValue;
}
function slotTotalValue(uint256 slot_) public view virtual override returns (uint256) {
return _slotValueInfo[slot_].slotTotalValue;
}
function _currency(uint256 slot_) internal view virtual returns (address);
function _repayRate(uint256 slot_) internal view virtual returns (uint256);
function _beforeRepay(address /** txSender_ */, uint256 slot_, address currency_, uint256 /** repayCurrencyAmount_ */) internal virtual {
require(currency_ == _currency(slot_), "FMR: invalid currency");
}
function _beforeRepayWithBalance(address /** txSender_ */, uint256 slot_, address currency_, uint256 /** repayCurrencyAmount_ */) internal virtual {
require(currency_ == _currency(slot_), "FMR: invalid currency");
}
function _beforeClaim(uint256 /** tokenId_ */, uint256 slot_, address currency_, uint256 /** claimValue_ */) internal virtual {
require(currency_ == _currency(slot_), "FMR: invalid currency");
}
function _beforeTransfer(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromTokenBalance_, uint256 transferValue_) internal virtual {}
uint256[46] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTDelegateUpgradeable.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/helpers/ERC20TransferHelper.sol";
import "./IFCFSMultiRepayableDelegate.sol";
import "./IFCFSMultiRepayableConcrete.sol";
abstract contract FCFSMultiRepayableDelegate is IFCFSMultiRepayableDelegate, BaseSFTDelegateUpgradeable {
function repay(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override nonReentrant {
IFCFSMultiRepayableConcrete(concrete()).repayOnlyDelegate(_msgSender(), slot_, currency_, repayCurrencyAmount_);
ERC20TransferHelper.doTransferIn(currency_, _msgSender(), repayCurrencyAmount_);
emit Repay(slot_, _msgSender(), currency_, repayCurrencyAmount_);
}
function repayWithBalance(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override nonReentrant {
require(allowRepayWithBalance(), "MultiRepayableDelegate: cannot repay with balance");
IFCFSMultiRepayableConcrete(concrete()).repayWithBalanceOnlyDelegate(_msgSender(), slot_, currency_, repayCurrencyAmount_);
emit Repay(slot_, _msgSender(), currency_, repayCurrencyAmount_);
}
function claimTo(address to_, uint256 tokenId_, address currency_, uint256 claimValue_) external virtual override nonReentrant {
require(claimValue_ > 0, "MultiRepayableDelegate: claim value is zero");
require(_isApprovedOrOwner(_msgSender(), tokenId_), "MultiRepayableDelegate: caller is not owner nor approved");
uint256 slot = ERC3525Upgradeable.slotOf(tokenId_);
uint256 claimableValue = IFCFSMultiRepayableConcrete(concrete()).claimableValue(tokenId_);
require(claimValue_ <= claimableValue, "MultiRepayableDelegate: over claim");
uint256 claimCurrencyAmount = IFCFSMultiRepayableConcrete(concrete()).claimOnlyDelegate(tokenId_, slot, currency_, claimValue_);
if (claimValue_ == ERC3525Upgradeable.balanceOf(tokenId_)) {
ERC3525Upgradeable._burn(tokenId_);
} else {
ERC3525Upgradeable._burnValue(tokenId_, claimValue_);
}
ERC20TransferHelper.doTransferOut(currency_, payable(to_), claimCurrencyAmount);
emit Claim(to_, tokenId_, claimValue_, currency_, claimCurrencyAmount);
}
function _beforeValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual override(ERC3525SlotEnumerableUpgradeable) {
super._beforeValueTransfer(from_, to_, fromTokenId_, toTokenId_, slot_, value_);
if (from_ == address(0) && fromTokenId_ == 0) {
IFCFSMultiRepayableConcrete(concrete()).mintOnlyDelegate(toTokenId_, slot_, value_);
}
if (from_ != address(0) && fromTokenId_ != 0 && to_ != address(0) && toTokenId_ != 0) {
IFCFSMultiRepayableConcrete(concrete()).transferOnlyDelegate(fromTokenId_, toTokenId_,
ERC3525Upgradeable.balanceOf(fromTokenId_), value_);
}
}
function allowRepayWithBalance() public view virtual returns (bool) {
return true;
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IFCFSMultiRepayableConcrete {
struct SlotRepayInfo {
uint256 repaidCurrencyAmount;
uint256 currencyBalance;
}
struct SlotValueInfo {
uint256 slotInitialValue;
uint256 slotTotalValue;
}
function repayOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function repayWithBalanceOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function mintOnlyDelegate(uint256 tokenId_, uint256 slot_, uint256 mintValue_) external;
function claimOnlyDelegate(uint256 tokenId_, uint256 slot_, address currency_, uint256 claimValue_) external returns (uint256);
function transferOnlyDelegate(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromTokenBalance_, uint256 transferValue_) external;
function slotRepaidCurrencyAmount(uint256 slot_) external view returns (uint256);
function slotCurrencyBalance(uint256 slot_) external view returns (uint256);
function slotInitialValue(uint256 slot_) external view returns (uint256);
function slotTotalValue(uint256 slot_) external view returns (uint256);
function claimableValue(uint256 tokenId_) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IFCFSMultiRepayableDelegate {
event Repay(uint256 indexed slot, address indexed payer, address currency, uint256 repayCurrencyAmount);
event Claim(address indexed to, uint256 indexed tokenId, uint256 claimValue, address currency, uint256 claimCurrencyAmount);
function repay(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function repayWithBalance(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function claimTo(address to_, uint256 tokenId_, address currency_, uint256 claimValue_) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISFTIssuableConcrete {
function createSlotOnlyDelegate(address txSender_, bytes calldata inputSlotInfo_) external returns (uint256 slot_);
function mintOnlyDelegate(address txSender_, address currency_, address mintTo_, uint256 slot_, uint256 tokenId_, uint256 amount_) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISFTIssuableDelegate {
function createSlotOnlyIssueMarket(address txSender, bytes calldata inputSlotInfo) external returns(uint256 slot);
function mintOnlyIssueMarket(address txSender, address currency, address mintTo, uint256 slot, uint256 value) external payable returns(uint256 tokenId);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTConcreteUpgradeable.sol";
import "./ISFTIssuableDelegate.sol";
import "./ISFTIssuableConcrete.sol";
abstract contract SFTIssuableConcrete is ISFTIssuableConcrete, BaseSFTConcreteUpgradeable {
function __SFTIssuableConcrete_init() internal onlyInitializing {
__BaseSFTConcrete_init();
}
function __SFTIssuableConcrete_init_unchained() internal onlyInitializing {
}
function createSlotOnlyDelegate(address txSender_, bytes calldata inputSlotInfo_) external virtual override onlyDelegate returns (uint256 slot_) {
slot_ = _createSlot(txSender_, inputSlotInfo_);
require(slot_ != 0, "SFTIssuableConcrete: invalid slot");
}
function mintOnlyDelegate(address txSender_, address currency_, address mintTo_, uint256 slot_, uint256 tokenId_, uint256 amount_)
external virtual override onlyDelegate {
_mint(txSender_, currency_, mintTo_, slot_, tokenId_, amount_);
}
function _createSlot(address txSender_, bytes memory inputSlotInfo_) internal virtual returns (uint256 slot_);
function _mint(address txSender_, address currency_, address mintTo_, uint256 slot_, uint256 tokenId_, uint256 amount_) internal virtual;
uint256[50] private __gap;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Constants.sol";
import "@solvprotocol/contracts-v3-address-resolver/contracts/ResolverCache.sol";
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTDelegateUpgradeable.sol";
import "./ISFTIssuableDelegate.sol";
import "./ISFTIssuableConcrete.sol";
abstract contract SFTIssuableDelegate is ISFTIssuableDelegate, BaseSFTDelegateUpgradeable, ResolverCache {
function __SFTIssuableDelegate_init(address resolver_, string memory name_, string memory symbol_, uint8 decimals_,
address concrete_, address metadata_, address owner_) internal onlyInitializing {
__BaseSFTDelegate_init(name_, symbol_, decimals_, concrete_, metadata_, owner_);
__ResolverCache_init(resolver_);
}
function __SFTIssuableDelegate_init_unchained() internal onlyInitializing {
}
function createSlotOnlyIssueMarket(address txSender_, bytes calldata inputSlotInfo_) external virtual override nonReentrant returns(uint256 slot_) {
require(_msgSender() == _issueMarket(), "SFTIssuableDelegate: only issue market");
slot_ = ISFTIssuableConcrete(concrete()).createSlotOnlyDelegate(txSender_, inputSlotInfo_);
require(!_slotExists(slot_), "SFTIssuableDelegate: slot already exists");
ERC3525SlotEnumerableUpgradeable._createSlot(slot_);
emit CreateSlot(slot_, txSender_, inputSlotInfo_);
}
function mintOnlyIssueMarket(address txSender_, address currency_, address mintTo_, uint256 slot_, uint256 value_) external payable virtual override nonReentrant returns(uint256 tokenId_) {
require(_msgSender() == _issueMarket(), "SFTIssuableDelegate: only issue market");
tokenId_ = ERC3525Upgradeable._mint(mintTo_, slot_, value_);
ISFTIssuableConcrete(concrete()).mintOnlyDelegate(txSender_, currency_, mintTo_, slot_, tokenId_, value_);
emit MintValue(tokenId_, slot_, value_);
}
function _resolverAddressesRequired() internal view virtual override returns (bytes32[] memory) {
bytes32[] memory existAddresses = super._resolverAddressesRequired();
bytes32[] memory newAddresses = new bytes32[](1);
newAddresses[0] = Constants.CONTRACT_ISSUE_MARKET;
return _combineArrays(existAddresses, newAddresses);
}
function _issueMarket() internal view virtual returns (address) {
return getRequiredAddress(Constants.CONTRACT_ISSUE_MARKET, "SFTIssuableDelegate: issueMarket not set");
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IMultiRechargeableConcrete {
struct SlotRechargeInfo {
uint256 totalValue; // accumulated minted value
uint256 rechargedAmount; // accumulated recharged currency amount
}
struct TokenClaimInfo {
uint256 claimedAmount; // accumulated claimed currency amount
}
function rechargeOnlyDelegate(uint256 slot_, address currency_, uint256 rechargeAmount_) external payable;
function mintOnlyDelegate(uint256 tokenId_, uint256 slot_, uint256 value_) external;
function claimOnlyDelegate(uint256 tokenId_, address currency_, uint256 amount_) external;
function transferOnlyDelegate(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromBalance_, uint256 value_) external;
function totalValue(uint256 slot_) external view returns (uint256);
function rechargedAmount(uint256 slot_) external view returns (uint256);
function claimedAmount(uint256 tokenId_) external view returns(uint256);
function claimableAmount(uint256 tokenId_) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/erc-3525/ERC3525Upgradeable.sol";
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTConcreteUpgradeable.sol";
import "./IMultiRechargeableConcrete.sol";
abstract contract MultiRechargeableConcrete is IMultiRechargeableConcrete, BaseSFTConcreteUpgradeable {
mapping(uint256 => SlotRechargeInfo) private _slotRechargeInfos;
mapping(uint256 => TokenClaimInfo) private _tokenClaimInfos;
function rechargeOnlyDelegate(uint256 slot_, address currency_, uint256 rechargeAmount_) external payable virtual override onlyDelegate {
require(currency_ == _currency(slot_), "MultiRechargeableConcrete: invalid currency");
_slotRechargeInfos[slot_].rechargedAmount += rechargeAmount_;
}
function mintOnlyDelegate(uint256 /** tokenId_ */, uint256 slot_, uint256 value_) external virtual override onlyDelegate {
require(_slotRechargeInfos[slot_].rechargedAmount == 0, "MultiRechargeableConcrete: already recharged");
_slotRechargeInfos[slot_].totalValue += value_;
}
function claimOnlyDelegate(uint256 tokenId_, address currency_, uint256 amount_) external virtual override onlyDelegate {
uint256 slot = ERC3525Upgradeable(delegate()).slotOf(tokenId_);
require(currency_ == _currency(slot), "MultiRechargeableConcrete: currency not supported");
uint256 claimable = claimableAmount(tokenId_);
require(amount_ <= claimable, "MultiRechargeableConcrete: insufficient amount to claim");
_tokenClaimInfos[tokenId_].claimedAmount += amount_;
}
function transferOnlyDelegate(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromBalance_, uint256 transferValue_) external virtual override onlyDelegate {
uint256 transferClaimedAmount = (transferValue_ * _tokenClaimInfos[fromTokenId_].claimedAmount) / fromBalance_;
_tokenClaimInfos[fromTokenId_].claimedAmount -= transferClaimedAmount;
_tokenClaimInfos[toTokenId_].claimedAmount += transferClaimedAmount;
}
function claimableAmount(uint256 tokenId_) public view virtual override returns (uint256) {
uint256 slot = ERC3525Upgradeable(delegate()).slotOf(tokenId_);
uint256 balance = ERC3525Upgradeable(delegate()).balanceOf(tokenId_);
SlotRechargeInfo storage slotRechargeInfo = _slotRechargeInfos[slot];
TokenClaimInfo storage tokenClaimInfo = _tokenClaimInfos[tokenId_];
return (balance * slotRechargeInfo.rechargedAmount) / slotRechargeInfo.totalValue - tokenClaimInfo.claimedAmount;
}
function totalValue(uint256 slot_) public view override returns (uint256) {
return _slotRechargeInfos[slot_].totalValue;
}
function rechargedAmount(uint256 slot_) public view override returns (uint256) {
return _slotRechargeInfos[slot_].rechargedAmount;
}
function claimedAmount(uint256 tokenId_) public view override returns(uint256) {
return _tokenClaimInfos[tokenId_].claimedAmount;
}
function _afterRecharge(uint256 slot_, uint256 value_) internal virtual {}
function _afterClaim(uint256 tokenId_, uint256 value_) internal virtual {}
function _currency(uint256 slot_) internal view virtual returns (address);
uint256[48] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IMultiRepayableConcrete {
struct SlotRepayInfo {
uint256 initialValue;
uint256 totalValue;
uint256 repaidCurrencyAmount;
}
struct TokenRepayInfo {
uint256 initialValue;
}
function repayOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function repayWithBalanceOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function mintOnlyDelegate(uint256 tokenId_, uint256 slot_, uint256 mintValue_) external;
function claimOnlyDelegate(uint256 tokenId_, uint256 slot_, address currency_, uint256 claimValue_) external returns (uint256);
function transferOnlyDelegate(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromTokenBalance_, uint256 transferValue_) external;
function slotInitialValue(uint256 slot_) external view returns (uint256);
function slotTotalValue(uint256 slot_) external view returns (uint256);
function repaidCurrencyAmount(uint256 slot_) external view returns (uint256);
function tokenInitialValue(uint256 tokenId_) external view returns (uint256);
function claimableValue(uint256 tokenId_) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IMultiRepayableDelegate {
event Repay(uint256 indexed slot, address indexed payer, uint256 repayCurrencyAmount);
event Claim(address indexed to, uint256 indexed tokenId, uint256 claimValue);
function repay(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function repayWithBalance(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable;
function claimTo(address to_, uint256 tokenId_, address currency_, uint256 claimValue_) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Constants.sol";
import "@solvprotocol/erc-3525/ERC3525Upgradeable.sol";
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTConcreteUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./IMultiRepayableConcrete.sol";
abstract contract MultiRepayableConcrete is IMultiRepayableConcrete, BaseSFTConcreteUpgradeable {
mapping(uint256 => SlotRepayInfo) internal _slotRepayInfo;
mapping(uint256 => TokenRepayInfo) internal _tokenRepayInfo;
// currency address => the portion of balance that has been allocated to any slots
mapping(address => uint256) public allocatedCurrencyBalance;
uint32 internal constant REPAY_RATE_SCALAR = 1e8;
function repayOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override onlyDelegate {
_beforeRepay(txSender_, slot_, currency_, repayCurrencyAmount_);
_slotRepayInfo[slot_].repaidCurrencyAmount += repayCurrencyAmount_;
allocatedCurrencyBalance[currency_] += repayCurrencyAmount_;
}
function repayWithBalanceOnlyDelegate(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override onlyDelegate {
_beforeRepayWithBalance(txSender_, slot_, currency_, repayCurrencyAmount_);
uint256 balance = ERC20(currency_).balanceOf(delegate());
require(repayCurrencyAmount_ <= balance - allocatedCurrencyBalance[currency_], "MultiRepayableConcrete: insufficient unallocated balance");
_slotRepayInfo[slot_].repaidCurrencyAmount += repayCurrencyAmount_;
allocatedCurrencyBalance[currency_] += repayCurrencyAmount_;
}
function mintOnlyDelegate(uint256 tokenId_, uint256 slot_, uint256 mintValue_) external virtual override onlyDelegate {
_beforeMint(tokenId_, slot_, mintValue_);
_slotRepayInfo[slot_].initialValue += mintValue_;
_slotRepayInfo[slot_].totalValue += mintValue_;
_tokenRepayInfo[tokenId_].initialValue += mintValue_;
}
function claimOnlyDelegate(uint256 tokenId_, uint256 slot_, address currency_, uint256 claimValue_) external virtual override onlyDelegate returns (uint256 claimCurrencyAmount_) {
_beforeClaim(tokenId_, slot_, currency_, claimValue_);
_slotRepayInfo[slot_].totalValue -= claimValue_;
uint8 valueDecimals = ERC3525Upgradeable(delegate()).valueDecimals();
uint8 currencyDecimals = ERC20(_currency(slot_)).decimals();
claimCurrencyAmount_ = claimValue_ * _repayRate(slot_) * (10 ** currencyDecimals) / Constants.FULL_PERCENTAGE / REPAY_RATE_SCALAR / (10 ** valueDecimals);
allocatedCurrencyBalance[currency_] -= claimCurrencyAmount_;
}
function transferOnlyDelegate(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromTokenBalance_, uint256 transferValue_) external virtual override onlyDelegate {
_beforeTransfer(fromTokenId_, toTokenId_, fromTokenBalance_, transferValue_);
uint256 transferInitialValue = 0;
if (fromTokenId_ != toTokenId_ && fromTokenBalance_ > 0) {
transferInitialValue = transferValue_ * _tokenRepayInfo[fromTokenId_].initialValue / fromTokenBalance_;
}
_tokenRepayInfo[fromTokenId_].initialValue -= transferInitialValue;
_tokenRepayInfo[toTokenId_].initialValue += transferInitialValue;
}
function slotInitialValue(uint256 slot_) public view returns (uint256) {
return _slotRepayInfo[slot_].initialValue;
}
function slotTotalValue(uint256 slot_) public view virtual override returns (uint256) {
return _slotRepayInfo[slot_].totalValue;
}
function repaidCurrencyAmount(uint256 slot_) public view virtual override returns (uint256) {
return _slotRepayInfo[slot_].repaidCurrencyAmount;
}
function tokenInitialValue(uint256 tokenId_) public view virtual override returns (uint256) {
return _tokenRepayInfo[tokenId_].initialValue;
}
function claimableValue(uint256 tokenId_) public view virtual override returns (uint256) {
uint256 slot = ERC3525Upgradeable(delegate()).slotOf(tokenId_);
uint256 balance = ERC3525Upgradeable(delegate()).balanceOf(tokenId_);
uint8 valueDecimals = ERC3525Upgradeable(delegate()).valueDecimals();
uint8 currencyDecimals = ERC20(_currency(slot)).decimals();
uint256 initialValueOfSlot = _slotRepayInfo[slot].initialValue;
uint256 initialValueOfToken = tokenInitialValue(tokenId_);
uint256 slotDueAmount = initialValueOfSlot * _repayRate(slot) * (10 ** currencyDecimals) / Constants.FULL_PERCENTAGE / REPAY_RATE_SCALAR / (10 ** valueDecimals);
uint256 slotRepaidAmount = repaidCurrencyAmount(slot);
uint256 tokenTotalClaimableValue = slotRepaidAmount >= slotDueAmount ? initialValueOfToken : initialValueOfToken * slotRepaidAmount / slotDueAmount;
uint256 tokenClaimedBalance = initialValueOfToken - balance;
return tokenTotalClaimableValue > tokenClaimedBalance ? tokenTotalClaimableValue - tokenClaimedBalance : 0;
}
function _currency(uint256 slot_) internal view virtual returns (address);
function _repayRate(uint256 slot_) internal view virtual returns (uint256);
function _beforeRepay(address /** txSender_ */, uint256 slot_, address currency_, uint256 /** repayCurrencyAmount_ */) internal virtual {
require(currency_ == _currency(slot_), "MultiRepayableConcrete: invalid currency");
}
function _beforeRepayWithBalance(address /** txSender_ */, uint256 slot_, address currency_, uint256 /** repayCurrencyAmount_ */) internal virtual {
require(currency_ == _currency(slot_), "MultiRepayableConcrete: invalid currency");
}
function _beforeMint(uint256 /** tokenId_ */, uint256 slot_, uint256 mintValue_) internal virtual {
// skip repayment check when minting in the process of transferring from id to address
if (mintValue_ > 0) {
require(repaidCurrencyAmount(slot_) == 0, "MultiRepayableConcrete: already repaid");
}
}
function _beforeClaim(uint256 /** tokenId_ */, uint256 slot_, address currency_, uint256 /** claimValue_ */) internal virtual {
require(currency_ == _currency(slot_), "MultiRepayableConcrete: invalid currency");
}
function _beforeTransfer(uint256 fromTokenId_, uint256 toTokenId_, uint256 fromTokenBalance_, uint256 transferValue_) internal virtual {}
uint256[47] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTDelegateUpgradeable.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/helpers/ERC20TransferHelper.sol";
import "./IMultiRepayableDelegate.sol";
import "./IMultiRepayableConcrete.sol";
abstract contract MultiRepayableDelegate is IMultiRepayableDelegate, BaseSFTDelegateUpgradeable {
function repay(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override nonReentrant {
IMultiRepayableConcrete(concrete()).repayOnlyDelegate(_msgSender(), slot_, currency_, repayCurrencyAmount_);
ERC20TransferHelper.doTransferIn(currency_, _msgSender(), repayCurrencyAmount_);
emit Repay(slot_, _msgSender(), repayCurrencyAmount_);
}
function repayWithBalance(uint256 slot_, address currency_, uint256 repayCurrencyAmount_) external payable virtual override nonReentrant {
require(allowRepayWithBalance(), "MultiRepayableDelegate: cannot repay with balance");
IMultiRepayableConcrete(concrete()).repayWithBalanceOnlyDelegate(_msgSender(), slot_, currency_, repayCurrencyAmount_);
emit Repay(slot_, _msgSender(), repayCurrencyAmount_);
}
function claimTo(address to_, uint256 tokenId_, address currency_, uint256 claimValue_) external virtual override nonReentrant {
require(claimValue_ > 0, "MultiRepayableDelegate: claim value is zero");
require(_isApprovedOrOwner(_msgSender(), tokenId_), "MultiRepayableDelegate: caller is not owner nor approved");
uint256 slot = ERC3525Upgradeable.slotOf(tokenId_);
uint256 claimableValue = IMultiRepayableConcrete(concrete()).claimableValue(tokenId_);
require(claimValue_ <= claimableValue, "MultiRepayableDelegate: over claim");
if (claimValue_ == ERC3525Upgradeable.balanceOf(tokenId_)) {
ERC3525Upgradeable._burn(tokenId_);
} else {
ERC3525Upgradeable._burnValue(tokenId_, claimValue_);
}
uint256 claimCurrencyAmount = IMultiRepayableConcrete(concrete()).claimOnlyDelegate(tokenId_, slot, currency_, claimValue_);
ERC20TransferHelper.doTransferOut(currency_, payable(to_), claimCurrencyAmount);
emit Claim(to_, tokenId_, claimValue_);
}
function _beforeValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual override(ERC3525SlotEnumerableUpgradeable) {
super._beforeValueTransfer(from_, to_, fromTokenId_, toTokenId_, slot_, value_);
if (from_ == address(0) && fromTokenId_ == 0) {
IMultiRepayableConcrete(concrete()).mintOnlyDelegate(toTokenId_, slot_, value_);
}
if (from_ != address(0) && fromTokenId_ != 0 && to_ != address(0) && toTokenId_ != 0) {
IMultiRepayableConcrete(concrete()).transferOnlyDelegate(fromTokenId_, toTokenId_,
ERC3525Upgradeable.balanceOf(fromTokenId_), value_);
}
}
function allowRepayWithBalance() public view virtual returns (bool) {
return true;
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../issuable/ISFTIssuableConcrete.sol";
interface ISFTValueIssuableConcrete is ISFTIssuableConcrete {
function burnOnlyDelegate(uint256 tokenId, uint256 burnValue) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../issuable/ISFTIssuableDelegate.sol";
interface ISFTValueIssuableDelegate is ISFTIssuableDelegate {
function mintValueOnlyIssueMarket(address txSender, address currency, uint256 tokenId, uint256 mintValue) external payable;
function burnOnlyIssueMarket(uint256 tokenId, uint256 burnValue) external;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTConcreteUpgradeable.sol";
import "./ISFTValueIssuableDelegate.sol";
import "./ISFTValueIssuableConcrete.sol";
import "../issuable/SFTIssuableConcrete.sol";
abstract contract SFTValueIssuableConcrete is ISFTValueIssuableConcrete, SFTIssuableConcrete {
function __SFTValueIssuableConcrete_init() internal onlyInitializing {
__SFTIssuableConcrete_init();
}
function __SFTValueIssuableConcrete_init_unchained() internal onlyInitializing {
}
function burnOnlyDelegate(uint256 tokenId_, uint256 burnValue_) external virtual override onlyDelegate {
_burn(tokenId_, burnValue_);
}
function _burn(uint256 tokenId_, uint256 burnValue_) internal virtual;
uint256[50] private __gap;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Constants.sol";
import "@solvprotocol/contracts-v3-address-resolver/contracts/ResolverCache.sol";
import "@solvprotocol/contracts-v3-sft-core/contracts/BaseSFTDelegateUpgradeable.sol";
import "./ISFTValueIssuableDelegate.sol";
import "./ISFTValueIssuableConcrete.sol";
import "../issuable/SFTIssuableDelegate.sol";
error OnlyMarket();
abstract contract SFTValueIssuableDelegate is ISFTValueIssuableDelegate, SFTIssuableDelegate {
event BurnValue(uint256 indexed tokenId, uint256 burnValue);
function __SFTValueIssuableDelegate_init(
address resolver_, string memory name_, string memory symbol_, uint8 decimals_,
address concrete_, address metadata_, address owner_
) internal onlyInitializing {
__SFTIssuableDelegate_init(resolver_, name_, symbol_, decimals_, concrete_, metadata_, owner_);
}
function __SFTValueIssuableDelegate_init_unchained() internal onlyInitializing {
}
function mintValueOnlyIssueMarket(
address txSender_, address currency_, uint256 tokenId_, uint256 mintValue_
) external payable virtual override nonReentrant {
if (_msgSender() != _issueMarket()) {
revert OnlyMarket();
}
address owner = ERC3525Upgradeable.ownerOf(tokenId_);
uint256 slot = ERC3525Upgradeable.slotOf(tokenId_);
ERC3525Upgradeable._mintValue(tokenId_, mintValue_);
ISFTIssuableConcrete(concrete()).mintOnlyDelegate(txSender_, currency_, owner, slot, tokenId_, mintValue_);
emit MintValue(tokenId_, slot, mintValue_);
}
function burnOnlyIssueMarket(uint256 tokenId_, uint256 burnValue_) external virtual override nonReentrant {
if (_msgSender() != _issueMarket()) {
revert OnlyMarket();
}
uint256 actualBurnValue = burnValue_ == 0 ? ERC3525Upgradeable.balanceOf(tokenId_) : burnValue_;
ISFTValueIssuableConcrete(concrete()).burnOnlyDelegate(tokenId_, actualBurnValue);
if (burnValue_ == 0) {
ERC3525Upgradeable._burn(tokenId_);
} else {
ERC3525Upgradeable._burnValue(tokenId_, burnValue_);
}
emit BurnValue(tokenId_, actualBurnValue);
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/OwnControl.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/SFTConcreteControl.sol";
import "./interface/IBaseSFTConcrete.sol";
abstract contract BaseSFTConcreteUpgradeable is IBaseSFTConcrete, SFTConcreteControl {
modifier onlyDelegateOwner {
require(_msgSender() == OwnControl(delegate()).owner(), "only delegate owner");
_;
}
function __BaseSFTConcrete_init() internal onlyInitializing {
__SFTConcreteControl_init();
}
function isSlotValid(uint256 slot_) external view virtual override returns (bool) {
return _isSlotValid(slot_);
}
function _isSlotValid(uint256 slot_) internal view virtual returns (bool);
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@solvprotocol/erc-3525/ERC3525SlotEnumerableUpgradeable.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/ISFTConcreteControl.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/SFTDelegateControl.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/OwnControl.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Constants.sol";
import "./interface/IBaseSFTDelegate.sol";
import "./interface/IBaseSFTConcrete.sol";
abstract contract BaseSFTDelegateUpgradeable is IBaseSFTDelegate, ERC3525SlotEnumerableUpgradeable,
OwnControl, SFTDelegateControl, ReentrancyGuardUpgradeable {
event CreateSlot(uint256 indexed _slot, address indexed _creator, bytes _slotInfo);
event MintValue(uint256 indexed _tokenId, uint256 indexed _slot, uint256 _value);
function __BaseSFTDelegate_init(
string memory name_, string memory symbol_, uint8 decimals_,
address concrete_, address metadata_, address owner_
) internal onlyInitializing {
ERC3525Upgradeable.__ERC3525_init(name_, symbol_, decimals_);
OwnControl.__OwnControl_init(owner_);
ERC3525Upgradeable._setMetadataDescriptor(metadata_);
SFTDelegateControl.__SFTDelegateControl_init(concrete_);
__ReentrancyGuard_init();
//address of concrete must be zero when initializing impletion contract avoid failed after upgrade
if (concrete_ != Constants.ZERO_ADDRESS) {
ISFTConcreteControl(concrete_).setDelegate(address(this));
}
}
function delegateToConcreteView(bytes calldata data) external view override returns (bytes memory) {
(bool success, bytes memory returnData) = concrete().staticcall(data);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}
return returnData;
}
function contractType() external view virtual returns (string memory);
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IBaseSFTConcrete {
function isSlotValid(uint256 slot_) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IBaseSFTDelegate {
function delegateToConcreteView(bytes calldata data) external view returns (bytes memory);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Constants.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/helpers/ERC20TransferHelper.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/issuable/SFTIssuableConcrete.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/multi-rechargeable/MultiRechargeableConcrete.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/multi-repayable/MultiRepayableConcrete.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IEarnConcrete.sol";
contract EarnConcrete is IEarnConcrete, SFTIssuableConcrete, MultiRepayableConcrete {
mapping(address => bool) internal _allowCurrencies;
mapping(uint256 => SlotBaseInfo) internal _slotBaseInfos;
mapping(uint256 => SlotExtInfo) internal _slotExtInfos;
function initialize() external initializer {
__SFTIssuableConcrete_init();
}
function setCurrencyOnlyDelegate(address currency_, bool isAllowed_) external override onlyDelegate {
_setCurrency(currency_, isAllowed_);
}
function setInterestRateOnlyDelegate(address txSender_, uint256 slot_, int32 interestRate_) external override onlyDelegate {
SlotExtInfo storage extInfo = _slotExtInfos[slot_];
require(extInfo.interestType == InterestType.FLOATING, "EarnConcrete: not floating interest");
require(txSender_ == extInfo.supervisor, "EarnConcrete: only supervisor");
require(slotTotalValue(slot_) == slotInitialValue(slot_), "EarnConcrete: already claimed");
extInfo.interestRate = interestRate_;
extInfo.isInterestRateSet = true;
}
function claimableValue(uint256 tokenId_) public view virtual override returns (uint256) {
uint256 slot = ERC3525Upgradeable(delegate()).slotOf(tokenId_);
if (_slotExtInfos[slot].interestType == InterestType.FLOATING && !_slotExtInfos[slot].isInterestRateSet) {
return 0;
}
return super.claimableValue(tokenId_);
}
function getSlot(address issuer_, address currency_, uint64 valueDate_, uint64 maturity_, uint64 createTime_, bool transferable_) public view returns (uint256) {
uint256 chainId;
assembly { chainId := chainid() }
return uint256(keccak256(abi.encodePacked(chainId, delegate(), issuer_, currency_, valueDate_, maturity_, createTime_, transferable_)));
}
function slotBaseInfo(uint256 slot_) external view override returns (SlotBaseInfo memory) {
return _slotBaseInfos[slot_];
}
function slotExtInfo(uint256 slot_) external view override returns (SlotExtInfo memory) {
return _slotExtInfos[slot_];
}
function _isSlotValid(uint256 slot_) internal view virtual override returns (bool) {
return _slotBaseInfos[slot_].isValid;
}
function _createSlot(address txSender_, bytes memory inputSlotInfo_) internal virtual override returns (uint256 slot_) {
InputSlotInfo memory input = abi.decode(inputSlotInfo_, (InputSlotInfo));
_validateSlotInfo(input);
require(_allowCurrencies[input.currency], "EarnConcrete: currency not allowed");
SlotBaseInfo memory baseInfo = SlotBaseInfo({
issuer: txSender_,
currency: input.currency,
valueDate: input.valueDate,
maturity: input.maturity,
createTime: input.createTime,
transferable: input.transferable,
isValid: true
});
slot_ = getSlot(txSender_, input.currency, input.valueDate, input.maturity, input.createTime, input.transferable);
_slotBaseInfos[slot_] = baseInfo;
_slotExtInfos[slot_] = SlotExtInfo({
supervisor: input.supervisor,
issueQuota: input.issueQuota,
interestType: input.interestType,
interestRate: input.interestRate,
isInterestRateSet: input.interestType == InterestType.FIXED,
externalURI: input.externalURI
});
}
function _mint(address /** txSender_ */, address currency_, address /** mintTo_ */, uint256 slot_, uint256 /** tokenId_ */, uint256 /** amount_ */) internal virtual override {
SlotBaseInfo storage base = _slotBaseInfos[slot_];
require(base.isValid, "EarnConcrete: invalid slot");
require(base.currency == currency_, "EarnConcrete: currency not match");
uint256 issueQuota = _slotExtInfos[slot_].issueQuota;
uint256 issuedAmount = MultiRepayableConcrete.slotInitialValue(slot_);
require(issuedAmount <= issueQuota, "EarnConcrete: issueQuota exceeded");
}
function _validateSlotInfo(InputSlotInfo memory input_) internal view virtual {
require(input_.valueDate > block.timestamp, "EarnConcrete: invalid valueDate");
require(input_.maturity > input_.valueDate, "EarnConcrete: invalid maturity");
}
function isSlotTransferable(uint256 slot_) external view override returns (bool) {
return _slotBaseInfos[slot_].transferable;
}
function isCurrencyAllowed(address currency_) external view returns (bool) {
return _allowCurrencies[currency_];
}
function _setCurrency(address currency_, bool isAllowed_) internal virtual {
_allowCurrencies[currency_] = isAllowed_;
}
function _currency(uint256 slot_) internal view virtual override returns (address) {
return _slotBaseInfos[slot_].currency;
}
function _repayRate(uint256 slot_) internal view virtual override returns (uint256) {
SlotBaseInfo storage baseInfo = _slotBaseInfos[slot_];
SlotExtInfo storage extInfo = _slotExtInfos[slot_];
uint256 scaledFullPercentage = uint256(Constants.FULL_PERCENTAGE) * MultiRepayableConcrete.REPAY_RATE_SCALAR;
uint256 scaledPositiveInterestRate =
(extInfo.interestRate < 0 ? uint256(int256(0 - extInfo.interestRate)) : uint256(int256(extInfo.interestRate))) *
MultiRepayableConcrete.REPAY_RATE_SCALAR * (baseInfo.maturity - baseInfo.valueDate) / Constants.SECONDS_PER_YEAR;
return extInfo.interestRate < 0 ? scaledFullPercentage - scaledPositiveInterestRate : scaledFullPercentage + scaledPositiveInterestRate;
}
function _beforeRepayWithBalance(address txSender_, uint256 slot_, address currency_, uint256 repayCurrencyAmount_) internal virtual override {
super._beforeRepayWithBalance(txSender_, slot_, currency_, repayCurrencyAmount_);
require(txSender_ == _slotBaseInfos[slot_].issuer, "EarnConcrete: only issuer");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-abilities/contracts/issuable/SFTIssuableDelegate.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/multi-repayable/MultiRepayableDelegate.sol";
import "./IEarnConcrete.sol";
contract EarnDelegate is SFTIssuableDelegate, MultiRepayableDelegate {
event SetCurrency(address indexed currency, bool isAllowed);
event SetInterestRate(uint256 indexed slot, int32 interestRate);
bool private __allowRepayWithBalance;
function initialize(
address resolver_, string calldata name_, string calldata symbol_, uint8 decimals_,
address concrete_, address descriptor_, address owner_, bool allowRepayWithBalance_
) external initializer {
__SFTIssuableDelegate_init(resolver_, name_, symbol_, decimals_, concrete_, descriptor_, owner_);
__allowRepayWithBalance = allowRepayWithBalance_;
}
function _beforeValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual override(ERC3525SlotEnumerableUpgradeable, MultiRepayableDelegate) {
MultiRepayableDelegate._beforeValueTransfer(from_, to_, fromTokenId_, toTokenId_, slot_, value_);
// untransferable
if (from_ != address(0) && to_ != address(0)) {
require(IEarnConcrete(concrete()).isSlotTransferable(slot_), "untransferable");
}
}
function setCurrencyOnlyOwner(address currency_, bool isAllowed_) external onlyOwner {
IEarnConcrete(concrete()).setCurrencyOnlyDelegate(currency_, isAllowed_);
emit SetCurrency(currency_, isAllowed_);
}
function setInterestRateOnlySupervisor(uint256 slot_, int32 interestRate_) external {
IEarnConcrete(concrete()).setInterestRateOnlyDelegate(_msgSender(), slot_, interestRate_);
emit SetInterestRate(slot_, interestRate_);
}
function allowRepayWithBalance() public view virtual override returns (bool) {
return __allowRepayWithBalance;
}
function contractType() external view virtual override returns (string memory) {
return "Closed-end Fund";
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/OwnControl.sol";
import "@solvprotocol/erc-3525/periphery/ERC3525MetadataDescriptor.sol";
import "./EarnDelegate.sol";
import "./EarnConcrete.sol";
import "./svgs/DefaultEarnSVG.sol";
contract EarnMetadataDescriptor is ERC3525MetadataDescriptor, Initializable, OwnControl {
using Strings for uint256;
using Strings for address;
event SetPayableSVG(
address indexed payableAddress,
address oldPayableSVG,
address newPayableSVG
);
mapping(address => address) internal _payableSVGs;
function initialize(address owner_, address defaultPayableSVG_) external initializer {
OwnControl.__OwnControl_init(owner_);
_setPayableSVG(address(0), defaultPayableSVG_);
}
function setPayableSVG(address payableAddress_, address payableSVG_) public onlyOwner {
_setPayableSVG(payableAddress_, payableSVG_);
}
function _setPayableSVG(address payableAddress_, address payableSVG_) internal {
emit SetPayableSVG(payableAddress_, _payableSVGs[payableAddress_], payableSVG_);
_payableSVGs[payableAddress_] = payableSVG_;
}
function getPayableSVG(address payableAddress_) external view returns (address) {
address payableSVG = _payableSVGs[payableAddress_];
if (payableSVG == address(0)) {
payableSVG = _payableSVGs[address(0)];
}
return payableSVG;
}
function _tokenName(uint256 tokenId_) internal view virtual override returns (string memory) {
EarnDelegate delegate = EarnDelegate(msg.sender);
return string(abi.encodePacked(delegate.name(), " #", tokenId_.toString()));
}
function _tokenImage(uint256 tokenId_) internal view virtual override returns (bytes memory) {
address payableSVG = _payableSVGs[_msgSender()];
if (payableSVG == address(0)) {
payableSVG = _payableSVGs[address(0)];
}
return
abi.encodePacked(
'data:image/svg+xml;base64,',
Base64.encode(bytes(DefaultEarnSVG(payableSVG).generateSVG(_msgSender(), tokenId_)))
);
}
function _slotProperties(uint256 slot_) internal view virtual override returns (string memory) {
EarnDelegate delegate = EarnDelegate(msg.sender);
EarnConcrete concrete = EarnConcrete(delegate.concrete());
return
string(
abi.encodePacked(
'[',
_formatSlotBaseInfos(concrete, slot_),
_formatSlotExtInfos(concrete, slot_),
']'
)
);
}
function _formatSlotBaseInfos(EarnConcrete concrete_, uint256 slot_) internal view virtual returns (bytes memory) {
EarnConcrete.SlotBaseInfo memory baseInfo = concrete_.slotBaseInfo(slot_);
uint256 chainId;
assembly {
chainId := chainid()
}
return
abi.encodePacked(
abi.encodePacked(
'{"name":"chain_id",',
'"description":"chain id",',
'"value":"', chainId.toString(), '",',
'"is_intrinsic":true,',
'"order":1,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"payable_token_address",',
'"description":"Address of this contract.",',
'"value":"', concrete_.delegate().toHexString(), '",',
'"is_intrinsic":true,',
'"order":2,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"issuer",',
'"description":"Issuer of this slot.",',
'"value":"', baseInfo.issuer.toHexString(), '",',
'"is_intrinsic":true,',
'"order":3,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"currency",',
'"description":"Currency of this slot.",',
'"value":"', baseInfo.currency.toHexString(), '",',
'"is_intrinsic":true,',
'"order":4,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"value_date",',
'"description":"Value date of this slot.",',
'"value":', uint256(baseInfo.valueDate).toString(), ',',
'"is_intrinsic":true,',
'"order":5,',
'"display_type":"date"},'
),
abi.encodePacked(
'{"name":"maturity",',
'"description":"Maturity date of this slot.",',
'"value":', uint256(baseInfo.maturity).toString(), ',',
'"is_intrinsic":true,',
'"order":6,',
'"display_type":"date"},'
),
abi.encodePacked(
'{"name":"create_time",',
'"description":"Time when this slot is created.",',
'"value":', uint256(baseInfo.createTime).toString(), ',',
'"is_intrinsic":true,',
'"order":7,',
'"display_type":"date"},'
),
abi.encodePacked(
'{"name":"transferable",',
'"description":"Indicate if tokens of this slot are transferable.",',
'"value":', baseInfo.transferable ? 'true' : 'false', ',',
'"is_intrinsic":true,',
'"order":8,',
'"display_type":"boolean"},'
)
);
}
function _formatSlotExtInfos(EarnConcrete concrete_, uint256 slot_) internal view virtual returns (bytes memory) {
EarnConcrete.SlotExtInfo memory extInfo = concrete_.slotExtInfo(slot_);
uint256 slotTotalValue = concrete_.slotTotalValue(slot_);
uint256 repaidCurrencyAmount = concrete_.repaidCurrencyAmount(slot_);
return
abi.encodePacked(
abi.encodePacked(
'{"name":"supervisor",',
'"description":"Fund supervisor of this slot.",',
'"value":"', extInfo.supervisor.toHexString(), '",',
'"is_intrinsic":false,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"issue_quota",',
'"description":"Issue quota of this slot.",',
'"value":', uint256(extInfo.issueQuota).toString(), ',',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"interest_type",',
'"description":"Interest type of this slot.",',
'"value":', uint256(extInfo.interestType).toString(), ',',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"interest_rate",',
'"description":"Interest rate of this slot.",',
'"value":', _formatInterestRate(extInfo.interestRate), ',',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"is_interest_rate_set",',
'"description":"Indicate if the interest rate of this slot is set.",',
'"value":', extInfo.isInterestRateSet ? 'true' : 'false', ',',
'"is_intrinsic":false,',
'"display_type":"boolean"},'
),
abi.encodePacked(
'{"name":"total_value",',
'"description":"Total issued value of this slot.",',
'"value":', slotTotalValue.toString(), ',',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"repaid_amount",',
'"description":"Repaid amount of this slot.",',
'"value":', repaidCurrencyAmount.toString(), ',',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"external_url",',
'"description":"External URI of this slot.",',
'"value":"', extInfo.externalURI, '",',
'"is_intrinsic":false,',
'"display_type":"string"}'
)
);
}
function _tokenProperties(uint256 tokenId_) internal view virtual override returns (string memory) {
EarnDelegate delegate = EarnDelegate(msg.sender);
EarnConcrete concrete = EarnConcrete(delegate.concrete());
uint256 slot = delegate.slotOf(tokenId_);
EarnConcrete.SlotBaseInfo memory baseInfo = concrete.slotBaseInfo(slot);
EarnConcrete.SlotExtInfo memory extInfo = concrete.slotExtInfo(slot);
return
string(
abi.encodePacked(
/* solhint-disable */
'{"issuer":"', baseInfo.issuer.toHexString(),
'","currency":"', baseInfo.currency.toHexString(),
'","interest_type":"', uint256(extInfo.interestType).toString(),
'","interest_rate":', _formatInterestRate(extInfo.interestRate),
',"value_date":', uint256(baseInfo.valueDate).toString(),
',"maturity":', uint256(baseInfo.maturity).toString(),
'}'
/* solhint-enable */
)
);
}
function _formatInterestRate(int32 interestRate_) internal pure returns (string memory) {
return
interestRate_ < 0 ?
string(abi.encodePacked('-', uint256(int256(0 - interestRate_)).toString())) :
uint256(int256(interestRate_)).toString();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IEarnConcrete {
enum InterestType {
FIXED,
FLOATING
}
struct InputSlotInfo {
address currency;
address supervisor;
uint256 issueQuota;
InterestType interestType;
int32 interestRate;
uint64 valueDate;
uint64 maturity;
uint64 createTime;
bool transferable;
string externalURI;
}
struct SlotBaseInfo {
address issuer;
address currency;
uint64 valueDate;
uint64 maturity;
uint64 createTime;
bool transferable;
bool isValid;
}
struct SlotExtInfo {
address supervisor;
uint256 issueQuota;
InterestType interestType;
int32 interestRate;
bool isInterestRateSet;
string externalURI;
}
function slotBaseInfo(uint256 slot_) external returns (SlotBaseInfo memory);
function slotExtInfo(uint256 slot_) external returns (SlotExtInfo memory);
function isSlotTransferable(uint256 slot_) external returns (bool);
function isCurrencyAllowed(address currency_) external returns (bool);
function setCurrencyOnlyDelegate(address currency_, bool isAllowed_) external;
function setInterestRateOnlyDelegate(address txSender_, uint256 slot_, int32 interestRate_) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/StringConvertor.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Dates.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../EarnDelegate.sol";
import "../EarnConcrete.sol";
contract DefaultEarnSVG {
using Strings for uint256;
using Strings for address;
using StringConvertor for uint256;
using StringConvertor for bytes;
using Dates for uint256;
struct SVGParams {
address payableAddress;
string payableName;
string currencyTokenSymbol;
string tokenId;
string parValue;
string maturity;
string term;
string interestRate;
address issuer;
}
/// @dev payable => background colors [upper-left-0 upper-left-1 lower-right-0 lower-right-1]
mapping(address => string[]) public backgroundColors;
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "only owner");
_;
}
constructor(
address owner_,
string[] memory backgroundColors_
) {
owner = owner_;
backgroundColors[address(0)] = backgroundColors_;
}
function setBackgroundColors(address payable_, string[] memory backgroundColors_) public onlyOwner {
backgroundColors[payable_] = backgroundColors_;
}
function generateSVG(address payable_, uint256 tokenId_)
external
virtual
view
returns (string memory)
{
EarnDelegate payableDelegate = EarnDelegate(payable_);
EarnConcrete payableConcrete = EarnConcrete(payableDelegate.concrete());
uint256 slot = payableDelegate.slotOf(tokenId_);
EarnConcrete.SlotBaseInfo memory baseInfo = payableConcrete.slotBaseInfo(slot);
EarnConcrete.SlotExtInfo memory extInfo = payableConcrete.slotExtInfo(slot);
ERC20 currencyToken = ERC20(baseInfo.currency);
SVGParams memory svgParams;
svgParams.payableAddress = payable_;
svgParams.payableName = payableDelegate.name();
svgParams.currencyTokenSymbol = currencyToken.symbol();
svgParams.tokenId = tokenId_.toString();
svgParams.parValue = string(_formatValue(payableDelegate.balanceOf(tokenId_), payableDelegate.valueDecimals()));
svgParams.maturity = uint256(baseInfo.maturity).dateToString();
svgParams.term = uint256((baseInfo.maturity - baseInfo.valueDate) / 86400).toString();
svgParams.interestRate = extInfo.isInterestRateSet ?
string(
extInfo.interestRate < 0 ?
abi.encodePacked("-", uint256(int256(0 - extInfo.interestRate)).toDecimalsString(2), "%") :
abi.encodePacked(uint256(int256(extInfo.interestRate)).toDecimalsString(2), "%")
) :
"Floating";
svgParams.issuer = baseInfo.issuer;
return generateSVG(svgParams);
}
function generateSVG(SVGParams memory params)
public
virtual
view
returns (string memory)
{
return
string(
abi.encodePacked(
'<svg width="600" height="400" viewBox="0 0 600 400" fill="none" xmlns="http://www.w3.org/2000/svg">',
_generateDefs(params),
_generateBackground(),
_generateContent(params),
'</svg>'
)
);
}
function _generateDefs(SVGParams memory params) internal virtual view returns (string memory) {
string memory color_upper_left_0 = backgroundColors[address(0)][0];
string memory color_upper_left_1 = backgroundColors[address(0)][1];
string memory color_lower_right_0 = backgroundColors[address(0)][2];
string memory color_lower_right_1 = backgroundColors[address(0)][3];
if (backgroundColors[params.payableAddress].length > 3) {
color_upper_left_0 = backgroundColors[params.payableAddress][0];
color_upper_left_1 = backgroundColors[params.payableAddress][1];
color_lower_right_0 = backgroundColors[params.payableAddress][2];
color_lower_right_1 = backgroundColors[params.payableAddress][3];
}
return
string(
abi.encodePacked(
'<defs>',
abi.encodePacked(
'<filter id="f_3525_3" x="275" y="-220" width="600" height="800" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">',
'<feFlood flood-opacity="0" result="e_3525_1"/>',
'<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>',
'<feOffset dy="6"/>',
'<feGaussianBlur stdDeviation="25"/>',
'<feComposite in2="hardAlpha" operator="out"/>',
'<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.3 0 0 0 0 0.5 0 0 0 0.6 0"/>',
'<feBlend mode="normal" in2="e_3525_1" result="e_3525_2"/>',
'<feBlend mode="normal" in="SourceGraphic" in2="e_3525_2"/>',
'</filter>'
),
abi.encodePacked(
'<linearGradient id="lg_3525_1" x1="500" y1="360" x2="420" y2="-60" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', color_upper_left_0, '"/>',
'<stop offset="1" stop-color="', color_upper_left_1, '"/>',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="lg_3525_2" x1="120" y1="200" x2="620" y2="-128" gradientUnits="userSpaceOnUse">',
'<stop offset="0.15" stop-color="', color_lower_right_0, '"/>',
'<stop offset="0.6" stop-color="', color_lower_right_1, '"/>',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="lg_3525_3" x1="120" y1="200" x2="620" y2="-128" gradientUnits="userSpaceOnUse">',
'<stop offset="0.45" stop-color="', color_lower_right_0, '"/>',
'<stop offset="1" stop-color="', color_lower_right_1, '"/>',
'</linearGradient>'
),
'</defs>'
)
);
}
function _generateBackground() internal pure virtual returns (string memory) {
return
string(
abi.encodePacked(
'<rect width="600" height="400" rx="20" fill="white"/>',
'<rect x="0.5" y="0.5" width="599" height="399" rx="20" stroke="#F3F3F3"/>',
'<mask id="m_3525_3" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="300" y="0" width="300" height="400">',
'<path d="M300 0H580C590 0 600 8 600 20V380C600 392 590 400 580 400H300V0Z" fill="white"/>',
'</mask>',
'<g mask="url(#m_3525_3)">',
'<path d="M300 400L600 400L600 0L300 0Z" fill="url(#lg_3525_1)"/>',
'<path d="M222 400L600 400L600 -64Z" fill="url(#lg_3525_2)"/>',
'<g filter="url(#f_3525_3)">',
'<path d="M336 400L600 400L600 -85Z" fill="url(#lg_3525_3)"/>',
'</g>',
'</g>',
'<path d="M30 199H263 M30 242H263 M30 285H263 M30 328H263" opacity="0.5" stroke="#DDDDDD" stroke-width="1"/>'
)
);
}
function _generateContent(SVGParams memory params) internal pure virtual returns (string memory) {
return
string(
abi.encodePacked(
'<text fill="#202020" font-family="Arial" font-size="14">',
abi.encodePacked(
'<tspan x="30" y="55" font-size="18" font-weight="bold">', params.payableName, '</tspan>',
'<tspan x="30" y="95" font-size="28">', params.parValue,
'<tspan font-size="14"> ', params.currencyTokenSymbol, '</tspan>',
'</tspan>',
'<tspan x="30" y="180" font-weight="bold">ID #', params.tokenId, '</tspan>'
),
abi.encodePacked(
'<tspan x="30" y="223">APR</tspan>',
'<tspan x="262" y="223" text-anchor="end">', params.interestRate, '</tspan>'
'<tspan x="30" y="266">Term</tspan>',
'<tspan x="262" y="266" text-anchor="end">', params.term, 'd</tspan>',
'<tspan x="30" y="309">Maturity date</tspan>',
'<tspan x="262" y="309" text-anchor="end">', params.maturity, '</tspan>'
),
abi.encodePacked(
'<tspan x="30" y="354" font-size="9">Issuer: ', params.issuer.toHexString(), '</tspan>',
'<tspan x="30" y="372" font-size="9" fill="#929292">Powered by Solv Protocol</tspan>'
),
'</text>'
)
);
}
function _formatValue(uint256 value, uint8 decimals) private pure returns (bytes memory) {
return value.toDecimalsString(decimals).trimRight(decimals - 2).addThousandsSeparator();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
abstract contract AdminControl is Initializable, ContextUpgradeable {
event NewAdmin(address oldAdmin, address newAdmin);
event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
address public admin;
address public pendingAdmin;
modifier onlyAdmin() {
require(_msgSender() == admin, "only admin");
_;
}
function __AdminControl_init(address admin_) internal onlyInitializing {
__AdminControl_init_unchained(admin_);
}
function __AdminControl_init_unchained(address admin_) internal onlyInitializing {
admin = admin_;
emit NewAdmin(address(0), admin_);
}
function setPendingAdmin(address newPendingAdmin_) external virtual onlyAdmin {
emit NewPendingAdmin(pendingAdmin, newPendingAdmin_);
pendingAdmin = newPendingAdmin_;
}
function acceptAdmin() external virtual {
require(_msgSender() == pendingAdmin, "only pending admin");
emit NewAdmin(admin, pendingAdmin);
admin = pendingAdmin;
pendingAdmin = address(0);
}
uint256[48] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AdminControl.sol";
abstract contract GovernorControl is AdminControl {
event NewGovernor(address oldGovernor, address newGovernor);
address public governor;
modifier onlyGovernor() {
require(governor == _msgSender(), "only governor");
_;
}
function __GovernorControl_init(address governor_) internal onlyInitializing {
__GovernorControl_init_unchained(governor_);
__AdminControl_init_unchained(_msgSender());
}
function __GovernorControl_init_unchained(address governor_) internal onlyInitializing {
_setGovernor(governor_);
}
function setGovernorOnlyAdmin(address newGovernor_) public onlyAdmin {
_setGovernor(newGovernor_);
}
function _setGovernor(address newGovernor_) internal {
require(newGovernor_ != address(0), "Governor address connot be 0");
emit NewGovernor(governor, newGovernor_);
governor = newGovernor_;
}
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISFTConcreteControl {
event NewDelegate(address old_, address new_);
function setDelegate(address newDelegate_) external;
function delegate() external view returns (address);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISFTDelegateControl {
event NewConcrete(address old_, address new_);
function concrete() external view returns (address);
function setConcreteOnlyAdmin(address newConcrete_) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AdminControl.sol";
abstract contract OwnControl is AdminControl {
event NewOwner(address oldOwner, address newOwner);
address public owner;
modifier onlyOwner() {
require(owner == _msgSender(), "only owner");
_;
}
function __OwnControl_init(address owner_) internal onlyInitializing {
__OwnControl_init_unchained(owner_);
__AdminControl_init_unchained(_msgSender());
}
function __OwnControl_init_unchained(address owner_) internal onlyInitializing {
_setOwner(owner_);
}
function setOwnerOnlyAdmin(address newOwner_) public onlyAdmin {
_setOwner(newOwner_);
}
function _setOwner(address newOwner_) internal {
require(newOwner_ != address(0), "Owner address connot be 0");
emit NewOwner(owner, newOwner_);
owner = newOwner_;
}
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AdminControl.sol";
import "./ISFTConcreteControl.sol";
abstract contract SFTConcreteControl is ISFTConcreteControl, AdminControl {
address private _delegate;
modifier onlyDelegate() {
require(_msgSender() == _delegate, "only delegate");
_;
}
function __SFTConcreteControl_init() internal onlyInitializing {
__AdminControl_init_unchained(_msgSender());
__SFTConcreteControl_init_unchained();
}
function __SFTConcreteControl_init_unchained() internal onlyInitializing {}
function delegate() public view override returns (address) {
return _delegate;
}
function setDelegate(address newDelegate_) external override {
if (_delegate != address(0)) {
require(_msgSender() == admin, "only admin");
}
emit NewDelegate(_delegate, newDelegate_);
_delegate = newDelegate_;
}
uint256[49] private __gap;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AdminControl.sol";
import "./ISFTDelegateControl.sol";
abstract contract SFTDelegateControl is ISFTDelegateControl, AdminControl {
address private _concrete;
function __SFTDelegateControl_init(address concrete_) internal onlyInitializing {
__AdminControl_init_unchained(_msgSender());
__SFTDelegateControl_init_unchained(concrete_);
}
function __SFTDelegateControl_init_unchained(address concrete_) internal onlyInitializing {
_concrete = concrete_;
}
function concrete() public view override returns (address) {
return _concrete;
}
function setConcreteOnlyAdmin(address newConcrete_) external override onlyAdmin {
emit NewConcrete(_concrete, newConcrete_);
_concrete = newConcrete_;
}
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../misc/Constants.sol";
interface ERC20Interface {
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
}
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library ERC20TransferHelper {
function doApprove(address underlying, address spender, uint256 amount) internal {
require(underlying.code.length > 0, "invalid underlying");
(bool success, bytes memory data) = underlying.call(
abi.encodeWithSelector(
ERC20Interface.approve.selector,
spender,
amount
)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "SAF");
}
function doTransferIn(address underlying, address from, uint256 amount) internal {
if (underlying == Constants.ETH_ADDRESS) {
// Sanity checks
require(tx.origin == from || msg.sender == from, "sender mismatch");
require(msg.value >= amount, "value mismatch");
} else {
require(underlying.code.length > 0, "invalid underlying");
(bool success, bytes memory data) = underlying.call(
abi.encodeWithSelector(
ERC20Interface.transferFrom.selector,
from,
address(this),
amount
)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "STF");
}
}
function doTransferOut(address underlying, address payable to, uint256 amount) internal {
if (underlying == Constants.ETH_ADDRESS) {
(bool success, ) = to.call{value: amount}(new bytes(0));
require(success, "STE");
} else {
require(underlying.code.length > 0, "invalid underlying");
(bool success, bytes memory data) = underlying.call(
abi.encodeWithSelector(
ERC20Interface.transfer.selector,
to,
amount
)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "ST");
}
}
function getCashPrior(address underlying_) internal view returns (uint256) {
if (underlying_ == Constants.ETH_ADDRESS) {
uint256 startingBalance = address(this).balance - msg.value;
return startingBalance;
} else {
ERC20Interface token = ERC20Interface(underlying_);
return token.balanceOf(address(this));
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
// ----------------------------------------------------------------------------
// BokkyPooBah's DateTime Library v1.01
//
// A gas-efficient Solidity date and time library
//
// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary
//
// Tested date range 1970/01/01 to 2345/12/31
//
// Conventions:
// Unit | Range | Notes
// :-------- |:-------------:|:-----
// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC
// year | 1970 ... 2345 |
// month | 1 ... 12 |
// day | 1 ... 31 |
// hour | 0 ... 23 |
// minute | 0 ... 59 |
// second | 0 ... 59 |
// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday
//
//
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.
// ----------------------------------------------------------------------------
library BokkyPooBahsDateTimeLibrary {
uint constant SECONDS_PER_DAY = 24 * 60 * 60;
uint constant SECONDS_PER_HOUR = 60 * 60;
uint constant SECONDS_PER_MINUTE = 60;
int constant OFFSET19700101 = 2440588;
uint constant DOW_MON = 1;
uint constant DOW_TUE = 2;
uint constant DOW_WED = 3;
uint constant DOW_THU = 4;
uint constant DOW_FRI = 5;
uint constant DOW_SAT = 6;
uint constant DOW_SUN = 7;
// ------------------------------------------------------------------------
// Calculate the number of days from 1970/01/01 to year/month/day using
// the date conversion algorithm from
// http://aa.usno.navy.mil/faq/docs/JD_Formula.php
// and subtracting the offset 2440588 so that 1970/01/01 is day 0
//
// days = day
// - 32075
// + 1461 * (year + 4800 + (month - 14) / 12) / 4
// + 367 * (month - 2 - (month - 14) / 12 * 12) / 12
// - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4
// - offset
// ------------------------------------------------------------------------
function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) {
require(year >= 1970);
int _year = int(year);
int _month = int(month);
int _day = int(day);
int __days = _day
- 32075
+ 1461 * (_year + 4800 + (_month - 14) / 12) / 4
+ 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12
- 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4
- OFFSET19700101;
_days = uint(__days);
}
// ------------------------------------------------------------------------
// Calculate year/month/day from the number of days since 1970/01/01 using
// the date conversion algorithm from
// http://aa.usno.navy.mil/faq/docs/JD_Formula.php
// and adding the offset 2440588 so that 1970/01/01 is day 0
//
// int L = days + 68569 + offset
// int N = 4 * L / 146097
// L = L - (146097 * N + 3) / 4
// year = 4000 * (L + 1) / 1461001
// L = L - 1461 * year / 4 + 31
// month = 80 * L / 2447
// dd = L - 2447 * month / 80
// L = month / 11
// month = month + 2 - 12 * L
// year = 100 * (N - 49) + year + L
// ------------------------------------------------------------------------
function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) {
int __days = int(_days);
int L = __days + 68569 + OFFSET19700101;
int N = 4 * L / 146097;
L = L - (146097 * N + 3) / 4;
int _year = 4000 * (L + 1) / 1461001;
L = L - 1461 * _year / 4 + 31;
int _month = 80 * L / 2447;
int _day = L - 2447 * _month / 80;
L = _month / 11;
_month = _month + 2 - 12 * L;
_year = 100 * (N - 49) + _year + L;
year = uint(_year);
month = uint(_month);
day = uint(_day);
}
function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) {
timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;
}
function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) {
timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second;
}
function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) {
(year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) {
(year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
uint secs = timestamp % SECONDS_PER_DAY;
hour = secs / SECONDS_PER_HOUR;
secs = secs % SECONDS_PER_HOUR;
minute = secs / SECONDS_PER_MINUTE;
second = secs % SECONDS_PER_MINUTE;
}
function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) {
if (year >= 1970 && month > 0 && month <= 12) {
uint daysInMonth = _getDaysInMonth(year, month);
if (day > 0 && day <= daysInMonth) {
valid = true;
}
}
}
function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) {
if (isValidDate(year, month, day)) {
if (hour < 24 && minute < 60 && second < 60) {
valid = true;
}
}
}
function isLeapYear(uint timestamp) internal pure returns (bool leapYear) {
(uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
leapYear = _isLeapYear(year);
}
function _isLeapYear(uint year) internal pure returns (bool leapYear) {
leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
function isWeekDay(uint timestamp) internal pure returns (bool weekDay) {
weekDay = getDayOfWeek(timestamp) <= DOW_FRI;
}
function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) {
weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;
}
function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) {
(uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
daysInMonth = _getDaysInMonth(year, month);
}
function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
daysInMonth = 31;
} else if (month != 2) {
daysInMonth = 30;
} else {
daysInMonth = _isLeapYear(year) ? 29 : 28;
}
}
// 1 = Monday, 7 = Sunday
function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) {
uint _days = timestamp / SECONDS_PER_DAY;
dayOfWeek = (_days + 3) % 7 + 1;
}
function getYear(uint timestamp) internal pure returns (uint year) {
(year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
function getMonth(uint timestamp) internal pure returns (uint month) {
(,month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
function getDay(uint timestamp) internal pure returns (uint day) {
(,,day) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
function getHour(uint timestamp) internal pure returns (uint hour) {
uint secs = timestamp % SECONDS_PER_DAY;
hour = secs / SECONDS_PER_HOUR;
}
function getMinute(uint timestamp) internal pure returns (uint minute) {
uint secs = timestamp % SECONDS_PER_HOUR;
minute = secs / SECONDS_PER_MINUTE;
}
function getSecond(uint timestamp) internal pure returns (uint second) {
second = timestamp % SECONDS_PER_MINUTE;
}
function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {
(uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
year += _years;
uint daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
require(newTimestamp >= timestamp);
}
function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {
(uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
month += _months;
year += (month - 1) / 12;
month = (month - 1) % 12 + 1;
uint daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
require(newTimestamp >= timestamp);
}
function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp + _days * SECONDS_PER_DAY;
require(newTimestamp >= timestamp);
}
function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;
require(newTimestamp >= timestamp);
}
function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;
require(newTimestamp >= timestamp);
}
function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp + _seconds;
require(newTimestamp >= timestamp);
}
function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {
(uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
year -= _years;
uint daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
require(newTimestamp <= timestamp);
}
function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {
(uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
uint yearMonth = year * 12 + (month - 1) - _months;
year = yearMonth / 12;
month = yearMonth % 12 + 1;
uint daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
require(newTimestamp <= timestamp);
}
function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp - _days * SECONDS_PER_DAY;
require(newTimestamp <= timestamp);
}
function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;
require(newTimestamp <= timestamp);
}
function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;
require(newTimestamp <= timestamp);
}
function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {
newTimestamp = timestamp - _seconds;
require(newTimestamp <= timestamp);
}
function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) {
require(fromTimestamp <= toTimestamp);
(uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
(uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
_years = toYear - fromYear;
}
function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) {
require(fromTimestamp <= toTimestamp);
(uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
(uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
_months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;
}
function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) {
require(fromTimestamp <= toTimestamp);
_days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;
}
function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) {
require(fromTimestamp <= toTimestamp);
_hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;
}
function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) {
require(fromTimestamp <= toTimestamp);
_minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;
}
function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) {
require(fromTimestamp <= toTimestamp);
_seconds = toTimestamp - fromTimestamp;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library Constants {
uint32 internal constant FULL_PERCENTAGE = 10000;
uint32 internal constant SECONDS_PER_YEAR = 360 * 24 * 60 * 60;
address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant ZERO_ADDRESS = 0x0000000000000000000000000000000000000000;
bytes32 internal constant CONTRACT_ISSUE_MARKET= "IssueMarket";
bytes32 internal constant CONTRACT_ISSUE_MARKET_PRICE_STRATEGY_MANAGER = "IMPriceStrategyManager";
bytes32 internal constant CONTRACT_ISSUE_MARKET_WHITELIST_STRATEGY_MANAGER = "IMWhitelistStrategyManager";
bytes32 internal constant CONTRACT_ISSUE_MARKET_UNDERWRITER_PROFIT_TOKEN = "IMUnderwriterProfitToken";
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Strings.sol";
import './BokkyPooBahsDateTimeLibrary.sol';
library Dates {
using Strings for uint256;
function datetimeToString(uint256 timestamp)
internal
pure
returns (string memory)
{
(uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
= BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp);
return
string(
abi.encodePacked(
abi.encodePacked(
year.toString(), '/',
month < 10 ? '0' : '', month.toString(), '/',
day < 10 ? '0' : '', day.toString(), ' '
),
abi.encodePacked(
hour < 10 ? '0' : '', hour.toString(), ':',
minute < 10 ? '0' : '', minute.toString(), ':',
second < 10 ? '0' : '', second.toString()
)
)
);
}
function dateToString(uint256 timestamp)
internal
pure
returns (string memory)
{
(uint256 year, uint256 month, uint256 day)
= BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp);
return
string(
abi.encodePacked(
year.toString(), '/',
month < 10 ? '0' : '', month.toString(), '/',
day < 10 ? '0' : '', day.toString()
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Strings.sol";
library StringConvertor {
using Strings for uint256;
/**
* @dev Converts a `uint256` to its decimals representation according to the specified decimals.
*/
function toDecimalsString(uint256 value, uint8 decimals)
internal
pure
returns (bytes memory)
{
uint256 base = 10 ** decimals;
string memory round = (value / base).toString();
string memory fraction = (value % base).toString();
uint256 fractionLength = bytes(fraction).length;
bytes memory fullStr = abi.encodePacked(round, '.');
if (fractionLength < decimals) {
for (uint8 i = 0; i < decimals - fractionLength; i++) {
fullStr = abi.encodePacked(fullStr, '0');
}
}
return abi.encodePacked(fullStr, fraction);
}
/**
* @dev Trim a string from the right according to the specified cut length.
*/
function trimRight(bytes memory self, uint256 cutLength)
internal
pure
returns (bytes memory newString)
{
newString = new bytes(self.length - cutLength);
for (uint256 index = 0; index < newString.length; index++) {
newString[index] = self[index];
}
}
/**
* @dev Add thousands separator to a numeric string.
*/
function addThousandsSeparator(bytes memory self)
internal
pure
returns (bytes memory newString)
{
uint256 roundLength = 0;
for (uint256 i = 0; i < self.length; i++) {
if (self[i] != '.') {
roundLength++;
} else {
break;
}
}
if (roundLength <= 3) {
newString = self;
} else {
newString = new bytes(self.length + (roundLength - 1) / 3);
uint256 newIndex = 0;
for (uint256 oriIndex = 0; oriIndex < self.length; oriIndex++) {
newString[newIndex++] = self[oriIndex];
if (oriIndex < roundLength - 1 && (roundLength - oriIndex - 1) % 3 == 0) {
newString[newIndex++] = ',';
}
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "./ERC3525Upgradeable.sol";
import "./extensions/IERC3525SlotEnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract ERC3525SlotEnumerableUpgradeable is Initializable, ContextUpgradeable, ERC3525Upgradeable, IERC3525SlotEnumerableUpgradeable {
function __ERC3525SlotEnumerable_init(
string memory name_,
string memory symbol_,
uint8 decimals_
) internal onlyInitializing {
__ERC3525_init_unchained(name_, symbol_, decimals_);
}
function __ERC3525SlotEnumerable_init_unchained(
string memory,
string memory,
uint8
) internal onlyInitializing {
}
struct SlotData {
uint256 slot;
uint256[] slotTokens;
}
// slot => tokenId => index
mapping(uint256 => mapping(uint256 => uint256)) private _slotTokensIndex;
SlotData[] private _allSlots;
// slot => index
mapping(uint256 => uint256) private _allSlotsIndex;
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165Upgradeable, ERC3525Upgradeable) returns (bool) {
return
interfaceId == type(IERC3525SlotEnumerableUpgradeable).interfaceId ||
super.supportsInterface(interfaceId);
}
function slotCount() public view virtual override returns (uint256) {
return _allSlots.length;
}
function slotByIndex(uint256 index_) public view virtual override returns (uint256) {
require(index_ < ERC3525SlotEnumerableUpgradeable.slotCount(), "ERC3525SlotEnumerable: slot index out of bounds");
return _allSlots[index_].slot;
}
function _slotExists(uint256 slot_) internal view virtual returns (bool) {
return _allSlots.length != 0 && _allSlots[_allSlotsIndex[slot_]].slot == slot_;
}
function tokenSupplyInSlot(uint256 slot_) public view virtual override returns (uint256) {
if (!_slotExists(slot_)) {
return 0;
}
return _allSlots[_allSlotsIndex[slot_]].slotTokens.length;
}
function tokenInSlotByIndex(uint256 slot_, uint256 index_) public view virtual override returns (uint256) {
require(index_ < ERC3525SlotEnumerableUpgradeable.tokenSupplyInSlot(slot_), "ERC3525SlotEnumerable: slot token index out of bounds");
return _allSlots[_allSlotsIndex[slot_]].slotTokens[index_];
}
function _tokenExistsInSlot(uint256 slot_, uint256 tokenId_) private view returns (bool) {
SlotData storage slotData = _allSlots[_allSlotsIndex[slot_]];
return slotData.slotTokens.length > 0 && slotData.slotTokens[_slotTokensIndex[slot_][tokenId_]] == tokenId_;
}
function _createSlot(uint256 slot_) internal virtual {
require(!_slotExists(slot_), "ERC3525SlotEnumerable: slot already exists");
SlotData memory slotData = SlotData({
slot: slot_,
slotTokens: new uint256[](0)
});
_addSlotToAllSlotsEnumeration(slotData);
emit SlotChanged(0, 0, slot_);
}
function _beforeValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual override {
super._beforeValueTransfer(from_, to_, fromTokenId_, toTokenId_, slot_, value_);
if (from_ == address(0) && fromTokenId_ == 0 && !_slotExists(slot_)) {
_createSlot(slot_);
}
//Shh - currently unused
to_;
toTokenId_;
value_;
}
function _afterValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual override {
if (from_ == address(0) && fromTokenId_ == 0 && !_tokenExistsInSlot(slot_, toTokenId_)) {
_addTokenToSlotEnumeration(slot_, toTokenId_);
} else if (to_ == address(0) && toTokenId_ == 0 && _tokenExistsInSlot(slot_, fromTokenId_)) {
_removeTokenFromSlotEnumeration(slot_, fromTokenId_);
}
//Shh - currently unused
value_;
super._afterValueTransfer(from_, to_, fromTokenId_, toTokenId_, slot_, value_);
}
function _addSlotToAllSlotsEnumeration(SlotData memory slotData) private {
_allSlotsIndex[slotData.slot] = _allSlots.length;
_allSlots.push(slotData);
}
function _addTokenToSlotEnumeration(uint256 slot_, uint256 tokenId_) private {
SlotData storage slotData = _allSlots[_allSlotsIndex[slot_]];
_slotTokensIndex[slot_][tokenId_] = slotData.slotTokens.length;
slotData.slotTokens.push(tokenId_);
}
function _removeTokenFromSlotEnumeration(uint256 slot_, uint256 tokenId_) private {
SlotData storage slotData = _allSlots[_allSlotsIndex[slot_]];
uint256 lastTokenIndex = slotData.slotTokens.length - 1;
uint256 lastTokenId = slotData.slotTokens[lastTokenIndex];
uint256 tokenIndex = _slotTokensIndex[slot_][tokenId_];
slotData.slotTokens[tokenIndex] = lastTokenId;
_slotTokensIndex[slot_][lastTokenId] = tokenIndex;
delete _slotTokensIndex[slot_][tokenId_];
slotData.slotTokens.pop();
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[47] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
import "./IERC721Upgradeable.sol";
import "./IERC3525Upgradeable.sol";
import "./IERC721ReceiverUpgradeable.sol";
import "./IERC3525ReceiverUpgradeable.sol";
import "./extensions/IERC721EnumerableUpgradeable.sol";
import "./extensions/IERC721MetadataUpgradeable.sol";
import "./extensions/IERC3525MetadataUpgradeable.sol";
import "./periphery/interface/IERC3525MetadataDescriptorUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract ERC3525Upgradeable is Initializable, ContextUpgradeable, IERC3525MetadataUpgradeable, IERC721EnumerableUpgradeable {
using StringsUpgradeable for address;
using StringsUpgradeable for uint256;
using AddressUpgradeable for address;
using CountersUpgradeable for CountersUpgradeable.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;
CountersUpgradeable.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;
IERC3525MetadataDescriptorUpgradeable public metadataDescriptor;
function __ERC3525_init(string memory name_, string memory symbol_, uint8 decimals_) internal onlyInitializing {
__ERC3525_init_unchained(name_, symbol_, decimals_);
}
function __ERC3525_init_unchained(string memory name_, string memory symbol_, uint8 decimals_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(IERC165Upgradeable).interfaceId ||
interfaceId == type(IERC3525Upgradeable).interfaceId ||
interfaceId == type(IERC721Upgradeable).interfaceId ||
interfaceId == type(IERC3525MetadataUpgradeable).interfaceId ||
interfaceId == type(IERC721EnumerableUpgradeable).interfaceId ||
interfaceId == type(IERC721MetadataUpgradeable).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/", StringsUpgradeable.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 = ERC3525Upgradeable.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, ERC3525Upgradeable.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 = ERC3525Upgradeable.ownerOf(tokenId_);
require(to_ != owner, "ERC3525: approval to current owner");
require(
_msgSender() == owner || ERC3525Upgradeable.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_ < ERC3525Upgradeable.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_ < ERC3525Upgradeable.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 = ERC3525Upgradeable.ownerOf(tokenId_);
return (
operator_ == owner ||
ERC3525Upgradeable.isApprovedForAll(owner, operator_) ||
ERC3525Upgradeable.getApproved(tokenId_) == operator_
);
}
function _spendAllowance(address operator_, uint256 tokenId_, uint256 value_) internal virtual {
uint256 currentAllowance = ERC3525Upgradeable.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 = ERC3525Upgradeable.ownerOf(tokenId_);
uint256 slot = ERC3525Upgradeable.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(ERC3525Upgradeable.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(ERC3525Upgradeable.ownerOf(tokenId_) == from_, "ERC3525: transfer from invalid owner");
require(to_ != address(0), "ERC3525: transfer to the zero address");
uint256 slot = ERC3525Upgradeable.slotOf(tokenId_);
uint256 value = ERC3525Upgradeable.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_
) internal virtual returns (bool) {
address to = ERC3525Upgradeable.ownerOf(toTokenId_);
if (to.isContract()) {
try IERC165Upgradeable(to).supportsInterface(type(IERC3525ReceiverUpgradeable).interfaceId) returns (bool retval) {
if (retval) {
bytes4 receivedVal = IERC3525ReceiverUpgradeable(to).onERC3525Received(_msgSender(), fromTokenId_, toTokenId_, value_, data_);
return receivedVal == IERC3525ReceiverUpgradeable.onERC3525Received.selector;
} else {
return true;
}
} catch (bytes memory /** reason */) {
return true;
}
} 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
IERC721ReceiverUpgradeable(to_).onERC721Received(_msgSender(), from_, tokenId_, data_) returns (bytes4 retval) {
return retval == IERC721ReceiverUpgradeable.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 = IERC3525MetadataDescriptorUpgradeable(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();
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[41] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "../IERC3525.sol";
import "./IERC721Metadata.sol";
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "../IERC3525Upgradeable.sol";
import "./IERC721MetadataUpgradeable.sol";
/**
* @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 IERC3525MetadataUpgradeable is IERC3525Upgradeable, IERC721MetadataUpgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "../IERC3525Upgradeable.sol";
import "./IERC721EnumerableUpgradeable.sol";
/**
* @title ERC-3525 Semi-Fungible Token Standard, optional extension for slot enumeration
* @dev Interfaces for any contract that wants to support enumeration of slots as well as tokens
* with the same slot.
* See https://eips.ethereum.org/EIPS/eip-3525
* Note: the ERC-165 identifier for this interface is 0x3b741b9e.
*/
interface IERC3525SlotEnumerableUpgradeable is IERC3525Upgradeable, IERC721EnumerableUpgradeable {
/**
* @notice Get the total amount of slots stored by the contract.
* @return The total amount of slots
*/
function slotCount() external view returns (uint256);
/**
* @notice Get the slot at the specified index of all slots stored by the contract.
* @param _index The index in the slot list
* @return The slot at `index` of all slots.
*/
function slotByIndex(uint256 _index) external view returns (uint256);
/**
* @notice Get the total amount of tokens with the same slot.
* @param _slot The slot to query token supply for
* @return The total amount of tokens with the specified `_slot`
*/
function tokenSupplyInSlot(uint256 _slot) external view returns (uint256);
/**
* @notice Get the token at the specified index of all tokens with the same slot.
* @param _slot The slot to query tokens with
* @param _index The index in the token list of the slot
* @return The token ID at `_index` of all tokens with `_slot`
*/
function tokenInSlotByIndex(uint256 _slot, uint256 _index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "../IERC721Upgradeable.sol";
/**
* @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 IERC721EnumerableUpgradeable is IERC721Upgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "../IERC721.sol";
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "../IERC721Upgradeable.sol";
/**
* @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 IERC721MetadataUpgradeable is IERC721Upgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./IERC721.sol";
/**
* @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);
}// SPDX-License-Identifier: MIT
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 IERC3525ReceiverUpgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import "./IERC721Upgradeable.sol";
/**
* @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 IERC3525Upgradeable is IERC165Upgradeable, IERC721Upgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @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);
}// SPDX-License-Identifier: MIT
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 IERC721ReceiverUpgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
/**
* @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 IERC721Upgradeable is IERC165Upgradeable {
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "./interface/IERC3525MetadataDescriptor.sol";
import "../extensions/IERC3525Metadata.sol";
contract ERC3525MetadataDescriptor is IERC3525MetadataDescriptor {
using Strings for uint256;
function constructContractURI() external view override returns (string memory) {
IERC3525Metadata erc3525 = IERC3525Metadata(msg.sender);
return
string(
abi.encodePacked(
/* solhint-disable */
'data:application/json;base64,',
Base64.encode(
abi.encodePacked(
'{"name":"',
erc3525.name(),
'","description":"',
_contractDescription(),
'","image":"',
_contractImage(),
'","valueDecimals":"',
uint256(erc3525.valueDecimals()).toString(),
'"}'
)
)
/* solhint-enable */
)
);
}
function constructSlotURI(uint256 slot_) external view override returns (string memory) {
return
string(
abi.encodePacked(
/* solhint-disable */
'data:application/json;base64,',
Base64.encode(
abi.encodePacked(
'{"name":"',
_slotName(slot_),
'","description":"',
_slotDescription(slot_),
'","image":"',
_slotImage(slot_),
'","properties":',
_slotProperties(slot_),
'}'
)
)
/* solhint-enable */
)
);
}
function constructTokenURI(uint256 tokenId_) external view override returns (string memory) {
IERC3525Metadata erc3525 = IERC3525Metadata(msg.sender);
return
string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
abi.encodePacked(
/* solhint-disable */
'{"name":"',
_tokenName(tokenId_),
'","description":"',
_tokenDescription(tokenId_),
'","image":"',
_tokenImage(tokenId_),
'","balance":"',
erc3525.balanceOf(tokenId_).toString(),
'","slot":"',
erc3525.slotOf(tokenId_).toString(),
'","properties":',
_tokenProperties(tokenId_),
"}"
/* solhint-enable */
)
)
)
);
}
function _contractDescription() internal view virtual returns (string memory) {
return "";
}
function _contractImage() internal view virtual returns (bytes memory) {
return "";
}
function _slotName(uint256 slot_) internal view virtual returns (string memory) {
slot_;
return "";
}
function _slotDescription(uint256 slot_) internal view virtual returns (string memory) {
slot_;
return "";
}
function _slotImage(uint256 slot_) internal view virtual returns (bytes memory) {
slot_;
return "";
}
function _slotProperties(uint256 slot_) internal view virtual returns (string memory) {
slot_;
return "[]";
}
function _tokenName(uint256 tokenId_) internal view virtual returns (string memory) {
// solhint-disable-next-line
return
string(
abi.encodePacked(
IERC3525Metadata(msg.sender).name(),
" #", tokenId_.toString()
)
);
}
function _tokenDescription(uint256 tokenId_) internal view virtual returns (string memory) {
tokenId_;
return "";
}
function _tokenImage(uint256 tokenId_) internal view virtual returns (bytes memory) {
tokenId_;
return "";
}
function _tokenProperties(uint256 tokenId_) internal view virtual returns (string memory) {
tokenId_;
return "{}";
}
}// SPDX-License-Identifier: MIT
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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC3525MetadataDescriptorUpgradeable {
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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOpenFundRedemptionConcrete {
struct RedeemInfo {
bytes32 poolId;
address currency;
uint256 createTime;
uint256 nav;
}
function setRedeemNavOnlyDelegate(uint256 slot_, uint256 nav_) external;
function getRedeemInfo(uint256 slot_) external view returns (RedeemInfo memory);
function getRedeemNav(uint256 slot_) external view returns (uint256);
function getRedemptionFeeRate(uint256 slot_) external view returns (uint256);
function redemptionFeeReceiver() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOpenFundRedemptionDelegate {
function setRedeemNavOnlyMarket(uint256 slot_, uint256 nav_) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-abilities/contracts/value-issuable/SFTValueIssuableConcrete.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/fcfs-multi-repayable/FCFSMultiRepayableConcrete.sol";
import "./IOpenFundRedemptionConcrete.sol";
contract OpenFundRedemptionConcrete is IOpenFundRedemptionConcrete, SFTValueIssuableConcrete, FCFSMultiRepayableConcrete {
event SetRedemptionFeeReceiver(address indexed redemptionFeeReceiver);
event SetRedemtpionFeeRate(bytes32 indexed poolId, uint256 redemptionFeeRate);
mapping(uint256 => RedeemInfo) internal _redeemInfos;
address public redemptionFeeReceiver;
// poolId => redemptionFeeRate
mapping(bytes32 => uint256) public redemptionFeeRates; // base: 1e18
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize() external initializer {
__SFTIssuableConcrete_init();
}
function setRedeemNavOnlyDelegate(uint256 slot_, uint256 nav_) external virtual override onlyDelegate {
_redeemInfos[slot_].nav = nav_;
}
function setRedemptionFeeReceiverOnlyAdmin(address redemptionFeeReceiver_) external virtual onlyAdmin {
redemptionFeeReceiver = redemptionFeeReceiver_;
emit SetRedemptionFeeReceiver(redemptionFeeReceiver_);
}
function setRedemptionFeeRateOnlyAdmin(bytes32 poolId_, uint256 redemptionFeeRate_) external virtual onlyAdmin {
redemptionFeeRates[poolId_] = redemptionFeeRate_;
emit SetRedemtpionFeeRate(poolId_, redemptionFeeRate_);
}
function getRedemptionFeeRate(uint256 slot_) external view virtual returns (uint256) {
return redemptionFeeRates[_redeemInfos[slot_].poolId];
}
function getRedeemInfo(uint256 slot_) external view virtual override returns (RedeemInfo memory) {
return _redeemInfos[slot_];
}
function getRedeemNav(uint256 slot_) external view virtual override returns (uint256) {
return _redeemInfos[slot_].nav;
}
function _isSlotValid( uint256 slot_) internal view virtual override returns (bool) {
return _redeemInfos[slot_].createTime != 0;
}
function _createSlot( address /* txSender_ */, bytes memory inputSlotInfo_) internal virtual override returns (uint256 slot_) {
RedeemInfo memory redeemInfo = abi.decode(inputSlotInfo_, (RedeemInfo));
require(redeemInfo.poolId != bytes32(0), "OFRC: invalid poolId");
require(redeemInfo.currency != address(0), "OFRC: invalid currency");
require(redeemInfo.createTime != 0, "OFRC: invalid createTime");
slot_ = _getSlot(redeemInfo.poolId, redeemInfo.currency, redeemInfo.createTime);
// if the slot is already created, do nothing
if (_redeemInfos[slot_].createTime == 0) {
_redeemInfos[slot_] = redeemInfo;
}
}
function _getSlot(bytes32 poolId_, address currency_, uint256 createTime_) internal view virtual returns (uint256) {
uint256 chainId;
assembly { chainId := chainid() }
return uint256(keccak256(abi.encodePacked(chainId, delegate(), poolId_, currency_, createTime_)));
}
function _mint(
address /** txSender_ */, address currency_, address /** mintTo_ */,
uint256 slot_, uint256 /** tokenId_ */, uint256 /** amount_ */
) internal virtual override {
require(_isSlotValid(slot_), "OFRC: invalid slot");
require(_redeemInfos[slot_].currency == currency_, "OFRC: invalid currency");
}
function _burn(uint256 tokenId_, uint256 burnValue_) internal virtual override {
uint256 slot = ERC3525Upgradeable(delegate()).slotOf(tokenId_);
FCFSMultiRepayableConcrete._slotValueInfo[slot].slotTotalValue -= burnValue_;
}
function _currency( uint256 slot_) internal view virtual override returns (address) {
return _redeemInfos[slot_].currency;
}
function _repayRate( uint256 slot_) internal view virtual override returns (uint256) {
return _redeemInfos[slot_].nav;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-abilities/contracts/fcfs-multi-repayable/FCFSMultiRepayableDelegate.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/value-issuable/SFTValueIssuableDelegate.sol";
import "./IOpenFundRedemptionDelegate.sol";
import "./IOpenFundRedemptionConcrete.sol";
contract OpenFundRedemptionDelegate is IOpenFundRedemptionDelegate, SFTValueIssuableDelegate, FCFSMultiRepayableDelegate {
bytes32 internal constant CONTRACT_OPEN_FUND_MARKET = "OpenFundMarket";
bool private __allowRepayWithBalance;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(
address resolver_, string calldata name_, string calldata symbol_, uint8 decimals_,
address concrete_, address descriptor_, address owner_, bool allowRepayWithBalance_
) external initializer {
__SFTIssuableDelegate_init(resolver_, name_, symbol_, decimals_, concrete_, descriptor_, owner_);
__allowRepayWithBalance = allowRepayWithBalance_;
}
function setRedeemNavOnlyMarket(uint256 slot_, uint256 nav_) external virtual override {
require(_msgSender() == _issueMarket(), "OFRD: only market");
IOpenFundRedemptionConcrete(concrete()).setRedeemNavOnlyDelegate(slot_, nav_);
}
function claimTo(address to_, uint256 tokenId_, address currency_, uint256 claimValue_) external virtual override nonReentrant {
require(claimValue_ > 0, "MultiRepayableDelegate: claim value is zero");
require(_isApprovedOrOwner(_msgSender(), tokenId_), "MultiRepayableDelegate: caller is not owner nor approved");
uint256 slot = ERC3525Upgradeable.slotOf(tokenId_);
uint256 claimableValue = IFCFSMultiRepayableConcrete(concrete()).claimableValue(tokenId_);
require(claimValue_ <= claimableValue, "MultiRepayableDelegate: over claim");
uint256 claimCurrencyAmount = IFCFSMultiRepayableConcrete(concrete()).claimOnlyDelegate(tokenId_, slot, currency_, claimValue_);
uint256 feeRate = IOpenFundRedemptionConcrete(concrete()).getRedemptionFeeRate(slot);
uint256 feeAmount = claimCurrencyAmount * feeRate / 1e18;
if (claimValue_ == ERC3525Upgradeable.balanceOf(tokenId_)) {
ERC3525Upgradeable._burn(tokenId_);
} else {
ERC3525Upgradeable._burnValue(tokenId_, claimValue_);
}
address feeReceiver = IOpenFundRedemptionConcrete(concrete()).redemptionFeeReceiver();
ERC20TransferHelper.doTransferOut(currency_, payable(feeReceiver), feeAmount);
ERC20TransferHelper.doTransferOut(currency_, payable(to_), claimCurrencyAmount - feeAmount);
emit Claim(to_, tokenId_, claimValue_, currency_, claimCurrencyAmount);
}
function allowRepayWithBalance() public view virtual override returns (bool) {
return __allowRepayWithBalance;
}
function _beforeValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual override(ERC3525SlotEnumerableUpgradeable, FCFSMultiRepayableDelegate) {
FCFSMultiRepayableDelegate._beforeValueTransfer(from_, to_, fromTokenId_, toTokenId_, slot_, value_);
}
function _resolverAddressesRequired() internal view virtual override returns (bytes32[] memory addressNames) {
addressNames = new bytes32[](1);
addressNames[0] = CONTRACT_OPEN_FUND_MARKET;
}
function _issueMarket() internal view virtual override returns (address) {
return getRequiredAddress(CONTRACT_OPEN_FUND_MARKET, "OFRD: OpenFundMarket not set");
}
function contractType() external view virtual override returns (string memory) {
return "Open Fund Redemptions";
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-earn/contracts/EarnMetadataDescriptor.sol";
import "./OpenFundRedemptionDelegate.sol";
import "./OpenFundRedemptionConcrete.sol";
contract OpenFundRedemptionMetadataDescriptor is EarnMetadataDescriptor {
using Strings for uint256;
using Strings for address;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function _slotProperties(uint256 slot_) internal view virtual override returns (string memory) {
OpenFundRedemptionDelegate delegate = OpenFundRedemptionDelegate(msg.sender);
OpenFundRedemptionConcrete concrete = OpenFundRedemptionConcrete(delegate.concrete());
OpenFundRedemptionConcrete.RedeemInfo memory redeemInfo = concrete.getRedeemInfo(slot_);
uint256 chainId;
assembly {
chainId := chainid()
}
return
string(
abi.encodePacked(
'[',
abi.encodePacked(
'{"name":"chain_id",',
'"description":"chain id",',
'"value":"', chainId.toString(), '",',
'"is_intrinsic":true,',
'"order":1,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"payable_token_address",',
'"description":"Address of this contract.",',
'"value":"', concrete.delegate().toHexString(), '",',
'"is_intrinsic":true,',
'"order":2,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"pool_id",',
'"description":"Pool ID in the Open-end Fund Market.",',
'"value":"', uint256(redeemInfo.poolId).toHexString(), '",',
'"is_intrinsic":true,',
'"order":3,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"currency",',
'"description":"Currency of this slot.",',
'"value":"', redeemInfo.currency.toHexString(), '",',
'"is_intrinsic":true,',
'"order":4,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"create_time",',
'"description":"Time when this slot is created.",',
'"value":"', redeemInfo.createTime.toString(), '",',
'"is_intrinsic":true,',
'"order":3,',
'"display_type":"date"},'
),
abi.encodePacked(
'{"name":"nav",',
'"description":"Settled nav of this slot.",',
'"value":"', redeemInfo.nav.toString(), '",',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
']'
)
);
}
function _tokenProperties(uint256 tokenId_) internal view virtual override returns (string memory) {
OpenFundRedemptionDelegate delegate = OpenFundRedemptionDelegate(msg.sender);
OpenFundRedemptionConcrete concrete = OpenFundRedemptionConcrete(delegate.concrete());
uint256 slot = delegate.slotOf(tokenId_);
OpenFundRedemptionConcrete.RedeemInfo memory redeemInfo = concrete.getRedeemInfo(slot);
return
string(
abi.encodePacked(
/* solhint-disable */
'{"pool_id":"', uint256(redeemInfo.poolId).toHexString(),
'","currency":"', redeemInfo.currency.toHexString(),
'","create_time":"', redeemInfo.createTime.toString(),
'","nav":"', redeemInfo.nav.toString(),
'"}'
/* solhint-enable */
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../OpenFundRedemptionDelegate.sol";
import "../OpenFundRedemptionConcrete.sol";
import "../../svg-base/OpenFundSVGBase.sol";
contract DefaultOpenFundRedemptionSVG is OpenFundSVGBase {
using Strings for uint256;
using Strings for address;
using Dates for uint256;
struct SVGParams {
address payableAddress;
string tokenId;
uint256 slot;
string payableName;
string currencyTokenSymbol;
string tokenBalance;
string value;
string nav;
address issuer;
string svgGenerationTime;
}
function generateSVG(address payable_, uint256 tokenId_)
external
view
virtual
override
returns (string memory)
{
OpenFundRedemptionDelegate payableDelegate = OpenFundRedemptionDelegate(payable_);
OpenFundRedemptionConcrete payableConcrete = OpenFundRedemptionConcrete(payableDelegate.concrete());
uint256 tokenBalance = payableDelegate.balanceOf(tokenId_);
uint256 slot = payableDelegate.slotOf(tokenId_);
OpenFundRedemptionConcrete.RedeemInfo memory redeemInfo = payableConcrete.getRedeemInfo(slot);
(,, OpenFundMarketStorage.ManagerInfo memory managerInfo, ,,,,,,) = OpenFundMarketStorage(_market()).poolInfos(redeemInfo.poolId);
uint256 value = tokenBalance * redeemInfo.nav / (10 ** payableDelegate.valueDecimals());
SVGParams memory svgParams;
svgParams.payableAddress = payable_;
svgParams.tokenId = tokenId_.toString();
svgParams.slot = slot;
svgParams.payableName = payableDelegate.name();
svgParams.currencyTokenSymbol = ERC20(redeemInfo.currency).symbol();
svgParams.tokenBalance = string(_formatValue(tokenBalance, payableDelegate.valueDecimals()));
svgParams.value = redeemInfo.nav == 0 ? 'Pending' : string(abi.encodePacked(_formatValue(value, ERC20(redeemInfo.currency).decimals()), ' ', svgParams.currencyTokenSymbol));
svgParams.nav = redeemInfo.nav == 0 ? 'Pending' : string(_formatValue(redeemInfo.nav, ERC20(redeemInfo.currency).decimals()));
svgParams.issuer = managerInfo.poolManager;
svgParams.svgGenerationTime = block.timestamp.datetimeToString();
return generateSVG(svgParams);
}
function generateSVG(SVGParams memory params)
public
virtual
view
returns (string memory)
{
return
string(
abi.encodePacked(
'<svg width="600" height="400" viewBox="0 0 600 400" fill="none" xmlns="http://www.w3.org/2000/svg">',
_generateBackground(params.payableAddress, params.slot),
_generateContent(params),
'</svg>'
)
);
}
function _generateContent(SVGParams memory params) internal view virtual returns (string memory) {
SVGBackgroundGenerator.SVGColorInfo memory svgColorInfo = SVGBackgroundGenerator(svgBackgroundGenerator).getSVGColorInfo(params.payableAddress, params.slot);
return
string(
abi.encodePacked(
'<rect x="154" y="278" width="96" height="16" rx="8" fill="', svgColorInfo.backgroundColor, '" />',
'<text fill="#202020" font-family="Arial" font-size="12">',
abi.encodePacked(
'<tspan x="26" y="61" font-size="16" font-weight="bold">AMOUNT</tspan>',
'<tspan x="26" y="108" font-size="38" font-weight="bold">', params.tokenBalance, '</tspan>',
'<tspan x="26" y="143" font-size="14" font-weight="bold" fill="', svgColorInfo.backgroundColor, '">', params.payableName, '</tspan>',
'<tspan x="26" y="162">#', params.tokenId, '</tspan>'
),
abi.encodePacked(
'<tspan x="26" y="290">STATUS</tspan>'
'<tspan x="26" y="310">VALUE</tspan>',
'<tspan x="26" y="330">NAV</tspan>',
'<tspan x="238" y="290" text-anchor="end" font-size="10" fill="white">REDEMPTION</tspan>',
'<tspan x="250" y="310" text-anchor="end">', params.value, '</tspan>',
'<tspan x="250" y="330" text-anchor="end">', params.nav, '</tspan>'
),
abi.encodePacked(
'<tspan x="26" y="364" font-size="7">Issuer: ', params.issuer.toHexString(), '</tspan>',
'<tspan x="26" y="376" font-size="7">Updated: ', params.svgGenerationTime, '</tspan>',
'<tspan x="498" y="376" font-size="7" fill="white" fill-opacity="0.6">Powered by Solv Protocol</tspan>'
),
'</text>'
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-earn/contracts/IEarnConcrete.sol";
interface IOpenFundShareConcrete is IEarnConcrete {
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOpenFundShareDelegate {
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-earn/contracts/EarnDelegate.sol";
import "@solvprotocol/contracts-v3-sft-abilities/contracts/value-issuable/SFTValueIssuableDelegate.sol";
import "./IOpenFundShareDelegate.sol";
import "./IOpenFundShareConcrete.sol";
contract OpenFundShareDelegate is IOpenFundShareDelegate, EarnDelegate, SFTValueIssuableDelegate {
bytes32 internal constant CONTRACT_OPEN_FUND_MARKET = "OpenFundMarket";
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function _beforeValueTransfer(
address from_,
address to_,
uint256 fromTokenId_,
uint256 toTokenId_,
uint256 slot_,
uint256 value_
) internal virtual override(ERC3525SlotEnumerableUpgradeable, EarnDelegate) {
EarnDelegate._beforeValueTransfer(from_, to_, fromTokenId_, toTokenId_, slot_, value_);
}
function _resolverAddressesRequired() internal view virtual override returns (bytes32[] memory addressNames) {
addressNames = new bytes32[](1);
addressNames[0] = CONTRACT_OPEN_FUND_MARKET;
}
function _issueMarket() internal view virtual override returns (address) {
return getRequiredAddress(CONTRACT_OPEN_FUND_MARKET, "OFSD: Market not set");
}
function contractType() external view virtual override(BaseSFTDelegateUpgradeable, EarnDelegate) returns (string memory) {
return "Open Fund Shares";
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-sft-earn/contracts/EarnMetadataDescriptor.sol";
contract OpenFundShareMetadataDescriptor is EarnMetadataDescriptor {
using Strings for uint256;
using Strings for address;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function _formatSlotExtInfos(EarnConcrete concrete_, uint256 slot_) internal view virtual override returns (bytes memory) {
EarnConcrete.SlotExtInfo memory extInfo = concrete_.slotExtInfo(slot_);
uint256 slotTotalValue = concrete_.slotTotalValue(slot_);
return
abi.encodePacked(
abi.encodePacked(
'{"name":"supervisor",',
'"description":"Fund supervisor of this slot.",',
'"value":"', extInfo.supervisor.toHexString(), '",',
'"is_intrinsic":false,',
'"display_type":"string"},'
),
abi.encodePacked(
'{"name":"interest_rate",',
'"description":"Interest rate of this slot.",',
'"value":', _formatInterestRate(extInfo.interestRate), ',',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"is_interest_rate_set",',
'"description":"Indicate if the interest rate of this slot is set.",',
'"value":', extInfo.isInterestRateSet ? 'true' : 'false', ',',
'"is_intrinsic":false,',
'"display_type":"boolean"},'
),
abi.encodePacked(
'{"name":"total_value",',
'"description":"Total issued value of this slot.",',
'"value":', slotTotalValue.toString(), ',',
'"is_intrinsic":false,',
'"display_type":"number"},'
),
abi.encodePacked(
'{"name":"external_url",',
'"description":"External URI of this slot.",',
'"value":"', extInfo.externalURI, '",',
'"is_intrinsic":false,',
'"display_type":"string"}'
)
);
}
function _tokenProperties(uint256 tokenId_) internal view virtual override returns (string memory) {
EarnDelegate delegate = EarnDelegate(msg.sender);
EarnConcrete concrete = EarnConcrete(delegate.concrete());
uint256 slot = delegate.slotOf(tokenId_);
EarnConcrete.SlotBaseInfo memory baseInfo = concrete.slotBaseInfo(slot);
EarnConcrete.SlotExtInfo memory extInfo = concrete.slotExtInfo(slot);
return
string(
abi.encodePacked(
/* solhint-disable */
'{"issuer":"', baseInfo.issuer.toHexString(),
'","supervisor":"', extInfo.supervisor.toHexString(),
'","currency":"', baseInfo.currency.toHexString(),
'"}'
/* solhint-enable */
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../OpenFundShareDelegate.sol";
import "../OpenFundShareConcrete.sol";
import "../../svg-base/OpenFundSVGBase.sol";
contract DefaultOpenFundShareSVG is OpenFundSVGBase {
using Strings for uint256;
using Strings for address;
using Dates for uint256;
struct SVGParams {
address payableAddress;
string tokenId;
uint256 slot;
string payableName;
string currencyTokenSymbol;
string tokenBalance;
string estValue;
string navDate;
address issuer;
string svgGenerationTime;
}
function generateSVG(address payable_, uint256 tokenId_)
external
view
virtual
override
returns (string memory)
{
OpenFundShareDelegate payableDelegate = OpenFundShareDelegate(payable_);
OpenFundShareConcrete payableConcrete = OpenFundShareConcrete(payableDelegate.concrete());
uint256 tokenBalance = payableDelegate.balanceOf(tokenId_);
uint256 slot = payableDelegate.slotOf(tokenId_);
OpenFundShareConcrete.SlotBaseInfo memory baseInfo = payableConcrete.slotBaseInfo(slot);
bytes32 marketPoolId = keccak256(abi.encode(payable_, slot));
(,,,,,, address navOracle, ,,) = OpenFundMarketStorage(_market()).poolInfos(marketPoolId);
(uint256 nav, uint256 navDate) = INavOracle(navOracle).getSubscribeNav(marketPoolId, block.timestamp);
uint256 estValue = tokenBalance * nav / (10 ** payableDelegate.valueDecimals());
SVGParams memory svgParams;
svgParams.payableAddress = payable_;
svgParams.tokenId = tokenId_.toString();
svgParams.slot = slot;
svgParams.payableName = payableDelegate.name();
svgParams.currencyTokenSymbol = ERC20(baseInfo.currency).symbol();
svgParams.tokenBalance = string(_formatValue(tokenBalance, payableDelegate.valueDecimals()));
svgParams.estValue = string(_formatValue(estValue, ERC20(baseInfo.currency).decimals()));
svgParams.navDate = navDate.dateToString();
svgParams.issuer = baseInfo.issuer;
svgParams.svgGenerationTime = block.timestamp.datetimeToString();
return generateSVG(svgParams);
}
function generateSVG(SVGParams memory params)
public
virtual
view
returns (string memory)
{
return
string(
abi.encodePacked(
'<svg width="600" height="400" viewBox="0 0 600 400" fill="none" xmlns="http://www.w3.org/2000/svg">',
_generateBackground(params.payableAddress, params.slot),
_generateContent(params),
'</svg>'
)
);
}
function _generateContent(SVGParams memory params) internal view virtual returns (string memory) {
SVGBackgroundGenerator.SVGColorInfo memory svgColorInfo = SVGBackgroundGenerator(svgBackgroundGenerator).getSVGColorInfo(params.payableAddress, params.slot);
return
string(
abi.encodePacked(
'<text fill="#202020" font-family="Arial" font-size="12">',
abi.encodePacked(
'<tspan x="26" y="61" font-size="16" font-weight="bold">AMOUNT</tspan>',
'<tspan x="26" y="108" font-size="38" font-weight="bold">', params.tokenBalance, '</tspan>',
'<tspan x="26" y="143" font-size="14" font-weight="bold" fill="', svgColorInfo.backgroundColor, '">', params.payableName, '</tspan>',
'<tspan x="26" y="162">#', params.tokenId, '</tspan>'
),
abi.encodePacked(
'<tspan x="26" y="300">EST. VALUE</tspan>',
'<tspan x="26" y="320">NAV DATE</tspan>',
'<tspan x="250" y="300" text-anchor="end">', params.estValue, ' ', params.currencyTokenSymbol, '</tspan>',
'<tspan x="250" y="320" text-anchor="end">', params.navDate, '</tspan>'
),
abi.encodePacked(
'<tspan x="26" y="364" font-size="7">Issuer: ', params.issuer.toHexString(), '</tspan>',
'<tspan x="26" y="376" font-size="7">Updated: ', params.svgGenerationTime, '</tspan>',
'<tspan x="498" y="376" font-size="7" fill="white" fill-opacity="0.6">Powered by Solv Protocol</tspan>'
),
'</text>'
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/StringConvertor.sol";
import "@solvprotocol/contracts-v3-solidity-utils/contracts/misc/Dates.sol";
import "@solvprotocol/contracts-v3-address-resolver/contracts/ResolverCache.sol";
import "@solvprotocol/contracts-v3-open-fund-market/contracts/OpenFundMarketStorage.sol";
import "@solvprotocol/contracts-v3-open-fund-market/contracts/oracle/INavOracle.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./SVGBackgroundGenerator.sol";
abstract contract OpenFundSVGBase is ResolverCache {
using StringConvertor for uint256;
using StringConvertor for bytes;
bytes32 internal constant CONTRACT_OPEN_FUND_MARKET = "OpenFundMarket";
address public svgBackgroundGenerator;
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "only owner");
_;
}
function initialize(address resolver_, address svgBackgroundGenerator_, address owner_) external initializer {
__ResolverCache_init(resolver_);
svgBackgroundGenerator = svgBackgroundGenerator_;
owner = owner_;
}
function generateSVG(address payable_, uint256 tokenId_) external virtual view returns (string memory);
function _generateBackground(address sft_, uint256 slot_) internal view virtual returns (string memory) {
return SVGBackgroundGenerator(svgBackgroundGenerator).generateBackground(sft_, slot_);
}
function _formatValue(uint256 value, uint8 decimals) internal pure returns (bytes memory) {
if(value < (10 ** decimals)) {
return value.toDecimalsString(decimals).trimRight(decimals - 6);
} else {
return value.toDecimalsString(decimals).trimRight(decimals - 2).addThousandsSeparator();
}
}
function _resolverAddressesRequired() internal view virtual override returns (bytes32[] memory addressNames) {
addressNames = new bytes32[](1);
addressNames[0] = CONTRACT_OPEN_FUND_MARKET;
}
function _market() internal view virtual returns (address) {
return getRequiredAddress(CONTRACT_OPEN_FUND_MARKET, "OFS_SVG: Market not set");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@solvprotocol/contracts-v3-solidity-utils/contracts/access/OwnControl.sol";
import "@solvprotocol/contracts-v3-address-resolver/contracts/ResolverCache.sol";
import "@solvprotocol/contracts-v3-open-fund-market/contracts/OpenFundMarketStorage.sol";
import "../open-fund-redemptions/OpenFundRedemptionDelegate.sol";
import "../open-fund-redemptions/OpenFundRedemptionConcrete.sol";
contract SVGBackgroundGenerator is OwnControl, ResolverCache {
struct SVGColorInfo {
uint256 strategyCount;
string backgroundColor;
string[] patternColors;
}
event SetSVGColorInfo(address sft, uint256 slot, SVGColorInfo svgColorInfo);
bytes32 internal constant CONTRACT_OPEN_FUND_MARKET = "OpenFundMarket";
mapping(address => mapping(uint256 => SVGColorInfo)) internal _svgColorInfos;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address resolver_, address owner_, SVGColorInfo calldata defaultColorInfo_) external initializer {
__ResolverCache_init(resolver_);
__OwnControl_init(owner_);
_setSVGColorInfo(address(0), 0, defaultColorInfo_);
}
function generateBackground(address sft_, uint256 slot_) external view virtual returns (string memory background_) {
(address shareAddress, uint256 shareSlot) = _getShareAddressAndSlot(sft_, slot_);
SVGColorInfo storage colorInfo = _svgColorInfos[shareAddress][shareSlot];
if (colorInfo.strategyCount == 0) {
colorInfo = _svgColorInfos[address(0)][0];
}
bytes memory outline = abi.encodePacked(
'<rect width="600" height="400" rx="20" fill="white" />',
'<rect x="0.5" y="0.5" width="599" height="399" rx="20" stroke="#F9F9F9" />',
'<mask id="m_3525_1" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="300" y="0" width="300" height="400">',
'<path d="M300 0H580C590 0 600 8 600 20V380C600 392 590 400 580 400H300V0Z" fill="white" />',
'</mask>'
);
bytes memory figure;
if (colorInfo.strategyCount == 1) {
figure = abi.encodePacked(
abi.encodePacked(
'<defs>',
abi.encodePacked(
'<linearGradient id="p_3525_1" x1="540" y1="120" x2="360" y2="275" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
'</defs>'
),
abi.encodePacked(
'<g mask="url(#m_3525_1)">',
'<rect x="300" width="300" height="400" fill="', colorInfo.backgroundColor, '" />',
'<circle cx="450" cy="200" r="115" fill="url(#p_3525_1)"></circle>',
'</g>'
)
);
} else if (colorInfo.strategyCount == 2) {
figure = abi.encodePacked(
abi.encodePacked(
'<defs>',
abi.encodePacked(
'<linearGradient id="p_3525_1" x1="410" y1="180" x2="565" y2="70" gradientUnits="userSpaceOnUse">',
'<stop offset="0.1" stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="0.9" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_2" x1="370" y1="346" x2="480" y2="205" gradientUnits="userSpaceOnUse">',
'<stop offset="0.06" stop-color="', colorInfo.patternColors[2], '" />',
'<stop offset="0.9" stop-color="', colorInfo.patternColors[3], '" />',
'</linearGradient>'
),
'</defs>'
),
abi.encodePacked(
'<g mask="url(#m_3525_1)">',
'<rect x="300" width="300" height="400" fill="', colorInfo.backgroundColor, '" />',
'<circle cx="489" cy="125" r="77" fill="url(#p_3525_1)"></circle>',
'<circle cx="411" cy="269" r="77" fill="url(#p_3525_2)"></circle>',
'</g>'
)
);
} else if (colorInfo.strategyCount == 3) {
figure = abi.encodePacked(
abi.encodePacked(
'<defs>',
abi.encodePacked(
'<linearGradient id="p_3525_1" x1="330" y1="340" x2="460" y2="60" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_2" x1="450" y1="220" x2="560" y2="60" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[2], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[3], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_3" x1="460" y1="340" x2="550" y2="240" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[4], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[5], '" />',
'</linearGradient>'
),
'</defs>'
),
abi.encodePacked(
'<g mask="url(#m_3525_1)">',
'<rect x="300" width="300" height="400" fill="', colorInfo.backgroundColor, '" />',
'<path d="M333 292A55 55 0 0 0 443 292V108A55 55 0 0 0 333 108Z" fill="url(#p_3525_1)"/>',
'<path d="M457 165A55 55 0 0 0 567 165V108A55 55 0 0 0 457 108Z" fill="url(#p_3525_2)"/>',
'<circle cx="512" cy="292" r="55" fill="url(#p_3525_3)"></circle>',
'</g>'
)
);
} else {
figure = abi.encodePacked(
abi.encodePacked(
'<defs>',
abi.encodePacked(
'<linearGradient id="p_3525_1" x1="410" y1="40" x2="360" y2="140" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_2" x1="585" y1="125" x2="460" y2="-14" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_3" x1="315" y1="200" x2="440" y2="65" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_4" x1="490" y1="120" x2="540" y2="220" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_5" x1="410" y1="195" x2="360" y2="300" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_6" x1="585" y1="280" x2="460" y2="140" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_7" x1="315" y1="360" x2="440" y2="220" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
abi.encodePacked(
'<linearGradient id="p_3525_8" x1="490" y1="270" x2="540" y2="375" gradientUnits="userSpaceOnUse">',
'<stop stop-color="', colorInfo.patternColors[0], '" />',
'<stop offset="1" stop-color="', colorInfo.patternColors[1], '" />',
'</linearGradient>'
),
'</defs>'
),
abi.encodePacked(
'<g mask="url(#m_3525_1)">',
'<rect x="300" width="300" height="400" fill="', colorInfo.backgroundColor, '" />',
'<circle cx="367" cy="83" r="35" fill="url(#p_3525_1)"></circle>',
'<path d="M444 48A35 35 0 0 0 444 118H533A 35 35 0 0 0 533 48Z" fill="url(#p_3525_2)" />',
'<path d="M367 126A35 35 0 0 0 367 196H456A 35 35 0 0 0 456 126Z" fill="url(#p_3525_3)" />',
'<circle cx="533" cy="161" r="35" fill="url(#p_3525_4)"></circle>',
'<circle cx="367" cy="239" r="35" fill="url(#p_3525_5)"></circle>',
'<path d="M444 204A35 35 0 0 0 444 274H533A 35 35 0 0 0 533 204Z" fill="url(#p_3525_6)" />',
'<path d="M367 282A35 35 0 0 0 367 352H456A 35 35 0 0 0 456 282Z" fill="url(#p_3525_7)" />',
'<circle cx="533" cy="317" r="35" fill="url(#p_3525_8)"></circle>',
'</g>'
)
);
}
return string(abi.encodePacked(outline, figure));
}
function setSVGColorInfo(address sft_, uint256 slot_, SVGColorInfo calldata svgColorInfo_) external virtual onlyOwner {
_setSVGColorInfo(sft_, slot_, svgColorInfo_);
}
function getSVGColorInfo(address sft_, uint256 slot_) public view virtual returns (SVGColorInfo memory colorInfo) {
(address shareAddress, uint256 shareSlot) = _getShareAddressAndSlot(sft_, slot_);
colorInfo = _svgColorInfos[shareAddress][shareSlot];
if (colorInfo.strategyCount == 0) {
colorInfo = _svgColorInfos[address(0)][0];
}
}
function _setSVGColorInfo(address sft_, uint256 slot_, SVGColorInfo calldata svgColorInfo_) internal virtual {
_svgColorInfos[sft_][slot_] = svgColorInfo_;
emit SetSVGColorInfo(sft_, slot_, svgColorInfo_);
}
function _getShareAddressAndSlot(address sftAddress_, uint256 sftSlot_)
internal
view
virtual
returns (address, uint256)
{
string memory contractType = BaseSFTDelegateUpgradeable(sftAddress_).contractType();
if (keccak256(abi.encodePacked(contractType)) == keccak256(abi.encodePacked("Open Fund Shares"))) {
return (sftAddress_, sftSlot_);
} else {
OpenFundRedemptionConcrete concrete = OpenFundRedemptionConcrete(OpenFundRedemptionDelegate(sftAddress_).concrete());
OpenFundRedemptionConcrete.RedeemInfo memory redeemInfo = concrete.getRedeemInfo(sftSlot_);
(OpenFundMarketStorage.PoolSFTInfo memory poolSFTInfo, ,,,,,,,,) = OpenFundMarketStorage(_market()).poolInfos(redeemInfo.poolId);
return (poolSFTInfo.openFundShare, poolSFTInfo.openFundShareSlot);
}
}
function _resolverAddressesRequired() internal view virtual override returns (bytes32[] memory addressNames) {
addressNames = new bytes32[](1);
addressNames[0] = CONTRACT_OPEN_FUND_MARKET;
}
function _market() internal view virtual returns (address) {
return getRequiredAddress(CONTRACT_OPEN_FUND_MARKET, "SVG_BGG: Market not set");
}
}{
"optimizer": {
"enabled": true,
"runs": 1
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BurnNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"old_","type":"address"},{"indexed":false,"internalType":"address","name":"new_","type":"address"}],"name":"NewDelegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"inputs":[],"name":"acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allocatedCurrencyBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"burnValue_","type":"uint256"}],"name":"burnOnlyDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"address","name":"currency_","type":"address"},{"internalType":"uint256","name":"claimValue_","type":"uint256"}],"name":"claimOnlyDelegate","outputs":[{"internalType":"uint256","name":"claimCurrencyAmount_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"claimableValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"txSender_","type":"address"},{"internalType":"bytes","name":"inputSlotInfo_","type":"bytes"}],"name":"createSlotOnlyDelegate","outputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"issuer_","type":"address"},{"internalType":"address","name":"currency_","type":"address"},{"internalType":"uint64","name":"valueDate_","type":"uint64"},{"internalType":"uint64","name":"maturity_","type":"uint64"},{"internalType":"uint64","name":"createTime_","type":"uint64"},{"internalType":"bool","name":"transferable_","type":"bool"}],"name":"getSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"currency_","type":"address"}],"name":"isCurrencyAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"isSlotTransferable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"isSlotValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"uint256","name":"mintValue_","type":"uint256"}],"name":"mintOnlyDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"txSender_","type":"address"},{"internalType":"address","name":"currency_","type":"address"},{"internalType":"address","name":"mintTo_","type":"address"},{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"mintOnlyDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"repaidCurrencyAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"txSender_","type":"address"},{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"address","name":"currency_","type":"address"},{"internalType":"uint256","name":"repayCurrencyAmount_","type":"uint256"}],"name":"repayOnlyDelegate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"txSender_","type":"address"},{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"address","name":"currency_","type":"address"},{"internalType":"uint256","name":"repayCurrencyAmount_","type":"uint256"}],"name":"repayWithBalanceOnlyDelegate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"currency_","type":"address"},{"internalType":"bool","name":"isAllowed_","type":"bool"}],"name":"setCurrencyOnlyDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newDelegate_","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"txSender_","type":"address"},{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"int32","name":"interestRate_","type":"int32"}],"name":"setInterestRateOnlyDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingAdmin_","type":"address"}],"name":"setPendingAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"slotBaseInfo","outputs":[{"components":[{"internalType":"address","name":"issuer","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"uint64","name":"valueDate","type":"uint64"},{"internalType":"uint64","name":"maturity","type":"uint64"},{"internalType":"uint64","name":"createTime","type":"uint64"},{"internalType":"bool","name":"transferable","type":"bool"},{"internalType":"bool","name":"isValid","type":"bool"}],"internalType":"struct IEarnConcrete.SlotBaseInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"slotExtInfo","outputs":[{"components":[{"internalType":"address","name":"supervisor","type":"address"},{"internalType":"uint256","name":"issueQuota","type":"uint256"},{"internalType":"enum IEarnConcrete.InterestType","name":"interestType","type":"uint8"},{"internalType":"int32","name":"interestRate","type":"int32"},{"internalType":"bool","name":"isInterestRateSet","type":"bool"},{"internalType":"string","name":"externalURI","type":"string"}],"internalType":"struct IEarnConcrete.SlotExtInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"slotInitialValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"slotTotalValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"tokenInitialValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromTokenId_","type":"uint256"},{"internalType":"uint256","name":"toTokenId_","type":"uint256"},{"internalType":"uint256","name":"fromTokenBalance_","type":"uint256"},{"internalType":"uint256","name":"transferValue_","type":"uint256"}],"name":"transferOnlyDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e4565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e2576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b612d7b80620000f46000396000f3fe6080604052600436106101525760003560e01c80630e18b681146101575780631ed8e8151461016e57806326782247146101ae578063302b586a146101db578063339bc561146101fb57806335f28fa5146102285780633b2f483014610248578063492e38791461025b5780634dd18bf51461027b57806356b040451461029b5780635a195d19146102bb5780638129fc1c1461030557806389197e231461031a5780638b52d6681461033a57806394f7e23e1461035a57806398af7bf9146104b7578063a6a978d8146104d7578063abab3eab146104ea578063c15a4e6914610517578063c89e436114610537578063ca5eb5e11461054c578063cc7ec17a1461056c578063d1db0b1d1461058c578063d8e4e1d3146105ac578063dae85ba3146105e7578063e7e9a78514610607578063f31b3b8c14610627578063f851a44014610647578063febae68014610667575b600080fd5b34801561016357600080fd5b5061016c610687565b005b34801561017a57600080fd5b5061019b6101893660046122e4565b600090815260fc602052604090205490565b6040519081526020015b60405180910390f35b3480156101ba57600080fd5b506034546101ce906001600160a01b031681565b6040516101a591906122fd565b3480156101e757600080fd5b5061016c6101f6366004612311565b610744565b34801561020757600080fd5b5061021b6102163660046122e4565b610803565b6040516101a591906123a9565b34801561023457600080fd5b5061016c610243366004612435565b610966565b61016c610256366004612476565b610a0a565b34801561026757600080fd5b5061019b6102763660046122e4565b610ba3565b34801561028757600080fd5b5061016c6102963660046124be565b610bb5565b3480156102a757600080fd5b5061019b6102b63660046122e4565b610c51565b3480156102c757600080fd5b506102f56102d63660046124be565b6001600160a01b0316600090815261012d602052604090205460ff1690565b60405190151581526020016101a5565b34801561031157600080fd5b5061016c610d3a565b34801561032657600080fd5b5061016c6103353660046124db565b610e4c565b34801561034657600080fd5b506102f56103553660046122e4565b610e95565b34801561036657600080fd5b506104416103753660046122e4565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915250600090815261012e6020908152604091829020825160e08101845281546001600160a01b0390811682526001830154908116938201939093526001600160401b03600160a01b909304831693810193909352600201548082166060840152600160401b8104909116608083015260ff600160801b82048116151560a0840152600160881b90910416151560c082015290565b6040516101a5919081516001600160a01b039081168252602080840151909116908201526040808301516001600160401b03908116918301919091526060808401518216908301526080808401519091169082015260a08281015115159082015260c09182015115159181019190915260e00190565b3480156104c357600080fd5b5061016c6104d236600461254f565b610eb9565b61016c6104e5366004612476565b611060565b3480156104f657600080fd5b5061019b6105053660046124be565b60fd6020526000908152604090205481565b34801561052357600080fd5b5061019b6105323660046122e4565b6110f8565b34801561054357600080fd5b506101ce61110d565b34801561055857600080fd5b5061016c6105673660046124be565b61111c565b34801561057857600080fd5b5061016c610587366004612591565b6111c9565b34801561059857600080fd5b5061019b6105a73660046125d6565b61120a565b3480156105b857600080fd5b506102f56105c73660046122e4565b600090815261012e6020526040902060020154600160801b900460ff1690565b3480156105f357600080fd5b5061019b610602366004612658565b61129e565b34801561061357600080fd5b5061016c6106223660046126dc565b611370565b34801561063357600080fd5b5061019b610642366004612715565b6113cc565b34801561065357600080fd5b506033546101ce906001600160a01b031681565b34801561067357600080fd5b5061019b6106823660046122e4565b6115a6565b6034546001600160a01b0316336001600160a01b0316146106e45760405162461bcd60e51b815260206004820152601260248201527137b7363c903832b73234b7339030b236b4b760711b60448201526064015b60405180910390fd5b603354603454604051600080516020612d2683398151915292610715926001600160a01b0391821692911690612744565b60405180910390a160348054603380546001600160a01b03199081166001600160a01b03841617909155169055565b6065546001600160a01b0316336001600160a01b0316146107775760405162461bcd60e51b81526004016106db9061275e565b60008385141580156107895750600083115b156107b657600085815260fc602052604090205483906107a9908461279b565b6107b391906127b2565b90505b600085815260fc6020526040812080548392906107d49084906127d4565b9091555050600084815260fc6020526040812080548392906107f79084906127e7565b90915550505050505050565b61083a6040805160c08101825260008082526020820181905290918201908152600060208201819052604082015260609081015290565b600082815261012f6020908152604091829020825160c08101845281546001600160a01b03168152600180830154938201939093526002820154909391929184019160ff9091169081111561089157610891612343565b60018111156108a2576108a2612343565b815260028201546101008104600390810b6020840152600160281b90910460ff1615156040830152820180546060909201916108dd906127fa565b80601f0160208091040260200160405190810160405280929190818152602001828054610909906127fa565b80156109565780601f1061092b57610100808354040283529160200191610956565b820191906000526020600020905b81548152906001019060200180831161093957829003601f168201915b5050505050815250509050919050565b6065546001600160a01b0316336001600160a01b0316146109995760405162461bcd60e51b81526004016106db9061275e565b600082815260fb6020526040812080548392906109b79084906127e7565b9091555050600082815260fb6020526040812060010180548392906109dd9084906127e7565b9091555050600083815260fc602052604081208054839290610a009084906127e7565b9091555050505050565b6065546001600160a01b0316336001600160a01b031614610a3d5760405162461bcd60e51b81526004016106db9061275e565b610a49848484846115c6565b6000826001600160a01b03166370a08231610a6261110d565b6040518263ffffffff1660e01b8152600401610a7e91906122fd565b602060405180830381865afa158015610a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abf9190612834565b6001600160a01b038416600090815260fd6020526040902054909150610ae590826127d4565b821115610b555760405162461bcd60e51b815260206004820152603860248201527f4d756c7469526570617961626c65436f6e63726574653a20696e73756666696360448201527769656e7420756e616c6c6f63617465642062616c616e636560401b60648201526084016106db565b600084815260fb602052604081206002018054849290610b769084906127e7565b90915550506001600160a01b038316600090815260fd6020526040812080548492906107f79084906127e7565b600090815260fb602052604090205490565b6033546001600160a01b0316336001600160a01b031614610be85760405162461bcd60e51b81526004016106db9061284d565b6034546040517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991610c27916001600160a01b03909116908490612744565b60405180910390a1603480546001600160a01b0319166001600160a01b0392909216919091179055565b600080610c5c61110d565b6001600160a01b031663263f3e7e846040518263ffffffff1660e01b8152600401610c8991815260200190565b602060405180830381865afa158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca9190612834565b90506001600082815261012f602052604090206002015460ff166001811115610cf557610cf5612343565b148015610d1c5750600081815261012f6020526040902060020154600160281b900460ff16155b15610d2a5750600092915050565b610d3383611638565b9392505050565b600054610100900460ff1615808015610d5a5750600054600160ff909116105b80610d745750303b158015610d74575060005460ff166001145b610dd75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106db565b6000805460ff191660011790558015610dfa576000805461ff0019166101001790555b610e026118f8565b8015610e49576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b50565b6065546001600160a01b0316336001600160a01b031614610e7f5760405162461bcd60e51b81526004016106db9061275e565b610e8d868686868686611929565b505050505050565b600081815261012e6020526040812060020154600160881b900460ff165b92915050565b6065546001600160a01b0316336001600160a01b031614610eec5760405162461bcd60e51b81526004016106db9061275e565b600082815261012f602052604090206001600282015460ff166001811115610f1657610f16612343565b14610f6f5760405162461bcd60e51b815260206004820152602360248201527f4561726e436f6e63726574653a206e6f7420666c6f6174696e6720696e746572604482015262195cdd60ea1b60648201526084016106db565b80546001600160a01b03858116911614610fcb5760405162461bcd60e51b815260206004820152601d60248201527f4561726e436f6e63726574653a206f6e6c792073757065727669736f7200000060448201526064016106db565b610fd483610ba3565b610fdd846110f8565b1461102a5760405162461bcd60e51b815260206004820152601d60248201527f4561726e436f6e63726574653a20616c726561647920636c61696d656400000060448201526064016106db565b600201805460ff60281b1963ffffffff909316610100029290921665ffffffffff001990921691909117600160281b1790555050565b6065546001600160a01b0316336001600160a01b0316146110935760405162461bcd60e51b81526004016106db9061275e565b61109f84848484611a73565b600083815260fb6020526040812060020180548392906110c09084906127e7565b90915550506001600160a01b038216600090815260fd6020526040812080548392906110ed9084906127e7565b909155505050505050565b600090815260fb602052604090206001015490565b6065546001600160a01b031690565b6065546001600160a01b031615611160576033546001600160a01b0316336001600160a01b0316146111605760405162461bcd60e51b81526004016106db9061284d565b6065546040517f91a2062b5d99931cce4660685e1c239d69642eedbb9cef9679a393f064ec36269161119f916001600160a01b03909116908490612744565b60405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b0316336001600160a01b0316146111fc5760405162461bcd60e51b81526004016106db9061275e565b6112068282611aed565b5050565b6000468061121661110d565b604080516020808201949094526001600160601b0319606093841b8116828401529b831b8c1660548201529990911b90991660688901526001600160c01b031960c097881b8116607c8a015295871b861660848901529390951b909316608c860152151560f81b60948501528451808503607501815260959094019094525050805191012090565b6065546000906001600160a01b0316336001600160a01b0316146112d45760405162461bcd60e51b81526004016106db9061275e565b6113148484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611cc592505050565b905080600003610d335760405162461bcd60e51b815260206004820152602160248201527f5346544973737561626c65436f6e63726574653a20696e76616c696420736c6f6044820152601d60fa1b60648201526084016106db565b6065546001600160a01b0316336001600160a01b0316146113a35760405162461bcd60e51b81526004016106db9061275e565b6001600160a01b038216600090815261012d60205260409020805460ff19168215151790555050565b6065546000906001600160a01b0316336001600160a01b0316146114025760405162461bcd60e51b81526004016106db9061275e565b61140e85858585611a73565b600084815260fb60205260408120600101805484929061142f9084906127d4565b909155506000905061143f61110d565b6001600160a01b0316633e7e86696040518163ffffffff1660e01b8152600401602060405180830381865afa15801561147c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a09190612871565b905060006114ad86612002565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150e9190612871565b905061151b82600a612978565b6305f5e10061271061152e84600a612978565b6115378a612021565b611541908961279b565b61154b919061279b565b61155591906127b2565b61155f91906127b2565b61156991906127b2565b6001600160a01b038616600090815260fd60205260408120805492955085929091906115969084906127d4565b9091555092979650505050505050565b600090815260fb602052604090206002015490565b50505050565b505050565b6115d284848484611a73565b600083815261012e60205260409020546001600160a01b038581169116146115bb5760405162461bcd60e51b815260206004820152601960248201527822b0b93721b7b731b932ba329d1037b7363c9034b9b9bab2b960391b60448201526064016106db565b60008061164361110d565b6001600160a01b031663263f3e7e846040518263ffffffff1660e01b815260040161167091815260200190565b602060405180830381865afa15801561168d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b19190612834565b905060006116bd61110d565b6001600160a01b0316639cc7f708856040518263ffffffff1660e01b81526004016116ea91815260200190565b602060405180830381865afa158015611707573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172b9190612834565b9050600061173761110d565b6001600160a01b0316633e7e86696040518163ffffffff1660e01b8152600401602060405180830381865afa158015611774573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117989190612871565b905060006117a584612002565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118069190612871565b600085815260fb602052604081205491925061182e88600090815260fc602052604090205490565b9050600061183d85600a612978565b6305f5e10061271061185087600a612978565b6118598b612021565b611863908861279b565b61186d919061279b565b61187791906127b2565b61188191906127b2565b61188b91906127b2565b90506000611898886115a6565b90506000828210156118be57826118af838661279b565b6118b991906127b2565b6118c0565b835b905060006118ce89866127d4565b90508082116118de5760006118e8565b6118e881836127d4565b9c9b505050505050505050505050565b600054610100900460ff1661191f5760405162461bcd60e51b81526004016106db90612987565b61192761212e565b565b600083815261012e602052604090206002810154600160881b900460ff166119905760405162461bcd60e51b815260206004820152601a60248201527911585c9b90dbdb98dc995d194e881a5b9d985b1a59081cdb1bdd60321b60448201526064016106db565b60018101546001600160a01b038781169116146119ef5760405162461bcd60e51b815260206004820181905260248201527f4561726e436f6e63726574653a2063757272656e6379206e6f74206d6174636860448201526064016106db565b600084815261012f602052604081206001015490611a0c86610ba3565b905081811115611a685760405162461bcd60e51b815260206004820152602160248201527f4561726e436f6e63726574653a20697373756551756f746120657863656564656044820152601960fa1b60648201526084016106db565b505050505050505050565b611a7c83612002565b6001600160a01b0316826001600160a01b0316146115bb5760405162461bcd60e51b815260206004820152602860248201527f4d756c7469526570617961626c65436f6e63726574653a20696e76616c69642060448201526763757272656e637960c01b60648201526084016106db565b6000611af761110d565b6001600160a01b031663263f3e7e846040518263ffffffff1660e01b8152600401611b2491815260200190565b602060405180830381865afa158015611b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b659190612834565b600081815261012f60205260409020600281015491925090600160281b900460ff1615611ba55760405163e5d8776760e01b815260040160405180910390fd5b82156115bb576000611bb561110d565b6001600160a01b0316639cc7f708866040518263ffffffff1660e01b8152600401611be291815260200190565b602060405180830381865afa158015611bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c239190612834565b600086815260fc6020526040812054919250908290611c42908761279b565b611c4c91906127b2565b600087815260fc6020526040812080549293508392909190611c6f9084906127d4565b9091555050600084815260fb602052604081208054839290611c929084906127d4565b9091555050600084815260fb602052604081206001018054879290611cb89084906127d4565b9091555050505050505050565b60008082806020019051810190611cdc9190612ace565b9050611ce78161215d565b80516001600160a01b0316600090815261012d602052604090205460ff16611d5c5760405162461bcd60e51b815260206004820152602260248201527f4561726e436f6e63726574653a2063757272656e6379206e6f7420616c6c6f77604482015261195960f21b60648201526084016106db565b60006040518060e00160405280866001600160a01b0316815260200183600001516001600160a01b031681526020018360a001516001600160401b031681526020018360c001516001600160401b031681526020018360e001516001600160401b0316815260200183610100015115158152602001600115158152509050611dfd8583600001518460a001518560c001518660e0015187610100015161120a565b600081815261012e6020908152604091829020845181546001600160a01b039182166001600160a01b03199091161782558286015160018084018054878a01516001600160401b03908116600160a01b026001600160e01b0319909216948616949094171790556060808901516002909501805460808b015160a08c015160c0808e01511515600160881b0260ff60881b19921515600160801b029290921661ffff60801b19938916600160401b026001600160801b03199095169a909816999099179290921716949094179390931790925585519384018652888501519092168352878501519383019390935291860151939650929183019190811115611f0757611f07612343565b8152608084015160030b6020820152604001600084606001516001811115611f3157611f31612343565b148152610120840151602091820152600085815261012f8252604090819020835181546001600160a01b0319166001600160a01b0390911617815591830151600180840191909155908301516002830180549192909160ff1916908381811115611f9d57611f9d612343565b0217905550606082015160028201805460808501511515600160281b0260ff60281b1963ffffffff909416610100029390931665ffffffffff00199091161791909117905560a08201516003820190611ff69082612c18565b50905050505092915050565b600090815261012e60205260409020600101546001600160a01b031690565b600081815261012e6020908152604080832061012f90925282208261204c6305f5e10061271061279b565b600184015460028501549192506000916301da9c009161207f916001600160401b03600160a01b90920482169116612cd7565b60028501546001600160401b0391909116906305f5e10090600061010090910460030b126120b9576002860154610100900460030b6120d5565b60028601546120d190610100900460030b6000612cfe565b60030b5b6120df919061279b565b6120e9919061279b565b6120f391906127b2565b6002840154909150600061010090910460030b1261211a5761211581836127e7565b612124565b61212481836127d4565b9695505050505050565b600054610100900460ff166121555760405162461bcd60e51b81526004016106db90612987565b611927612222565b428160a001516001600160401b0316116121b95760405162461bcd60e51b815260206004820152601f60248201527f4561726e436f6e63726574653a20696e76616c69642076616c7565446174650060448201526064016106db565b8060a001516001600160401b03168160c001516001600160401b031611610e495760405162461bcd60e51b815260206004820152601e60248201527f4561726e436f6e63726574653a20696e76616c6964206d61747572697479000060448201526064016106db565b600054610100900460ff166122495760405162461bcd60e51b81526004016106db90612987565b6122523361225a565b6119276122bd565b600054610100900460ff166122815760405162461bcd60e51b81526004016106db90612987565b603380546001600160a01b0319166001600160a01b038316179055604051600080516020612d2683398151915290610e40906000908490612744565b600054610100900460ff166119275760405162461bcd60e51b81526004016106db90612987565b6000602082840312156122f657600080fd5b5035919050565b6001600160a01b0391909116815260200190565b6000806000806080858703121561232757600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052602160045260246000fd5b60005b8381101561237457818101518382015260200161235c565b50506000910152565b60008151808452612395816020860160208601612359565b601f01601f19169290920160200192915050565b6020815260018060a01b0382511660208201526020820151604082015260006040830151600281106123eb57634e487b7160e01b600052602160045260246000fd5b806060840152506060830151612406608084018260030b9052565b50608083015180151560a08401525060a083015160c08084015261242d60e084018261237d565b949350505050565b60008060006060848603121561244a57600080fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114610e4957600080fd5b6000806000806080858703121561248c57600080fd5b843561249781612461565b93506020850135925060408501356124ae81612461565b9396929550929360600135925050565b6000602082840312156124d057600080fd5b8135610d3381612461565b60008060008060008060c087890312156124f457600080fd5b86356124ff81612461565b9550602087013561250f81612461565b9450604087013561251f81612461565b959894975094956060810135955060808101359460a0909101359350915050565b8060030b8114610e4957600080fd5b60008060006060848603121561256457600080fd5b833561256f81612461565b925060208401359150604084013561258681612540565b809150509250925092565b600080604083850312156125a457600080fd5b50508035926020909101359150565b6001600160401b0381168114610e4957600080fd5b8015158114610e4957600080fd5b60008060008060008060c087890312156125ef57600080fd5b86356125fa81612461565b9550602087013561260a81612461565b9450604087013561261a816125b3565b9350606087013561262a816125b3565b9250608087013561263a816125b3565b915060a087013561264a816125c8565b809150509295509295509295565b60008060006040848603121561266d57600080fd5b833561267881612461565b925060208401356001600160401b038082111561269457600080fd5b818601915086601f8301126126a857600080fd5b8135818111156126b757600080fd5b8760208285010111156126c957600080fd5b6020830194508093505050509250925092565b600080604083850312156126ef57600080fd5b82356126fa81612461565b9150602083013561270a816125c8565b809150509250929050565b6000806000806080858703121561272b57600080fd5b843593506020850135925060408501356124ae81612461565b6001600160a01b0392831681529116602082015260400190565b6020808252600d908201526c6f6e6c792064656c656761746560981b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610eb357610eb3612785565b6000826127cf57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610eb357610eb3612785565b80820180821115610eb357610eb3612785565b600181811c9082168061280e57607f821691505b60208210810361282e57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561284657600080fd5b5051919050565b6020808252600a908201526937b7363c9030b236b4b760b11b604082015260600190565b60006020828403121561288357600080fd5b815160ff81168114610d3357600080fd5b600181815b808511156128cf5781600019048211156128b5576128b5612785565b808516156128c257918102915b93841c9390800290612899565b509250929050565b6000826128e657506001610eb3565b816128f357506000610eb3565b816001811461290957600281146129135761292f565b6001915050610eb3565b60ff84111561292457612924612785565b50506001821b610eb3565b5060208310610133831016604e8410600b8410161715612952575081810a610eb3565b61295c8383612894565b806000190482111561297057612970612785565b029392505050565b6000610d3360ff8416836128d7565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715612a0b57612a0b6129d2565b60405290565b8051612a1c81612461565b919050565b805160028110612a1c57600080fd5b8051612a1c81612540565b8051612a1c816125b3565b8051612a1c816125c8565b600082601f830112612a6257600080fd5b81516001600160401b0380821115612a7c57612a7c6129d2565b604051601f8301601f19908116603f01168101908282118183101715612aa457612aa46129d2565b81604052838152866020858801011115612abd57600080fd5b612124846020830160208901612359565b600060208284031215612ae057600080fd5b81516001600160401b0380821115612af757600080fd5b908301906101408286031215612b0c57600080fd5b612b146129e8565b612b1d83612a11565b8152612b2b60208401612a11565b602082015260408301516040820152612b4660608401612a21565b6060820152612b5760808401612a30565b6080820152612b6860a08401612a3b565b60a0820152612b7960c08401612a3b565b60c0820152612b8a60e08401612a3b565b60e0820152610100612b9d818501612a46565b908201526101208381015183811115612bb557600080fd5b612bc188828701612a51565b918301919091525095945050505050565b601f8211156115c157600081815260208120601f850160051c81016020861015612bf95750805b601f850160051c820191505b81811015610e8d57828155600101612c05565b81516001600160401b03811115612c3157612c316129d2565b612c4581612c3f84546127fa565b84612bd2565b602080601f831160018114612c7a5760008415612c625750858301515b600019600386901b1c1916600185901b178555610e8d565b600085815260208120601f198616915b82811015612ca957888601518255948401946001909101908401612c8a565b5085821015612cc75787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160401b03828116828216039080821115612cf757612cf7612785565b5092915050565b600382810b9082900b03637fffffff198112637fffffff82131715610eb357610eb361278556fef9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dca2646970667358221220e356f216a9bec8b45ee4e16c99e34d18ae0cdc3edac6d1ccb5a58c9a3d422e7564736f6c63430008110033
Deployed Bytecode
0x6080604052600436106101525760003560e01c80630e18b681146101575780631ed8e8151461016e57806326782247146101ae578063302b586a146101db578063339bc561146101fb57806335f28fa5146102285780633b2f483014610248578063492e38791461025b5780634dd18bf51461027b57806356b040451461029b5780635a195d19146102bb5780638129fc1c1461030557806389197e231461031a5780638b52d6681461033a57806394f7e23e1461035a57806398af7bf9146104b7578063a6a978d8146104d7578063abab3eab146104ea578063c15a4e6914610517578063c89e436114610537578063ca5eb5e11461054c578063cc7ec17a1461056c578063d1db0b1d1461058c578063d8e4e1d3146105ac578063dae85ba3146105e7578063e7e9a78514610607578063f31b3b8c14610627578063f851a44014610647578063febae68014610667575b600080fd5b34801561016357600080fd5b5061016c610687565b005b34801561017a57600080fd5b5061019b6101893660046122e4565b600090815260fc602052604090205490565b6040519081526020015b60405180910390f35b3480156101ba57600080fd5b506034546101ce906001600160a01b031681565b6040516101a591906122fd565b3480156101e757600080fd5b5061016c6101f6366004612311565b610744565b34801561020757600080fd5b5061021b6102163660046122e4565b610803565b6040516101a591906123a9565b34801561023457600080fd5b5061016c610243366004612435565b610966565b61016c610256366004612476565b610a0a565b34801561026757600080fd5b5061019b6102763660046122e4565b610ba3565b34801561028757600080fd5b5061016c6102963660046124be565b610bb5565b3480156102a757600080fd5b5061019b6102b63660046122e4565b610c51565b3480156102c757600080fd5b506102f56102d63660046124be565b6001600160a01b0316600090815261012d602052604090205460ff1690565b60405190151581526020016101a5565b34801561031157600080fd5b5061016c610d3a565b34801561032657600080fd5b5061016c6103353660046124db565b610e4c565b34801561034657600080fd5b506102f56103553660046122e4565b610e95565b34801561036657600080fd5b506104416103753660046122e4565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915250600090815261012e6020908152604091829020825160e08101845281546001600160a01b0390811682526001830154908116938201939093526001600160401b03600160a01b909304831693810193909352600201548082166060840152600160401b8104909116608083015260ff600160801b82048116151560a0840152600160881b90910416151560c082015290565b6040516101a5919081516001600160a01b039081168252602080840151909116908201526040808301516001600160401b03908116918301919091526060808401518216908301526080808401519091169082015260a08281015115159082015260c09182015115159181019190915260e00190565b3480156104c357600080fd5b5061016c6104d236600461254f565b610eb9565b61016c6104e5366004612476565b611060565b3480156104f657600080fd5b5061019b6105053660046124be565b60fd6020526000908152604090205481565b34801561052357600080fd5b5061019b6105323660046122e4565b6110f8565b34801561054357600080fd5b506101ce61110d565b34801561055857600080fd5b5061016c6105673660046124be565b61111c565b34801561057857600080fd5b5061016c610587366004612591565b6111c9565b34801561059857600080fd5b5061019b6105a73660046125d6565b61120a565b3480156105b857600080fd5b506102f56105c73660046122e4565b600090815261012e6020526040902060020154600160801b900460ff1690565b3480156105f357600080fd5b5061019b610602366004612658565b61129e565b34801561061357600080fd5b5061016c6106223660046126dc565b611370565b34801561063357600080fd5b5061019b610642366004612715565b6113cc565b34801561065357600080fd5b506033546101ce906001600160a01b031681565b34801561067357600080fd5b5061019b6106823660046122e4565b6115a6565b6034546001600160a01b0316336001600160a01b0316146106e45760405162461bcd60e51b815260206004820152601260248201527137b7363c903832b73234b7339030b236b4b760711b60448201526064015b60405180910390fd5b603354603454604051600080516020612d2683398151915292610715926001600160a01b0391821692911690612744565b60405180910390a160348054603380546001600160a01b03199081166001600160a01b03841617909155169055565b6065546001600160a01b0316336001600160a01b0316146107775760405162461bcd60e51b81526004016106db9061275e565b60008385141580156107895750600083115b156107b657600085815260fc602052604090205483906107a9908461279b565b6107b391906127b2565b90505b600085815260fc6020526040812080548392906107d49084906127d4565b9091555050600084815260fc6020526040812080548392906107f79084906127e7565b90915550505050505050565b61083a6040805160c08101825260008082526020820181905290918201908152600060208201819052604082015260609081015290565b600082815261012f6020908152604091829020825160c08101845281546001600160a01b03168152600180830154938201939093526002820154909391929184019160ff9091169081111561089157610891612343565b60018111156108a2576108a2612343565b815260028201546101008104600390810b6020840152600160281b90910460ff1615156040830152820180546060909201916108dd906127fa565b80601f0160208091040260200160405190810160405280929190818152602001828054610909906127fa565b80156109565780601f1061092b57610100808354040283529160200191610956565b820191906000526020600020905b81548152906001019060200180831161093957829003601f168201915b5050505050815250509050919050565b6065546001600160a01b0316336001600160a01b0316146109995760405162461bcd60e51b81526004016106db9061275e565b600082815260fb6020526040812080548392906109b79084906127e7565b9091555050600082815260fb6020526040812060010180548392906109dd9084906127e7565b9091555050600083815260fc602052604081208054839290610a009084906127e7565b9091555050505050565b6065546001600160a01b0316336001600160a01b031614610a3d5760405162461bcd60e51b81526004016106db9061275e565b610a49848484846115c6565b6000826001600160a01b03166370a08231610a6261110d565b6040518263ffffffff1660e01b8152600401610a7e91906122fd565b602060405180830381865afa158015610a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abf9190612834565b6001600160a01b038416600090815260fd6020526040902054909150610ae590826127d4565b821115610b555760405162461bcd60e51b815260206004820152603860248201527f4d756c7469526570617961626c65436f6e63726574653a20696e73756666696360448201527769656e7420756e616c6c6f63617465642062616c616e636560401b60648201526084016106db565b600084815260fb602052604081206002018054849290610b769084906127e7565b90915550506001600160a01b038316600090815260fd6020526040812080548492906107f79084906127e7565b600090815260fb602052604090205490565b6033546001600160a01b0316336001600160a01b031614610be85760405162461bcd60e51b81526004016106db9061284d565b6034546040517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991610c27916001600160a01b03909116908490612744565b60405180910390a1603480546001600160a01b0319166001600160a01b0392909216919091179055565b600080610c5c61110d565b6001600160a01b031663263f3e7e846040518263ffffffff1660e01b8152600401610c8991815260200190565b602060405180830381865afa158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca9190612834565b90506001600082815261012f602052604090206002015460ff166001811115610cf557610cf5612343565b148015610d1c5750600081815261012f6020526040902060020154600160281b900460ff16155b15610d2a5750600092915050565b610d3383611638565b9392505050565b600054610100900460ff1615808015610d5a5750600054600160ff909116105b80610d745750303b158015610d74575060005460ff166001145b610dd75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106db565b6000805460ff191660011790558015610dfa576000805461ff0019166101001790555b610e026118f8565b8015610e49576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b50565b6065546001600160a01b0316336001600160a01b031614610e7f5760405162461bcd60e51b81526004016106db9061275e565b610e8d868686868686611929565b505050505050565b600081815261012e6020526040812060020154600160881b900460ff165b92915050565b6065546001600160a01b0316336001600160a01b031614610eec5760405162461bcd60e51b81526004016106db9061275e565b600082815261012f602052604090206001600282015460ff166001811115610f1657610f16612343565b14610f6f5760405162461bcd60e51b815260206004820152602360248201527f4561726e436f6e63726574653a206e6f7420666c6f6174696e6720696e746572604482015262195cdd60ea1b60648201526084016106db565b80546001600160a01b03858116911614610fcb5760405162461bcd60e51b815260206004820152601d60248201527f4561726e436f6e63726574653a206f6e6c792073757065727669736f7200000060448201526064016106db565b610fd483610ba3565b610fdd846110f8565b1461102a5760405162461bcd60e51b815260206004820152601d60248201527f4561726e436f6e63726574653a20616c726561647920636c61696d656400000060448201526064016106db565b600201805460ff60281b1963ffffffff909316610100029290921665ffffffffff001990921691909117600160281b1790555050565b6065546001600160a01b0316336001600160a01b0316146110935760405162461bcd60e51b81526004016106db9061275e565b61109f84848484611a73565b600083815260fb6020526040812060020180548392906110c09084906127e7565b90915550506001600160a01b038216600090815260fd6020526040812080548392906110ed9084906127e7565b909155505050505050565b600090815260fb602052604090206001015490565b6065546001600160a01b031690565b6065546001600160a01b031615611160576033546001600160a01b0316336001600160a01b0316146111605760405162461bcd60e51b81526004016106db9061284d565b6065546040517f91a2062b5d99931cce4660685e1c239d69642eedbb9cef9679a393f064ec36269161119f916001600160a01b03909116908490612744565b60405180910390a1606580546001600160a01b0319166001600160a01b0392909216919091179055565b6065546001600160a01b0316336001600160a01b0316146111fc5760405162461bcd60e51b81526004016106db9061275e565b6112068282611aed565b5050565b6000468061121661110d565b604080516020808201949094526001600160601b0319606093841b8116828401529b831b8c1660548201529990911b90991660688901526001600160c01b031960c097881b8116607c8a015295871b861660848901529390951b909316608c860152151560f81b60948501528451808503607501815260959094019094525050805191012090565b6065546000906001600160a01b0316336001600160a01b0316146112d45760405162461bcd60e51b81526004016106db9061275e565b6113148484848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611cc592505050565b905080600003610d335760405162461bcd60e51b815260206004820152602160248201527f5346544973737561626c65436f6e63726574653a20696e76616c696420736c6f6044820152601d60fa1b60648201526084016106db565b6065546001600160a01b0316336001600160a01b0316146113a35760405162461bcd60e51b81526004016106db9061275e565b6001600160a01b038216600090815261012d60205260409020805460ff19168215151790555050565b6065546000906001600160a01b0316336001600160a01b0316146114025760405162461bcd60e51b81526004016106db9061275e565b61140e85858585611a73565b600084815260fb60205260408120600101805484929061142f9084906127d4565b909155506000905061143f61110d565b6001600160a01b0316633e7e86696040518163ffffffff1660e01b8152600401602060405180830381865afa15801561147c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a09190612871565b905060006114ad86612002565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150e9190612871565b905061151b82600a612978565b6305f5e10061271061152e84600a612978565b6115378a612021565b611541908961279b565b61154b919061279b565b61155591906127b2565b61155f91906127b2565b61156991906127b2565b6001600160a01b038616600090815260fd60205260408120805492955085929091906115969084906127d4565b9091555092979650505050505050565b600090815260fb602052604090206002015490565b50505050565b505050565b6115d284848484611a73565b600083815261012e60205260409020546001600160a01b038581169116146115bb5760405162461bcd60e51b815260206004820152601960248201527822b0b93721b7b731b932ba329d1037b7363c9034b9b9bab2b960391b60448201526064016106db565b60008061164361110d565b6001600160a01b031663263f3e7e846040518263ffffffff1660e01b815260040161167091815260200190565b602060405180830381865afa15801561168d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b19190612834565b905060006116bd61110d565b6001600160a01b0316639cc7f708856040518263ffffffff1660e01b81526004016116ea91815260200190565b602060405180830381865afa158015611707573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172b9190612834565b9050600061173761110d565b6001600160a01b0316633e7e86696040518163ffffffff1660e01b8152600401602060405180830381865afa158015611774573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117989190612871565b905060006117a584612002565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118069190612871565b600085815260fb602052604081205491925061182e88600090815260fc602052604090205490565b9050600061183d85600a612978565b6305f5e10061271061185087600a612978565b6118598b612021565b611863908861279b565b61186d919061279b565b61187791906127b2565b61188191906127b2565b61188b91906127b2565b90506000611898886115a6565b90506000828210156118be57826118af838661279b565b6118b991906127b2565b6118c0565b835b905060006118ce89866127d4565b90508082116118de5760006118e8565b6118e881836127d4565b9c9b505050505050505050505050565b600054610100900460ff1661191f5760405162461bcd60e51b81526004016106db90612987565b61192761212e565b565b600083815261012e602052604090206002810154600160881b900460ff166119905760405162461bcd60e51b815260206004820152601a60248201527911585c9b90dbdb98dc995d194e881a5b9d985b1a59081cdb1bdd60321b60448201526064016106db565b60018101546001600160a01b038781169116146119ef5760405162461bcd60e51b815260206004820181905260248201527f4561726e436f6e63726574653a2063757272656e6379206e6f74206d6174636860448201526064016106db565b600084815261012f602052604081206001015490611a0c86610ba3565b905081811115611a685760405162461bcd60e51b815260206004820152602160248201527f4561726e436f6e63726574653a20697373756551756f746120657863656564656044820152601960fa1b60648201526084016106db565b505050505050505050565b611a7c83612002565b6001600160a01b0316826001600160a01b0316146115bb5760405162461bcd60e51b815260206004820152602860248201527f4d756c7469526570617961626c65436f6e63726574653a20696e76616c69642060448201526763757272656e637960c01b60648201526084016106db565b6000611af761110d565b6001600160a01b031663263f3e7e846040518263ffffffff1660e01b8152600401611b2491815260200190565b602060405180830381865afa158015611b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b659190612834565b600081815261012f60205260409020600281015491925090600160281b900460ff1615611ba55760405163e5d8776760e01b815260040160405180910390fd5b82156115bb576000611bb561110d565b6001600160a01b0316639cc7f708866040518263ffffffff1660e01b8152600401611be291815260200190565b602060405180830381865afa158015611bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c239190612834565b600086815260fc6020526040812054919250908290611c42908761279b565b611c4c91906127b2565b600087815260fc6020526040812080549293508392909190611c6f9084906127d4565b9091555050600084815260fb602052604081208054839290611c929084906127d4565b9091555050600084815260fb602052604081206001018054879290611cb89084906127d4565b9091555050505050505050565b60008082806020019051810190611cdc9190612ace565b9050611ce78161215d565b80516001600160a01b0316600090815261012d602052604090205460ff16611d5c5760405162461bcd60e51b815260206004820152602260248201527f4561726e436f6e63726574653a2063757272656e6379206e6f7420616c6c6f77604482015261195960f21b60648201526084016106db565b60006040518060e00160405280866001600160a01b0316815260200183600001516001600160a01b031681526020018360a001516001600160401b031681526020018360c001516001600160401b031681526020018360e001516001600160401b0316815260200183610100015115158152602001600115158152509050611dfd8583600001518460a001518560c001518660e0015187610100015161120a565b600081815261012e6020908152604091829020845181546001600160a01b039182166001600160a01b03199091161782558286015160018084018054878a01516001600160401b03908116600160a01b026001600160e01b0319909216948616949094171790556060808901516002909501805460808b015160a08c015160c0808e01511515600160881b0260ff60881b19921515600160801b029290921661ffff60801b19938916600160401b026001600160801b03199095169a909816999099179290921716949094179390931790925585519384018652888501519092168352878501519383019390935291860151939650929183019190811115611f0757611f07612343565b8152608084015160030b6020820152604001600084606001516001811115611f3157611f31612343565b148152610120840151602091820152600085815261012f8252604090819020835181546001600160a01b0319166001600160a01b0390911617815591830151600180840191909155908301516002830180549192909160ff1916908381811115611f9d57611f9d612343565b0217905550606082015160028201805460808501511515600160281b0260ff60281b1963ffffffff909416610100029390931665ffffffffff00199091161791909117905560a08201516003820190611ff69082612c18565b50905050505092915050565b600090815261012e60205260409020600101546001600160a01b031690565b600081815261012e6020908152604080832061012f90925282208261204c6305f5e10061271061279b565b600184015460028501549192506000916301da9c009161207f916001600160401b03600160a01b90920482169116612cd7565b60028501546001600160401b0391909116906305f5e10090600061010090910460030b126120b9576002860154610100900460030b6120d5565b60028601546120d190610100900460030b6000612cfe565b60030b5b6120df919061279b565b6120e9919061279b565b6120f391906127b2565b6002840154909150600061010090910460030b1261211a5761211581836127e7565b612124565b61212481836127d4565b9695505050505050565b600054610100900460ff166121555760405162461bcd60e51b81526004016106db90612987565b611927612222565b428160a001516001600160401b0316116121b95760405162461bcd60e51b815260206004820152601f60248201527f4561726e436f6e63726574653a20696e76616c69642076616c7565446174650060448201526064016106db565b8060a001516001600160401b03168160c001516001600160401b031611610e495760405162461bcd60e51b815260206004820152601e60248201527f4561726e436f6e63726574653a20696e76616c6964206d61747572697479000060448201526064016106db565b600054610100900460ff166122495760405162461bcd60e51b81526004016106db90612987565b6122523361225a565b6119276122bd565b600054610100900460ff166122815760405162461bcd60e51b81526004016106db90612987565b603380546001600160a01b0319166001600160a01b038316179055604051600080516020612d2683398151915290610e40906000908490612744565b600054610100900460ff166119275760405162461bcd60e51b81526004016106db90612987565b6000602082840312156122f657600080fd5b5035919050565b6001600160a01b0391909116815260200190565b6000806000806080858703121561232757600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052602160045260246000fd5b60005b8381101561237457818101518382015260200161235c565b50506000910152565b60008151808452612395816020860160208601612359565b601f01601f19169290920160200192915050565b6020815260018060a01b0382511660208201526020820151604082015260006040830151600281106123eb57634e487b7160e01b600052602160045260246000fd5b806060840152506060830151612406608084018260030b9052565b50608083015180151560a08401525060a083015160c08084015261242d60e084018261237d565b949350505050565b60008060006060848603121561244a57600080fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114610e4957600080fd5b6000806000806080858703121561248c57600080fd5b843561249781612461565b93506020850135925060408501356124ae81612461565b9396929550929360600135925050565b6000602082840312156124d057600080fd5b8135610d3381612461565b60008060008060008060c087890312156124f457600080fd5b86356124ff81612461565b9550602087013561250f81612461565b9450604087013561251f81612461565b959894975094956060810135955060808101359460a0909101359350915050565b8060030b8114610e4957600080fd5b60008060006060848603121561256457600080fd5b833561256f81612461565b925060208401359150604084013561258681612540565b809150509250925092565b600080604083850312156125a457600080fd5b50508035926020909101359150565b6001600160401b0381168114610e4957600080fd5b8015158114610e4957600080fd5b60008060008060008060c087890312156125ef57600080fd5b86356125fa81612461565b9550602087013561260a81612461565b9450604087013561261a816125b3565b9350606087013561262a816125b3565b9250608087013561263a816125b3565b915060a087013561264a816125c8565b809150509295509295509295565b60008060006040848603121561266d57600080fd5b833561267881612461565b925060208401356001600160401b038082111561269457600080fd5b818601915086601f8301126126a857600080fd5b8135818111156126b757600080fd5b8760208285010111156126c957600080fd5b6020830194508093505050509250925092565b600080604083850312156126ef57600080fd5b82356126fa81612461565b9150602083013561270a816125c8565b809150509250929050565b6000806000806080858703121561272b57600080fd5b843593506020850135925060408501356124ae81612461565b6001600160a01b0392831681529116602082015260400190565b6020808252600d908201526c6f6e6c792064656c656761746560981b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610eb357610eb3612785565b6000826127cf57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610eb357610eb3612785565b80820180821115610eb357610eb3612785565b600181811c9082168061280e57607f821691505b60208210810361282e57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561284657600080fd5b5051919050565b6020808252600a908201526937b7363c9030b236b4b760b11b604082015260600190565b60006020828403121561288357600080fd5b815160ff81168114610d3357600080fd5b600181815b808511156128cf5781600019048211156128b5576128b5612785565b808516156128c257918102915b93841c9390800290612899565b509250929050565b6000826128e657506001610eb3565b816128f357506000610eb3565b816001811461290957600281146129135761292f565b6001915050610eb3565b60ff84111561292457612924612785565b50506001821b610eb3565b5060208310610133831016604e8410600b8410161715612952575081810a610eb3565b61295c8383612894565b806000190482111561297057612970612785565b029392505050565b6000610d3360ff8416836128d7565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b0381118282101715612a0b57612a0b6129d2565b60405290565b8051612a1c81612461565b919050565b805160028110612a1c57600080fd5b8051612a1c81612540565b8051612a1c816125b3565b8051612a1c816125c8565b600082601f830112612a6257600080fd5b81516001600160401b0380821115612a7c57612a7c6129d2565b604051601f8301601f19908116603f01168101908282118183101715612aa457612aa46129d2565b81604052838152866020858801011115612abd57600080fd5b612124846020830160208901612359565b600060208284031215612ae057600080fd5b81516001600160401b0380821115612af757600080fd5b908301906101408286031215612b0c57600080fd5b612b146129e8565b612b1d83612a11565b8152612b2b60208401612a11565b602082015260408301516040820152612b4660608401612a21565b6060820152612b5760808401612a30565b6080820152612b6860a08401612a3b565b60a0820152612b7960c08401612a3b565b60c0820152612b8a60e08401612a3b565b60e0820152610100612b9d818501612a46565b908201526101208381015183811115612bb557600080fd5b612bc188828701612a51565b918301919091525095945050505050565b601f8211156115c157600081815260208120601f850160051c81016020861015612bf95750805b601f850160051c820191505b81811015610e8d57828155600101612c05565b81516001600160401b03811115612c3157612c316129d2565b612c4581612c3f84546127fa565b84612bd2565b602080601f831160018114612c7a5760008415612c625750858301515b600019600386901b1c1916600185901b178555610e8d565b600085815260208120601f198616915b82811015612ca957888601518255948401946001909101908401612c8a565b5085821015612cc75787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160401b03828116828216039080821115612cf757612cf7612785565b5092915050565b600382810b9082900b03637fffffff198112637fffffff82131715610eb357610eb361278556fef9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dca2646970667358221220e356f216a9bec8b45ee4e16c99e34d18ae0cdc3edac6d1ccb5a58c9a3d422e7564736f6c63430008110033
Deployed Bytecode Sourcemap
301:1126:86:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1072:225:49;;;;;;;;;;;;;:::i;:::-;;3976:154:34;;;;;;;;;;-1:-1:-1;3976:154:34;;;;;:::i;:::-;4059:7;4085:25;;;:15;:25;;;;;:38;;3976:154;;;;345:25:92;;;333:2;318:18;3976:154:34;;;;;;;;445:27:49;;;;;;;;;;-1:-1:-1;445:27:49;;;;-1:-1:-1;;;;;445:27:49;;;;;;;;;;:::i;2879:640:34:-;;;;;;;;;;-1:-1:-1;2879:640:34;;;;;:::i;:::-;;:::i;2613:132:44:-;;;;;;;;;;-1:-1:-1;2613:132:44;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1831:351:34:-;;;;;;;;;;-1:-1:-1;1831:351:34;;;;;:::i;:::-;;:::i;1207:618::-;;;;;;:::i;:::-;;:::i;3525:129::-;;;;;;;;;;-1:-1:-1;3525:129:34;;;;;:::i;:::-;;:::i;870:196:49:-;;;;;;;;;;-1:-1:-1;870:196:49;;;;;:::i;:::-;;:::i;1734:362:44:-;;;;;;;;;;-1:-1:-1;1734:362:44;;;;;:::i;:::-;;:::i;5098:126::-;;;;;;;;;;-1:-1:-1;5098:126:44;;;;;:::i;:::-;-1:-1:-1;;;;;5190:27:44;5167:4;5190:27;;;:16;:27;;;;;;;;;5098:126;;;;4231:14:92;;4224:22;4206:41;;4194:2;4179:18;5098:126:44;4066:187:92;917:85:44;;;;;;;;;;;;;:::i;762:243:28:-;;;;;;;;;;-1:-1:-1;762:243:28;;;;;:::i;:::-;;:::i;662:116:40:-;;;;;;;;;;-1:-1:-1;662:116:40;;;;;:::i;:::-;;:::i;2472:135:44:-;;;;;;;;;;-1:-1:-1;2472:135:44;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2579:21:44;;;;:14;:21;;;;;;;;;2572:28;;;;;;;;;-1:-1:-1;;;;;2572:28:44;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;2572:28:44;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2572:28:44;;;;;;;;;;-1:-1:-1;;;2572:28:44;;;;;;;;;;-1:-1:-1;;;2572:28:44;;;;;;;;;;;2472:135;;;;;;;5266:13:92;;-1:-1:-1;;;;;5262:22:92;;;5244:41;;5345:4;5333:17;;;5327:24;5323:33;;;5301:20;;;5294:63;5404:4;5392:17;;;5386:24;-1:-1:-1;;;;;5485:21:92;;;5463:20;;;5456:51;;;;5567:4;5555:17;;;5549:24;5545:33;;5523:20;;;5516:63;5639:4;5627:17;;;5621:24;5617:33;;;5595:20;;;5588:63;5224:3;5709:17;;;5703:24;5696:32;5689:40;5667:20;;;5660:70;5800:4;5788:17;;;5782:24;5775:32;5768:40;5746:20;;;5739:70;;;;5193:3;5178:19;;4999:816;1163:565:44;;;;;;;;;;-1:-1:-1;1163:565:44;;;;;:::i;:::-;;:::i;819:382:34:-;;;;;;:::i;:::-;;:::i;698:59::-;;;;;;;;;;-1:-1:-1;698:59:34;;;;;:::i;:::-;;;;;;;;;;;;;;3664:142;;;;;;;;;;-1:-1:-1;3664:142:34;;;;;:::i;:::-;;:::i;602:92:54:-;;;;;;;;;;;;;:::i;700:261::-;;;;;;;;;;-1:-1:-1;700:261:54;;;;;:::i;:::-;;:::i;565:138:38:-;;;;;;;;;;-1:-1:-1;565:138:38;;;;;:::i;:::-;;:::i;2102:364:44:-;;;;;;;;;;-1:-1:-1;2102:364:44;;;;;:::i;:::-;;:::i;4953:139::-;;;;;;;;;;-1:-1:-1;4953:139:44;;;;;:::i;:::-;5028:4;5051:21;;;:14;:21;;;;;:34;;;-1:-1:-1;;;5051:34:44;;;;;4953:139;495:261:28;;;;;;;;;;-1:-1:-1;495:261:28;;;;;:::i;:::-;;:::i;1008:152:44:-;;;;;;;;;;-1:-1:-1;1008:152:44;;;;;:::i;:::-;;:::i;2188:685:34:-;;;;;;;;;;-1:-1:-1;2188:685:34;;;;;:::i;:::-;;:::i;419:20:49:-;;;;;;;;;;-1:-1:-1;419:20:49;;;;-1:-1:-1;;;;;419:20:49;;;3812:158:34;;;;;;;;;;-1:-1:-1;3812:158:34;;;;;:::i;:::-;;:::i;1072:225:49:-;1146:12;;-1:-1:-1;;;;;1146:12:49;929:10:3;-1:-1:-1;;;;;1130:28:49;;1122:59;;;;-1:-1:-1;;;1122:59:49;;9635:2:92;1122:59:49;;;9617:21:92;9674:2;9654:18;;;9647:30;-1:-1:-1;;;9693:18:92;;;9686:48;9751:18;;1122:59:49;;;;;;;;;1205:5;;1212:12;;1196:29;;-1:-1:-1;;;;;;;;;;;1196:29:49;;;-1:-1:-1;;;;;1205:5:49;;;;1212:12;;;1196:29;:::i;:::-;;;;;;;;1243:12;;;1235:5;:20;;-1:-1:-1;;;;;;1235:20:49;;;-1:-1:-1;;;;;1243:12:49;;1235:20;;;;1265:25;;;1072:225::o;2879:640:34:-;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;3137:28:34::1;3199:10;3183:12;:26;;:51;;;;;3233:1;3213:17;:21;3183:51;3179:184;;;3290:29;::::0;;;:15:::1;:29;::::0;;;;:42;3335:17;;3273:59:::1;::::0;:14;:59:::1;:::i;:::-;:79;;;;:::i;:::-;3250:102;;3179:184;3372:29;::::0;;;:15:::1;:29;::::0;;;;:66;;3418:20;;3372:29;:66:::1;::::0;3418:20;;3372:66:::1;:::i;:::-;::::0;;;-1:-1:-1;;3448:27:34::1;::::0;;;:15:::1;:27;::::0;;;;:64;;3492:20;;3448:27;:64:::1;::::0;3492:20;;3448:64:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;2879:640:34:o;2613:132:44:-;2681:18;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2681:18:44;2718:20;;;;:13;:20;;;;;;;;;2711:27;;;;;;;;;-1:-1:-1;;;;;2711:27:44;;;;;;;;;;;;;;;;;;;;;2718:20;;2711:27;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2711:27:44;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2613:132;;;:::o;1831:351:34:-;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;2009:21:34::1;::::0;;;:14:::1;:21;::::0;;;;:48;;2047:10;;2009:21;:48:::1;::::0;2047:10;;2009:48:::1;:::i;:::-;::::0;;;-1:-1:-1;;2067:21:34::1;::::0;;;:14:::1;:21;::::0;;;;:32:::1;;:46:::0;;2103:10;;2067:21;:46:::1;::::0;2103:10;;2067:46:::1;:::i;:::-;::::0;;;-1:-1:-1;;2123:25:34::1;::::0;;;:15:::1;:25;::::0;;;;:52;;2165:10;;2123:25;:52:::1;::::0;2165:10;;2123:52:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;1831:351:34:o;1207:618::-;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;1385:74:34::1;1409:9;1420:5;1427:9;1438:20;1385:23;:74::i;:::-;1469:15;1493:9;-1:-1:-1::0;;;;;1487:26:34::1;;1514:10;:8;:10::i;:::-;1487:38;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1577:35:34;::::1;;::::0;;;:24:::1;:35;::::0;;;;;1469:56;;-1:-1:-1;1567:45:34::1;::::0;1469:56;1567:45:::1;:::i;:::-;1543:20;:69;;1535:138;;;::::0;-1:-1:-1;;;1535:138:34;;11997:2:92;1535:138:34::1;::::0;::::1;11979:21:92::0;12036:2;12016:18;;;12009:30;12075:34;12055:18;;;12048:62;-1:-1:-1;;;12126:18:92;;;12119:54;12190:19;;1535:138:34::1;11795:420:92::0;1535:138:34::1;1683:21;::::0;;;:14:::1;:21;::::0;;;;:42:::1;;:66:::0;;1729:20;;1683:21;:66:::1;::::0;1729:20;;1683:66:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;1759:35:34;::::1;;::::0;;;:24:::1;:35;::::0;;;;:59;;1798:20;;1759:35;:59:::1;::::0;1798:20;;1759:59:::1;:::i;3525:129::-:0;3587:7;3613:21;;;:14;:21;;;;;:34;;3525:129::o;870:196:49:-;534:5;;-1:-1:-1;;;;;534:5:49;929:10:3;-1:-1:-1;;;;;518:21:49;;510:44;;;;-1:-1:-1;;;510:44:49;;;;;;;:::i;:::-;979:12:::1;::::0;963:47:::1;::::0;::::1;::::0;::::1;::::0;-1:-1:-1;;;;;979:12:49;;::::1;::::0;993:16;;963:47:::1;:::i;:::-;;;;;;;;1020:12;:31:::0;;-1:-1:-1;;;;;;1020:31:49::1;-1:-1:-1::0;;;;;1020:31:49;;;::::1;::::0;;;::::1;::::0;;870:196::o;1734:362:44:-;1814:7;1833:12;1867:10;:8;:10::i;:::-;-1:-1:-1;;;;;1848:37:44;;1886:8;1848:47;;;;;;;;;;;;;345:25:92;;333:2;318:18;;199:177;1848:47:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1833:62;-1:-1:-1;1945:21:44;1909:19;;;;:13;:19;;;;;:32;;;;;;:57;;;;;;;:::i;:::-;;:99;;;;-1:-1:-1;1971:19:44;;;;:13;:19;;;;;:37;;;-1:-1:-1;;;1971:37:44;;;;1970:38;1909:99;1905:138;;;-1:-1:-1;2031:1:44;;1734:362;-1:-1:-1;;1734:362:44:o;1905:138::-;2059:30;2080:8;2059:20;:30::i;:::-;2052:37;1734:362;-1:-1:-1;;;1734:362:44:o;917:85::-;3268:19:0;3291:13;;;;;;3290:14;;3336:34;;;;-1:-1:-1;3354:12:0;;3369:1;3354:12;;;;:16;3336:34;3335:108;;;-1:-1:-1;3415:4:0;1476:19:2;:23;;;3376:66:0;;-1:-1:-1;3425:12:0;;;;;:17;3376:66;3314:201;;;;-1:-1:-1;;;3314:201:0;;12761:2:92;3314:201:0;;;12743:21:92;12800:2;12780:18;;;12773:30;12839:34;12819:18;;;12812:62;-1:-1:-1;;;12890:18:92;;;12883:44;12944:19;;3314:201:0;12559:410:92;3314:201:0;3525:12;:16;;-1:-1:-1;;3525:16:0;3540:1;3525:16;;;3551:65;;;;3585:13;:20;;-1:-1:-1;;3585:20:0;;;;;3551:65;970:28:44::1;:26;:28::i;:::-;3640:14:0::0;3636:99;;;3686:5;3670:21;;-1:-1:-1;;3670:21:0;;;3710:14;;-1:-1:-1;13126:36:92;;3710:14:0;;13114:2:92;13099:18;3710:14:0;;;;;;;;3636:99;3258:483;917:85:44:o;762:243:28:-;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;939:62:28::1;945:9;956;967:7;976:5;983:8;993:7;939:5;:62::i;:::-;762:243:::0;;;;;;:::o;662:116:40:-;738:4;2851:21:44;;;:14;:21;;;;;:29;;;-1:-1:-1;;;2851:29:44;;;;755:19:40;748:26;662:116;-1:-1:-1;;662:116:40:o;1163:565:44:-;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;1296:27:44::1;1326:20:::0;;;:13:::1;:20;::::0;;;;1388:21:::1;1364:20;::::0;::::1;::::0;::::1;;::::0;:45;::::1;;;;;;:::i;:::-;;1356:93;;;::::0;-1:-1:-1;;;1356:93:44;;13375:2:92;1356:93:44::1;::::0;::::1;13357:21:92::0;13414:2;13394:18;;;13387:30;13453:34;13433:18;;;13426:62;-1:-1:-1;;;13504:18:92;;;13497:33;13547:19;;1356:93:44::1;13173:399:92::0;1356:93:44::1;1480:18:::0;;-1:-1:-1;;;;;1467:31:44;;::::1;1480:18:::0;::::1;1467:31;1459:73;;;::::0;-1:-1:-1;;;1459:73:44;;13779:2:92;1459:73:44::1;::::0;::::1;13761:21:92::0;13818:2;13798:18;;;13791:30;13857:31;13837:18;;;13830:59;13906:18;;1459:73:44::1;13577:353:92::0;1459:73:44::1;1575:23;1592:5;1575:16;:23::i;:::-;1550:21;1565:5;1550:14;:21::i;:::-;:48;1542:90;;;::::0;-1:-1:-1;;;1542:90:44;;14137:2:92;1542:90:44::1;::::0;::::1;14119:21:92::0;14176:2;14156:18;;;14149:30;14215:31;14195:18;;;14188:59;14264:18;;1542:90:44::1;13935:353:92::0;1542:90:44::1;1643:20;;:36:::0;;-1:-1:-1;;;;1643:36:44::1;::::0;;;::::1;;1689:32:::0;;;;-1:-1:-1;;1689:32:44;;;;;;;-1:-1:-1;;;1689:32:44::1;::::0;;-1:-1:-1;;1163:565:44:o;819:382:34:-;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;986:63:34::1;999:9;1010:5;1017:9;1028:20;986:12;:63::i;:::-;1059:21;::::0;;;:14:::1;:21;::::0;;;;:42:::1;;:66:::0;;1105:20;;1059:21;:66:::1;::::0;1105:20;;1059:66:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;1135:35:34;::::1;;::::0;;;:24:::1;:35;::::0;;;;:59;;1174:20;;1135:35;:59:::1;::::0;1174:20;;1135:59:::1;:::i;:::-;::::0;;;-1:-1:-1;;;;;;819:382:34:o;3664:142::-;3741:7;3767:21;;;:14;:21;;;;;:32;;;;3664:142::o;602:92:54:-;678:9;;-1:-1:-1;;;;;678:9:54;;602:92::o;700:261::-;775:9;;-1:-1:-1;;;;;775:9:54;:23;771:98;;838:5;;-1:-1:-1;;;;;838:5:54;929:10:3;-1:-1:-1;;;;;822:21:54;;814:44;;;;-1:-1:-1;;;814:44:54;;;;;;;:::i;:::-;896:9;;884:36;;;;;;-1:-1:-1;;;;;896:9:54;;;;907:12;;884:36;:::i;:::-;;;;;;;;930:9;:24;;-1:-1:-1;;;;;;930:24:54;-1:-1:-1;;;;;930:24:54;;;;;;;;;;700:261::o;565:138:38:-;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;672:27:38::1;678:8;688:10;672:5;:27::i;:::-;565:138:::0;;:::o;2102:364:44:-;2253:7;2313:9;;2378:10;:8;:10::i;:::-;2352:108;;;;;;;14606:19:92;;;;-1:-1:-1;;;;;;14656:2:92;14701:15;;;14697:24;;14683:12;;;14676:46;14756:15;;;14752:24;;14738:12;;;14731:46;14811:15;;;;14807:24;;;14793:12;;;14786:46;-1:-1:-1;;;;;;14863:3:92;14909:16;;;14905:25;;14891:12;;;14884:47;14966:16;;;14962:25;;14947:13;;;14940:48;15023:16;;;;15019:25;;;15004:13;;;14997:48;15092:14;15085:22;15080:3;15076:32;15061:13;;;15054:55;2352:108:44;;;;;;;;;15125:13:92;;;;2352:108:44;;;-1:-1:-1;;2342:119:44;;;;;;2102:364::o;495:261:28:-;294:9:54;;625:13:28;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;654:38:28::1;666:9;677:14;;654:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;654:11:28::1;::::0;-1:-1:-1;;;654:38:28:i:1;:::-;645:47;;704:5;713:1;704:10:::0;696:56:::1;;;::::0;-1:-1:-1;;;696:56:28;;15351:2:92;696:56:28::1;::::0;::::1;15333:21:92::0;15390:2;15370:18;;;15363:30;15429:34;15409:18;;;15402:62;-1:-1:-1;;;15480:18:92;;;15473:31;15521:19;;696:56:28::1;15149:397:92::0;1008:152:44;294:9:54;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;-1:-1:-1;;;;;5315:27:44;;;;;;:16;:27;;;;;:40;;-1:-1:-1;;5315:40:44;;;;;;;565:138:38;;:::o;2188:685:34:-;294:9:54;;2336:28:34;;-1:-1:-1;;;;;294:9:54;929:10:3;-1:-1:-1;;;;;278:25:54;;270:51;;;;-1:-1:-1;;;270:51:54;;;;;;;:::i;:::-;2376:53:34::1;2389:8;2399:5;2406:9;2417:11;2376:12;:53::i;:::-;2439:21;::::0;;;:14:::1;:21;::::0;;;;:32:::1;;:47:::0;;2475:11;;2439:21;:47:::1;::::0;2475:11;;2439:47:::1;:::i;:::-;::::0;;;-1:-1:-1;2497:19:34::1;::::0;-1:-1:-1;2538:10:34::1;:8;:10::i;:::-;-1:-1:-1::0;;;;;2519:44:34::1;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2497:68;;2575:22;2606:16;2616:5;2606:9;:16::i;:::-;-1:-1:-1::0;;;;;2600:32:34::1;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2575:59:::0;-1:-1:-1;2777:19:34::1;2783:13:::0;2777:2:::1;:19;:::i;:::-;809:3;125:5:58;2702:22:34;2708:16:::0;2702:2:::1;:22;:::i;:::-;2681:17;2692:5;2681:10;:17::i;:::-;2667:31;::::0;:11;:31:::1;:::i;:::-;:58;;;;:::i;:::-;:86;;;;:::i;:::-;:106;;;;:::i;:::-;:130;;;;:::i;:::-;-1:-1:-1::0;;;;;2807:35:34;::::1;;::::0;;;:24:::1;:35;::::0;;;;:59;;2644:153;;-1:-1:-1;2644:153:34;;2807:35;;;:59:::1;::::0;2644:153;;2807:59:::1;:::i;:::-;::::0;;;-1:-1:-1;2188:685:34;;;-1:-1:-1;;;;;;;2188:685:34:o;3812:158::-;3895:7;3921:21;;;:14;:21;;;;;:42;;;;3812:158::o;6477:137::-;;;;;:::o;1296:128:86:-;;;;:::o;6291:328:44:-;6443:80;6473:9;6484:5;6491:9;6502:20;6443:29;:80::i;:::-;6554:21;;;;:14;:21;;;;;:28;-1:-1:-1;;;;;6541:41:44;;;6554:28;;6541:41;6533:79;;;;-1:-1:-1;;;6533:79:44;;17414:2:92;6533:79:44;;;17396:21:92;17453:2;17433:18;;;17426:30;-1:-1:-1;;;17472:18:92;;;17465:55;17537:18;;6533:79:44;17212:349:92;4136:1108:34;4216:7;4235:12;4269:10;:8;:10::i;:::-;-1:-1:-1;;;;;4250:37:34;;4288:8;4250:47;;;;;;;;;;;;;345:25:92;;333:2;318:18;;199:177;4250:47:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4235:62;;4307:15;4344:10;:8;:10::i;:::-;-1:-1:-1;;;;;4325:40:34;;4366:8;4325:50;;;;;;;;;;;;;345:25:92;;333:2;318:18;;199:177;4325:50:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4307:68;;4385:19;4426:10;:8;:10::i;:::-;-1:-1:-1;;;;;4407:44:34;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4385:68;;4463:22;4494:15;4504:4;4494:9;:15::i;:::-;-1:-1:-1;;;;;4488:31:34;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4531:26;4560:20;;;:14;:20;;;;;:33;4463:58;;-1:-1:-1;4633:27:34;4651:8;4059:7;4085:25;;;:15;:25;;;;;:38;;3976:154;4633:27;4603:57;-1:-1:-1;4671:21:34;4811:19;4817:13;4811:2;:19;:::i;:::-;809:3;125:5:58;4736:22:34;4742:16;4736:2;:22;:::i;:::-;4716:16;4727:4;4716:10;:16::i;:::-;4695:37;;:18;:37;:::i;:::-;:64;;;;:::i;:::-;:92;;;;:::i;:::-;:112;;;;:::i;:::-;:136;;;;:::i;:::-;4671:160;;4841:24;4868:26;4889:4;4868:20;:26::i;:::-;4841:53;;4904:32;4959:13;4939:16;:33;;:112;;5038:13;4997:38;5019:16;4997:19;:38;:::i;:::-;:54;;;;:::i;:::-;4939:112;;;4975:19;4939:112;4904:147;-1:-1:-1;5062:27:34;5092:29;5114:7;5092:19;:29;:::i;:::-;5062:59;;5165:19;5138:24;:46;:99;;5236:1;5138:99;;;5187:46;5214:19;5187:24;:46;:::i;:::-;5131:106;4136:1108;-1:-1:-1;;;;;;;;;;;;4136:1108:34:o;312:96:28:-;5363:13:0;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:0;;;;;;;:::i;:::-;380:24:28::1;:22;:24::i;:::-;312:96::o:0;4075:606:44:-;4259:25;4287:21;;;:14;:21;;;;;4326:12;;;;-1:-1:-1;;;4326:12:44;;;;4318:51;;;;-1:-1:-1;;;4318:51:44;;18180:2:92;4318:51:44;;;18162:21:92;18219:2;18199:18;;;18192:30;-1:-1:-1;;;18238:18:92;;;18231:56;18304:18;;4318:51:44;17978:350:92;4318:51:44;4387:13;;;;-1:-1:-1;;;;;4387:26:44;;;:13;;:26;4379:71;;;;-1:-1:-1;;;4379:71:44;;18535:2:92;4379:71:44;;;18517:21:92;;;18554:18;;;18547:30;18613:34;18593:18;;;18586:62;18665:18;;4379:71:44;18333:356:92;4379:71:44;4461:18;4482:20;;;:13;:20;;;;;:31;;;;4546:46;4496:5;4546:39;:46::i;:::-;4523:69;;4626:10;4610:12;:26;;4602:72;;;;-1:-1:-1;;;4602:72:44;;18896:2:92;4602:72:44;;;18878:21:92;18935:2;18915:18;;;18908:30;18974:34;18954:18;;;18947:62;-1:-1:-1;;;19025:18:92;;;19018:31;19066:19;;4602:72:44;18694:397:92;4602:72:44;4249:432;;;4075:606;;;;;;:::o;5410:235:34:-;5577:16;5587:5;5577:9;:16::i;:::-;-1:-1:-1;;;;;5564:29:34;:9;-1:-1:-1;;;;;5564:29:34;;5556:82;;;;-1:-1:-1;;;5556:82:34;;19298:2:92;5556:82:34;;;19280:21:92;19337:2;19317:18;;;19310:30;19376:34;19356:18;;;19349:62;-1:-1:-1;;;19427:18:92;;;19420:38;19475:19;;5556:82:34;19096:404:92;526:764:86;615:12;650:10;:8;:10::i;:::-;-1:-1:-1;;;;;630:38:86;;669:8;630:48;;;;;;;;;;;;;345:25:92;;333:2;318:18;;199:177;630:48:86;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;688:31;722:19;;;:13;:19;;;;;755:29;;;;722:19;;-1:-1:-1;722:19:86;-1:-1:-1;;;755:29:86;;;;751:83;;;807:16;;-1:-1:-1;;;807:16:86;;;;;;;;;;;751:83;848:14;;844:440;;878:20;921:10;:8;:10::i;:::-;-1:-1:-1;;;;;901:41:86;;943:8;901:51;;;;;;;;;;;;;345:25:92;;333:2;318:18;;199:177;901:51:86;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;966:29;1011:25;;;:15;:25;;;;;:38;878:74;;-1:-1:-1;966:29:86;878:74;;998:51;;:10;:51;:::i;:::-;:66;;;;:::i;:::-;1078:25;;;;:15;:25;;;;;:63;;966:98;;-1:-1:-1;966:98:86;;1078:25;;;:63;;966:98;;1078:63;:::i;:::-;;;;-1:-1:-1;;1156:20:86;;;;:14;:20;;;;;:58;;1193:21;;1156:20;:58;;1193:21;;1156:58;:::i;:::-;;;;-1:-1:-1;;1228:20:86;;;;:14;:20;;;;;:31;;:45;;1263:10;;1228:20;:45;;1263:10;;1228:45;:::i;:::-;;;;-1:-1:-1;;;;605:685:86;;526:764;;:::o;2893:1176:44:-;2997:13;3022:26;3062:14;3051:43;;;;;;;;;;;;:::i;:::-;3022:72;;3104:24;3122:5;3104:17;:24::i;:::-;3164:14;;-1:-1:-1;;;;;3147:32:44;;;;;:16;:32;;;;;;;;3139:79;;;;-1:-1:-1;;;3139:79:44;;22850:2:92;3139:79:44;;;22832:21:92;22889:2;22869:18;;;22862:30;22928:34;22908:18;;;22901:62;-1:-1:-1;;;22979:18:92;;;22972:32;23021:19;;3139:79:44;22648:398:92;3139:79:44;3229:28;3260:286;;;;;;;;3295:9;-1:-1:-1;;;;;3260:286:44;;;;;3328:5;:14;;;-1:-1:-1;;;;;3260:286:44;;;;;3367:5;:15;;;-1:-1:-1;;;;;3260:286:44;;;;;3406:5;:14;;;-1:-1:-1;;;;;3260:286:44;;;;;3446:5;:16;;;-1:-1:-1;;;;;3260:286:44;;;;;3490:5;:18;;;3260:286;;;;;;3531:4;3260:286;;;;;3229:317;;3565:105;3573:9;3584:5;:14;;;3600:5;:15;;;3617:5;:14;;;3633:5;:16;;;3651:5;:18;;;3565:7;:105::i;:::-;3681:21;;;;:14;:21;;;;;;;;;:32;;;;-1:-1:-1;;;;;3681:32:44;;;-1:-1:-1;;;;;;3681:32:44;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3681:32:44;;;-1:-1:-1;;;3681:32:44;-1:-1:-1;;;;;;3681:32:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;3681:32:44;-1:-1:-1;;;;3681:32:44;;;-1:-1:-1;;;3681:32:44;;;;;-1:-1:-1;;;;3681:32:44;;;-1:-1:-1;;;3681:32:44;-1:-1:-1;;;;;;3681:32:44;;;;;;;;;;;;;;;;;;;;;;;;;;;3746:316;;;;;;;3784:16;;;;3746:316;;;;;3826:16;;;;3746:316;;;;;;;3870:18;;;;3557:113;;-1:-1:-1;3746:316:44;;;;;3870:18;3746:316;;;;;;;:::i;:::-;;;3916:18;;;;3746:316;;;;;;;;-1:-1:-1;3967:5:44;:18;;;:40;;;;;;;;:::i;:::-;;3746:316;;4034:17;;;;3746:316;;;;;-1:-1:-1;3723:20:44;;;:13;:20;;;;;;;:339;;;;-1:-1:-1;;;;;;3723:339:44;-1:-1:-1;;;;;3723:339:44;;;;;;;;;;-1:-1:-1;3723:339:44;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3723:339:44;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;3723:339:44;;;;;;;;;;;;;;;-1:-1:-1;;;3723:339:44;-1:-1:-1;;;;3723:339:44;;;;;;;;;;-1:-1:-1;;3723:339:44;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;3012:1057;;2893:1176;;;;:::o;5365:137::-;5439:7;5465:21;;;:14;:21;;;;;:30;;;-1:-1:-1;;;;;5465:30:44;;5365:137::o;5508:777::-;5583:7;5634:21;;;:14;:21;;;;;;;;5695:13;:20;;;;;5583:7;5757:77;809:3:34;125:5:58;5757:77:44;:::i;:::-;6084:18;;;;6064:17;;;;5726:108;;-1:-1:-1;5844:34:44;;181:18:58;;6064:38:44;;-1:-1:-1;;;;;;;;6084:18:44;;;;;;6064:17;:38;:::i;:::-;5895:20;;;;-1:-1:-1;;;;;5894:209:44;;;;;809:3:34;;5918:1:44;5895:20;;;;;;:24;:108;;5981:20;;;;;;;;;5895:108;;;5941:20;;;;5937:24;;5941:20;;;;;5937:1;:24;:::i;:::-;5930:32;;5895:108;5894:166;;;;:::i;:::-;:209;;;;:::i;:::-;:238;;;;:::i;:::-;6150:20;;;;5844:288;;-1:-1:-1;6173:1:44;6150:20;;;;;;:24;:128;;6229:49;6252:26;6229:20;:49;:::i;:::-;6150:128;;;6177:49;6200:26;6177:20;:49;:::i;:::-;6143:135;5508:777;-1:-1:-1;;;;;;5508:777:44:o;564:95:40:-;5363:13:0;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:0;;;;;;;:::i;:::-;628:27:40::1;:25;:27::i;4687:260:44:-:0;4802:15;4783:6;:16;;;-1:-1:-1;;;;;4783:34:44;;4775:78;;;;-1:-1:-1;;;4775:78:44;;25848:2:92;4775:78:44;;;25830:21:92;25887:2;25867:18;;;25860:30;25926:33;25906:18;;;25899:61;25977:18;;4775:78:44;25646:355:92;4775:78:44;4889:6;:16;;;-1:-1:-1;;;;;4871:34:44;:6;:15;;;-1:-1:-1;;;;;4871:34:44;;4863:77;;;;-1:-1:-1;;;4863:77:44;;26208:2:92;4863:77:44;;;26190:21:92;26247:2;26227:18;;;26220:30;26286:32;26266:18;;;26259:60;26336:18;;4863:77:44;26006:354:92;345:170:54;5363:13:0;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:0;;;;;;;:::i;:::-;418:43:54::1;929:10:3::0;418:29:54::1;:43::i;:::-;471:37;:35;:37::i;709:155:49:-:0;5363:13:0;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:0;;;;;;;:::i;:::-;800:5:49::1;:14:::0;;-1:-1:-1;;;;;;800:14:49::1;-1:-1:-1::0;;;;;800:14:49;::::1;;::::0;;829:28:::1;::::0;-1:-1:-1;;;;;;;;;;;829:28:49;::::1;::::0;-1:-1:-1;;800:14:49;;829:28:::1;:::i;521:75:54:-:0;5363:13:0;;;;;;;5355:69;;;;-1:-1:-1;;;5355:69:0;;;;;;;:::i;14:180:92:-;73:6;126:2;114:9;105:7;101:23;97:32;94:52;;;142:1;139;132:12;94:52;-1:-1:-1;165:23:92;;14:180;-1:-1:-1;14:180:92:o;381:203::-;-1:-1:-1;;;;;545:32:92;;;;527:51;;515:2;500:18;;381:203::o;589:385::-;675:6;683;691;699;752:3;740:9;731:7;727:23;723:33;720:53;;;769:1;766;759:12;720:53;-1:-1:-1;;792:23:92;;;862:2;847:18;;834:32;;-1:-1:-1;913:2:92;898:18;;885:32;;964:2;949:18;936:32;;-1:-1:-1;589:385:92;-1:-1:-1;589:385:92:o;979:127::-;1040:10;1035:3;1031:20;1028:1;1021:31;1071:4;1068:1;1061:15;1095:4;1092:1;1085:15;1303:250;1388:1;1398:113;1412:6;1409:1;1406:13;1398:113;;;1488:11;;;1482:18;1469:11;;;1462:39;1434:2;1427:10;1398:113;;;-1:-1:-1;;1545:1:92;1527:16;;1520:27;1303:250::o;1558:271::-;1600:3;1638:5;1632:12;1665:6;1660:3;1653:19;1681:76;1750:6;1743:4;1738:3;1734:14;1727:4;1720:5;1716:16;1681:76;:::i;:::-;1811:2;1790:15;-1:-1:-1;;1786:29:92;1777:39;;;;1818:4;1773:50;;1558:271;-1:-1:-1;;1558:271:92:o;1834:988::-;2021:2;2010:9;2003:21;2096:1;2092;2087:3;2083:11;2079:19;2070:6;2064:13;2060:39;2055:2;2044:9;2040:18;2033:67;2154:2;2146:6;2142:15;2136:22;2131:2;2120:9;2116:18;2109:50;1984:4;2206:2;2198:6;2194:15;2188:22;2246:1;2232:12;2229:19;2219:150;;2291:10;2286:3;2282:20;2279:1;2272:31;2326:4;2323:1;2316:15;2354:4;2351:1;2344:15;2219:150;2405:12;2400:2;2389:9;2385:18;2378:40;;2467:2;2459:6;2455:15;2449:22;2480:53;2528:3;2517:9;2513:19;2497:14;1186:1;1175:20;1163:33;;1111:91;2480:53;-1:-1:-1;2582:3:92;2570:16;;2564:23;1277:13;;1270:21;2643:3;2628:19;;1258:34;2596:52;2697:3;2689:6;2685:16;2679:23;2740:4;2733;2722:9;2718:20;2711:34;2762:54;2811:3;2800:9;2796:19;2780:14;2762:54;:::i;:::-;2754:62;1834:988;-1:-1:-1;;;;1834:988:92:o;2827:316::-;2904:6;2912;2920;2973:2;2961:9;2952:7;2948:23;2944:32;2941:52;;;2989:1;2986;2979:12;2941:52;-1:-1:-1;;3012:23:92;;;3082:2;3067:18;;3054:32;;-1:-1:-1;3133:2:92;3118:18;;;3105:32;;2827:316;-1:-1:-1;2827:316:92:o;3148:131::-;-1:-1:-1;;;;;3223:31:92;;3213:42;;3203:70;;3269:1;3266;3259:12;3284:525;3370:6;3378;3386;3394;3447:3;3435:9;3426:7;3422:23;3418:33;3415:53;;;3464:1;3461;3454:12;3415:53;3503:9;3490:23;3522:31;3547:5;3522:31;:::i;:::-;3572:5;-1:-1:-1;3624:2:92;3609:18;;3596:32;;-1:-1:-1;3680:2:92;3665:18;;3652:32;3693:33;3652:32;3693:33;:::i;:::-;3284:525;;;;-1:-1:-1;3745:7:92;;3799:2;3784:18;3771:32;;-1:-1:-1;;3284:525:92:o;3814:247::-;3873:6;3926:2;3914:9;3905:7;3901:23;3897:32;3894:52;;;3942:1;3939;3932:12;3894:52;3981:9;3968:23;4000:31;4025:5;4000:31;:::i;4258:736::-;4362:6;4370;4378;4386;4394;4402;4455:3;4443:9;4434:7;4430:23;4426:33;4423:53;;;4472:1;4469;4462:12;4423:53;4511:9;4498:23;4530:31;4555:5;4530:31;:::i;:::-;4580:5;-1:-1:-1;4637:2:92;4622:18;;4609:32;4650:33;4609:32;4650:33;:::i;:::-;4702:7;-1:-1:-1;4761:2:92;4746:18;;4733:32;4774:33;4733:32;4774:33;:::i;:::-;4258:736;;;;-1:-1:-1;4826:7:92;;4880:2;4865:18;;4852:32;;-1:-1:-1;4931:3:92;4916:19;;4903:33;;4983:3;4968:19;;;4955:33;;-1:-1:-1;4258:736:92;-1:-1:-1;;4258:736:92:o;5820:118::-;5907:5;5904:1;5893:20;5886:5;5883:31;5873:59;;5928:1;5925;5918:12;5943:452;6018:6;6026;6034;6087:2;6075:9;6066:7;6062:23;6058:32;6055:52;;;6103:1;6100;6093:12;6055:52;6142:9;6129:23;6161:31;6186:5;6161:31;:::i;:::-;6211:5;-1:-1:-1;6263:2:92;6248:18;;6235:32;;-1:-1:-1;6319:2:92;6304:18;;6291:32;6332:31;6291:32;6332:31;:::i;:::-;6382:7;6372:17;;;5943:452;;;;;:::o;6400:248::-;6468:6;6476;6529:2;6517:9;6508:7;6504:23;6500:32;6497:52;;;6545:1;6542;6535:12;6497:52;-1:-1:-1;;6568:23:92;;;6638:2;6623:18;;;6610:32;;-1:-1:-1;6400:248:92:o;6653:129::-;-1:-1:-1;;;;;6727:30:92;;6717:41;;6707:69;;6772:1;6769;6762:12;6787:118;6873:5;6866:13;6859:21;6852:5;6849:32;6839:60;;6895:1;6892;6885:12;6910:943;7008:6;7016;7024;7032;7040;7048;7101:3;7089:9;7080:7;7076:23;7072:33;7069:53;;;7118:1;7115;7108:12;7069:53;7157:9;7144:23;7176:31;7201:5;7176:31;:::i;:::-;7226:5;-1:-1:-1;7283:2:92;7268:18;;7255:32;7296:33;7255:32;7296:33;:::i;:::-;7348:7;-1:-1:-1;7407:2:92;7392:18;;7379:32;7420;7379;7420;:::i;:::-;7471:7;-1:-1:-1;7530:2:92;7515:18;;7502:32;7543;7502;7543;:::i;:::-;7594:7;-1:-1:-1;7653:3:92;7638:19;;7625:33;7667:32;7625:33;7667:32;:::i;:::-;7718:7;-1:-1:-1;7777:3:92;7762:19;;7749:33;7791:30;7749:33;7791:30;:::i;:::-;7840:7;7830:17;;;6910:943;;;;;;;;:::o;7858:726::-;7937:6;7945;7953;8006:2;7994:9;7985:7;7981:23;7977:32;7974:52;;;8022:1;8019;8012:12;7974:52;8061:9;8048:23;8080:31;8105:5;8080:31;:::i;:::-;8130:5;-1:-1:-1;8186:2:92;8171:18;;8158:32;-1:-1:-1;;;;;8239:14:92;;;8236:34;;;8266:1;8263;8256:12;8236:34;8304:6;8293:9;8289:22;8279:32;;8349:7;8342:4;8338:2;8334:13;8330:27;8320:55;;8371:1;8368;8361:12;8320:55;8411:2;8398:16;8437:2;8429:6;8426:14;8423:34;;;8453:1;8450;8443:12;8423:34;8498:7;8493:2;8484:6;8480:2;8476:15;8472:24;8469:37;8466:57;;;8519:1;8516;8509:12;8466:57;8550:2;8546;8542:11;8532:21;;8572:6;8562:16;;;;;7858:726;;;;;:::o;8589:382::-;8654:6;8662;8715:2;8703:9;8694:7;8690:23;8686:32;8683:52;;;8731:1;8728;8721:12;8683:52;8770:9;8757:23;8789:31;8814:5;8789:31;:::i;:::-;8839:5;-1:-1:-1;8896:2:92;8881:18;;8868:32;8909:30;8868:32;8909:30;:::i;:::-;8958:7;8948:17;;;8589:382;;;;;:::o;8976:452::-;9062:6;9070;9078;9086;9139:3;9127:9;9118:7;9114:23;9110:33;9107:53;;;9156:1;9153;9146:12;9107:53;9192:9;9179:23;9169:33;;9249:2;9238:9;9234:18;9221:32;9211:42;;9303:2;9292:9;9288:18;9275:32;9316:31;9341:5;9316:31;:::i;9780:304::-;-1:-1:-1;;;;;10010:15:92;;;9992:34;;10062:15;;10057:2;10042:18;;10035:43;9942:2;9927:18;;9780:304::o;10089:337::-;10291:2;10273:21;;;10330:2;10310:18;;;10303:30;-1:-1:-1;;;10364:2:92;10349:18;;10342:43;10417:2;10402:18;;10089:337::o;10431:127::-;10492:10;10487:3;10483:20;10480:1;10473:31;10523:4;10520:1;10513:15;10547:4;10544:1;10537:15;10563:168;10636:9;;;10667;;10684:15;;;10678:22;;10664:37;10654:71;;10705:18;;:::i;10736:217::-;10776:1;10802;10792:132;;10846:10;10841:3;10837:20;10834:1;10827:31;10881:4;10878:1;10871:15;10909:4;10906:1;10899:15;10792:132;-1:-1:-1;10938:9:92;;10736:217::o;10958:128::-;11025:9;;;11046:11;;;11043:37;;;11060:18;;:::i;11091:125::-;11156:9;;;11177:10;;;11174:36;;;11190:18;;:::i;11221:380::-;11300:1;11296:12;;;;11343;;;11364:61;;11418:4;11410:6;11406:17;11396:27;;11364:61;11471:2;11463:6;11460:14;11440:18;11437:38;11434:161;;11517:10;11512:3;11508:20;11505:1;11498:31;11552:4;11549:1;11542:15;11580:4;11577:1;11570:15;11434:161;;11221:380;;;:::o;11606:184::-;11676:6;11729:2;11717:9;11708:7;11704:23;11700:32;11697:52;;;11745:1;11742;11735:12;11697:52;-1:-1:-1;11768:16:92;;11606:184;-1:-1:-1;11606:184:92:o;12220:334::-;12422:2;12404:21;;;12461:2;12441:18;;;12434:30;-1:-1:-1;;;12495:2:92;12480:18;;12473:40;12545:2;12530:18;;12220:334::o;15551:273::-;15619:6;15672:2;15660:9;15651:7;15647:23;15643:32;15640:52;;;15688:1;15685;15678:12;15640:52;15720:9;15714:16;15770:4;15763:5;15759:16;15752:5;15749:27;15739:55;;15790:1;15787;15780:12;15829:422;15918:1;15961:5;15918:1;15975:270;15996:7;15986:8;15983:21;15975:270;;;16055:4;16051:1;16047:6;16043:17;16037:4;16034:27;16031:53;;;16064:18;;:::i;:::-;16114:7;16104:8;16100:22;16097:55;;;16134:16;;;;16097:55;16213:22;;;;16173:15;;;;15975:270;;;15979:3;15829:422;;;;;:::o;16256:806::-;16305:5;16335:8;16325:80;;-1:-1:-1;16376:1:92;16390:5;;16325:80;16424:4;16414:76;;-1:-1:-1;16461:1:92;16475:5;;16414:76;16506:4;16524:1;16519:59;;;;16592:1;16587:130;;;;16499:218;;16519:59;16549:1;16540:10;;16563:5;;;16587:130;16624:3;16614:8;16611:17;16608:43;;;16631:18;;:::i;:::-;-1:-1:-1;;16687:1:92;16673:16;;16702:5;;16499:218;;16801:2;16791:8;16788:16;16782:3;16776:4;16773:13;16769:36;16763:2;16753:8;16750:16;16745:2;16739:4;16736:12;16732:35;16729:77;16726:159;;;-1:-1:-1;16838:19:92;;;16870:5;;16726:159;16917:34;16942:8;16936:4;16917:34;:::i;:::-;16987:6;16983:1;16979:6;16975:19;16966:7;16963:32;16960:58;;;16998:18;;:::i;:::-;17036:20;;16256:806;-1:-1:-1;;;16256:806:92:o;17067:140::-;17125:5;17154:47;17195:4;17185:8;17181:19;17175:4;17154:47;:::i;17566:407::-;17768:2;17750:21;;;17807:2;17787:18;;;17780:30;17846:34;17841:2;17826:18;;17819:62;-1:-1:-1;;;17912:2:92;17897:18;;17890:41;17963:3;17948:19;;17566:407::o;19505:127::-;19566:10;19561:3;19557:20;19554:1;19547:31;19597:4;19594:1;19587:15;19621:4;19618:1;19611:15;19637:250;19704:2;19698:9;19746:6;19734:19;;-1:-1:-1;;;;;19768:34:92;;19804:22;;;19765:62;19762:88;;;19830:18;;:::i;:::-;19866:2;19859:22;19637:250;:::o;19892:138::-;19971:13;;19993:31;19971:13;19993:31;:::i;:::-;19892:138;;;:::o;20035:157::-;20124:13;;20166:1;20156:12;;20146:40;;20182:1;20179;20172:12;20197:134;20274:13;;20296:29;20274:13;20296:29;:::i;20336:136::-;20414:13;;20436:30;20414:13;20436:30;:::i;20477:132::-;20553:13;;20575:28;20553:13;20575:28;:::i;20614:699::-;20668:5;20721:3;20714:4;20706:6;20702:17;20698:27;20688:55;;20739:1;20736;20729:12;20688:55;20762:13;;-1:-1:-1;;;;;20824:10:92;;;20821:36;;;20837:18;;:::i;:::-;20912:2;20906:9;20880:2;20966:13;;-1:-1:-1;;20962:22:92;;;20986:2;20958:31;20954:40;20942:53;;;21010:18;;;21030:22;;;21007:46;21004:72;;;21056:18;;:::i;:::-;21096:10;21092:2;21085:22;21131:2;21123:6;21116:18;21177:3;21170:4;21165:2;21157:6;21153:15;21149:26;21146:35;21143:55;;;21194:1;21191;21184:12;21143:55;21207:76;21280:2;21273:4;21265:6;21261:17;21254:4;21246:6;21242:17;21207:76;:::i;21318:1325::-;21419:6;21472:2;21460:9;21451:7;21447:23;21443:32;21440:52;;;21488:1;21485;21478:12;21440:52;21515:16;;-1:-1:-1;;;;;21580:14:92;;;21577:34;;;21607:1;21604;21597:12;21577:34;21630:22;;;;21686:6;21668:16;;;21664:29;21661:49;;;21706:1;21703;21696:12;21661:49;21732:17;;:::i;:::-;21772:33;21802:2;21772:33;:::i;:::-;21765:5;21758:48;21838:42;21876:2;21872;21868:11;21838:42;:::i;:::-;21833:2;21826:5;21822:14;21815:66;21927:2;21923;21919:11;21913:18;21908:2;21901:5;21897:14;21890:42;21964:52;22012:2;22008;22004:11;21964:52;:::i;:::-;21959:2;21952:5;21948:14;21941:76;22050:41;22086:3;22082:2;22078:12;22050:41;:::i;:::-;22044:3;22037:5;22033:15;22026:66;22125:42;22162:3;22158:2;22154:12;22125:42;:::i;:::-;22119:3;22112:5;22108:15;22101:67;22201:42;22238:3;22234:2;22230:12;22201:42;:::i;:::-;22195:3;22188:5;22184:15;22177:67;22277:42;22314:3;22310:2;22306:12;22277:42;:::i;:::-;22271:3;22264:5;22260:15;22253:67;22339:3;22374:39;22409:2;22405;22401:11;22374:39;:::i;:::-;22358:14;;;22351:63;22433:3;22467:11;;;22461:18;22491:16;;;22488:36;;;22520:1;22517;22510:12;22488:36;22556:56;22604:7;22593:8;22589:2;22585:17;22556:56;:::i;:::-;22540:14;;;22533:80;;;;-1:-1:-1;22544:5:92;21318:1325;-1:-1:-1;;;;;21318:1325:92:o;23177:545::-;23279:2;23274:3;23271:11;23268:448;;;23315:1;23340:5;23336:2;23329:17;23385:4;23381:2;23371:19;23455:2;23443:10;23439:19;23436:1;23432:27;23426:4;23422:38;23491:4;23479:10;23476:20;23473:47;;;-1:-1:-1;23514:4:92;23473:47;23569:2;23564:3;23560:12;23557:1;23553:20;23547:4;23543:31;23533:41;;23624:82;23642:2;23635:5;23632:13;23624:82;;;23687:17;;;23668:1;23657:13;23624:82;;23898:1352;24018:10;;-1:-1:-1;;;;;24040:30:92;;24037:56;;;24073:18;;:::i;:::-;24102:97;24192:6;24152:38;24184:4;24178:11;24152:38;:::i;:::-;24146:4;24102:97;:::i;:::-;24254:4;;24318:2;24307:14;;24335:1;24330:663;;;;25037:1;25054:6;25051:89;;;-1:-1:-1;25106:19:92;;;25100:26;25051:89;-1:-1:-1;;23855:1:92;23851:11;;;23847:24;23843:29;23833:40;23879:1;23875:11;;;23830:57;25153:81;;24300:944;;24330:663;23124:1;23117:14;;;23161:4;23148:18;;-1:-1:-1;;24366:20:92;;;24484:236;24498:7;24495:1;24492:14;24484:236;;;24587:19;;;24581:26;24566:42;;24679:27;;;;24647:1;24635:14;;;;24514:19;;24484:236;;;24488:3;24748:6;24739:7;24736:19;24733:201;;;24809:19;;;24803:26;-1:-1:-1;;24892:1:92;24888:14;;;24904:3;24884:24;24880:37;24876:42;24861:58;24846:74;;24733:201;-1:-1:-1;;;;;24980:1:92;24964:14;;;24960:22;24947:36;;-1:-1:-1;23898:1352:92:o;25255:183::-;-1:-1:-1;;;;;25374:10:92;;;25362;;;25358:27;;25397:12;;;25394:38;;;25412:18;;:::i;:::-;25394:38;25255:183;;;;:::o;25443:198::-;25541:1;25530:16;;;25512;;;;25508:39;-1:-1:-1;;25562:26:92;;25600:10;25590:21;;25559:53;25556:79;;;25615:18;;:::i
Swarm Source
ipfs://e356f216a9bec8b45ee4e16c99e34d18ae0cdc3edac6d1ccb5a58c9a3d422e75
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.