Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x6F2aF87135FEfbd60bc3b4478f0770640c125B6D
Balance 0 ETH
Nonce 1
Code Size 7861 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

7861 bytes
0x608060408181526004918236101561001657600080fd5b600092833560e01c9182630dd3930d1461125757508163361652c91461118a57816337d2aae91461105c57816355b43fe114610de657816360e72adb14610bd257816368c3362714610b7c578163710dc95714610b5d5781637785c0b614610b015781638694af78146109f55781638a3a8b291461093f5781639e5d82b914610904578163bb6c191a14610846578163bb87d2aa14610485578163c0f1d8c6146103a1578163d5002f2e1461037f578163dcb6f63814610308578163f8c7038714610231578163fafc08c414610181575063fe7f3b51146100f657600080fd5b3461017d578160031936011261017d579060a0825161011481611587565b36903781518092600a92935b6001906005828701101561015557908260029286546001600160801b038116825260801c602082015201940194019392610120565b61017b9291506001600160801b0360a0955416905261017383611587565b518092611664565bf35b5080fd5b90503461022d576020908160031936011261022957356001600160a01b038116908190036102295783526001808252828420835181548082529186528386208185019693949192879190855b81811061021657505050826101e39103836115bd565b8451948186019282875251809352850195925b8281106102035785870386f35b83518752958101959281019284016101f6565b82548452928401929187019187016101cd565b8380fd5b8280fd5b828434610305578060031936011261030557600f5482516370a0823160e01b8152308582015290602090829060249082906001600160a01b03165afa9081156102fb5782916102ca575b506001600160801b03600e541691670de0b6b3a7640000928381029381850414901517156102b7576020846102b08585611983565b9051908152f35b634e487b7160e01b815260118552602490fd5b90506020813d82116102f3575b816102e4602093836115bd565b8101031261017d57518461027b565b3d91506102d7565b83513d84823e3d90fd5b80fd5b905082346103055780600319360112610305579060c083516103298161156c565b36903782519091815b6001906006828401101561036757908560029286546001600160801b038116825260801c602082015201940191019092610332565b60c08461017b886103778361156c565b518092611633565b50503461017d578160031936011261017d57602090600d5460801c9051908152f35b50503461017d57602036600319011261017d576102b0602092826001600160801b0391826103cd6115de565b1681526002865220908351916103e28361153b565b54906001600160401b038083168452868401938284881c16855261042c64ffffffffff8560c01c16808984015260ff606084019660e81c16865261042461174a565b904211611722565b61046f828251161515885190610441826115a2565b601b82527f5374616b696e673a205374616b696e67206e6f742065786973747300000000008b830152611722565b511692511660ff600d5460801c92511692611d0a565b83833461017d57606036600319011261017d576104a061160d565b6104a8611623565b9160018060a01b0391826010541682516331a9108f60e11b815260443588820152602081602481855afa90811561083c5787916107fc575b50602491610528602092878751916104f7836115a2565b601e83527f5374616b696e673a205a6f6d626965206f776e6572207265717569726564000086840152163314611722565b8451635284cdd760e11b81526044358a82015292839182905afa9081156107f25786916107af575b509061055e6105c792611bfd565b9361057b61056a611ac7565b6001600160401b0384161515611722565b610592610586611b00565b600660ff891610611722565b61059b86611b56565b93906105c26001600160801b0380966001600160401b03871693549060031b1c1688611bc4565b611bc4565b600d5484811685811461079c57908986600181940116809a816001600160801b031980951617600d553383526001602052610604828b8520611c66565b5064ffffffffff6106388661063161062c8261061f87611b71565b90549060031b1c16611b8c565b611ba7565b16426117ac565b166001600160401b038b80519561064e8761153b565b828c1687526020870195898b16875282880194855260ff60608901961686528152600260205220945116600160401b600160c01b03855494518d1b169164ffffffffff60c01b905160c01b169260ff60e81b905160e81b169361ffff60f01b16171717179055600e5481836106ce6001600160401b038916828516611be2565b16911617600e556106e5600d54938460801c611be2565b60801b16911617600d55670de0b6b3a7640000916001600160401b038381831602938183168504149116151715610789577f42429601bd1b722443ccb2a6ae7a2f2c054a4793932abbf351508fa261b9a32293929161077591600f54168451916323b872dd60e01b602084015233602484015230604484015260648301526064825261077082611587565b6117d2565b81519360443585521660208401523392a380f35b634e487b7160e01b875260118852602487fd5b634e487b7160e01b8a5260118b5260248afd5b90506020813d6020116107ea575b816107ca602093836115bd565b810103126107e6575161ffff811681036107e65761055e610550565b8580fd5b3d91506107bd565b83513d88823e3d90fd5b90506020813d602011610834575b81610817602093836115bd565b81010312610830575184811681036108305760246104e0565b8680fd5b3d915061080a565b84513d89823e3d90fd5b82843461030557816003193601126103055761086061160d565b9060646001600160401b03610873611623565b931691610889610881611ac7565b841515611722565b6108a0610894611b00565b600660ff871610611722565b6108a984611b56565b92906108c7856001600160801b0380968194549060031b1c16611bc4565b16029182169182036108f1576020856102b08686866108eb81600d5460801c611be2565b91611d0a565b634e487b7160e01b815260118652602490fd5b50503461017d57602036600319011261017d57602091816001600160801b03918261092d6115de565b1681526002855220548251921c168152f35b50503461017d57602036600319011261017d579060ff826080936109616115de565b9380606083516109708161153b565b828152826020820152828582015201526001600160801b038095168152600260205220908051916109a08361153b565b54916001600160401b0383169485825260208201908085851c1682528383019186606064ffffffffff95868960c01c168652019660e81c16865284519788525116602087015251169084015251166060820152f35b82843461030557606036600319011261030557610a1061160d565b610a18611623565b916044359060ff82169283830361017d576001600160401b03610a93911693610a4a610a42611ac7565b861515611722565b610a55610586611b00565b6005875191610a63836115a2565b602083527f5374616b696e673a205a6f6d626965206c6576656c20697320696e76616c6964602084015210611722565b6005821015610aee576020856102b08686610adf816105c28960808160011c600a0154610abf88611b56565b92906001600160801b03938491549060031b1c169360071b161c16611bc4565b6108eb81600d5460801c611be2565b634e487b7160e01b815260328652602490fd5b82843461030557806003193601126103055760c08251610b208161156c565b36903781516007916001826006828401101561036757908560029286546001600160801b038116825260801c602082015201940191019092610332565b50503461017d578160031936011261017d576020906003549051908152f35b83833461017d578160031936011261017d576001600160801b03600e541691670de0b6b3a764000092838102938185041490151715610bbf576020838351908152f35b634e487b7160e01b815260118452602490fd5b90503461022d576020908160031936011261022957610bef6115de565b923385526001835280852093610c5d610c236001600160801b03809316809760019160005201602052604060002054151590565b835190610c2f826115a2565b601e82527f5374616b696e673a205374616b696e6720696420697320696e76616c6964000087830152611722565b8486526002845281862092825193610c748561153b565b54936001600160401b039182861682528682018487871c168152610cb664ffffffffff8860c01c16808886015260ff606086019960e81c16895261042461174a565b8383511691670de0b6b3a764000092838102938185041490151715610dd3575090848392858296955116928282511693600d54948560801c809c5160ff1691610cfe93611d0a565b90610d08916117ac565b986001600160801b03199687925116610d20916117b9565b60801b16911617600d55511691600e549281841690610d3e916117b9565b16911617600e55338552600183528381862090610d5a916119be565b5083855260028352808520859055600f54815163a9059cbb60e01b81860152336024820152604480820185905281526001600160a01b0390911690610d9e8161153b565b610da7916117d2565b5190815233917facdcb9041bb85f01fdf7810fea123661a101242c5fe3cb55c577abdbfd8351c291a380f35b634e487b7160e01b8b526011905260248afd5b9190503461022d578060031936011261022d57610e0161160d565b610e09611623565b926001600160401b0380921691821590610e2b610e24611ac7565b8315611722565b60ff861690610e44610e3b611b00565b60068410611722565b610e4d87611b56565b91906001600160801b03928391549060031b1c166064028281169081036110495786610e7891611bc4565b92600d5491838316848114611036579189918580808f96600101169d8e8096816001600160801b0319809b1617600d553389526001602052882090610ebc91611c66565b50610ec690611b71565b90549060031b1c16610ed790611b8c565b610ee090611ba7565b610eeb9116426117ac565b64ffffffffff16908b805195610f008761153b565b8c87526020870195898b168752828801948552606088019586528152600260205220945116845493518c1b600160401b600160c01b03169164ffffffffff60c01b905160c01b169260ff60e81b905160e81b169361ffff60f01b16171717179055600e5481838881841690610f7491611be2565b16911617600e55600d54928360801c90610f8d91611be2565b60801b16911617600d55670de0b6b3a76400008084029384041417156110235750600f5482516323b872dd60e01b6020820152336024820152306044820152606480820193909352918252610fef91906001600160a01b031661077082611587565b7f42429601bd1b722443ccb2a6ae7a2f2c054a4793932abbf351508fa261b9a322815191848352606460208401523392a380f35b634e487b7160e01b855260119052602484fd5b634e487b7160e01b8c526011885260248cfd5b634e487b7160e01b8a526011865260248afd5b90503461022d57602080600319360112610229576001600160a01b038235818116949193908590036107e65785548251630f6266a760e01b81523092810192835233602084015290948516918490829081906040010381855afa908115611180577247756172643a207a65726f206164647265737360681b926110f8611143969593611129938b91611153575b506110f26116ad565b90611722565b87835191611105836115a2565b601183527047756172643a2073616d652076616c756560781b878401521415611722565b5191611134836115a2565b60138352820152831515611722565b6001600160a01b03191617815580f35b6111739150873d8911611179575b61116b81836115bd565b810190611695565b386110e9565b503d611161565b83513d89823e3d90fd5b90503461022d57602036600319011261022d5780359063ffffffff82168092036102295783548351630f6266a760e01b815230928101928352336020808501919091529092909183918290036040019082906001600160a01b03165afa90811561124a5792611227602093927fee2589b7e912878a6a500663abeeaa8eb0bc43c6ef8626f3a6706962e7784dc395879161123357506110f26116ad565b8160035551908152a180f35b6111739150853d81116111795761116b81836115bd565b50505051903d90823e3d90fd5b83828634610305576101609081600319360112610305573660231215610305576112808561156c565b60c4938536861161022d5784905b8682106115235750503660e3121561017d578051946112ac86611587565b856101649136831161151f57905b82821061150757505082548251630f6266a760e01b8152308782019081523360208281019190915293509091839183916001600160a01b0316908290819060400103915afa90811561124a579061131a9185916114ea57506110f26116ad565b825b600681106114c45750825b60058082101561135b57906113516001600160801b0382611356941b8a01511615156110f2611cd1565b611cc2565b611327565b50508686949581855b600381106114705750508591855b6002808210156113d457879088905b8781831061139957505050600a820155600101611372565b6113ca88946001600160801b03600194959a5116908a8a1b60031b6001600160801b03811b9283911b169119161790565b9301960190611381565b505093919096949592968697875b6001811061143257505050509061142461142e927fc167bb3935aa4427dca7338db343e033afb1111a921c79afe8eb3a5f4355b4cc9697600c55518094611633565b60c0830190611664565ba180f35b90919298826114656001926001600160801b038d51169085881b60031b6001600160801b03811b9283911b169119161790565b9a01939291016113e2565b86875b866002821061148b5750506007820155600101611364565b6114bb85936001600160801b036001949751169087891b60031b6001600160801b03811b9283911b169119161790565b92019301611473565b806113516001600160801b036114e59360051b8b01511615156110f2611cd1565b61131c565b6115019150833d85116111795761116b81836115bd565b896110e9565b60208091611514846115f9565b8152019101906112ba565b8480fd5b60208091611530846115f9565b81520191019061128e565b608081019081106001600160401b0382111761155657604052565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b0382111761155657604052565b60a081019081106001600160401b0382111761155657604052565b604081019081106001600160401b0382111761155657604052565b90601f801991011681019081106001600160401b0382111761155657604052565b600435906001600160801b03821682036115f457565b600080fd5b35906001600160801b03821682036115f457565b600435906001600160401b03821682036115f457565b6024359060ff821682036115f457565b6000915b6006831061164457505050565b6001906001600160801b0383511681526020809101920192019190611637565b6000915b6005831061167557505050565b6001906001600160801b0383511681526020809101920192019190611668565b908160209103126115f4575180151581036115f45790565b604051906116ba826115a2565b601082526f47756172643a204e6f2072696768747360801b6020830152565b6020808252825181830181905290939260005b82811061170e57505060409293506000838284010152601f8019910116010190565b8181018601518482016040015285016116ec565b1561172a5750565b60405162461bcd60e51b815290819061174690600483016116d9565b0390fd5b60405190611757826115a2565b601b82527f5374616b696e67205374616b696e67206973206e6f74206f76657200000000006020830152565b8181029291811591840414171561179657565b634e487b7160e01b600052601160045260246000fd5b9190820180921161179657565b6001600160801b03918216908216039190821161179657565b6040516001600160a01b039091169291906117ec816115a2565b6020918282527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564838301526000808285829451910182895af13d15611902573d956001600160401b0387116118ee576118669495966040519061185888601f19601f84011601836115bd565b81528093873d92013e61190e565b8051908282159283156118d6575b5050501561187f5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b6118e69350820181019101611695565b388281611874565b634e487b7160e01b83526041600452602483fd5b61186693949591506060915b919290156119705750815115611922575090565b3b1561192b5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b82519091501561172a5750805190602001fd5b9190820391821161179657565b80548210156119a85760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b90600182019060009281845282602052604084205490811515600014611ac05760001991808301818111611aac57825490848201918211611a9857808203611a4a575b50505080548015611a3657820191611a198383611990565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b611a83611a5a611a6a9386611990565b90549060031b1c92839286611990565b819391549060031b600019811b9283911b169119161790565b90558652846020526040862055388080611a01565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b5050505090565b60405190611ad4826115a2565b601c82527f5374616b696e673a20526571756972656420616d6f756e74203e2030000000006020830152565b60405190606082018281106001600160401b03821117611556576040526024825263185b1a5960e21b6040837f5374616b696e673a205374616b696e6720696e74657276616c20697320696e7660208201520152565b9060068210156119a85760108260011c6007019260041b1690565b9060068210156119a85760108260011c6004019260041b1690565b90601e6001600160801b038093160291821691820361179657565b90620151806001600160801b038093160291821691820361179657565b9190916001600160801b038080941691160291821691820361179657565b9190916001600160801b038080941691160191821161179657565b61ffff1661047e8111611c1a57506001600160801b03600a541690565b6104f68111611c2d5750600a5460801c90565b61056e8111611c4657506001600160801b03600b541690565b6105d210611c5757600b5460801c90565b6001600160801b03600c541690565b6000828152600182016020526040902054611cbb57805490680100000000000000008210156115565782611ca4611a6a846001809601855584611990565b905580549260005201602052604060002055600190565b5050600090565b60001981146117965760010190565b60405190611cde826115a2565b601982527f5374616b696e673a20496e70757420697320696e76616c6964000000000000006020830152565b9260018060a01b03600f5416604051936370a0823160e01b855260208560248160049530878301525afa948515611e7357600095611e40575b506001600160801b039384600e5416670de0b6b3a76400009687820291808304891490151715611e2b579186611d7d611d85938295611983565b911690611783565b9116908115611e165790611da191049584600354911690611783565b848102948186041490151715611e01576006821015611dec5791816080611dda946201d4c0969460011c01549160071b161c1690611783565b0480821015611de7575090565b905090565b603290634e487b7160e01b6000525260246000fd5b601190634e487b7160e01b6000525260246000fd5b601283634e487b7160e01b6000525260246000fd5b601185634e487b7160e01b6000525260246000fd5b90946020823d8211611e6b575b81611e5a602093836115bd565b810103126103055750519338611d43565b3d9150611e4d565b6040513d6000823e3d90fdfea2646970667358221220fd48593135757eab36a6bc5597a6dd0846258c1d9b2e404f595265d728b72c2564736f6c63430008110033

