Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60a06040 | 15992879 | 740 days ago | IN | 0 ETH | 0.02196286 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
MembershipVault
Compiler Version
v0.8.16+commit.07a7930e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // solhint-disable func-name-mixedcase pragma solidity ^0.8.16; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/interfaces/IERC721EnumerableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; import {IMembershipVault, Position} from "../../../interfaces/IMembershipVault.sol"; import {Context} from "../../../cake/Context.sol"; import {Base} from "../../../cake/Base.sol"; import "../../../cake/Routing.sol" as Routing; import {ERC721NonTransferable} from "../ERC721NonTransferable.sol"; import {Epochs} from "./Epochs.sol"; import {ERCInterfaces} from "../ERCInterfaces.sol"; using Routing.Context for Context; using StringsUpgradeable for uint256; /** * @title MembershipVault * @notice Track assets held by owners in a vault, as well as the total held in the vault. Assets * are not accounted for until the next epoch for MEV protection. * @author Goldfinch */ contract MembershipVault is IMembershipVault, Base, ERC721NonTransferable, IERC721EnumerableUpgradeable, IERC721MetadataUpgradeable, Initializable { /// Thrown when depositing from address(0) error ZeroAddressInvalid(); /// Thrown when trying to access tokens from an address with no tokens error NoTokensOwned(); /// Thrown when trying to access more than one token for an address error OneTokenPerAddress(); /// Thrown when querying token supply with an index greater than the supply error IndexGreaterThanTokenSupply(); /// Thrown when checking totals in future epochs error NoTotalsInFutureEpochs(); /// Thrown when adjusting holdings in an unsupported way error InvalidHoldingsAdjustment(uint256 eligibleAmount, uint256 nextEpochAmount); /// Thrown when requesting a nonexistant token error NonexistantToken(uint256 tokenId); /** * @notice The vault has been checkpointed * @param total how much is stored in the vault at the current block.timestamp */ event Checkpoint(uint256 total); /// @notice Totals by epoch. totalAmounts is always tracking past epochs, the current /// epoch, and the next epoch. There are a few cases: /// 1. Checkpointing /// Noop for the same epoch. Checkpointing occurs before any mutative action /// so for new epochs, the last-set epoch value (totalAmounts[previousEpoch + 1]) /// is copied to each epoch up to the current epoch + 1 /// 2. Increasing /// Checkpointing already occurred, so current epoch and next epoch /// are properly set up. Increasing just updates the next epoch value /// 3. Decreasing /// Checkpointing already occurred like above. Decreasing updates the eligible /// and next epoch values mapping(uint256 => uint256) private totalAmounts; /// @notice last epoch the vault was checkpointed uint256 private checkpointEpoch; /// @notice all positions held by the vault mapping(uint256 => Position) private positions; /// @notice owners and their position mapping(address => uint256) private owners; /// @notice counter tracking most current membership id uint256 private membershipIdsTracker; /// @notice base uri for the nft string public baseURI; //solhint-disable-next-line no-empty-blocks constructor(Context _context) Base(_context) {} function initialize() public initializer { checkpointEpoch = Epochs.current(); } ////////////////////////////////////////////////////////////////// // ERC 721 + Enumerable function totalSupply() public view returns (uint256) { return membershipIdsTracker; } function ownerOf(uint256 membershipId) external view returns (address owner) { return positions[membershipId].owner; } function balanceOf(address owner) external view returns (uint256) { return owners[owner] > 0 ? 1 : 0; } function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256) { uint256 membershipId = owners[owner]; if (membershipId == 0) revert NoTokensOwned(); if (index > 0) revert OneTokenPerAddress(); return membershipId; } function tokenByIndex(uint256 index) external view returns (uint256) { if (index >= totalSupply()) revert IndexGreaterThanTokenSupply(); return index + 1; } function supportsInterface(bytes4 id) external pure override returns (bool) { return (id == ERCInterfaces.ERC721 || id == ERCInterfaces.ERC721_ENUMERABLE || id == ERCInterfaces.ERC165); } ////////////////////////////////////////////////////////////////// // ERC721 Metadata /// @inheritdoc IERC721MetadataUpgradeable function name() external pure returns (string memory) { return "Goldfinch Membership"; } /// @inheritdoc IERC721MetadataUpgradeable function symbol() external pure returns (string memory) { return "GFMEMBER"; } /// @inheritdoc IERC721MetadataUpgradeable function tokenURI(uint256 tokenId) external view returns (string memory) { if (tokenId == 0) revert NonexistantToken(tokenId); if (tokenId > membershipIdsTracker) revert NonexistantToken(tokenId); return string(abi.encodePacked(baseURI, tokenId.toString())); } /// @notice Set the base uri for the contract function setBaseURI(string calldata uri) external onlyAdmin { baseURI = uri; } ////////////////////////////////////////////////////////////////// // IMembershipVault /// @inheritdoc IMembershipVault function currentValueOwnedBy(address owner) external view override returns (uint256) { Position memory position = positions[owners[owner]]; if (Epochs.current() > position.checkpointEpoch) { return position.nextEpochAmount; } return position.eligibleAmount; } /// @inheritdoc IMembershipVault function currentTotal() external view override returns (uint256) { return totalAtEpoch(Epochs.current()); } /// @inheritdoc IMembershipVault function totalAtEpoch(uint256 epoch) public view returns (uint256) { if (epoch > Epochs.next()) revert NoTotalsInFutureEpochs(); if (epoch > checkpointEpoch) { // If querying for an epoch past the checkpoint, always use the next amount. This is the amount // that will become eligible for every epoch after `checkpointEpoch`. return totalAmounts[checkpointEpoch + 1]; } return totalAmounts[epoch]; } /// @inheritdoc IMembershipVault function positionOwnedBy(address owner) external view returns (Position memory) { return positions[owners[owner]]; } // @inheritdoc IMembershipVault function adjustHoldings( address owner, uint256 eligibleAmount, uint256 nextEpochAmount ) external onlyOperator(Routing.Keys.MembershipDirector) returns (uint256) { if (nextEpochAmount < eligibleAmount) revert InvalidHoldingsAdjustment(eligibleAmount, nextEpochAmount); uint256 membershipId = _fetchOrCreateMembership(owner); _checkpoint(owner); Position memory position = positions[membershipId]; positions[membershipId].eligibleAmount = eligibleAmount; positions[membershipId].nextEpochAmount = nextEpochAmount; totalAmounts[Epochs.current()] = (totalAmounts[Epochs.current()] - position.eligibleAmount) + eligibleAmount; totalAmounts[Epochs.next()] = (totalAmounts[Epochs.next()] - position.nextEpochAmount) + nextEpochAmount; emit AdjustedHoldings({owner: owner, eligibleAmount: eligibleAmount, nextEpochAmount: nextEpochAmount}); emit VaultTotalUpdate({ eligibleAmount: totalAmounts[Epochs.current()], nextEpochAmount: totalAmounts[Epochs.next()] }); return membershipId; } // @inheritdoc IMembershipVault function checkpoint(address owner) external onlyOperator(Routing.Keys.MembershipDirector) { return _checkpoint(owner); } ////////////////////////////////////////////////////////////////// // Private function _fetchOrCreateMembership(address owner) private returns (uint256) { if (owner == address(0)) revert ZeroAddressInvalid(); uint256 membershipId = owners[owner]; if (membershipId > 0) return membershipId; membershipIdsTracker++; membershipId = membershipIdsTracker; positions[membershipId].owner = owner; positions[membershipId].createdTimestamp = block.timestamp; positions[membershipId].checkpointEpoch = Epochs.current(); owners[owner] = membershipId; emit Transfer({from: address(0), to: owner, tokenId: membershipId}); return membershipId; } function _checkpoint(address owner) private { uint256 currentEpoch = Epochs.current(); if (currentEpoch > checkpointEpoch) { // Promote the last checkpoint's nextAmount to all subsequent epochs up to currentEpoch + 1. This // guarantees that total[current] and total[next] are always properly set before any operations // are performed. uint256 lastCheckpointNextAmount = totalAmounts[checkpointEpoch + 1]; for (uint256 epoch = checkpointEpoch + 2; epoch <= currentEpoch + 1; epoch++) { totalAmounts[epoch] = lastCheckpointNextAmount; } checkpointEpoch = Epochs.current(); } uint256 membershipId = owners[owner]; if (membershipId > 0) { // positionId of 0 means that no position exists. This occurs if checkpoint is called // before a position is created. Position memory previousPosition = positions[membershipId]; // Promote `nextEpochAmount` to `eligibleAmount` if epochs have progressed if (currentEpoch > previousPosition.checkpointEpoch) { positions[membershipId].eligibleAmount = previousPosition.nextEpochAmount; positions[membershipId].checkpointEpoch = Epochs.current(); } } emit Checkpoint(totalAmounts[Epochs.current()]); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../token/ERC20/IERC20Upgradeable.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../token/ERC721/extensions/IERC721EnumerableUpgradeable.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../token/ERC721/extensions/IERC721MetadataUpgradeable.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../token/ERC721/IERC721Upgradeable.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 a proxied contract can't have 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. * * 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. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount ) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721Upgradeable is IERC165Upgradeable { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC721Upgradeable.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721EnumerableUpgradeable is IERC721Upgradeable { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC721Upgradeable.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721MetadataUpgradeable is IERC721Upgradeable { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT 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 pragma solidity ^0.8.16; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../interfaces/IAccessControl.sol"; /// @title Cake access control /// @author landakram /// @notice This contact centralizes contract-to-contract access control using a simple /// access-control list. There are two types of actors: operators and admins. Operators /// are callers involved in a regular end-user tx. This would likely be another Goldfinch /// contract for which the current contract is a dependency. Admins are callers allowed /// for specific admin actions (like changing parameters, topping up funds, etc.). contract AccessControl is Initializable, IAccessControl { /// @dev Mapping from contract address to contract admin; mapping(address => address) public admins; function initialize(address admin) public initializer { admins[address(this)] = admin; emit AdminSet(address(this), admin); } /// @inheritdoc IAccessControl function setAdmin(address resource, address admin) external { requireSuperAdmin(msg.sender); admins[resource] = admin; emit AdminSet(resource, admin); } /// @inheritdoc IAccessControl function requireAdmin(address resource, address accessor) public view { if (accessor == address(0)) revert ZeroAddress(); bool isAdmin = admins[resource] == accessor; if (!isAdmin) revert RequiresAdmin(resource, accessor); } /// @inheritdoc IAccessControl function requireSuperAdmin(address accessor) public view { // The super admin is the admin of this AccessControl contract requireAdmin({resource: address(this), accessor: accessor}); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {Context} from "./Context.sol"; import "./Routing.sol" as Routing; using Routing.Context for Context; /// @title Base contract for application-layer /// @author landakram /// @notice This base contract is what all application-layer contracts should inherit from. /// It provides `Context`, as well as some convenience functions for working with it and /// using access control. All public methods on the inheriting contract should likely /// use one of the modifiers to assert valid callers. abstract contract Base { error RequiresOperator(address resource, address accessor); error ZeroAddress(); /// @dev this is safe for proxies as immutable causes the context to be written to /// bytecode on deployment. The proxy then treats this as a constant. Context immutable context; constructor(Context _context) { context = _context; } modifier onlyOperator(bytes4 operatorId) { requireOperator(operatorId, msg.sender); _; } modifier onlyOperators(bytes4[2] memory operatorIds) { requireAnyOperator(operatorIds, msg.sender); _; } modifier onlyAdmin() { context.accessControl().requireAdmin(address(this), msg.sender); _; } function requireAnyOperator(bytes4[2] memory operatorIds, address accessor) private view { if (accessor == address(0)) revert ZeroAddress(); bool validOperator = isOperator(operatorIds[0], accessor) || isOperator(operatorIds[1], accessor); if (!validOperator) revert RequiresOperator(address(this), accessor); } function requireOperator(bytes4 operatorId, address accessor) private view { if (accessor == address(0)) revert ZeroAddress(); if (!isOperator(operatorId, accessor)) revert RequiresOperator(address(this), accessor); } function isOperator(bytes4 operatorId, address accessor) private view returns (bool) { return context.router().contracts(operatorId) == accessor; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {AccessControl} from "./AccessControl.sol"; import {Router} from "./Router.sol"; import "./Routing.sol" as Routing; using Routing.Context for Context; /// @title Entry-point for all application-layer contracts. /// @author landakram /// @notice This contract provides an interface for retrieving other contract addresses and doing access /// control. contract Context { /// @notice Used for retrieving other contract addresses. /// @dev This variable is immutable. This is done to save gas, as it is expected to be referenced /// in every end-user call with a call-chain length > 0. Note that it is written into the contract /// bytecode at contract creation time, so if the contract is deployed as the implementation for proxies, /// every proxy will share the same Router address. Router public immutable router; constructor(Router _router) { router = _router; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {AccessControl} from "./AccessControl.sol"; import {IRouter} from "../interfaces/IRouter.sol"; import "./Routing.sol" as Routing; /// @title Router /// @author landakram /// @notice This contract provides service discovery for contracts using the cake framework. /// It can be used in conjunction with the convenience methods defined in the `Routing.Context` /// and `Routing.Keys` libraries. contract Router is Initializable, IRouter { /// @notice Mapping of keys to contract addresses. Keys are the first 4 bytes of the keccak of /// the contract's name. See Routing.sol for all options. mapping(bytes4 => address) public contracts; function initialize(AccessControl accessControl) public initializer { contracts[Routing.Keys.AccessControl] = address(accessControl); } /// @notice Associate a routing key to a contract address /// @dev This function is only callable by the Router admin /// @param key A routing key (defined in the `Routing.Keys` libary) /// @param addr A contract address function setContract(bytes4 key, address addr) public { AccessControl accessControl = AccessControl(contracts[Routing.Keys.AccessControl]); accessControl.requireAdmin(address(this), msg.sender); contracts[key] = addr; emit SetContract(key, addr); } }
// SPDX-License-Identifier: MIT // solhint-disable const-name-snakecase pragma solidity ^0.8.16; import "@openzeppelin/contracts-upgradeable/interfaces/IERC20Upgradeable.sol"; import {IMembershipVault} from "../interfaces/IMembershipVault.sol"; import {IGFILedger} from "../interfaces/IGFILedger.sol"; import {ICapitalLedger} from "../interfaces/ICapitalLedger.sol"; import {IMembershipDirector} from "../interfaces/IMembershipDirector.sol"; import {IMembershipOrchestrator} from "../interfaces/IMembershipOrchestrator.sol"; import {IMembershipLedger} from "../interfaces/IMembershipLedger.sol"; import {IMembershipCollector} from "../interfaces/IMembershipCollector.sol"; import {ISeniorPool} from "../interfaces/ISeniorPool.sol"; import {IPoolTokens} from "../interfaces/IPoolTokens.sol"; import {IStakingRewards} from "../interfaces/IStakingRewards.sol"; import {IERC20Splitter} from "../interfaces/IERC20Splitter.sol"; import {Context as ContextContract} from "./Context.sol"; import {IAccessControl} from "../interfaces/IAccessControl.sol"; import {Router} from "./Router.sol"; /// @title Routing.Keys /// @notice This library is used to define routing keys used by `Router`. /// @dev We use uints instead of enums for several reasons. First, keys can be re-ordered /// or removed. This is useful when routing keys are deprecated; they can be moved to a /// different section of the file. Second, other libraries or contracts can define their /// own routing keys independent of this global mapping. This is useful for test contracts. library Keys { // Membership bytes4 internal constant MembershipOrchestrator = bytes4(keccak256("MembershipOrchestrator")); bytes4 internal constant MembershipDirector = bytes4(keccak256("MembershipDirector")); bytes4 internal constant GFILedger = bytes4(keccak256("GFILedger")); bytes4 internal constant CapitalLedger = bytes4(keccak256("CapitalLedger")); bytes4 internal constant MembershipCollector = bytes4(keccak256("MembershipCollector")); bytes4 internal constant MembershipLedger = bytes4(keccak256("MembershipLedger")); bytes4 internal constant MembershipVault = bytes4(keccak256("MembershipVault")); // Tokens bytes4 internal constant GFI = bytes4(keccak256("GFI")); bytes4 internal constant FIDU = bytes4(keccak256("FIDU")); bytes4 internal constant USDC = bytes4(keccak256("USDC")); // Cake bytes4 internal constant AccessControl = bytes4(keccak256("AccessControl")); bytes4 internal constant Router = bytes4(keccak256("Router")); // Core bytes4 internal constant ReserveSplitter = bytes4(keccak256("ReserveSplitter")); bytes4 internal constant PoolTokens = bytes4(keccak256("PoolTokens")); bytes4 internal constant SeniorPool = bytes4(keccak256("SeniorPool")); bytes4 internal constant StakingRewards = bytes4(keccak256("StakingRewards")); bytes4 internal constant ProtocolAdmin = bytes4(keccak256("ProtocolAdmin")); bytes4 internal constant PauserAdmin = bytes4(keccak256("PauserAdmin")); } /// @title Routing.Context /// @notice This library provides convenience functions for getting contracts from `Router`. library Context { function accessControl(ContextContract context) internal view returns (IAccessControl) { return IAccessControl(context.router().contracts(Keys.AccessControl)); } function membershipVault(ContextContract context) internal view returns (IMembershipVault) { return IMembershipVault(context.router().contracts(Keys.MembershipVault)); } function capitalLedger(ContextContract context) internal view returns (ICapitalLedger) { return ICapitalLedger(context.router().contracts(Keys.CapitalLedger)); } function gfiLedger(ContextContract context) internal view returns (IGFILedger) { return IGFILedger(context.router().contracts(Keys.GFILedger)); } function gfi(ContextContract context) internal view returns (IERC20Upgradeable) { return IERC20Upgradeable(context.router().contracts(Keys.GFI)); } function membershipDirector(ContextContract context) internal view returns (IMembershipDirector) { return IMembershipDirector(context.router().contracts(Keys.MembershipDirector)); } function membershipOrchestrator(ContextContract context) internal view returns (IMembershipOrchestrator) { return IMembershipOrchestrator(context.router().contracts(Keys.MembershipOrchestrator)); } function stakingRewards(ContextContract context) internal view returns (IStakingRewards) { return IStakingRewards(context.router().contracts(Keys.StakingRewards)); } function poolTokens(ContextContract context) internal view returns (IPoolTokens) { return IPoolTokens(context.router().contracts(Keys.PoolTokens)); } function seniorPool(ContextContract context) internal view returns (ISeniorPool) { return ISeniorPool(context.router().contracts(Keys.SeniorPool)); } function fidu(ContextContract context) internal view returns (IERC20Upgradeable) { return IERC20Upgradeable(context.router().contracts(Keys.FIDU)); } function usdc(ContextContract context) internal view returns (IERC20Upgradeable) { return IERC20Upgradeable(context.router().contracts(Keys.USDC)); } function reserveSplitter(ContextContract context) internal view returns (IERC20Splitter) { return IERC20Splitter(context.router().contracts(Keys.ReserveSplitter)); } function membershipLedger(ContextContract context) internal view returns (IMembershipLedger) { return IMembershipLedger(context.router().contracts(Keys.MembershipLedger)); } function membershipCollector(ContextContract context) internal view returns (IMembershipCollector) { return IMembershipCollector(context.router().contracts(Keys.MembershipCollector)); } function protocolAdmin(ContextContract context) internal view returns (address) { return context.router().contracts(Keys.ProtocolAdmin); } function pauserAdmin(ContextContract context) internal view returns (address) { return context.router().contracts(Keys.PauserAdmin); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /// @title Cake access control /// @author landakram /// @notice This contact centralizes contract-to-contract access control using a simple /// access-control list. There are two types of actors: operators and admins. Operators /// are callers involved in a regular end-user tx. This would likely be another Goldfinch /// contract for which the current contract is a dependency. Admins are callers allowed /// for specific admin actions (like changing parameters, topping up funds, etc.). interface IAccessControl { error RequiresAdmin(address resource, address accessor); error ZeroAddress(); event AdminSet(address indexed resource, address indexed admin); /// @notice Set an admin for a given resource /// @param resource An address which with `admin` should be allowed to administer /// @param admin An address which should be allowed to administer `resource` /// @dev This method is only callable by the super-admin (the admin of this AccessControl /// contract) function setAdmin(address resource, address admin) external; /// @notice Require a valid admin for a given resource /// @param resource An address that `accessor` is attempting to access /// @param accessor An address on which to assert access control checks /// @dev This method reverts when `accessor` is not a valid admin function requireAdmin(address resource, address accessor) external view; /// @notice Require a super-admin. A super-admin is an admin of this AccessControl contract. /// @param accessor An address on which to assert access control checks /// @dev This method reverts when `accessor` is not a valid super-admin function requireSuperAdmin(address accessor) external view; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; enum CapitalAssetType { INVALID, ERC721 } interface ICapitalLedger { /** * @notice Emitted when a new capital erc721 deposit has been made * @param owner address owning the deposit * @param assetAddress address of the deposited ERC721 * @param positionId id for the deposit * @param assetTokenId id of the token from the ERC721 `assetAddress` * @param usdcEquivalent usdc equivalent value at the time of deposit */ event CapitalERC721Deposit( address indexed owner, address indexed assetAddress, uint256 positionId, uint256 assetTokenId, uint256 usdcEquivalent ); /** * @notice Emitted when a new ERC721 capital withdrawal has been made * @param owner address owning the deposit * @param positionId id for the capital position * @param assetAddress address of the underlying ERC721 * @param depositTimestamp block.timestamp of the original deposit */ event CapitalERC721Withdrawal( address indexed owner, uint256 positionId, address assetAddress, uint256 depositTimestamp ); /// Thrown when called with an invalid asset type for the function. Valid /// types are defined under CapitalAssetType error InvalidAssetType(CapitalAssetType); /** * @notice Account for a deposit of `id` for the ERC721 asset at `assetAddress`. * @dev reverts with InvalidAssetType if `assetAddress` is not an ERC721 * @param owner address that owns the position * @param assetAddress address of the ERC20 address * @param assetTokenId id of the ERC721 asset to add * @return id of the newly created position */ function depositERC721( address owner, address assetAddress, uint256 assetTokenId ) external returns (uint256); /** * @notice Get the id of the ERC721 asset held by position `id`. Pair this with * `assetAddressOf` to get the address & id of the nft. * @dev reverts with InvalidAssetType if `assetAddress` is not an ERC721 * @param positionId id of the position * @return id of the underlying ERC721 asset */ function erc721IdOf(uint256 positionId) external view returns (uint256); /** * @notice Completely withdraw a position * @param positionId id of the position */ function withdraw(uint256 positionId) external; /** * @notice Get the asset address of the position. Example: For an ERC721 position, this * returns the address of that ERC721 contract. * @param positionId id of the position * @return asset address of the position */ function assetAddressOf(uint256 positionId) external view returns (address); /** * @notice Get the owner of a given position. * @param positionId id of the position * @return owner of the position */ function ownerOf(uint256 positionId) external view returns (address); /** * @notice Total number of positions in the ledger * @return number of positions in the ledger */ function totalSupply() external view returns (uint256); /** * @notice Get the number of capital positions held by an address * @param addr address * @return positions held by address */ function balanceOf(address addr) external view returns (uint256); /** * @notice Returns a position ID owned by `owner` at a given `index` of its position list * @param owner owner of the positions * @param index index of the owner's balance to get the position ID of * @return position id * * @dev use with {balanceOf} to enumerate all of `owner`'s positions */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a position ID at a given `index` of all the positions stored by the contract. * @param index index to get the position ID at * @return position id * * @dev use with {totalSupply} to enumerate all positions */ function tokenByIndex(uint256 index) external view returns (uint256); /** * @notice Get the USDC value of `owner`s positions, reporting what is currently * eligible and the total amount. * @param owner address owning the positions * @return eligibleAmount USDC value of positions eligible for rewards * @return totalAmount total USDC value of positions * * @dev this is used by Membership to determine how much is eligible in * the current epoch vs the next epoch. */ function totalsOf(address owner) external view returns (uint256 eligibleAmount, uint256 totalAmount); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; pragma experimental ABIEncoderV2; interface ICreditLine { function borrower() external view returns (address); function limit() external view returns (uint256); function maxLimit() external view returns (uint256); function interestApr() external view returns (uint256); function paymentPeriodInDays() external view returns (uint256); function principalGracePeriodInDays() external view returns (uint256); function termInDays() external view returns (uint256); function lateFeeApr() external view returns (uint256); function isLate() external view returns (bool); function withinPrincipalGracePeriod() external view returns (bool); // Accounting variables function balance() external view returns (uint256); function interestOwed() external view returns (uint256); function principalOwed() external view returns (uint256); function termEndTime() external view returns (uint256); function nextDueTime() external view returns (uint256); function interestAccruedAsOf() external view returns (uint256); function lastFullPaymentTime() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; interface IERC20Splitter { function lastDistributionAt() external view returns (uint256); function distribute() external; function replacePayees(address[] calldata _payees, uint256[] calldata _shares) external; function pendingDistributionFor(address payee) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; interface IGFILedger { struct Position { // Owner of the position address owner; // Index of the position in the ownership array uint256 ownedIndex; // Amount of GFI held in the position uint256 amount; // When the position was deposited uint256 depositTimestamp; } /** * @notice Emitted when a new GFI deposit has been made * @param owner address owning the deposit * @param positionId id for the deposit * @param amount how much GFI was deposited */ event GFIDeposit(address indexed owner, uint256 indexed positionId, uint256 amount); /** * @notice Emitted when a new GFI withdrawal has been made. If the remaining amount is 0, the position has bee removed * @param owner address owning the withdrawn position * @param positionId id for the position * @param remainingAmount how much GFI is remaining in the position * @param depositTimestamp block.timestamp of the original deposit */ event GFIWithdrawal( address indexed owner, uint256 indexed positionId, uint256 withdrawnAmount, uint256 remainingAmount, uint256 depositTimestamp ); /** * @notice Account for a new deposit by the owner. * @param owner address to account for the deposit * @param amount how much was deposited * @return how much was deposited */ function deposit(address owner, uint256 amount) external returns (uint256); /** * @notice Account for a new withdraw by the owner. * @param positionId id of the position * @return how much was withdrawn */ function withdraw(uint256 positionId) external returns (uint256); /** * @notice Account for a new withdraw by the owner. * @param positionId id of the position * @param amount how much to withdraw * @return how much was withdrawn */ function withdraw(uint256 positionId, uint256 amount) external returns (uint256); /** * @notice Get the number of GFI positions held by an address * @param addr address * @return positions held by address */ function balanceOf(address addr) external view returns (uint256); /** * @notice Get the owner of a given position. * @param positionId id of the position * @return owner of the position */ function ownerOf(uint256 positionId) external view returns (address); /** * @notice Total number of positions in the ledger * @return number of positions in the ledger */ function totalSupply() external view returns (uint256); /** * @notice Returns a position ID owned by `owner` at a given `index` of its position list * @param owner owner of the positions * @param index index of the owner's balance to get the position ID of * @return position id * * @dev use with {balanceOf} to enumerate all of `owner`'s positions */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); /** * @dev Returns a position ID at a given `index` of all the positions stored by the contract. * @param index index to get the position ID at * @return token id * * @dev use with {totalSupply} to enumerate all positions */ function tokenByIndex(uint256 index) external view returns (uint256); /** * @notice Get amount of GFI of `owner`s positions, reporting what is currently * eligible and the total amount. * @return eligibleAmount GFI amount of positions eligible for rewards * @return totalAmount total GFI amount of positions * * @dev this is used by Membership to determine how much is eligible in * the current epoch vs the next epoch. */ function totalsOf(address owner) external view returns (uint256 eligibleAmount, uint256 totalAmount); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; interface IMembershipCollector { /// @notice Have the collector distribute `amount` of Fidu to `addr` /// @param addr address to distribute to /// @param amount amount to distribute function distributeFiduTo(address addr, uint256 amount) external; /// @notice Get the last epoch finalized by the collector. This means the /// collector will no longer add rewards to the epoch. /// @return the last finalized epoch function lastFinalizedEpoch() external view returns (uint256); /// @notice Get the rewards associated with `epoch`. This amount may change /// until `epoch` has been finalized (is less than or equal to getLastFinalizedEpoch) /// @return rewards associated with `epoch` function rewardsForEpoch(uint256 epoch) external view returns (uint256); /// @notice Estimate rewards for a given epoch. For epochs at or before lastFinalizedEpoch /// this will be the fixed, accurate reward for the epoch. For the current and other /// non-finalized epochs, this will be the value as if the epoch were finalized in that /// moment. /// @param epoch epoch to estimate the rewards of /// @return rewards associated with `epoch` function estimateRewardsFor(uint256 epoch) external view returns (uint256); /// @notice Finalize all unfinalized epochs. Causes the reserve splitter to distribute /// if there are unfinalized epochs so all possible rewards are distributed. function finalizeEpochs() external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; interface IMembershipDirector { /** * @notice Adjust an `owner`s membership score and position due to the change * in their GFI and Capital holdings * @param owner address who's holdings changed * @return id of membership position */ function consumeHoldingsAdjustment(address owner) external returns (uint256); /** * @notice Collect all membership yield enhancements for the owner. * @param owner address to claim rewards for * @return amount of yield enhancements collected */ function collectRewards(address owner) external returns (uint256); /** * @notice Check how many rewards are claimable for the owner. The return * value here is how much would be retrieved by calling `collectRewards`. * @param owner address to calculate claimable rewards for * @return the amount of rewards that could be claimed by the owner */ function claimableRewards(address owner) external view returns (uint256); /** * @notice Calculate the membership score * @param gfi Amount of gfi * @param capital Amount of capital in USDC * @return membership score */ function calculateMembershipScore(uint256 gfi, uint256 capital) external view returns (uint256); /** * @notice Get the current score of `owner` * @param owner address to check the score of * @return eligibleScore score that is currently eligible for rewards * @return totalScore score that will be elgible for rewards next epoch */ function currentScore(address owner) external view returns (uint256 eligibleScore, uint256 totalScore); /** * @notice Get the sum of all member scores that are currently eligible and that will be eligible next epoch * @return eligibleTotal sum of all member scores that are currently eligible * @return nextEpochTotal sum of all member scores that will be eligible next epoch */ function totalMemberScores() external view returns (uint256 eligibleTotal, uint256 nextEpochTotal); /** * @notice Estimate the score for an existing member, given some changes in GFI and capital * @param memberAddress the member's address * @param gfi the change in gfi holdings, denominated in GFI * @param capital the change in gfi holdings, denominated in USDC * @return score resulting score for the member given the GFI and capital changes */ function estimateMemberScore( address memberAddress, int256 gfi, int256 capital ) external view returns (uint256 score); /// @notice Finalize all unfinalized epochs. Causes the reserve splitter to distribute /// if there are unfinalized epochs so all possible rewards are distributed. function finalizeEpochs() external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; interface IMembershipLedger { /** * @notice Set `addr`s allocated rewards back to 0 * @param addr address to reset rewards on */ function resetRewards(address addr) external; /** * @notice Allocate `amount` rewards for `addr` but do not send them * @param addr address to distribute rewards to * @param amount amount of rewards to allocate for `addr` * @return rewards total allocated to `addr` */ function allocateRewardsTo(address addr, uint256 amount) external returns (uint256 rewards); /** * @notice Get the rewards allocated to a certain `addr` * @param addr the address to check pending rewards for * @return rewards pending rewards for `addr` */ function getPendingRewardsFor(address addr) external view returns (uint256 rewards); /** * @notice Get the alpha parameter for the cobb douglas function. Will always be in (0,1). * @return numerator numerator for the alpha param * @return denominator denominator for the alpha param */ function alpha() external view returns (uint128 numerator, uint128 denominator); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; import {Context} from "../cake/Context.sol"; struct CapitalDeposit { /// Address of the asset being deposited /// @dev must be supported in CapitalAssets.sol address assetAddress; /// Id of the nft uint256 id; } struct Deposit { /// Amount of gfi to deposit uint256 gfi; /// List of capital deposits CapitalDeposit[] capitalDeposits; } struct DepositResult { uint256 membershipId; uint256 gfiPositionId; uint256[] capitalPositionIds; } struct ERC20Withdrawal { uint256 id; uint256 amount; } struct Withdrawal { /// List of gfi token ids to withdraw ERC20Withdrawal[] gfiPositions; /// List of capital token ids to withdraw uint256[] capitalPositions; } /** * @title MembershipOrchestrator * @notice Externally facing gateway to all Goldfinch membership functionality. * @author Goldfinch */ interface IMembershipOrchestrator { /** * @notice Deposit multiple assets defined in `multiDeposit`. Assets can include GFI, Staked Fidu, * and others. * @param deposit struct describing all the assets to deposit * @return ids all of the ids of the created depoits, in the same order as deposit. If GFI is * present, it will be the first id. */ function deposit(Deposit calldata deposit) external returns (DepositResult memory); /** * @notice Withdraw multiple assets defined in `multiWithdraw`. Assets can be GFI or capital * positions ids. Caller must have been permitted to act upon all of the positions. * @param withdrawal all of the GFI and Capital ids to withdraw */ function withdraw(Withdrawal calldata withdrawal) external; /** * @notice Collect all membership rewards for the caller. * @return how many rewards were collected and sent to caller */ function collectRewards() external returns (uint256); /** * @notice Check how many rewards are claimable at this moment in time for caller. * @param addr the address to check claimable rewards for * @return how many rewards could be claimed by a call to `collectRewards` */ function claimableRewards(address addr) external view returns (uint256); /** * @notice Check the voting power of a given address * @param addr the address to check the voting power of * @return the voting power */ function votingPower(address addr) external view returns (uint256); /** * @notice Get all GFI in Membership held by `addr`. This returns the current eligible amount and the * total amount of GFI. * @param addr the owner * @return eligibleAmount how much GFI is currently eligible for rewards * @return totalAmount how much GFI is currently eligible for rewards */ function totalGFIHeldBy(address addr) external view returns (uint256 eligibleAmount, uint256 totalAmount); /** * @notice Get all capital, denominated in USDC, in Membership held by `addr`. This returns the current * eligible amount and the total USDC value of capital. * @param addr the owner * @return eligibleAmount how much USDC of capital is currently eligible for rewards * @return totalAmount how much USDC of capital is currently eligible for rewards */ function totalCapitalHeldBy(address addr) external view returns (uint256 eligibleAmount, uint256 totalAmount); /** * @notice Get the member score of `addr` * @param addr the owner * @return eligibleScore the currently eligible score * @return totalScore the total score that will be eligible next epoch * * @dev if eligibleScore == totalScore then there are no changes between now and the next epoch */ function memberScoreOf(address addr) external view returns (uint256 eligibleScore, uint256 totalScore); /** * @notice Estimate rewards for a given epoch. For epochs at or before lastFinalizedEpoch * this will be the fixed, accurate reward for the epoch. For the current and other * non-finalized epochs, this will be the value as if the epoch were finalized in that * moment. * @param epoch epoch to estimate the rewards of * @return rewards associated with `epoch` */ function estimateRewardsFor(uint256 epoch) external view returns (uint256); /** * @notice Calculate what the Membership Score would be if a `gfi` amount of GFI and `capital` amount * of Capital denominated in USDC were deposited. * @param gfi amount of GFI to estimate with * @param capital amount of capital to estimate with, denominated in USDC * @return score the resulting score */ function calculateMemberScore(uint256 gfi, uint256 capital) external view returns (uint256 score); /** * @notice Get the sum of all member scores that are currently eligible and that will be eligible next epoch * @return eligibleTotal sum of all member scores that are currently eligible * @return nextEpochTotal sum of all member scores that will be eligible next epoch */ function totalMemberScores() external view returns (uint256 eligibleTotal, uint256 nextEpochTotal); /** * @notice Estimate the score for an existing member, given some changes in GFI and capital * @param memberAddress the member's address * @param gfi the change in gfi holdings, denominated in GFI * @param capital the change in gfi holdings, denominated in USDC * @return score resulting score for the member given the GFI and capital changes */ function estimateMemberScore( address memberAddress, int256 gfi, int256 capital ) external view returns (uint256 score); /// @notice Finalize all unfinalized epochs. Causes the reserve splitter to distribute /// if there are unfinalized epochs so all possible rewards are distributed. function finalizeEpochs() external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; import "@openzeppelin/contracts-upgradeable/interfaces/IERC721Upgradeable.sol"; struct Position { // address owning the position address owner; // how much of the position is eligible as of checkpointEpoch uint256 eligibleAmount; // how much of the postion is eligible the epoch after checkpointEpoch uint256 nextEpochAmount; // when the position was first created uint256 createdTimestamp; // epoch of the last checkpoint uint256 checkpointEpoch; } /** * @title IMembershipVault * @notice Track assets held by owners in a vault, as well as the total held in the vault. Assets * are not accounted for until the next epoch for MEV protection. * @author Goldfinch */ interface IMembershipVault is IERC721Upgradeable { /** * @notice Emitted when an owner has adjusted their holdings in a vault * @param owner the owner increasing their holdings * @param eligibleAmount the new eligible amount * @param nextEpochAmount the new next epoch amount */ event AdjustedHoldings(address indexed owner, uint256 eligibleAmount, uint256 nextEpochAmount); /** * @notice Emitted when the total within the vault has changed * @param eligibleAmount new current amount * @param nextEpochAmount new next epoch amount */ event VaultTotalUpdate(uint256 eligibleAmount, uint256 nextEpochAmount); /** * @notice Get the current value of `owner`. This changes depending on the current * block.timestamp as increased holdings are not accounted for until the subsequent epoch. * @param owner address owning the positions * @return sum of all positions held by an address */ function currentValueOwnedBy(address owner) external view returns (uint256); /** * @notice Get the total value in the vault as of block.timestamp * @return total value in the vault as of block.timestamp */ function currentTotal() external view returns (uint256); /** * @notice Get the total value in the vault as of epoch * @return total value in the vault as of epoch */ function totalAtEpoch(uint256 epoch) external view returns (uint256); /** * @notice Get the position owned by `owner` * @return position owned by `owner` */ function positionOwnedBy(address owner) external view returns (Position memory); /** * @notice Record an adjustment in holdings. Eligible assets will update this epoch and * total assets will become eligible the subsequent epoch. * @param owner the owner to checkpoint * @param eligibleAmount amount of points to apply to the current epoch * @param nextEpochAmount amount of points to apply to the next epoch * @return id of the position */ function adjustHoldings( address owner, uint256 eligibleAmount, uint256 nextEpochAmount ) external returns (uint256); /** * @notice Checkpoint a specific owner & the vault total * @param owner the owner to checkpoint * * @dev to collect rewards, this must be called before `increaseHoldings` or * `decreaseHoldings`. Those functions must call checkpoint internally * so the historical data will be lost otherwise. */ function checkpoint(address owner) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; pragma experimental ABIEncoderV2; import "./openzeppelin/IERC721.sol"; interface IPoolTokens is IERC721 { event TokenMinted( address indexed owner, address indexed pool, uint256 indexed tokenId, uint256 amount, uint256 tranche ); event TokenRedeemed( address indexed owner, address indexed pool, uint256 indexed tokenId, uint256 principalRedeemed, uint256 interestRedeemed, uint256 tranche ); event TokenBurned(address indexed owner, address indexed pool, uint256 indexed tokenId); struct TokenInfo { address pool; uint256 tranche; uint256 principalAmount; uint256 principalRedeemed; uint256 interestRedeemed; } struct MintParams { uint256 principalAmount; uint256 tranche; } function mint(MintParams calldata params, address to) external returns (uint256); function redeem( uint256 tokenId, uint256 principalRedeemed, uint256 interestRedeemed ) external; function withdrawPrincipal(uint256 tokenId, uint256 principalAmount) external; function burn(uint256 tokenId) external; function onPoolCreated(address newPool) external; function getTokenInfo(uint256 tokenId) external view returns (TokenInfo memory); function validPool(address sender) external view returns (bool); function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /// @title IRouter /// @author landakram /// @notice This contract provides service discovery for contracts using the cake framework. /// It can be used in conjunction with the convenience methods defined in the `Routing.Context` /// and `Routing.Keys` libraries. interface IRouter { event SetContract(bytes4 indexed key, address indexed addr); /// @notice Associate a routing key to a contract address /// @dev This function is only callable by the Router admin /// @param key A routing key (defined in the `Routing.Keys` libary) /// @param addr A contract address function setContract(bytes4 key, address addr) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; pragma experimental ABIEncoderV2; import "./ITranchedPool.sol"; abstract contract ISeniorPool { uint256 public sharePrice; uint256 public totalLoansOutstanding; uint256 public totalWritedowns; function deposit(uint256 amount) external virtual returns (uint256 depositShares); function depositWithPermit( uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external virtual returns (uint256 depositShares); function withdraw(uint256 usdcAmount) external virtual returns (uint256 amount); function withdrawInFidu(uint256 fiduAmount) external virtual returns (uint256 amount); function sweepToCompound() public virtual; function sweepFromCompound() public virtual; function invest(ITranchedPool pool) public virtual; function estimateInvestment(ITranchedPool pool) public view virtual returns (uint256); function redeem(uint256 tokenId) public virtual; function writedown(uint256 tokenId) public virtual; function calculateWritedown(uint256 tokenId) public view virtual returns (uint256 writedownAmount); function assets() public view virtual returns (uint256); function getNumShares(uint256 amount) public view virtual returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; pragma experimental ABIEncoderV2; import {IERC721} from "./openzeppelin/IERC721.sol"; import {IERC721Metadata} from "./openzeppelin/IERC721Metadata.sol"; import {IERC721Enumerable} from "./openzeppelin/IERC721Enumerable.sol"; interface IStakingRewards is IERC721, IERC721Metadata, IERC721Enumerable { function getPosition(uint256 tokenId) external view returns (StakedPosition memory position); function unstake(uint256 tokenId, uint256 amount) external; function addToStake(uint256 tokenId, uint256 amount) external; function stakedBalanceOf(uint256 tokenId) external view returns (uint256); function depositToCurveAndStakeFrom( address nftRecipient, uint256 fiduAmount, uint256 usdcAmount ) external; function kick(uint256 tokenId) external; function accumulatedRewardsPerToken() external view returns (uint256); function lastUpdateTime() external view returns (uint256); /* ========== EVENTS ========== */ event RewardAdded(uint256 reward); event Staked( address indexed user, uint256 indexed tokenId, uint256 amount, StakedPositionType positionType, uint256 baseTokenExchangeRate ); event DepositedAndStaked(address indexed user, uint256 depositedAmount, uint256 indexed tokenId, uint256 amount); event DepositedToCurve(address indexed user, uint256 fiduAmount, uint256 usdcAmount, uint256 tokensReceived); event DepositedToCurveAndStaked( address indexed user, uint256 fiduAmount, uint256 usdcAmount, uint256 indexed tokenId, uint256 amount ); event Unstaked(address indexed user, uint256 indexed tokenId, uint256 amount, StakedPositionType positionType); event UnstakedMultiple(address indexed user, uint256[] tokenIds, uint256[] amounts); event UnstakedAndWithdrew(address indexed user, uint256 usdcReceivedAmount, uint256 indexed tokenId, uint256 amount); event UnstakedAndWithdrewMultiple( address indexed user, uint256 usdcReceivedAmount, uint256[] tokenIds, uint256[] amounts ); event RewardPaid(address indexed user, uint256 indexed tokenId, uint256 reward); event RewardsParametersUpdated( address indexed who, uint256 targetCapacity, uint256 minRate, uint256 maxRate, uint256 minRateAtPercent, uint256 maxRateAtPercent ); event EffectiveMultiplierUpdated(address indexed who, StakedPositionType positionType, uint256 multiplier); } /// @notice Indicates which ERC20 is staked enum StakedPositionType { Fidu, CurveLP } struct Rewards { uint256 totalUnvested; uint256 totalVested; // @dev DEPRECATED (definition kept for storage slot) // For legacy vesting positions, this was used in the case of slashing. // For non-vesting positions, this is unused. uint256 totalPreviouslyVested; uint256 totalClaimed; uint256 startTime; // @dev DEPRECATED (definition kept for storage slot) // For legacy vesting positions, this is the endTime of the vesting. // For non-vesting positions, this is 0. uint256 endTime; } struct StakedPosition { // @notice Staked amount denominated in `stakingToken().decimals()` uint256 amount; // @notice Struct describing rewards owed with vesting Rewards rewards; // @notice Multiplier applied to staked amount when locking up position uint256 leverageMultiplier; // @notice Time in seconds after which position can be unstaked uint256 lockedUntil; // @notice Type of the staked position StakedPositionType positionType; // @notice Multiplier applied to staked amount to denominate in `baseStakingToken().decimals()` // @dev This field should not be used directly; it may be 0 for staked positions created prior to GIP-1. // If you need this field, use `safeEffectiveMultiplier()`, which correctly handles old staked positions. uint256 unsafeEffectiveMultiplier; // @notice Exchange rate applied to staked amount to denominate in `baseStakingToken().decimals()` // @dev This field should not be used directly; it may be 0 for staked positions created prior to GIP-1. // If you need this field, use `safeBaseTokenExchangeRate()`, which correctly handles old staked positions. uint256 unsafeBaseTokenExchangeRate; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; pragma experimental ABIEncoderV2; import {IV2CreditLine} from "./IV2CreditLine.sol"; abstract contract ITranchedPool { IV2CreditLine public creditLine; uint256 public createdAt; enum Tranches { Reserved, Senior, Junior } struct TrancheInfo { uint256 id; uint256 principalDeposited; uint256 principalSharePrice; uint256 interestSharePrice; uint256 lockedUntil; } struct PoolSlice { TrancheInfo seniorTranche; TrancheInfo juniorTranche; uint256 totalInterestAccrued; uint256 principalDeployed; } function initialize( address _config, address _borrower, uint256 _juniorFeePercent, uint256 _limit, uint256 _interestApr, uint256 _paymentPeriodInDays, uint256 _termInDays, uint256 _lateFeeApr, uint256 _principalGracePeriodInDays, uint256 _fundableAt, uint256[] calldata _allowedUIDTypes ) public virtual; function getTranche(uint256 tranche) external view virtual returns (TrancheInfo memory); function pay(uint256 amount) external virtual; function poolSlices(uint256 index) external view virtual returns (PoolSlice memory); function lockJuniorCapital() external virtual; function lockPool() external virtual; function initializeNextSlice(uint256 _fundableAt) external virtual; function totalJuniorDeposits() external view virtual returns (uint256); function drawdown(uint256 amount) external virtual; function setFundableAt(uint256 timestamp) external virtual; function deposit(uint256 tranche, uint256 amount) external virtual returns (uint256 tokenId); function assess() external virtual; function depositWithPermit( uint256 tranche, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external virtual returns (uint256 tokenId); function availableToWithdraw(uint256 tokenId) external view virtual returns (uint256 interestRedeemable, uint256 principalRedeemable); function withdraw(uint256 tokenId, uint256 amount) external virtual returns (uint256 interestWithdrawn, uint256 principalWithdrawn); function withdrawMax(uint256 tokenId) external virtual returns (uint256 interestWithdrawn, uint256 principalWithdrawn); function withdrawMultiple(uint256[] calldata tokenIds, uint256[] calldata amounts) external virtual; function numSlices() external view virtual returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12; pragma experimental ABIEncoderV2; import "./ICreditLine.sol"; abstract contract IV2CreditLine is ICreditLine { function principal() external view virtual returns (uint256); function totalInterestAccrued() external view virtual returns (uint256); function termStartTime() external view virtual returns (uint256); function setLimit(uint256 newAmount) external virtual; function setMaxLimit(uint256 newAmount) external virtual; function setBalance(uint256 newBalance) external virtual; function setPrincipal(uint256 _principal) external virtual; function setTotalInterestAccrued(uint256 _interestAccrued) external virtual; function drawdown(uint256 amount) external virtual; function assess() external virtual returns ( uint256, uint256, uint256 ); function initialize( address _config, address owner, address _borrower, uint256 _limit, uint256 _interestApr, uint256 _paymentPeriodInDays, uint256 _termInDays, uint256 _lateFeeApr, uint256 _principalGracePeriodInDays ) public virtual; function setTermEndTime(uint256 newTermEndTime) external virtual; function setNextDueTime(uint256 newNextDueTime) external virtual; function setInterestOwed(uint256 newInterestOwed) external virtual; function setPrincipalOwed(uint256 newPrincipalOwed) external virtual; function setInterestAccruedAsOf(uint256 newInterestAccruedAsOf) external virtual; function setWritedownAmount(uint256 newWritedownAmount) external virtual; function setLastFullPaymentTime(uint256 newLastFullPaymentTime) external virtual; function setLateFeeApr(uint256 newLateFeeApr) external virtual; }
pragma solidity >=0.6.0; // This file copied from OZ, but with the version pragma updated to use >=. /** * @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); }
pragma solidity >=0.6.2; // This file copied from OZ, but with the version pragma updated to use >= & reference other >= pragma interfaces. // NOTE: Modified to reference our updated pragma version of IERC165 import "./IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of NFTs in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either {approve} or {setApprovalForAll}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either {approve} or {setApprovalForAll}. */ function transferFrom( address from, address to, uint256 tokenId ) external; function approve(address to, uint256 tokenId) external; function getApproved(uint256 tokenId) external view returns (address operator); function setApprovalForAll(address operator, bool _approved) external; function isApprovedForAll(address owner, address operator) external view returns (bool); function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
pragma solidity >=0.6.2; // This file copied from OZ, but with the version pragma updated to use >=. import "./IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { function totalSupply() external view returns (uint256); function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); function tokenByIndex(uint256 index) external view returns (uint256); }
pragma solidity >=0.6.2; // This file copied from OZ, but with the version pragma updated to use >=. import "./IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "@openzeppelin/contracts-upgradeable/interfaces/IERC721Upgradeable.sol"; /** * @title A read only ERC721 token * @notice A abstract registry of NFTs that only allows reading the NFTs and nothing * else (no minting, transferring, etc). This acts as a "view" into some set * of NFTs that may not otherwise adhere to the ERC721 standard. * @dev See `Transfer Mechanism` in the following link for the inspiration * behind this class: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md#rationale */ abstract contract ERC721NonTransferable is IERC721Upgradeable { // Throw if a mutating function is called error ReadOnly(); function safeTransferFrom( address, address, uint256 ) external pure { revert ReadOnly(); } function transferFrom( address, address, uint256 ) external pure { revert ReadOnly(); } function approve(address, uint256) external pure { revert ReadOnly(); } function getApproved(uint256) external pure returns (address) { revert ReadOnly(); } function setApprovalForAll(address, bool) external pure { revert ReadOnly(); } function isApprovedForAll(address, address) external pure returns (bool) { revert ReadOnly(); } function safeTransferFrom( address, address, uint256, bytes calldata ) external pure { revert ReadOnly(); } }
pragma solidity ^0.8.16; library ERCInterfaces { bytes4 internal constant ERC721 = 0x80ac58cd; bytes4 internal constant ERC721_ENUMERABLE = 0x780e9d63; bytes4 internal constant ERC165 = 0x01ffc9a7; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; library Epochs { uint256 internal constant EPOCH_SECONDS = 7 days; /** * @notice Get the epoch containing the timestamp `s` * @param s the timestamp * @return corresponding epoch */ function fromSeconds(uint256 s) internal pure returns (uint256) { return s / EPOCH_SECONDS; } /** * @notice Get the current epoch for the block.timestamp * @return current epoch */ function current() internal view returns (uint256) { return fromSeconds(block.timestamp); } /** * @notice Get the start timestamp for the current epoch * @return current epoch start timestamp */ function currentEpochStartTimestamp() internal view returns (uint256) { return startOf(current()); } /** * @notice Get the previous epoch given block.timestamp * @return previous epoch */ function previous() internal view returns (uint256) { return current() - 1; } /** * @notice Get the next epoch given block.timestamp * @return next epoch */ function next() internal view returns (uint256) { return current() + 1; } /** * @notice Get the Unix timestamp of the start of `epoch` * @param epoch the epoch * @return unix timestamp */ function startOf(uint256 epoch) internal pure returns (uint256) { return epoch * EPOCH_SECONDS; } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 100 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract Context","name":"_context","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"IndexGreaterThanTokenSupply","type":"error"},{"inputs":[{"internalType":"uint256","name":"eligibleAmount","type":"uint256"},{"internalType":"uint256","name":"nextEpochAmount","type":"uint256"}],"name":"InvalidHoldingsAdjustment","type":"error"},{"inputs":[],"name":"NoTokensOwned","type":"error"},{"inputs":[],"name":"NoTotalsInFutureEpochs","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"NonexistantToken","type":"error"},{"inputs":[],"name":"OneTokenPerAddress","type":"error"},{"inputs":[],"name":"ReadOnly","type":"error"},{"inputs":[{"internalType":"address","name":"resource","type":"address"},{"internalType":"address","name":"accessor","type":"address"}],"name":"RequiresOperator","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAddressInvalid","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"eligibleAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nextEpochAmount","type":"uint256"}],"name":"AdjustedHoldings","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"}],"name":"Checkpoint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"eligibleAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nextEpochAmount","type":"uint256"}],"name":"VaultTotalUpdate","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"eligibleAmount","type":"uint256"},{"internalType":"uint256","name":"nextEpochAmount","type":"uint256"}],"name":"adjustHoldings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"currentValueOwnedBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"membershipId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"positionOwnedBy","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"eligibleAmount","type":"uint256"},{"internalType":"uint256","name":"nextEpochAmount","type":"uint256"},{"internalType":"uint256","name":"createdTimestamp","type":"uint256"},{"internalType":"uint256","name":"checkpointEpoch","type":"uint256"}],"internalType":"struct Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bool","name":"","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"id","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"totalAtEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"pure","type":"function"}]
Contract Creation Code
60a060405234801561001057600080fd5b5060405161182038038061182083398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161178e6100926000396000818161057101526110c2015261178e6000f3fe608060405234801561001057600080fd5b50600436106101635760003560e01c80636352211e116100ce578063a22cb46511610087578063a22cb46514610300578063a350ed481461030e578063a5f2f66714610321578063a972985e1461037a578063b88d4fde1461038d578063c87b56dd1461039b578063e985e9c5146103ae57600080fd5b80636352211e1461027d5780636c0360eb146102a657806370a08231146102ae5780638129fc1c146102c15780639017a13c146102c957806395d89b41146102dc57600080fd5b80632f745c59116101205780632f745c59146102295780633da8bfc91461023c5780633de2d9721461024457806342842e0e1461021b5780634f6ccce71461025757806355f804b31461026a57600080fd5b806301ffc9a71461016857806306fdde0314610190578063081812fc146101c9578063095ea7b3146101f457806318160ddd1461020957806323b872dd1461021b575b600080fd5b61017b6101763660046111bf565b6103bc565b60405190151581526020015b60405180910390f35b6040805180820190915260148152730476f6c6466696e6368204d656d626572736869760641b60208201525b604051610187919061120d565b6101dc6101d7366004611240565b61040e565b6040516001600160a01b039091168152602001610187565b61020761020236600461126e565b610429565b005b6005545b604051908152602001610187565b61020761020236600461129a565b61020d61023736600461126e565b610442565b61020d6104a1565b61020d6102523660046112db565b6104b3565b61020d610265366004611240565b610537565b610207610278366004611341565b61056c565b6101dc61028b366004611240565b6000908152600360205260409020546001600160a01b031690565b6101bc610612565b61020d6102bc3660046112db565b6106a0565b6102076106d0565b61020d6102d7366004611240565b610793565b60408051808201909152600881526723a326a2a6a122a960c11b60208201526101bc565b610207610202366004611383565b61020d61031c3660046113c1565b610803565b61033461032f3660046112db565b610a43565b604051610187919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080918201519181019190915260a00190565b6102076103883660046112db565b610ade565b6102076102023660046113f6565b6101bc6103a9366004611240565b610b16565b61017b6101d7366004611469565b60006001600160e01b031982166380ac58cd60e01b14806103ed57506001600160e01b0319821663780e9d6360e01b145b8061040857506001600160e01b031982166301ffc9a760e01b145b92915050565b6000604051631a850ed760e31b815260040160405180910390fd5b604051631a850ed760e31b815260040160405180910390fd5b6001600160a01b03821660009081526004602052604081205480820361047b576040516334b5d06d60e21b815260040160405180910390fd5b821561049a57604051632316143b60e11b815260040160405180910390fd5b9392505050565b60006104ae6102d7610b94565b905090565b6001600160a01b0380821660009081526004602081815260408084205484526003808352818520825160a08101845281549097168752600181015493870193909352600283015491860191909152810154606085015201546080830181905290919061051d610b94565b111561052d576040015192915050565b6020015192915050565b600061054260055490565b821061056157604051633f7ee38f60e11b815260040160405180910390fd5b6104088260016114ad565b61059e7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610b9f565b604051632a6e138b60e11b81523060048201523360248201526001600160a01b0391909116906354dc27169060440160006040518083038186803b1580156105e557600080fd5b505afa1580156105f9573d6000803e3d6000fd5b506006925061060d9150839050848361155e565b505050565b6006805461061f906114d6565b80601f016020809104026020016040519081016040528092919081815260200182805461064b906114d6565b80156106985780601f1061066d57610100808354040283529160200191610698565b820191906000526020600020905b81548152906001019060200180831161067b57829003601f168201915b505050505081565b6001600160a01b0381166000908152600460205260408120546106c45760006106c7565b60015b60ff1692915050565b600054610100900460ff16806106e9575060005460ff16155b6107515760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b600054610100900460ff16158015610773576000805461ffff19166101011790555b61077b610b94565b6002558015610790576000805461ff00191690555b50565b600061079d610c8f565b8211156107bd57604051630bb92ffd60e21b815260040160405180910390fd5b6002548211156107f0576001600060025460016107da91906114ad565b8152602001908152602001600020549050919050565b5060009081526001602052604090205490565b60007f037db0999be9065c5f1306135b75a6ae2af104ed9f0d72669950e21e87a33f766108308133610ca4565b8383101561085b576040516368caeba760e01b81526004810185905260248101849052604401610748565b600061086686610d03565b905061087186610e02565b6000818152600360208181526040808420815160a08101835281546001600160a01b031681526001808301805483870190815260028501805496850196909652848801546060850152600490940154608084015288885295909452938a905590889055519192889291906108e3610b94565b8152602001908152602001600020546108fc919061161f565b61090691906114ad565b60016000610912610b94565b81526020019081526020016000208190555084816040015160016000610936610c8f565b81526020019081526020016000205461094f919061161f565b61095991906114ad565b60016000610965610c8f565b815260200190815260200160002081905550866001600160a01b03167fb5ac373069545fdd5da402c94d10b968168eb2c09893e9a1a1fd087b2b3b34b187876040516109bb929190918252602082015260400190565b60405180910390a27f32ea6f1ec4de7460c440fd872b28a1f5e867728132b4dcba7af1f3dfef775ba2600160006109f0610b94565b81526020019081526020016000205460016000610a0b610c8f565b815260200190815260200160002054604051610a31929190918252602082015260400190565b60405180910390a15095945050505050565b610a7e6040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b506001600160a01b039081166000908152600460208181526040808420548452600380835293819020815160a081018352815490961686526001810154928601929092526002820154908501529182015460608401520154608082015290565b7f037db0999be9065c5f1306135b75a6ae2af104ed9f0d72669950e21e87a33f76610b098133610ca4565b610b1282610e02565b5050565b606081600003610b3c57604051637705f84560e01b815260048101839052602401610748565b600554821115610b6257604051637705f84560e01b815260048101839052602401610748565b6006610b6d83610f9c565b604051602001610b7e929190611632565b6040516020818303038152906040529050919050565b60006104ae426110a5565b6000816001600160a01b031663f887ea406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0391906116b9565b6001600160a01b0316630c0450127f9a671f6643eb8ac838fd3c79576dd800fe704b35ad30189c60f0f14dab948f2a6040518263ffffffff1660e01b8152600401610c4e91906116d6565b602060405180830381865afa158015610c6b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040891906116b9565b6000610c99610b94565b6104ae9060016114ad565b6001600160a01b038116610ccb5760405163d92e233d60e01b815260040160405180910390fd5b610cd582826110b4565b610b125760405163889a56bb60e01b81523060048201526001600160a01b0382166024820152604401610748565b60006001600160a01b038216610d2c57604051630a64406560e11b815260040160405180910390fd5b6001600160a01b0382166000908152600460205260409020548015610d515792915050565b60058054906000610d61836116eb565b9091555050600554600081815260036020819052604090912080546001600160a01b0319166001600160a01b038716178155429101559050610da1610b94565b60008281526003602090815260408083206004908101949094556001600160a01b0387168084529390915280822084905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a492915050565b6000610e0c610b94565b9050600254811115610e94576000600160006002546001610e2d91906114ad565b815260200190815260200160002054905060006002546002610e4f91906114ad565b90505b610e5d8360016114ad565b8111610e8657600081815260016020526040902082905580610e7e816116eb565b915050610e52565b50610e8f610b94565b600255505b6001600160a01b0382166000908152600460205260409020548015610f4457600081815260036020818152604092839020835160a08101855281546001600160a01b0316815260018201549281019290925260028101549382019390935290820154606082015260049091015460808201819052831115610f4257604080820151600084815260036020529190912060010155610f2f610b94565b6000838152600360205260409020600401555b505b7fde5ae8a37da230f7df39b8ea385fa1ab48e7caa55f1c25eaaef1ed8690f3699860016000610f71610b94565b815260200190815260200160002054604051610f8f91815260200190565b60405180910390a1505050565b606081600003610fc35750506040805180820190915260018152600360fc1b602082015290565b8160005b8115610fed5780610fd7816116eb565b9150610fe69050600a8361171a565b9150610fc7565b60008167ffffffffffffffff811115611008576110086114c0565b6040519080825280601f01601f191660200182016040528015611032576020820181803683370190505b5090505b841561109d5761104760018361161f565b9150611054600a8661172e565b61105f9060306114ad565b60f81b81838151811061107457611074611742565b60200101906001600160f81b031916908160001a905350611096600a8661171a565b9450611036565b949350505050565b600061040862093a808361171a565b6000816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f887ea406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561111e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114291906116b9565b6001600160a01b0316630c045012856040518263ffffffff1660e01b815260040161116d91906116d6565b602060405180830381865afa15801561118a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ae91906116b9565b6001600160a01b0316149392505050565b6000602082840312156111d157600080fd5b81356001600160e01b03198116811461049a57600080fd5b60005b838110156112045781810151838201526020016111ec565b50506000910152565b602081526000825180602084015261122c8160408501602087016111e9565b601f01601f19169190910160400192915050565b60006020828403121561125257600080fd5b5035919050565b6001600160a01b038116811461079057600080fd5b6000806040838503121561128157600080fd5b823561128c81611259565b946020939093013593505050565b6000806000606084860312156112af57600080fd5b83356112ba81611259565b925060208401356112ca81611259565b929592945050506040919091013590565b6000602082840312156112ed57600080fd5b813561049a81611259565b60008083601f84011261130a57600080fd5b50813567ffffffffffffffff81111561132257600080fd5b60208301915083602082850101111561133a57600080fd5b9250929050565b6000806020838503121561135457600080fd5b823567ffffffffffffffff81111561136b57600080fd5b611377858286016112f8565b90969095509350505050565b6000806040838503121561139657600080fd5b82356113a181611259565b9150602083013580151581146113b657600080fd5b809150509250929050565b6000806000606084860312156113d657600080fd5b83356113e181611259565b95602085013595506040909401359392505050565b60008060008060006080868803121561140e57600080fd5b853561141981611259565b9450602086013561142981611259565b935060408601359250606086013567ffffffffffffffff81111561144c57600080fd5b611458888289016112f8565b969995985093965092949392505050565b6000806040838503121561147c57600080fd5b823561148781611259565b915060208301356113b681611259565b634e487b7160e01b600052601160045260246000fd5b8082018082111561040857610408611497565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806114ea57607f821691505b60208210810361150a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561060d57600081815260208120601f850160051c810160208610156115375750805b601f850160051c820191505b8181101561155657828155600101611543565b505050505050565b67ffffffffffffffff831115611576576115766114c0565b61158a8361158483546114d6565b83611510565b6000601f8411600181146115be57600085156115a65750838201355b600019600387901b1c1916600186901b178355611618565b600083815260209020601f19861690835b828110156115ef57868501358255602094850194600190920191016115cf565b508682101561160c5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8181038181111561040857610408611497565b6000808454611640816114d6565b60018281168015611658576001811461166d5761169c565b60ff198416875282151583028701945061169c565b8860005260208060002060005b858110156116935781548a82015290840190820161167a565b50505082870194505b5050505083516116b08183602088016111e9565b01949350505050565b6000602082840312156116cb57600080fd5b815161049a81611259565b6001600160e01b031991909116815260200190565b6000600182016116fd576116fd611497565b5060010190565b634e487b7160e01b600052601260045260246000fd5b60008261172957611729611704565b500490565b60008261173d5761173d611704565b500690565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220ef774c7db2d4ff1868e41276f302b861e7826ce08df1640db58558ea4ca4741464736f6c63430008100033000000000000000000000000d16bc944bf20c86c4ed47ce1a330a18538674c83
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101635760003560e01c80636352211e116100ce578063a22cb46511610087578063a22cb46514610300578063a350ed481461030e578063a5f2f66714610321578063a972985e1461037a578063b88d4fde1461038d578063c87b56dd1461039b578063e985e9c5146103ae57600080fd5b80636352211e1461027d5780636c0360eb146102a657806370a08231146102ae5780638129fc1c146102c15780639017a13c146102c957806395d89b41146102dc57600080fd5b80632f745c59116101205780632f745c59146102295780633da8bfc91461023c5780633de2d9721461024457806342842e0e1461021b5780634f6ccce71461025757806355f804b31461026a57600080fd5b806301ffc9a71461016857806306fdde0314610190578063081812fc146101c9578063095ea7b3146101f457806318160ddd1461020957806323b872dd1461021b575b600080fd5b61017b6101763660046111bf565b6103bc565b60405190151581526020015b60405180910390f35b6040805180820190915260148152730476f6c6466696e6368204d656d626572736869760641b60208201525b604051610187919061120d565b6101dc6101d7366004611240565b61040e565b6040516001600160a01b039091168152602001610187565b61020761020236600461126e565b610429565b005b6005545b604051908152602001610187565b61020761020236600461129a565b61020d61023736600461126e565b610442565b61020d6104a1565b61020d6102523660046112db565b6104b3565b61020d610265366004611240565b610537565b610207610278366004611341565b61056c565b6101dc61028b366004611240565b6000908152600360205260409020546001600160a01b031690565b6101bc610612565b61020d6102bc3660046112db565b6106a0565b6102076106d0565b61020d6102d7366004611240565b610793565b60408051808201909152600881526723a326a2a6a122a960c11b60208201526101bc565b610207610202366004611383565b61020d61031c3660046113c1565b610803565b61033461032f3660046112db565b610a43565b604051610187919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080918201519181019190915260a00190565b6102076103883660046112db565b610ade565b6102076102023660046113f6565b6101bc6103a9366004611240565b610b16565b61017b6101d7366004611469565b60006001600160e01b031982166380ac58cd60e01b14806103ed57506001600160e01b0319821663780e9d6360e01b145b8061040857506001600160e01b031982166301ffc9a760e01b145b92915050565b6000604051631a850ed760e31b815260040160405180910390fd5b604051631a850ed760e31b815260040160405180910390fd5b6001600160a01b03821660009081526004602052604081205480820361047b576040516334b5d06d60e21b815260040160405180910390fd5b821561049a57604051632316143b60e11b815260040160405180910390fd5b9392505050565b60006104ae6102d7610b94565b905090565b6001600160a01b0380821660009081526004602081815260408084205484526003808352818520825160a08101845281549097168752600181015493870193909352600283015491860191909152810154606085015201546080830181905290919061051d610b94565b111561052d576040015192915050565b6020015192915050565b600061054260055490565b821061056157604051633f7ee38f60e11b815260040160405180910390fd5b6104088260016114ad565b61059e7f000000000000000000000000d16bc944bf20c86c4ed47ce1a330a18538674c836001600160a01b0316610b9f565b604051632a6e138b60e11b81523060048201523360248201526001600160a01b0391909116906354dc27169060440160006040518083038186803b1580156105e557600080fd5b505afa1580156105f9573d6000803e3d6000fd5b506006925061060d9150839050848361155e565b505050565b6006805461061f906114d6565b80601f016020809104026020016040519081016040528092919081815260200182805461064b906114d6565b80156106985780601f1061066d57610100808354040283529160200191610698565b820191906000526020600020905b81548152906001019060200180831161067b57829003601f168201915b505050505081565b6001600160a01b0381166000908152600460205260408120546106c45760006106c7565b60015b60ff1692915050565b600054610100900460ff16806106e9575060005460ff16155b6107515760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b600054610100900460ff16158015610773576000805461ffff19166101011790555b61077b610b94565b6002558015610790576000805461ff00191690555b50565b600061079d610c8f565b8211156107bd57604051630bb92ffd60e21b815260040160405180910390fd5b6002548211156107f0576001600060025460016107da91906114ad565b8152602001908152602001600020549050919050565b5060009081526001602052604090205490565b60007f037db0999be9065c5f1306135b75a6ae2af104ed9f0d72669950e21e87a33f766108308133610ca4565b8383101561085b576040516368caeba760e01b81526004810185905260248101849052604401610748565b600061086686610d03565b905061087186610e02565b6000818152600360208181526040808420815160a08101835281546001600160a01b031681526001808301805483870190815260028501805496850196909652848801546060850152600490940154608084015288885295909452938a905590889055519192889291906108e3610b94565b8152602001908152602001600020546108fc919061161f565b61090691906114ad565b60016000610912610b94565b81526020019081526020016000208190555084816040015160016000610936610c8f565b81526020019081526020016000205461094f919061161f565b61095991906114ad565b60016000610965610c8f565b815260200190815260200160002081905550866001600160a01b03167fb5ac373069545fdd5da402c94d10b968168eb2c09893e9a1a1fd087b2b3b34b187876040516109bb929190918252602082015260400190565b60405180910390a27f32ea6f1ec4de7460c440fd872b28a1f5e867728132b4dcba7af1f3dfef775ba2600160006109f0610b94565b81526020019081526020016000205460016000610a0b610c8f565b815260200190815260200160002054604051610a31929190918252602082015260400190565b60405180910390a15095945050505050565b610a7e6040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b506001600160a01b039081166000908152600460208181526040808420548452600380835293819020815160a081018352815490961686526001810154928601929092526002820154908501529182015460608401520154608082015290565b7f037db0999be9065c5f1306135b75a6ae2af104ed9f0d72669950e21e87a33f76610b098133610ca4565b610b1282610e02565b5050565b606081600003610b3c57604051637705f84560e01b815260048101839052602401610748565b600554821115610b6257604051637705f84560e01b815260048101839052602401610748565b6006610b6d83610f9c565b604051602001610b7e929190611632565b6040516020818303038152906040529050919050565b60006104ae426110a5565b6000816001600160a01b031663f887ea406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0391906116b9565b6001600160a01b0316630c0450127f9a671f6643eb8ac838fd3c79576dd800fe704b35ad30189c60f0f14dab948f2a6040518263ffffffff1660e01b8152600401610c4e91906116d6565b602060405180830381865afa158015610c6b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040891906116b9565b6000610c99610b94565b6104ae9060016114ad565b6001600160a01b038116610ccb5760405163d92e233d60e01b815260040160405180910390fd5b610cd582826110b4565b610b125760405163889a56bb60e01b81523060048201526001600160a01b0382166024820152604401610748565b60006001600160a01b038216610d2c57604051630a64406560e11b815260040160405180910390fd5b6001600160a01b0382166000908152600460205260409020548015610d515792915050565b60058054906000610d61836116eb565b9091555050600554600081815260036020819052604090912080546001600160a01b0319166001600160a01b038716178155429101559050610da1610b94565b60008281526003602090815260408083206004908101949094556001600160a01b0387168084529390915280822084905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a492915050565b6000610e0c610b94565b9050600254811115610e94576000600160006002546001610e2d91906114ad565b815260200190815260200160002054905060006002546002610e4f91906114ad565b90505b610e5d8360016114ad565b8111610e8657600081815260016020526040902082905580610e7e816116eb565b915050610e52565b50610e8f610b94565b600255505b6001600160a01b0382166000908152600460205260409020548015610f4457600081815260036020818152604092839020835160a08101855281546001600160a01b0316815260018201549281019290925260028101549382019390935290820154606082015260049091015460808201819052831115610f4257604080820151600084815260036020529190912060010155610f2f610b94565b6000838152600360205260409020600401555b505b7fde5ae8a37da230f7df39b8ea385fa1ab48e7caa55f1c25eaaef1ed8690f3699860016000610f71610b94565b815260200190815260200160002054604051610f8f91815260200190565b60405180910390a1505050565b606081600003610fc35750506040805180820190915260018152600360fc1b602082015290565b8160005b8115610fed5780610fd7816116eb565b9150610fe69050600a8361171a565b9150610fc7565b60008167ffffffffffffffff811115611008576110086114c0565b6040519080825280601f01601f191660200182016040528015611032576020820181803683370190505b5090505b841561109d5761104760018361161f565b9150611054600a8661172e565b61105f9060306114ad565b60f81b81838151811061107457611074611742565b60200101906001600160f81b031916908160001a905350611096600a8661171a565b9450611036565b949350505050565b600061040862093a808361171a565b6000816001600160a01b03167f000000000000000000000000d16bc944bf20c86c4ed47ce1a330a18538674c836001600160a01b031663f887ea406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561111e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114291906116b9565b6001600160a01b0316630c045012856040518263ffffffff1660e01b815260040161116d91906116d6565b602060405180830381865afa15801561118a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ae91906116b9565b6001600160a01b0316149392505050565b6000602082840312156111d157600080fd5b81356001600160e01b03198116811461049a57600080fd5b60005b838110156112045781810151838201526020016111ec565b50506000910152565b602081526000825180602084015261122c8160408501602087016111e9565b601f01601f19169190910160400192915050565b60006020828403121561125257600080fd5b5035919050565b6001600160a01b038116811461079057600080fd5b6000806040838503121561128157600080fd5b823561128c81611259565b946020939093013593505050565b6000806000606084860312156112af57600080fd5b83356112ba81611259565b925060208401356112ca81611259565b929592945050506040919091013590565b6000602082840312156112ed57600080fd5b813561049a81611259565b60008083601f84011261130a57600080fd5b50813567ffffffffffffffff81111561132257600080fd5b60208301915083602082850101111561133a57600080fd5b9250929050565b6000806020838503121561135457600080fd5b823567ffffffffffffffff81111561136b57600080fd5b611377858286016112f8565b90969095509350505050565b6000806040838503121561139657600080fd5b82356113a181611259565b9150602083013580151581146113b657600080fd5b809150509250929050565b6000806000606084860312156113d657600080fd5b83356113e181611259565b95602085013595506040909401359392505050565b60008060008060006080868803121561140e57600080fd5b853561141981611259565b9450602086013561142981611259565b935060408601359250606086013567ffffffffffffffff81111561144c57600080fd5b611458888289016112f8565b969995985093965092949392505050565b6000806040838503121561147c57600080fd5b823561148781611259565b915060208301356113b681611259565b634e487b7160e01b600052601160045260246000fd5b8082018082111561040857610408611497565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806114ea57607f821691505b60208210810361150a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561060d57600081815260208120601f850160051c810160208610156115375750805b601f850160051c820191505b8181101561155657828155600101611543565b505050505050565b67ffffffffffffffff831115611576576115766114c0565b61158a8361158483546114d6565b83611510565b6000601f8411600181146115be57600085156115a65750838201355b600019600387901b1c1916600186901b178355611618565b600083815260209020601f19861690835b828110156115ef57868501358255602094850194600190920191016115cf565b508682101561160c5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8181038181111561040857610408611497565b6000808454611640816114d6565b60018281168015611658576001811461166d5761169c565b60ff198416875282151583028701945061169c565b8860005260208060002060005b858110156116935781548a82015290840190820161167a565b50505082870194505b5050505083516116b08183602088016111e9565b01949350505050565b6000602082840312156116cb57600080fd5b815161049a81611259565b6001600160e01b031991909116815260200190565b6000600182016116fd576116fd611497565b5060010190565b634e487b7160e01b600052601260045260246000fd5b60008261172957611729611704565b500490565b60008261173d5761173d611704565b500690565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220ef774c7db2d4ff1868e41276f302b861e7826ce08df1640db58558ea4ca4741464736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d16bc944bf20c86c4ed47ce1a330a18538674c83
-----Decoded View---------------
Arg [0] : _context (address): 0xd16BC944Bf20c86c4ED47Ce1a330a18538674C83
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d16bc944bf20c86c4ed47ce1a330a18538674c83
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.