Verified Source Code Full Match

Compiler: v0.8.17+commit.8df45f5f EVM: london Optimization: Yes (200 runs)
Guard.sol 33 lines
// SPDX-License-Identifier: PROPRIERTARY

// Author: Ilya A. Shlyakhovoy
// Email: [email protected]

pragma solidity 0.8.17;
import "./interfaces/IRights.sol";

abstract contract Guard {
    string constant NO_RIGHTS = "Guard: No rights";

    /// @notice only if person with rights calls the contract
    modifier haveRights() {
        require(_rights().haveRights(address(this), msg.sender), NO_RIGHTS);
        _;
    }

    /// @notice only if someone with rights calls the contract
    modifier haveRightsPerson(address who_) {
        require(_rights().haveRights(address(this), who_), NO_RIGHTS);
        _;
    }

    /// @notice only if who with rights calls the target function
    modifier haveRightsExt(address target_, address who_) {
        require(_rights().haveRights(target_, who_), NO_RIGHTS);
        _;
    }

    function _rights() internal view virtual returns (IRights);

    function setRights(address rights_) external virtual;
}
Structures.sol 97 lines
// SPDX-License-Identifier: PROPRIERTARY

// Author: Ilya A. Shlyakhovoy
// Email: [email protected]
pragma solidity 0.8.17;

/**
 * @dev Collection of structures
 */
library Structures {
    struct ActorData {
        uint256 adultTime;
        uint256 bornTime;
        string kidTokenUriHash;
        string adultTokenUriHash;
        uint16[10] props;
        uint8 childs;
        uint8 childsPossible;
        bool sex;
        bool born;
        bool immaculate;
        uint16 rank;
        address initialOwner;
    }

    struct Item {
        string itemKey;
        uint256 location;
        uint8 slots;
        string uri;
    }

    struct LootBox {
        uint256 price;
        uint16 total;
        uint16 available;
        bool paused;
        bool deleted;
        string uri;
        LootBoxItem[] items;
    }

    struct LootBoxItem {
        uint256 class;
        uint256 model;
        uint8 slots;
        uint16 promilles;
    }

    struct Estate {
        address lender;
        uint256 location;
        uint8 estateType;
        uint256 parent;
        uint256 coordinates;
    }

    struct Villa {
        uint256 location;
        uint256 fraction;
    }

    struct ManageAction {
        address target;
        address author;
        uint256 expiration;
        bytes4 signature;
        bytes data;
        bool executed;
    }

    struct InvestorData {
        address investor;
        uint256 promille;
    }

    struct Benefit {
        uint256 price;
        uint256 from;
        uint256 until;
        uint16 id;
        uint16 amount;
        uint8 level;
        uint8 issued;
    }

    struct BreedingParams {
        uint256 motherId;
        uint256 fatherId;
        uint256 breedingId;
        uint256 sessionId;
        uint256 breedingFee;
        uint256 deadline;
        address asset;
        bool isKidForMother;
    }
}
Staking.sol 351 lines
// SPDX-License-Identifier: PROPRIERTARY

// Author: Dmitry Kharlanchuk
// Email: [email protected]

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../utils/GuardExtension.sol";
import "../persons/interfaces/IActors.sol";
import "./interfaces/IStaking.sol";

contract Staking is IStaking, GuardExtension {
    using EnumerableSet for EnumerableSet.UintSet;
    using SafeERC20 for IERC20;

    mapping(address => EnumerableSet.UintSet) _stakesByAddress;
    mapping(uint128 => Stake) _stakes;

    uint256 private _maxAPR; // two decimals 100% == 10000
    uint128[6] private _intervalsMonth;
    uint128[6] private _intervalCoefficient;
    uint128[5] private _boosterCoefficient;
    uint128 private _counter;

    // Decimal places are not taken
    // Total supply 250,000,000 UDS
    uint128 private _totalShares;
    uint128 private totalStakes;

    IERC20 private _udsToken;
    IActors private _zombies;

    string private constant ZERO_AMOUNT = "Staking: Required amount > 0";
    string private constant NOT_ZOMBIE_OWNER = "Staking: Zombie owner required";
    string private constant NOT_EXISTS = "Staking: Staking not exists";
    string private constant NOT_OVER = "Staking Staking is not over";
    string private constant ALREADY_REWARDED = "Staking: Already rewarded";
    string private constant INVALID_ZOMBIE_LEVEL =
        "Staking: Zombie level is invalid";
    string private constant INVALID_INTERVAL =
        "Staking: Staking interval is invalid";
    string private constant INVALID_STAKING_ID =
        "Staking: Staking id is invalid";
    string private constant INVALID_INPUT = "Staking: Input is invalid";

    constructor(
        address rights_,
        address udsToken_,
        address zombies_,
        uint16 maxAPR_,
        uint128[6] memory intervalsMonth_,
        uint128[6] memory intervalCoefficients_,
        uint128[5] memory boosterCoefficients_
    ) GuardExtension(rights_) {
        _udsToken = IERC20(udsToken_);
        _zombies = IActors(zombies_);
        _setCoefficients(intervalCoefficients_, boosterCoefficients_);
        _setMaxApr(maxAPR_);
        _intervalsMonth = intervalsMonth_;
        _totalShares = 1; // set minimal shares to avoid devide by zero
    }

    /**
     * @dev Sets coefficients for staking time and the presence of zombie.
     *      The coefficient requires 2 decimal places (1.0 == 100)
     * @param intervalCoefficients_ Coefficients for staking time correspond to _intervalsMonth.
     * @param boosterCoefficients_ Coefficients for owning zombies correspond to the level of zombies.
     */
    function setCoefficients(
        uint128[6] memory intervalCoefficients_,
        uint128[5] memory boosterCoefficients_
    ) external haveRights {
        _setCoefficients(intervalCoefficients_, boosterCoefficients_);
    }

    /**
     * @dev Sets the upper limit of APR.
     * @param maxAPR_ Maximum APR percentage to two decimal places (100% == 10000).
     */
    function setMaxApr(uint32 maxAPR_) external haveRights {
        _setMaxApr(maxAPR_);
    }

    /**
     * @dev Stake user tokens for a specified period of time.
     * @param stakeAmount_ Number of tokens for staking. Specified without decimal places.
     * @param interval_ Time interval index 0-5 (see getMonthIntervals()).
     */
    function stake(uint64 stakeAmount_, uint8 interval_) public {
        _stake(stakeAmount_, interval_, 100, 0);
    }

    /**
     * @dev Stake user tokens for a specified period of time with discount for zombiew owners.
     * @param stakeAmount_ Number of tokens for staking. Specified without decimal places.
     * @param interval_ Time interval index 0-5 (see getMonthIntervals()).
     * @param zombieId_ Zombie ID.
     */
    function stakeByZombieOwner(
        uint64 stakeAmount_,
        uint8 interval_,
        uint256 zombieId_
    ) public {
        require(msg.sender == _zombies.ownerOf(zombieId_), NOT_ZOMBIE_OWNER);
        uint16 rank = _zombies.getRank(zombieId_);
        _stake(stakeAmount_, interval_, _getBoostByRank(rank), zombieId_);
    }

    /**
     * @dev Returns staked tokens along with the reward.
     * @param stakeId_ Staking ID.
     */
    function claim(uint128 stakeId_) public {
        require(
            _stakesByAddress[msg.sender].contains(stakeId_),
            INVALID_STAKING_ID
        );
        Stake memory currentStake = _stakes[stakeId_];
        require(currentStake.lockedUntil < block.timestamp, NOT_OVER);

        uint256 unwrappedStakeAmount = uint256(currentStake.amount) * 1e18;
        uint256 totalAmount = _calcReward(
            currentStake.amount,
            currentStake.shares,
            _totalShares,
            currentStake.interval
        ) + unwrappedStakeAmount;

        _totalShares -= currentStake.shares;
        totalStakes -= currentStake.amount;
        _stakesByAddress[msg.sender].remove(stakeId_);
        delete _stakes[stakeId_];

        _udsToken.safeTransfer(msg.sender, totalAmount);
        emit StakeClaimed(msg.sender, stakeId_, totalAmount);
    }

    /**
     * @dev Returns staking by ID.
     * @param stakeId_ Staking ID.
     */
    function getStake(uint128 stakeId_) public view returns (Stake memory) {
        return _stakes[stakeId_];
    }

    /**
     * @dev Returns all staking IDs by stake holder address.
     * @param stakeholder_ Address of stake holder.
     */
    function getStakesOf(
        address stakeholder_
    ) public view returns (uint256[] memory) {
        return _stakesByAddress[stakeholder_].values();
    }

    /**
     * @dev Returns shares for the staking by ID.
     * @param stakeId_ Staking ID.
     */
    function sharesOf(uint128 stakeId_) public view returns (uint128) {
        return _stakes[stakeId_].shares;
    }

    /**
     * @dev Returns the reward size for the specified staking ID under current conditions.
     * @param stakeId_ Staking ID.
     */
    function rewardOf(uint128 stakeId_) public view returns (uint256) {
        Stake memory currentStake = _stakes[stakeId_];
        require(currentStake.lockedUntil < block.timestamp, NOT_OVER);
        require(currentStake.amount > 0, NOT_EXISTS);
        return
            _calcReward(
                currentStake.amount,
                currentStake.shares,
                _totalShares,
                currentStake.interval                
            );
    }

    /**
     * @dev Calculates the reward based on the staking amount and interval.
     * @param stakeAmount_ Number of tokens for staking. Specified without decimal places.
     * @param interval_ Time interval index 0-5 (see getMonthIntervals()).
     */
    function estimateReward(
        uint64 stakeAmount_,
        uint8 interval_
    ) public view returns (uint256) {
        require(stakeAmount_ > 0, ZERO_AMOUNT);
        require(interval_ < 6, INVALID_INTERVAL);
        uint128 shares = _intervalCoefficient[interval_] * stakeAmount_ * 100;
        return _calcReward(stakeAmount_, shares, _totalShares + shares, interval_);
    }

    /**
     * @dev Calculates the reward based on the staking amount, interval and zombie level.
     * @param stakeAmount_ Number of tokens for staking. Specified without decimal places.
     * @param interval_ Time interval index 0-5 (see getMonthIntervals()).
     * @param zombieLevel_ Zombie level.
     */
    function estimateRewardForZombieOwner(
        uint64 stakeAmount_,
        uint8 interval_,
        uint8 zombieLevel_
    ) public view returns (uint256) {
        require(stakeAmount_ > 0, ZERO_AMOUNT);
        require(interval_ < 6, INVALID_INTERVAL);
        require(zombieLevel_ < 5, INVALID_ZOMBIE_LEVEL);
        uint128 shares = _boosterCoefficient[zombieLevel_] *
            _intervalCoefficient[interval_] *
            stakeAmount_;
        return _calcReward(stakeAmount_, shares, _totalShares + shares, interval_);
    }

    /**
     * @dev Returns total staked amount.
     */
    function getTotalStakes() public view returns (uint256) {
        return uint256(totalStakes) * 1e18;
    }

    /**
     * @dev Returns total staked shares.
     */
    function getTotalShares() public view returns (uint256) {
        return _totalShares;
    }

    /**
     * @dev Returns current reward pool for stake holder.
     */
    function getCurrentRewardsPool() public view returns (uint256) {
        return
            _udsToken.balanceOf(address(this)) - (uint256(totalStakes) * 1e18);
    }

    /**
     * @dev Returns an array of staking intervals specified in months (1 month == 30 days).
     */
    function getMonthIntervals() public view returns (uint128[6] memory) {
        return _intervalsMonth;
    }

    /**
     * @dev Returns boost coefficients for staking time in accordance with the interval.
     */
    function getIntervalCoefficients() public view returns (uint128[6] memory) {
        return _intervalCoefficient;
    }

    /**
     * @dev Returns boost coefficients for zombie ownership in accordance with the zombie level.
     */
    function getBoostCoefficients() public view returns (uint128[5] memory) {
        return _boosterCoefficient;
    }

    /**
     * @dev Returns APR limit for rewards.
     */
    function getMaxApr() public view returns (uint256) {
        return _maxAPR;
    }

    function _getBoostByRank(
        uint16 zombieRank_
    ) private view returns (uint128) {
        if (zombieRank_ <= 1150) {
            return _boosterCoefficient[0];
        } else if (zombieRank_ <= 1270) {
            return _boosterCoefficient[1];
        } else if (zombieRank_ <= 1390) {
            return _boosterCoefficient[2];
        } else if (zombieRank_ <= 1490) {
            return _boosterCoefficient[3];
        } else {
            return _boosterCoefficient[4];
        }
    }

    function _stake(
        uint64 stakeAmount_,
        uint8 interval_,
        uint128 boostCoefficient_,
        uint256 zombieId_
    ) private {
        require(stakeAmount_ > 0, ZERO_AMOUNT);
        require(interval_ < 6, INVALID_INTERVAL);
        uint128 shares = boostCoefficient_ *
            _intervalCoefficient[interval_] *
            stakeAmount_;
        ++_counter;
        uint128 stakeId = _counter;
        _stakesByAddress[msg.sender].add(stakeId);
        _stakes[stakeId] = Stake({
            amount: stakeAmount_,
            shares: shares,
            lockedUntil: uint40(
                block.timestamp + (_intervalsMonth[interval_] * 30 * 1 days)
            ),
            interval: interval_
        });

        totalStakes += stakeAmount_;
        _totalShares += shares;

        uint256 unwrappedAmount = uint256(stakeAmount_) * 1e18;
        _udsToken.safeTransferFrom(msg.sender, address(this), unwrappedAmount);

        emit StakeAdded(msg.sender, stakeId, zombieId_, boostCoefficient_);
    }

    function _setMaxApr(uint32 maxAPR_) private {
        _maxAPR = maxAPR_;
        emit MaxAprUpdated(maxAPR_);
    }

    function _setCoefficients(
        uint128[6] memory intervalCoefficients_,
        uint128[5] memory boosterCoefficients_
    ) private {
        for (uint256 i; i < 6; ++i) {
            require(intervalCoefficients_[i] > 0, INVALID_INPUT);
        }
        for (uint256 i; i < 5; ++i) {
            require(boosterCoefficients_[i] > 0, INVALID_INPUT);
        }
        _intervalCoefficient = intervalCoefficients_;
        _boosterCoefficient = boosterCoefficients_;
        emit CoefficientsUpdated(intervalCoefficients_, boosterCoefficients_);
    }

    function _calcReward(
        uint128 stakeAmount_,
        uint128 shares_,
        uint128 totalShares_,
        uint8 interval_        
    ) private view returns (uint256) {
        uint256 rewardPool = _udsToken.balanceOf(address(this)) -
            (uint256(totalStakes) * 1e18);
        uint256 rewards = rewardPool * shares_ / totalShares_;
        uint256 maxRewards = (_maxAPR * stakeAmount_ * 1e18 * _intervalsMonth[interval_]) /
            120000;

        return rewards < maxRewards ? rewards : maxRewards;
    }
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
GuardExtension.sol 30 lines
// SPDX-License-Identifier: PROPRIERTARY

// Author: Ilya A. Shlyakhovoy
// Email: [email protected]

pragma solidity 0.8.17;
import "./interfaces/IRights.sol";
import "../utils/Guard.sol";

abstract contract GuardExtension is Guard {
    IRights private _rightsContract;

    string private constant SAME_VALUE = "Guard: same value";
    string private constant ZERO_ADDRESS = "Guard: zero address";

    constructor(address rights_) {
        require(rights_ != address(0), ZERO_ADDRESS);
        _rightsContract = IRights(rights_);
    }

    function _rights() internal view virtual override returns (IRights) {
        return _rightsContract;
    }

    function setRights(address rights_) external virtual override haveRights {
        require(address(_rightsContract) != rights_, SAME_VALUE);
        require(rights_ != address(0), ZERO_ADDRESS);
        _rightsContract = IRights(rights_);
    }
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
IRights.sol 61 lines
// SPDX-License-Identifier: PROPRIERTARY

// Author: Ilya A. Shlyakhovoy
// Email: [email protected]

pragma solidity 0.8.17;

interface IRights {
    event AdminAdded(address indexed admin);
    event AdminDefined(address indexed admin, address indexed contractHash);
    event AdminRemoved(address indexed admin);
    event AdminCleared(address indexed admin, address indexed contractHash);

    /**
@notice Add a new admin for the Rigths contract
@param admin_ New admin address
*/

    function addAdmin(address admin_) external;

    /**
@notice Add a new admin for the any other contract
@param contract_ Contract address packed into address
@param admin_ New admin address
*/

    function addAdmin(address contract_, address admin_) external;

    /**
@notice Remove the existing admin from the Rigths contract
@param admin_ Admin address
*/

    function removeAdmin(address admin_) external;

    /**
@notice Remove the existing admin from the specified contract
@param contract_ Contract address packed into address
@param admin_ Admin address
*/

    function removeAdmin(address contract_, address admin_) external;

    /**
@notice Get the rights for the contract for the caller
@param contract_ Contract address packed into address
@return have rights or not
*/
    function haveRights(address contract_) external view returns (bool);

    /**
@notice Get the rights for the contract
@param contract_ Contract address packed into address
@param admin_ Admin address
@return have rights or not
*/
    function haveRights(address contract_, address admin_)
        external
        view
        returns (bool);
}
IERC721.sol 132 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @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`.
     *
     * 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;

    /**
     * @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 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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * 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 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 the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @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);
}
IStaking.sol 20 lines
// SPDX-License-Identifier: PROPRIERTARY

// Author: Dmitry Kharlanchuk
// Email: [email protected]

pragma solidity 0.8.17;

interface IStaking {
    event StakeAdded(address indexed staker, uint128 indexed stakeId, uint256 zombieId, uint128 boostCoefficient);
    event StakeClaimed(address indexed staker, uint128 indexed stakeId, uint256 totalAmount);
    event CoefficientsUpdated(uint128[6] intervalCoefficients, uint128[5] boosterCoefficients);
    event MaxAprUpdated(uint32 maxAPR_);

    struct Stake {
        uint64 amount;
        uint128 shares;
        uint40 lockedUntil;
        uint8 interval;
    }
}
IActors.sol 173 lines
// SPDX-License-Identifier: PROPRIERTARY

// Author: Ilya A. Shlyakhovoy
// Email: [email protected]

pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import {Structures} from "../../lib/Structures.sol";

interface IActors is IERC721Metadata {
    event Minted(address indexed owner, uint256 indexed id);

    event MintedImmaculate(address indexed owner, uint256 indexed id);

    event TokenUriDefined(uint256 indexed id, string kidUri, string adultUri);

    event ActorWasBorn(uint256 indexed id, uint256 bornTime);

    /**
@notice Get a total amount of issued tokens
@return The number of tokens minted
*/

    function total() external view returns (uint256);

    /**
    @notice Set an uri for the adult token (only for non immaculate)
    @param id_ token id
    @param adultHash_ ipfs hash of the kids metadata
    */
    function setMetadataHash(uint256 id_, string calldata adultHash_) external;

    /**
    @notice Set an uri for the adult and kid token (only for immaculate)
    @param id_ token id
    @param kidHash_ ipfs hash of the kids metadata
    @param adultHash_ ipfs hash of the adult metadata
    */
    function setMetadataHashes(
        uint256 id_,
        string calldata kidHash_,
        string calldata adultHash_
    ) external;

    /**
    @notice Get an uri for the kid token
    @param id_ token id
    @return Token uri for the kid actor
    */
    function tokenKidURI(uint256 id_) external view returns (string memory);

    /**
    @notice Get an uri for the adult token
    @param id_ token id
    @return Token uri for the adult actor
    */
    function tokenAdultURI(uint256 id_) external view returns (string memory);

    /**
@notice Create a new person token (not born yet)
@param id_ The id of new minted token
@param owner_ Owner of the token
@param props_ Array of the actor properties
@param sex_ The person sex (true = male, false = female)
@param born_ Is the child born or not
@param adultTime_ When child become adult actor, if 0 actor is not born yet
@param childs_ The amount of childs can be born (only for female)
@param immaculate_ True only for potion-breeded
@return The new id
*/
    function mint(
        uint256 id_,
        address owner_,
        uint16[10] memory props_,
        bool sex_,
        bool born_,
        uint256 adultTime_,
        uint8 childs_,
        bool immaculate_
    ) external returns (uint256);

    /**
@notice Get the person props
@param id_ Person token id
@return Array of the props
*/
    function getProps(uint256 id_) external view returns (uint16[10] memory);

    /**
    @notice Get the actor
    @param id_ Person token id
    @return Structures.ActorData full struct of actor
    */
    function getActor(uint256 id_)
        external
        view
        returns (Structures.ActorData memory);

    /**
@notice Get the person sex
@param id_ Person token id
@return true = male, false = female
*/
    function getSex(uint256 id_) external view returns (bool);

    /**
@notice Get the person childs
@param id_ Person token id
@return childs and possible available childs
*/
    function getChilds(uint256 id_) external view returns (uint8, uint8);

    /**
@notice Breed a child
@param id_ Person token id
*/
    function breedChild(uint256 id_) external;

    /**
@notice Get the person immaculate status
@param id_ Person token id
*/
    function getImmaculate(uint256 id_) external view returns (bool);

    /**
@notice Get the person born time
@param id_ Person token id
@return 0 = complete adult, or amount of tokens needed to be paid for
*/
    function getBornTime(uint256 id_) external view returns (uint256);

    /**
@notice Get the person born state
@param id_ Person token id
@return true = person is born
*/
    function isBorn(uint256 id_) external view returns (bool);

    /**
@notice Birth the person
@param id_ Person token id 
@param adultTime_ When person becomes adult
*/
    function born(uint256 id_, uint256 adultTime_) external;

    /**
@notice Get the person adult timestamp
@param id_ Person token id
@return timestamp
*/
    function getAdultTime(uint256 id_) external view returns (uint256);

    /**
@notice Grow the 
@param id_ Person token id 
@param time_ the deadline to grow
*/
    function setAdultTime(uint256 id_, uint256 time_) external;

    /**
@notice Get the person adult state
@param id_ Person token id
@return true = person is adult (price is 0 and current date > person's grow deadline)
*/
    function isAdult(uint256 id_) external view returns (bool);

    /**
@notice Get the person rank
@param id_ Person token id
@return person rank value
*/
    function getRank(uint256 id_) external view returns (uint16);
}
SafeERC20.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
EnumerableSet.sol 378 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}
IERC20Permit.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
IERC721Metadata.sol 27 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

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 {
    /**
     * @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);
}

Read Contract

estimateReward 0xbb6c191a → uint256
estimateRewardForZombieOwner 0x8694af78 → uint256
getBoostCoefficients 0xfe7f3b51 → uint128[5]
getCurrentRewardsPool 0xf8c70387 → uint256
getIntervalCoefficients 0x7785c0b6 → uint128[6]
getMaxApr 0x710dc957 → uint256
getMonthIntervals 0xdcb6f638 → uint128[6]
getStake 0x8a3a8b29 → tuple
getStakesOf 0xfafc08c4 → uint256[]
getTotalShares 0xd5002f2e → uint256
getTotalStakes 0x68c33627 → uint256
rewardOf 0xc0f1d8c6 → uint256
sharesOf 0x9e5d82b9 → uint128

Write Contract 6 functions

These functions modify contract state and require a wallet transaction to execute.

claim 0x60e72adb
uint128 stakeId_
setCoefficients 0x0dd3930d
uint128[6] intervalCoefficients_
uint128[5] boosterCoefficients_
setMaxApr 0x361652c9
uint32 maxAPR_
setRights 0x37d2aae9
address rights_
stake 0x55b43fe1
uint64 stakeAmount_
uint8 interval_
stakeByZombieOwner 0xbb87d2aa
uint64 stakeAmount_
uint8 interval_
uint256 zombieId_

Recent Transactions

No transactions found for this address