Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x2D168651d85fE8B16aeBF42272A9b64f24ac3603
Balance 0 ETH
Nonce 1
Code Size 20669 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

20669 bytes
0x608060405234801561001057600080fd5b506004361061027f5760003560e01c80638456cb591161015c578063cdd033c8116100ce578063dd4be68311610087578063dd4be68314610d3e578063e0a79b1614610da2578063e5c4686914610dc8578063f2fde38b14610dd0578063f94e5c8814610df6578063fbfcd24114610f195761027f565b8063cdd033c814610a9a578063d0cd4ee014610ad2578063d431350614610af8578063d43c953514610b35578063d768779a14610cda578063d939381414610d125761027f565b8063a4f3f0e511610120578063a4f3f0e51461084e578063b104e006146108ff578063b2bdfa7b1461091c578063bf6eac2f14610924578063c549e6b91461095a578063c922e937146109625761027f565b80638456cb59146107de57806385d895ef146107e657806388125f79146107ee57806396591e311461080b578063a019cb4b146108285761027f565b8063486ff0cd116101f5578063572b6c05116101b9578063572b6c05146107725780635c975abb146107985780635f96dc11146107a0578063715018a6146107a85780637bdb8cd3146107b05780637da0a877146107d65761027f565b8063486ff0cd146106445780634cd36531146106c15780634f64b2be146106fd5780635058c4601461071a578063539cd3b4146107465761027f565b80631d2002e7116102475780631d2002e7146103c157806326fa24e9146103de57806328523eb6146105b15780633f4ba83a146105f357806340a16688146105fb57806340f02ab61461063c5761027f565b806301193ad71461028457806301bc45c91461032757806304a624c61461034b5780631320da8b14610365578063187739a414610393575b600080fd5b6103256004803603602081101561029a57600080fd5b810190602081018135600160201b8111156102b457600080fd5b8201836020820111156102c657600080fd5b803590602001918460208302840111600160201b831117156102e757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610f21945050505050565b005b61032f6110df565b604080516001600160a01b039092168252519081900360200190f35b6103536110ee565b60408051918252519081900360200190f35b6103536004803603604081101561037b57600080fd5b506001600160a01b03813581169160200135166110f4565b610353600480360360408110156103a957600080fd5b506001600160a01b0381358116916020013516611111565b610325600480360360208110156103d757600080fd5b503561112e565b610404600480360360208110156103f457600080fd5b50356001600160a01b03166111c8565b6040518080602001806020018060200180602001806020018060200187810387528d818151815260200191508051906020019060200280838360005b83811015610458578181015183820152602001610440565b5050505090500187810386528c818151815260200191508051906020019060200280838360005b8381101561049757818101518382015260200161047f565b5050505090500187810385528b818151815260200191508051906020019060200280838360005b838110156104d65781810151838201526020016104be565b5050505090500187810384528a818151815260200191508051906020019060200280838360005b838110156105155781810151838201526020016104fd565b50505050905001878103835289818151815260200191508051906020019060200280838360005b8381101561055457818101518382015260200161053c565b50505050905001878103825288818151815260200191508051906020019060200280838360005b8381101561059357818101518382015260200161057b565b505050509050019c5050505050505050505050505060405180910390f35b6105df600480360360408110156105c757600080fd5b506001600160a01b038135811691602001351661143e565b604080519115158252519081900360200190f35b6105df61145e565b6105df600480360360a081101561061157600080fd5b5080356001600160a01b0316906020810135906040810135906060810135906080013560ff166114c7565b610353611627565b61064c61162d565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561068657818101518382015260200161066e565b50505050905090810190601f1680156106b35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610353600480360360808110156106d757600080fd5b508035906001600160a01b03602082013581169160408101359091169060600135611648565b61032f6004803603602081101561071357600080fd5b503561172e565b6103256004803603604081101561073057600080fd5b506001600160a01b038135169060200135611758565b61032f6004803603604081101561075c57600080fd5b506001600160a01b03813516906020013561197f565b6105df6004803603602081101561078857600080fd5b50356001600160a01b03166119b7565b6105df6119cb565b6103536119db565b6103256119e1565b610353600480360360208110156107c657600080fd5b50356001600160a01b0316611aae565b61032f611ac0565b6105df611acf565b610353611b31565b6103256004803603602081101561080457600080fd5b5035611b37565b6103256004803603602081101561082157600080fd5b5035611bd1565b61032f6004803603602081101561083e57600080fd5b50356001600160a01b0316611c6b565b6103256004803603604081101561086457600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561088e57600080fd5b8201836020820111156108a057600080fd5b803590602001918460208302840111600160201b831117156108c157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611c86945050505050565b6103536004803603602081101561091557600080fd5b5035611f66565b61032f611f87565b6103256004803603606081101561093a57600080fd5b506001600160a01b03813581169160208101359091169060400135611f96565b610353612704565b6103256004803603608081101561097857600080fd5b8135916001600160a01b0360208201351691810190606081016040820135600160201b8111156109a757600080fd5b8201836020820111156109b957600080fd5b803590602001918460208302840111600160201b831117156109da57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610a2957600080fd5b820183602082011115610a3b57600080fd5b803590602001918460208302840111600160201b83111715610a5c57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061270b945050505050565b61032560048036036060811015610ab057600080fd5b506001600160a01b038135811691602081013590911690604001351515612e68565b61032560048036036020811015610ae857600080fd5b50356001600160a01b0316612fbf565b61032560048036036080811015610b0e57600080fd5b506001600160a01b038135169060ff60208201351690604081013590606001351515613039565b61032560048036036060811015610b4b57600080fd5b810190602081018135600160201b811115610b6557600080fd5b820183602082011115610b7757600080fd5b803590602001918460208302840111600160201b83111715610b9857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610be757600080fd5b820183602082011115610bf957600080fd5b803590602001918460208302840111600160201b83111715610c1a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610c6957600080fd5b820183602082011115610c7b57600080fd5b803590602001918460208302840111600160201b83111715610c9c57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061326b945050505050565b61032560048036036080811015610cf057600080fd5b506001600160a01b038135169060208101359060408101359060600135613516565b6105df60048036036040811015610d2857600080fd5b506001600160a01b038135169060200135613646565b610d6460048036036020811015610d5457600080fd5b50356001600160a01b0316613c75565b60408051971515885260ff9096166020880152868601949094526060860192909252608085015260a0840152151560c0830152519081900360e00190f35b61035360048036036020811015610db857600080fd5b50356001600160a01b0316613cb9565b610353613ccb565b61032560048036036020811015610de657600080fd5b50356001600160a01b0316613cd1565b6105df60048036036040811015610e0c57600080fd5b810190602081018135600160201b811115610e2657600080fd5b820183602082011115610e3857600080fd5b803590602001918460208302840111600160201b83111715610e5957600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610ea857600080fd5b820183602082011115610eba57600080fd5b803590602001918460208302840111600160201b83111715610edb57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613dca945050505050565b610353613fbf565b610f29613fc5565b6001546001600160a01b03908116911614610f79576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6040805160008152602081019182905251610f9691600991614e71565b5060005b81518160ff16101561105d57600a54600090610fb99062015180613ff7565b9050828260ff1681518110610fca57fe5b6020026020010151811161101c576040805162461bcd60e51b8152602060048201526014602482015273496e76616c696420496e74657276616c2044617960601b604482015290519081900360640190fd5b6009838360ff168151811061102d57fe5b60209081029190910181015182546001818101855560009485529290932090920191909155919091019050610f9a565b507f29635226d0b00834767b0cf38daca8dc0fe978152b0a8a5b39eb281126352361600942604051808060200183815260200182810382528481815481526020019150805480156110cd57602002820191906000526020600020905b8154815260200190600101908083116110b9575b5050935050505060405180910390a150565b6002546001600160a01b031681565b600c5481565b600e60209081526000928352604080842090915290825290205481565b600760209081526000928352604080842090915290825290205481565b611136613fc5565b6001546001600160a01b03908116911614611186576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b600b8190556040805182815242602082015281517f886f1c6ee47e76ca7e1c7715d9662c5cbc03a9215b76899c702e3d1c38d1ee43929181900390910190a150565b6001600160a01b0381166000908152600d6020908152604091829020600281018054845181850281018501909552808552606094859485948594859485949193600384019360018101936004820193600583019360069093019288919083018282801561125e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611240575b50505050509550848054806020026020016040519081016040528092919081815260200182805480156112ba57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161129c575b505050505094508380548060200260200160405190810160405280929190818152602001828054801561132c57602002820191906000526020600020906000905b825461010083900a900460ff1615158152602060019283018181049485019490930390920291018084116112fb5790505b505050505093508280548060200260200160405190810160405280929190818152602001828054801561137e57602002820191906000526020600020905b81548152602001906001019080831161136a575b50505050509250818054806020026020016040519081016040528092919081815260200182805480156113d057602002820191906000526020600020905b8154815260200190600101908083116113bc575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561142257602002820191906000526020600020905b81548152602001906001019080831161140e575b5050505050905095509550955095509550955091939550919395565b600860209081526000928352604080842090915290825290205460ff1681565b6000611468613fc5565b6001546001600160a01b039081169116146114b8576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6114c0614040565b5060015b90565b60006114d1613fc5565b6001546001600160a01b03908116911614611521576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6001600160a01b03861660009081526005602052604090205460ff1661158d57600380546001810182556000919091527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b0319166001600160a01b0388161790555b6001600160a01b0386166000818152600560209081526040918290208054600160ff19909116811761ff00191661010060ff891602178255810189905560028101889055600301869055815188815290810187905280820186905242606082015290517f6b9e42b75b3aa79aee18ba04bd3f6dedba2d3e55228fadb89fd22817f7ef81ac916080908290030190a250600195945050505050565b600a5481565b6040805180820190915260018152603160f81b602082015290565b6001600160a01b038316600090815260056020819052604082200154819060ff16156116eb57600c5461167c9087906140e3565b955061169e6116976001600c5461413c90919063ffffffff16565b87906140e3565b90506116e46116ad848361417e565b6001600160a01b038088166000908152600760209081526040808320938a16835292905220546116de9089906140e3565b90613ff7565b9150611725565b6001600160a01b038086166000908152600760209081526040808320938816835292905220546117229084906116de9089906140e3565b91505b50949350505050565b6003818154811061173e57600080fd5b6000918252602090912001546001600160a01b0316905081565b611760613fc5565b6001546001600160a01b039081169116146117b0576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b80826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156117fe57600080fd5b505afa158015611812573d6000803e3d6000fd5b505050506040513d602081101561182857600080fd5b50511015611874576040805162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742042616c616e636560601b604482015290519081900360640190fd5b6001546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810184905290519184169163a9059cbb916044808201926020929091908290030181600087803b1580156118ca57600080fd5b505af11580156118de573d6000803e3d6000fd5b505050506040513d60208110156118f457600080fd5b5051611939576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b6040805182815242602082015281516001600160a01b038516927fcb92e2679de255302c9b8d0673cbdf8ef54667e943bf8f049bcaf6a85926ba1a928290030190a25050565b6004602052816000526040600020818154811061199b57600080fd5b6000918252602090912001546001600160a01b03169150829050565b6000546001600160a01b0390811691161490565b600054600160a01b900460ff1690565b60105481565b6119e9613fc5565b6002546001600160a01b03908116911614611a4b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f74207468652041646d696e604482015290519081900360640190fd5b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600254600180546001600160a01b0319166001600160a01b03909216919091179055565b60066020526000908152604090205481565b6000546001600160a01b031681565b6000611ad9613fc5565b6001546001600160a01b03908116911614611b29576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6114c06141d8565b60035490565b611b3f613fc5565b6001546001600160a01b03908116911614611b8f576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b600a8190556040805182815242602082015281517ff676bd50ed08b41fe017c9b4b7606b132ed9afafd39cbe090006c602170638bf929181900390910190a150565b611bd9613fc5565b6001546001600160a01b03908116911614611c29576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b600c8190556040805182815242602082015281517fd9124f37a22fb221df30d124c79aae3c3be0e56338cc2ed4d68ade2a51319f49929181900390910190a150565b600d602052600090815260409020546001600160a01b031681565b611c8e613fc5565b6001546001600160a01b03908116911614611cde576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b60408051600080825260208083018085526001600160a01b038716835260049091529290209051611d0f9290614ebc565b506001600160a01b03821660009081526005602052604090205460ff16611d76576040805162461bcd60e51b815260206004820152601660248201527514dd185ad95908151bdad95b88139bdd08115e1a5cdd60521b604482015290519081900360640190fd5b60005b81518160ff161015611ebf5760035482511115611dcd576040805162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908125b9c1d5d609a1b604482015290519081900360640190fd5b60056000838360ff1681518110611de057fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16611e51576040805162461bcd60e51b815260206004820152601660248201527514995dd85c9908151bdad95b88139bdd08115e1a5cdd60521b604482015290519081900360640190fd5b6001600160a01b03831660009081526004602052604090208251839060ff8416908110611e7a57fe5b60209081029190910181015182546001808201855560009485529290932090920180546001600160a01b0319166001600160a01b039093169290921790915501611d79565b506001600160a01b03821660008181526004602090815260409182902082514292810183905283815281549381018490527f533d99224d362fcbe71ce5ff0a8b2d61a9c08b8d1df27aab851edb881f3fb16b939192918190606082019085908015611f5357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611f35575b5050935050505060405180910390a25050565b60098181548110611f7657600080fd5b600091825260209091200154905081565b6001546001600160a01b031681565b611f9e6119cb565b15611fe3576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b826001600160a01b0316611ff5613fc5565b6001600160a01b03161415612051576040805162461bcd60e51b815260206004820152601f60248201527f5354414b453a20696e76616c6964207265666572726572206164647265737300604482015290519081900360640190fd5b6001600160a01b03821660009081526005602052604090205460ff166120be576040805162461bcd60e51b815260206004820152601a60248201527f5354414b45203a20546f6b656e206973206e6f74204578697374000000000000604482015290519081900360640190fd5b6001600160a01b0382166000908152600560205260408120600101549061211c908390600e906120ec613fc5565b6001600160a01b03908116825260208083019390935260409182016000908120918916815292529020549061417e565b10156121595760405162461bcd60e51b815260040180806020018281038252602a815260200180614ff8602a913960400191505060405180910390fd5b6001600160a01b03821660009081526005602052604081206002015490612187908390600e906120ec613fc5565b11156121c45760405162461bcd60e51b815260040180806020018281038252602a815260200180614fce602a913960400191505060405180910390fd5b6001600160a01b038216600090815260056020908152604080832060030154600f909252909120546121f6908361417e565b1115612249576040805162461bcd60e51b815260206004820152601860248201527f5354414b45203a204d61786c696d697420657863656564730000000000000000604482015290519081900360640190fd5b42612261600a5460105461417e90919063ffffffff16565b116122b3576040805162461bcd60e51b815260206004820152601d60248201527f5354414b453a205374616b696e672054696d6520436f6d706c65746564000000604482015290519081900360640190fd5b600d60006122bf613fc5565b6001600160a01b03166001600160a01b03168152602001908152602001600020600401600d60006122ee613fc5565b6001600160a01b03168152602080820192909252604001600090812060040154835460018101855593825291812090920155600d9061232b613fc5565b6001600160a01b031681526020808201929092526040016000908120600190810180549182018155825290829020918104909101805460ff601f9093166101000a9283021916909117905561237e613fc5565b600d600061238a613fc5565b6001600160a01b0390811682526020820192909252604001600090812080546001600160a01b03191693909216929092179055600d906123c8613fc5565b6001600160a01b03908116825260208083019390935260409091016000908120600201805460018101825590825292812090920180546001600160a01b031916918616919091179055600d9061241c613fc5565b6001600160a01b03908116825260208083019390935260409091016000908120600301805460018101825590825292812090920180546001600160a01b031916918516919091179055600d90612470613fc5565b6001600160a01b031681526020808201929092526040016000908120600601805460018101825590825291812042920191909155600d906124af613fc5565b6001600160a01b039081168252602080830193909352604091820160009081206005018054600181018255908252848220018590559085168152600f9092529020546124fb908261417e565b6001600160a01b0383166000908152600f6020526040812091909155612558908290600e90612528613fc5565b6001600160a01b03908116825260208083019390935260409182016000908120918816815292529020549061417e565b600e6000612564613fc5565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120919091556323b872dd6125a1613fc5565b30846040518463ffffffff1660e01b815260040180846001600160a01b03168152602001836001600160a01b031681526020018281526020019350505050602060405180830381600087803b1580156125f957600080fd5b505af115801561260d573d6000803e3d6000fd5b505050506040513d602081101561262357600080fd5b5051612668576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8811985a5b1959608a1b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b0316612684613fc5565b6001600160a01b03167f8d0a98609f00f26e55cd12ea38ffb8a0dfad170f6f001d682185fdce4ff424446126e26001600d60006126bf613fc5565b6001600160a01b031681526020810191909152604001600020600401549061413c565b60408051918252602082018790524282820152519081900360600190a4505050565b6201518081565b612713613fc5565b6001546001600160a01b03908116911614612763576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6001600160a01b0383166000908152600d6020526040812060050180548690811061278a57fe5b90600052602060002001541180156127ec57506001600160a01b0383166000908152600d602052604090206001018054859081106127c457fe5b90600052602060002090602091828204019190069054906101000a900460ff16151560011515145b6128275760405162461bcd60e51b81526004018080602001828103825260348152602001806150546034913960400191505060405180910390fd5b6001600160a01b0383166000908152600d6020526040902060050180548590811061284e57fe5b9060005260206000200154600d6000856001600160a01b03166001600160a01b03168152602001908152602001600020600301858154811061288c57fe5b60009182526020918290200154604080516370a0823160e01b815230600482015290516001600160a01b03909216926370a0823192602480840193829003018186803b1580156128db57600080fd5b505afa1580156128ef573d6000803e3d6000fd5b505050506040513d602081101561290557600080fd5b5051101561295a576040805162461bcd60e51b815260206004820181905260248201527f454d455247454e4359203a20496e73756666696369656e742042616c616e6365604482015290519081900360640190fd5b6001600160a01b0383166000908152600d6020526040812060050180548690811061298157fe5b906000526020600020015490506000600d6000866001600160a01b03166001600160a01b0316815260200190815260200160002060010186815481106129c357fe5b90600052602060002090602091828204019190066101000a81548160ff0219169083151502179055506000600d6000866001600160a01b03166001600160a01b031681526020019081526020016000206005018681548110612a2157fe5b60009182526020808320909101929092556001600160a01b0386168152600d90915260409020600301805486908110612a5657fe5b60009182526020808320909101546040805163a9059cbb60e01b81526001600160a01b038981166004830152602482018790529151919092169363a9059cbb93604480850194919392918390030190829087803b158015612ab657600080fd5b505af1158015612aca573d6000803e3d6000fd5b505050506040513d6020811015612ae057600080fd5b50600090505b8351811015612ddb576000838281518110612afd57fe5b6020026020010151905060006001600160a01b0316600d6000886001600160a01b03166001600160a01b031681526020019081526020016000206002018881548110612b4557fe5b6000918252602090912001546001600160a01b031614612d6d576000612b8368056bc75e2d631000006116de600b54856140e390919063ffffffff16565b9050612b8f828261413c565b9150858381518110612b9d57fe5b60200260200101516001600160a01b031663a9059cbb600d60008a6001600160a01b03166001600160a01b031681526020019081526020016000206002018a81548110612be657fe5b6000918252602080832090910154604080516001600160e01b031960e087901b1681526001600160a01b039092166004830152602482018790525160448083019491928390030190829087803b158015612c3f57600080fd5b505af1158015612c53573d6000803e3d6000fd5b505050506040513d6020811015612c6957600080fd5b5051612cbc576040805162461bcd60e51b815260206004820152601b60248201527f454d455247454e4359203a205472616e73666572204661696c65640000000000604482015290519081900360640190fd5b858381518110612cc857fe5b60200260200101516001600160a01b0316876001600160a01b0316600d60008a6001600160a01b03166001600160a01b031681526020019081526020016000206002018a81548110612d1657fe5b6000918252602091829020015460408051868152429381019390935280516001600160a01b03909216927fcc30edb66a991e48ca3676c277d3a35485ebfaf3016fa9536663b2689c8f5eef929081900390910190a4505b6001600160a01b0386166000908152600d602052604090206003018054612dd29188918a908110612d9a57fe5b9060005260206000200160009054906101000a90046001600160a01b0316878581518110612dc457fe5b602002602001015184614261565b50600101612ae6565b506001600160a01b0384166000908152600d60205260409020600301805486908110612e0357fe5b60009182526020918290200154604080518481524293810193909352828101889052516001600160a01b0391821692918716917fa4b627609e711628747558b171b04b9636337afdadac065ee7113fb91eab0b72919081900360600190a35050505050565b612e70613fc5565b6001546001600160a01b03908116911614612ec0576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6001600160a01b03831660009081526005602052604090205460ff168015612f0057506001600160a01b03821660009081526005602052604090205460ff165b612f43576040805162461bcd60e51b815260206004820152600f60248201526e151bdad95b881b9bdd08195e1a5cdd608a1b604482015290519081900360640190fd5b6001600160a01b03838116600081815260086020908152604080832094871680845294825291829020805460ff19168615151790819055825160ff90911615158152429181019190915281517f38dc54047237de43b07dc5d3a0cd9a29485be07da55d5611ddc91102542938ad929181900390910190a3505050565b612fc7613fc5565b6001546001600160a01b03908116911614613017576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b613041613fc5565b6001546001600160a01b03908116911614613091576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b8260ff16600114806130a657508260ff166002145b806130b457508260ff166003145b613105576040805162461bcd60e51b815260206004820152601760248201527f496e76616c6964204c6f636b61626c6520537461747573000000000000000000604482015290519081900360640190fd5b6001600160a01b03841660009081526005602052604090205460ff161515600114613169576040805162461bcd60e51b815260206004820152600f60248201526e151bdad95b88139bdd08115e1a5cdd608a1b604482015290519081900360640190fd5b8260ff16600114156131a05761317f428361417e565b6001600160a01b038516600090815260056020526040902060040155613202565b8260ff16600214156131cd576001600160a01b038416600090815260056020526040812060040155613202565b8260ff1660031415613202576001600160a01b038416600090815260056020819052604090912001805460ff19168215151790555b6001600160a01b0384166000818152600560208181526040928390206004810154920154835192835260ff16151590820152428183015290517f4030f7d2425e172fe94d03a4cfd07dcdbc4909529bdf15d2732aa1559ff9be7c9181900360600190a250505050565b613273613fc5565b6001546001600160a01b039081169116146132c3576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b815183511480156132d5575080518251145b613316576040805162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908125b9c1d5d609a1b604482015290519081900360640190fd5b60005b83518160ff1610156135105760056000858360ff168151811061333857fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1680156133a1575060056000848360ff168151811061337957fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff165b6133e4576040805162461bcd60e51b815260206004820152600f60248201526e151bdad95b881b9bdd08195e1a5cdd608a1b604482015290519081900360640190fd5b818160ff16815181106133f357fe5b602002602001015160076000868460ff168151811061340e57fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000858460ff168151811061344757fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002081905550828160ff168151811061348257fe5b60200260200101516001600160a01b0316848260ff16815181106134a257fe5b60200260200101516001600160a01b03167f2dc18c352fdd373a4dc83a7156d0dfe95082bd4d820bda50fa65ee3bcf8648f3848460ff16815181106134e357fe5b602002602001015142604051808381526020018281526020019250505060405180910390a3600101613319565b50505050565b61351e613fc5565b6001546001600160a01b0390811691161461356e576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6001600160a01b03841660009081526005602052604090205460ff166135cd576040805162461bcd60e51b815260206004820152600f60248201526e151bdad95b88139bdd08115e1a5cdd608a1b604482015290519081900360640190fd5b6001600160a01b0384166000818152600560209081526040918290206001810187905560028101869055600301849055815186815290810185905280820184905242606082015290517f6b9e42b75b3aa79aee18ba04bd3f6dedba2d3e55228fadb89fd22817f7ef81ac9181900360800190a250505050565b60006136506119cb565b15613695576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b826001600160a01b03166136a7613fc5565b6001600160a01b031614806136d657506001546001600160a01b03166136cb613fc5565b6001600160a01b0316145b613727576040805162461bcd60e51b815260206004820152601b60248201527f554e5354414b453a20496e76616c6964205573657220456e7472790000000000604482015290519081900360640190fd5b6001600160a01b0383166000908152600d6020526040812060030180548490811061374e57fe5b60009182526020808320909101546001600160a01b031680835260059091526040909120600401549091504210156137c5576040805162461bcd60e51b8152602060048201526015602482015274155394d51052d14e88151bdad95b88131bd8dad959605a1b604482015290519081900360640190fd5b6001600160a01b0381166000908152600560208190526040909120015460ff1615613890574261383d600a54600d6000886001600160a01b03166001600160a01b03168152602001908152602001600020600601868154811061382457fe5b906000526020600020015461417e90919063ffffffff16565b1115613890576040805162461bcd60e51b815260206004820181905260248201527f554e5354414b453a204c6f636b656420696e206f7074696f6e616c206c6f636b604482015290519081900360640190fd5b6001600160a01b0384166000908152600d602052604081206005018054859081106138b757fe5b9060005260206000200154118061391857506001600160a01b0384166000908152600d602052604090206001018054849081106138f057fe5b90600052602060002090602091828204019190069054906101000a900460ff16151560011515145b6139535760405162461bcd60e51b81526004018080602001828103825260328152602001806150226032913960400191505060405180910390fd5b6001600160a01b0384166000908152600d6020526040812060050180548590811061397a57fe5b60009182526020808320909101546001600160a01b038086168452600f8352604080852054918a168552600d909352918320600501805491945091929190879081106139c257fe5b60009182526020808320909101929092556001600160a01b0388168152600d909152604081206001018054879081106139f757fe5b90600052602060002090602091828204019190066101000a81548160ff02191690831515021790555081600d6000886001600160a01b03166001600160a01b031681526020019081526020016000206003018681548110613a5457fe5b60009182526020918290200154604080516370a0823160e01b815230600482015290516001600160a01b03909216926370a0823192602480840193829003018186803b158015613aa357600080fd5b505afa158015613ab7573d6000803e3d6000fd5b505050506040513d6020811015613acd57600080fd5b50511015613b22576040805162461bcd60e51b815260206004820152601e60248201527f554e5354414b45203a20496e73756666696369656e742042616c616e63650000604482015290519081900360640190fd5b6001600160a01b0386166000908152600d60205260409020600301805486908110613b4957fe5b60009182526020808320909101546040805163a9059cbb60e01b81526001600160a01b038b81166004830152602482018890529151919092169363a9059cbb93604480850194919392918390030190829087803b158015613ba957600080fd5b505af1158015613bbd573d6000803e3d6000fd5b505050506040513d6020811015613bd357600080fd5b50613be2905086868484614420565b6001600160a01b0386166000908152600d60205260409020600301805486908110613c0957fe5b60009182526020918290200154604080518581524293810193909352828101889052516001600160a01b0391821692918916917fa4b627609e711628747558b171b04b9636337afdadac065ee7113fb91eab0b72919081900360600190a3600193505050505b92915050565b600560208190526000918252604090912080546001820154600283015460038401546004850154949095015460ff8085169661010090950481169593949293911687565b600f6020526000908152604090205481565b600b5481565b613cd9613fc5565b6001546001600160a01b03908116911614613d29576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b6001600160a01b038116613d6e5760405162461bcd60e51b8152600401808060200182810382526026815260200180614f456026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000613dd4613fc5565b6001546001600160a01b03908116911614613e24576040805162461bcd60e51b81526020600482018190526024820152600080516020614fae833981519152604482015290519081900360640190fd5b8151835114613e6d576040805162461bcd60e51b815260206004820152601060248201526f496e76616c696420656c656d656e747360801b604482015290519081900360640190fd5b60005b83518160ff161015613fb55760056000858360ff1681518110613e8f57fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16613efc576040805162461bcd60e51b8152602060048201526012602482015271151bdad95b881a5cc81b9bdd08195e1a5cdd60721b604482015290519081900360640190fd5b6000838260ff1681518110613f0d57fe5b602002602001015111613f5f576040805162461bcd60e51b8152602060048201526015602482015274125b9d985b1a590814995dd85c9908105b5bdd5b9d605a1b604482015290519081900360640190fd5b828160ff1681518110613f6e57fe5b602002602001015160066000868460ff1681518110613f8957fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101613e70565b5060019392505050565b610e1081565b600060183610801590613fdc5750613fdc336119b7565b15613ff0575060131936013560601c6114c4565b50336114c4565b600061403983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506144d5565b9392505050565b6140486119cb565b614090576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6140c6613fc5565b604080516001600160a01b039092168252519081900360200190a1565b6000826140f257506000613c6f565b828202828482816140ff57fe5b04146140395760405162461bcd60e51b8152600401808060200182810382526021815260200180614f8d6021913960400191505060405180910390fd5b600061403983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614577565b600082820183811015614039576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6141e06119cb565b15614225576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586140c6613fc5565b6001600160a01b03821615613510576001600160a01b0382166000908152600660205260409020548111156142c75760405162461bcd60e51b8152600401808060200182810382526022815260200180614f6b6022913960400191505060405180910390fd5b6001600160a01b0382166000908152600660205260409020546142ea908261413c565b6001600160a01b03808416600081815260066020908152604080832095909555845163a9059cbb60e01b81529389166004850152602484018690529351919363a9059cbb936044808201949293918390030190829087803b15801561434e57600080fd5b505af1158015614362573d6000803e3d6000fd5b505050506040513d602081101561437857600080fd5b50516143bd576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b0316856001600160a01b03167fcd5e4f020ddad29434c2200a9edf2f8d7ec30f0d787f03b528ab7279aab0acbe8442604051808381526020018281526020019250505060405180910390a450505050565b60008061443a600a5460105461417e90919063ffffffff16565b91504282111561444b57504261445d565b600a5460105461445a9161417e565b90505b6001600160a01b0386166000908152600d6020526040902060060180546144a391908790811061448957fe5b90600052602060002001548261413c90919063ffffffff16565b91506144ad614f11565b84815260208101849052610e1083106144cc576144cc878783866145d1565b50505050505050565b600081836145615760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561452657818101518382015260200161450e565b50505050905090810190601f1680156145535780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161456d57fe5b0495945050505050565b600081848411156145c95760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561452657818101518382015260200161450e565b505050900390565b6000806145dc614f11565b6145e884610e10613ff7565b60208201526145fa8462015180613ff7565b815284516001600160a01b0388166000908152600d6020526040902060030180546146979261468c9290918a90811061462f57fe5b60009182526020808320909101546001600160a01b038d81168452600d909252604090922060030180549190921691908b90811061466957fe5b6000918252602090912001546001600160a01b03168960015b6020020151611648565b6020830151906140e3565b6001600160a01b0388166000908152600d6020526040812060020180549295509091889081106146c357fe5b6000918252602090912001546001600160a01b031614614918576146ff68056bc75e2d631000006116de600b54866140e390919063ffffffff16565b915061470b838361413c565b6001600160a01b0388166000908152600d602052604090206003018054919450908790811061473657fe5b60009182526020808320909101546001600160a01b038a81168452600d90925260409092206002018054919092169163a9059cbb918990811061477557fe5b6000918252602080832090910154604080516001600160e01b031960e087901b1681526001600160a01b039092166004830152602482018890525160448083019491928390030190829087803b1580156147ce57600080fd5b505af11580156147e2573d6000803e3d6000fd5b505050506040513d60208110156147f857600080fd5b50511515600114614842576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8811985a5b1959608a1b604482015290519081900360640190fd5b6001600160a01b0387166000908152600d6020526040902060030180548790811061486957fe5b6000918252602090912001546001600160a01b0316614886613fc5565b6001600160a01b0316600d60008a6001600160a01b03166001600160a01b0316815260200190815260200160002060020188815481106148c257fe5b6000918252602091829020015460408051878152429381019390935280516001600160a01b03909216927fcc30edb66a991e48ca3676c277d3a35485ebfaf3016fa9536663b2689c8f5eef929081900390910190a45b6001600160a01b0387166000908152600d60205260409020600301805461499a9189918990811061494557fe5b60009182526020808320909101546001600160a01b038c81168452600d909252604090922060030180549190921691908a90811061497f57fe5b6000918252602090912001546001600160a01b031686614261565b60015b60095460ff82161015614e675760098160ff16815481106149ba57fe5b600091825260209091200154825110614e5d576000614a086018614a02600160098660ff16815481106149e957fe5b906000526020600020015461413c90919063ffffffff16565b906140e3565b90506000614a1e8285600160200201519061413c565b9050600060046000600d60008e6001600160a01b03166001600160a01b031681526020019081526020016000206003018c81548110614a5957fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020805460ff8616908110614a8c57fe5b60009182526020808320909101546001600160a01b038e81168452600d909252604090922060030180549190921692508b908110614ac657fe5b6000918252602090912001546001600160a01b03828116911614801590614b4e57506001600160a01b038b166000908152600d60205260408120600301805460089291908d908110614b1457fe5b60009182526020808320909101546001600160a01b039081168452838201949094526040928301822093851682529290925290205460ff16155b15614e4f5788516001600160a01b038c166000908152600d602052604090206003018054614bab92614ba49290918e908110614b8657fe5b6000918252602090912001546001600160a01b0316848d6001614682565b83906140e3565b6001600160a01b038c166000908152600d60205260408120600201805492995090918c908110614bd757fe5b6000918252602090912001546001600160a01b031614614e0657614c1368056bc75e2d631000006116de600b548a6140e390919063ffffffff16565b9550614c1f878761413c565b9650806001600160a01b031663a9059cbb600d60008e6001600160a01b03166001600160a01b031681526020019081526020016000206002018c81548110614c6357fe5b6000918252602080832090910154604080516001600160e01b031960e087901b1681526001600160a01b039092166004830152602482018c90525160448083019491928390030190829087803b158015614cbc57600080fd5b505af1158015614cd0573d6000803e3d6000fd5b505050506040513d6020811015614ce657600080fd5b50511515600114614d30576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8811985a5b1959608a1b604482015290519081900360640190fd5b6001600160a01b038b166000908152600d6020526040902060030180548b908110614d5757fe5b6000918252602090912001546001600160a01b0316614d74613fc5565b6001600160a01b0316600d60008e6001600160a01b03166001600160a01b031681526020019081526020016000206002018c81548110614db057fe5b60009182526020918290200154604080518b8152429381019390935280516001600160a01b03909216927fcc30edb66a991e48ca3676c277d3a35485ebfaf3016fa9536663b2689c8f5eef929081900390910190a45b6001600160a01b038b166000908152600d602052604090206003018054614e4f918d918d908110614e3357fe5b6000918252602090912001546001600160a01b0316838a614261565b836001019350505050614e62565b614e67565b61499d565b5050505050505050565b828054828255906000526020600020908101928215614eac579160200282015b82811115614eac578251825591602001919060010190614e91565b50614eb8929150614f2f565b5090565b828054828255906000526020600020908101928215614eac579160200282015b82811115614eac57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614edc565b60405180604001604052806002906020820280368337509192915050565b5b80821115614eb85760008155600101614f3056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737353454e44203a20496e73756666696369656e74205265776172642042616c616e6365536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725354414b45203a204d617820416d6f756e742073686f756c642062652077697468696e207065726d69745354414b45203a204d696e20416d6f756e742073686f756c642062652077697468696e207065726d6974554e5354414b45203a20416c726561647920436c61696d656420286f722920496e73756666696369656e74205374616b6564454d455247454e4359203a20416c726561647920436c61696d656420286f722920496e73756666696369656e74205374616b6564a264697066735822122076c7fe17ab74a6f2bc65e1cc4ace360b5a67b50b88cd81f4c4185d84b71b527964736f6c63430007060033

Verified Source Code Partial Match

Compiler: v0.7.6+commit.7338295f EVM: istanbul Optimization: Yes (200 runs)
UnifarmV20.sol 1381 lines
// Sources flattened with hardhat v2.5.0 https://hardhat.org

// File contracts/forwarder/IRelayRecipient.sol

// SPDX-License-Identifier:MIT
pragma solidity ^0.7.6;

/**
 * a contract must implement this interface in order to support relayed transaction.
 * It is better to inherit the BaseRelayRecipient as its implementation.
 */
abstract contract IRelayRecipient {
    /**
     * return if the forwarder is trusted to forward relayed transactions to us.
     * the forwarder is required to verify the sender's signature, and verify
     * the call is not a replay.
     */
    function isTrustedForwarder(address forwarder)
        public
        view
        virtual
        returns (bool);

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, then the real sender is appended as the last 20 bytes
     * of the msg.data.
     * otherwise, return `msg.sender`
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender() internal view virtual returns (address payable);

    function versionRecipient() external view virtual returns (string memory);
}


// File contracts/forwarder/BaseRelayRecipient.sol

pragma solidity ^0.7.6;

/**
 * A base contract to be inherited by any contract that want to receive relayed transactions
 * A subclass must use "_msgSender()" instead of "msg.sender"
 */
abstract contract BaseRelayRecipient is IRelayRecipient {
    /*
     * Forwarder singleton we accept calls from
     */
    address public trustedForwarder;

    /*
     * require a function to be called through GSN only
     */
    modifier trustedForwarderOnly() {
        require(
            msg.sender == address(trustedForwarder),
            "Function can only be called through the trusted Forwarder"
        );
        _;
    }

    function isTrustedForwarder(address forwarder)
        public
        view
        override
        returns (bool)
    {
        return forwarder == trustedForwarder;
    }

    /**
     * return the sender of this call.
     * if the call came through our trusted forwarder, return the original sender.
     * otherwise, return `msg.sender`.
     * should be used in the contract anywhere instead of msg.sender
     */
    function _msgSender()
        internal
        view
        virtual
        override
        returns (address payable ret)
    {
        if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96, calldataload(sub(calldatasize(), 20)))
            }
        } else {
            return msg.sender;
        }
    }
}


// File contracts/abstract/Pausable.sol


pragma solidity >=0.6.0 <=0.8.0;

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */

abstract contract Pausable is BaseRelayRecipient {
  /**
   * @dev Emitted when the pause is triggered by `account`.
   */
  event Paused(address account);

  /**
   * @dev Emitted when the pause is lifted by `account`.
   */
  event Unpaused(address account);

  bool private _paused;

  /**
   * @dev Initializes the contract in unpaused state.
   */
  constructor() {
    _paused = false;
  }

  /**
   * @dev Returns true if the contract is paused, and false otherwise.
   */
  function paused() public view virtual returns (bool) {
    return _paused;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   *
   * Requirements:
   *
   * - The contract must not be paused.
   */
  modifier whenNotPaused() {
    require(!paused(), "Pausable: paused");
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   *
   * Requirements:
   *
   * - The contract must be paused.
   */
  modifier whenPaused() {
    require(paused(), "Pausable: not paused");
    _;
  }

  /**
   * @dev Triggers stopped state.
   *
   * Requirements:
   *
   * - The contract must not be paused.
   */
  function _pause() internal virtual whenNotPaused {
    _paused = true;
    emit Paused(_msgSender());
  }

  /**
   * @dev Returns to normal state.
   *
   * Requirements:
   *
   * - The contract must be paused.
   */
  function _unpause() internal virtual whenPaused {
    _paused = false;
    emit Unpaused(_msgSender());
  }
}


// File contracts/abstract/Ownable.sol


pragma solidity >=0.6.0 <=0.8.0;

abstract contract Ownable is Pausable {
    address public _owner;
    address public _admin;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor(address ownerAddress) {
        _owner = _msgSender();
        _admin = ownerAddress;
        emit OwnershipTransferred(address(0), _owner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyAdmin() {
        require(_admin == _msgSender(), "Ownable: caller is not the Admin");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyAdmin {
        emit OwnershipTransferred(_owner, _admin);
        _owner = _admin;
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}


// File contracts/libraries/SafeMath.sol


pragma solidity ^0.7.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */

library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}


// File contracts/interfaces/IERC20.sol


pragma solidity ^0.7.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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
    );
}


// File contracts/abstract/Admin.sol

pragma solidity ^0.7.0;



abstract contract Admin is Ownable {
  struct tokenInfo {
    bool isExist;
    uint8 decimal;
    uint256 userMinStake;
    uint256 userMaxStake;
    uint256 totalMaxStake;
    uint256 lockableDays;
    bool optionableStatus;
  }

  using SafeMath for uint256;
  address[] public tokens;
  mapping(address => address[]) public tokensSequenceList;
  mapping(address => tokenInfo) public tokenDetails;
  mapping(address => uint256) public rewardCap;
  mapping(address => mapping(address => uint256)) public tokenDailyDistribution;
  mapping(address => mapping(address => bool)) public tokenBlockedStatus;
  uint256[] public intervalDays = [1, 8, 15, 22];
  uint256 public constant DAYS = 1 days;
  uint256 public constant HOURS = 1 hours;
  uint256 public stakeDuration;
  uint256 public refPercentage;
  uint256 public optionableBenefit;

  event TokenDetails(
    address indexed tokenAddress,
    uint256 userMinStake,
    uint256 userMaxStake,
    uint256 totalMaxStake,
    uint256 updatedTime
  );

  event LockableTokenDetails(
    address indexed tokenAddress,
    uint256 lockableDys,
    bool optionalbleStatus,
    uint256 updatedTime
  );

  event DailyDistributionDetails(
    address indexed stakedTokenAddress,
    address indexed rewardTokenAddress,
    uint256 rewards,
    uint256 time
  );

  event SequenceDetails(
    address indexed stakedTokenAddress,
    address[] rewardTokenSequence,
    uint256 time
  );

  event StakeDurationDetails(uint256 updatedDuration, uint256 time);
  event OptionableBenefitDetails(uint256 updatedBenefit, uint256 time);
  event ReferrerPercentageDetails(uint256 updatedRefPercentage, uint256 time);
  event IntervalDaysDetails(uint256[] updatedIntervals, uint256 time);

  event BlockedDetails(
    address indexed stakedTokenAddress,
    address indexed rewardTokenAddress,
    bool blockedStatus,
    uint256 time
  );

  event WithdrawDetails(
    address indexed tokenAddress,
    uint256 withdrawalAmount,
    uint256 time
  );

  constructor(address _owner) Ownable(_owner) {
    stakeDuration = 90 days;
    refPercentage = 2500000000000000000;
    optionableBenefit = 2;
  }

  function addToken(
    address tokenAddress,
    uint256 userMinStake,
    uint256 userMaxStake,
    uint256 totalStake,
    uint8 decimal
  ) public onlyOwner returns (bool) {
    if (!(tokenDetails[tokenAddress].isExist)) tokens.push(tokenAddress);

    tokenDetails[tokenAddress].isExist = true;
    tokenDetails[tokenAddress].decimal = decimal;
    tokenDetails[tokenAddress].userMinStake = userMinStake;
    tokenDetails[tokenAddress].userMaxStake = userMaxStake;
    tokenDetails[tokenAddress].totalMaxStake = totalStake;

    emit TokenDetails(
      tokenAddress,
      userMinStake,
      userMaxStake,
      totalStake,
      block.timestamp
    );
    return true;
  }

  function setDailyDistribution(
    address[] memory stakedToken,
    address[] memory rewardToken,
    uint256[] memory dailyDistribution
  ) public onlyOwner {
    require(
      stakedToken.length == rewardToken.length &&
        rewardToken.length == dailyDistribution.length,
      "Invalid Input"
    );

    for (uint8 i = 0; i < stakedToken.length; i++) {
      require(
        tokenDetails[stakedToken[i]].isExist &&
          tokenDetails[rewardToken[i]].isExist,
        "Token not exist"
      );
      tokenDailyDistribution[stakedToken[i]][
        rewardToken[i]
      ] = dailyDistribution[i];

      emit DailyDistributionDetails(
        stakedToken[i],
        rewardToken[i],
        dailyDistribution[i],
        block.timestamp
      );
    }
  }

  function updateSequence(
    address stakedToken,
    address[] memory rewardTokenSequence
  ) public onlyOwner {
    tokensSequenceList[stakedToken] = new address[](0);
    require(tokenDetails[stakedToken].isExist, "Staked Token Not Exist");
    for (uint8 i = 0; i < rewardTokenSequence.length; i++) {
      require(rewardTokenSequence.length <= tokens.length, "Invalid Input");
      require(
        tokenDetails[rewardTokenSequence[i]].isExist,
        "Reward Token Not Exist"
      );
      tokensSequenceList[stakedToken].push(rewardTokenSequence[i]);
    }

    emit SequenceDetails(
      stakedToken,
      tokensSequenceList[stakedToken],
      block.timestamp
    );
  }

  function updateToken(
    address tokenAddress,
    uint256 userMinStake,
    uint256 userMaxStake,
    uint256 totalStake
  ) public onlyOwner {
    require(tokenDetails[tokenAddress].isExist, "Token Not Exist");
    tokenDetails[tokenAddress].userMinStake = userMinStake;
    tokenDetails[tokenAddress].userMaxStake = userMaxStake;
    tokenDetails[tokenAddress].totalMaxStake = totalStake;

    emit TokenDetails(
      tokenAddress,
      userMinStake,
      userMaxStake,
      totalStake,
      block.timestamp
    );
  }

  function lockableToken(
    address tokenAddress,
    uint8 lockableStatus,
    uint256 lockedDays,
    bool optionableStatus
  ) public onlyOwner {
    require(
      lockableStatus == 1 || lockableStatus == 2 || lockableStatus == 3,
      "Invalid Lockable Status"
    );
    require(tokenDetails[tokenAddress].isExist == true, "Token Not Exist");

    if (lockableStatus == 1) {
      tokenDetails[tokenAddress].lockableDays = block.timestamp.add(lockedDays);
    } else if (lockableStatus == 2) tokenDetails[tokenAddress].lockableDays = 0;
    else if (lockableStatus == 3)
      tokenDetails[tokenAddress].optionableStatus = optionableStatus;

    emit LockableTokenDetails(
      tokenAddress,
      tokenDetails[tokenAddress].lockableDays,
      tokenDetails[tokenAddress].optionableStatus,
      block.timestamp
    );
  }

  function updateStakeDuration(uint256 durationTime) public onlyOwner {
    stakeDuration = durationTime;

    emit StakeDurationDetails(stakeDuration, block.timestamp);
  }

  function updateOptionableBenefit(uint256 benefit) public onlyOwner {
    optionableBenefit = benefit;

    emit OptionableBenefitDetails(optionableBenefit, block.timestamp);
  }

  function updateRefPercentage(uint256 refPer) public onlyOwner {
    refPercentage = refPer;
    emit ReferrerPercentageDetails(refPercentage, block.timestamp);
  }

  function updateIntervalDays(uint256[] memory _interval) public onlyOwner {
    intervalDays = new uint256[](0);

    for (uint8 i = 0; i < _interval.length; i++) {
      uint256 noD = stakeDuration.div(DAYS);
      require(noD > _interval[i], "Invalid Interval Day");
      intervalDays.push(_interval[i]);
    }

    emit IntervalDaysDetails(intervalDays, block.timestamp);
  }

  function changeTokenBlockedStatus(
    address stakedToken,
    address rewardToken,
    bool status
  ) public onlyOwner {
    require(
      tokenDetails[stakedToken].isExist && tokenDetails[rewardToken].isExist,
      "Token not exist"
    );
    tokenBlockedStatus[stakedToken][rewardToken] = status;

    emit BlockedDetails(
      stakedToken,
      rewardToken,
      tokenBlockedStatus[stakedToken][rewardToken],
      block.timestamp
    );
  }

  function safeWithdraw(address tokenAddress, uint256 amount) public onlyOwner {
    require(
      IERC20(tokenAddress).balanceOf(address(this)) >= amount,
      "Insufficient Balance"
    );
    require(IERC20(tokenAddress).transfer(_owner, amount), "Transfer failed");
    emit WithdrawDetails(tokenAddress, amount, block.timestamp);
  }

  function viewTokensCount() external view returns (uint256) {
    return tokens.length;
  }

  function setRewardCap(
    address[] memory tokenAddresses,
    uint256[] memory rewards
  ) external onlyOwner returns (bool) {
    require(tokenAddresses.length == rewards.length, "Invalid elements");
    for (uint8 v = 0; v < tokenAddresses.length; v++) {
      require(tokenDetails[tokenAddresses[v]].isExist, "Token is not exist");
      require(rewards[v] > 0, "Invalid Reward Amount");
      rewardCap[tokenAddresses[v]] = rewards[v];
    }
    return true;
  }
}


// File contracts/UnifarmV20.sol

pragma solidity ^0.7.6;

/**
 * @title Unifarm Contract
 * @author OroPocket
 */

contract UnifarmV20 is Admin {
    // Wrappers over Solidity's arithmetic operations
    using SafeMath for uint256;

    // Stores Stake Details
    struct stakeInfo {
        address user;
        bool[] isActive;
        address[] referrer;
        address[] tokenAddress;
        uint256[] stakeId;
        uint256[] stakedAmount;
        uint256[] startTime;
    }

    // Mapping
    mapping(address => stakeInfo) public stakingDetails;
    mapping(address => mapping(address => uint256)) public userTotalStaking;
    mapping(address => uint256) public totalStaking;
    uint256 public poolStartTime;

    // Events
    event Stake(
        address indexed userAddress,
        uint256 stakeId,
        address indexed referrerAddress,
        address indexed tokenAddress,
        uint256 stakedAmount,
        uint256 time
    );

    event Claim(
        address indexed userAddress,
        address indexed stakedTokenAddress,
        address indexed tokenAddress,
        uint256 claimRewards,
        uint256 time
    );

    event UnStake(
        address indexed userAddress,
        address indexed unStakedtokenAddress,
        uint256 unStakedAmount,
        uint256 time,
        uint256 stakeId
    );

    event ReferralEarn(
        address indexed userAddress,
        address indexed callerAddress,
        address indexed rewardTokenAddress,
        uint256 rewardAmount,
        uint256 time
    );

    constructor(address _trustedForwarder) Admin(_msgSender()) {
        poolStartTime = block.timestamp;
        trustedForwarder = _trustedForwarder;
    }

    /**
     * @notice Stake tokens to earn rewards
     * @param tokenAddress Staking token address
     * @param amount Amount of tokens to be staked
     */

    function stake(
        address referrerAddress,
        address tokenAddress,
        uint256 amount
    ) external whenNotPaused {
        // checks
        require(
            _msgSender() != referrerAddress,
            "STAKE: invalid referrer address"
        );
        require(
            tokenDetails[tokenAddress].isExist,
            "STAKE : Token is not Exist"
        );
        require(
            userTotalStaking[_msgSender()][tokenAddress].add(amount) >=
                tokenDetails[tokenAddress].userMinStake,
            "STAKE : Min Amount should be within permit"
        );
        require(
            userTotalStaking[_msgSender()][tokenAddress].add(amount) <=
                tokenDetails[tokenAddress].userMaxStake,
            "STAKE : Max Amount should be within permit"
        );
        require(
            totalStaking[tokenAddress].add(amount) <=
                tokenDetails[tokenAddress].totalMaxStake,
            "STAKE : Maxlimit exceeds"
        );

        require(
            poolStartTime.add(stakeDuration) > block.timestamp,
            "STAKE: Staking Time Completed"
        );

        // Storing stake details
        stakingDetails[_msgSender()].stakeId.push(
            stakingDetails[_msgSender()].stakeId.length
        );
        stakingDetails[_msgSender()].isActive.push(true);
        stakingDetails[_msgSender()].user = _msgSender();
        stakingDetails[_msgSender()].referrer.push(referrerAddress);
        stakingDetails[_msgSender()].tokenAddress.push(tokenAddress);
        stakingDetails[_msgSender()].startTime.push(block.timestamp);

        // Update total staking amount
        stakingDetails[_msgSender()].stakedAmount.push(amount);
        totalStaking[tokenAddress] = totalStaking[tokenAddress].add(amount);
        userTotalStaking[_msgSender()][tokenAddress] = userTotalStaking[
            _msgSender()
        ][tokenAddress].add(amount);

        // Transfer tokens from user to contract
        require(
            IERC20(tokenAddress).transferFrom(
                _msgSender(),
                address(this),
                amount
            ),
            "Transfer Failed"
        );

        // Emit state changes
        emit Stake(
            _msgSender(),
            (stakingDetails[_msgSender()].stakeId.length.sub(1)),
            referrerAddress,
            tokenAddress,
            amount,
            block.timestamp
        );
    }

    /**
     * @notice Claim accumulated rewards
     * @param stakeId Stake ID of the user
     * @param stakedAmount Staked amount of the user
     */

    function claimRewards(
        address userAddress,
        uint256 stakeId,
        uint256 stakedAmount,
        uint256 totalStake
    ) internal {
        // Local variables
        uint256 interval;
        uint256 endOfProfit;

        interval = poolStartTime.add(stakeDuration);

        // Interval calculation
        if (interval > block.timestamp) endOfProfit = block.timestamp;
        else endOfProfit = poolStartTime.add(stakeDuration);

        interval = endOfProfit.sub(
            stakingDetails[userAddress].startTime[stakeId]
        );
        uint256[2] memory stakeData;
        stakeData[0] = (stakedAmount);
        stakeData[1] = (totalStake);

        // Reward calculation
        if (interval >= HOURS)
            _rewardCalculation(userAddress, stakeId, stakeData, interval);
    }

    function _rewardCalculation(
        address userAddress,
        uint256 stakeId,
        uint256[2] memory stakingData,
        uint256 interval
    ) internal {
        uint256 rewardsEarned;
        uint256 refEarned;
        uint256[2] memory noOfDays;

        noOfDays[1] = interval.div(HOURS);
        noOfDays[0] = interval.div(DAYS);

        rewardsEarned = noOfDays[1].mul(
            getOneDayReward(
                stakingData[0],
                stakingDetails[userAddress].tokenAddress[stakeId],
                stakingDetails[userAddress].tokenAddress[stakeId],
                stakingData[1]
            )
        );

        // Referrer Earning
        if (stakingDetails[userAddress].referrer[stakeId] != address(0)) {
            refEarned = (rewardsEarned.mul(refPercentage)).div(100 ether);
            rewardsEarned = rewardsEarned.sub(refEarned);

            require(
                IERC20(stakingDetails[userAddress].tokenAddress[stakeId])
                    .transfer(
                        stakingDetails[userAddress].referrer[stakeId],
                        refEarned
                    ) == true,
                "Transfer Failed"
            );

            emit ReferralEarn(
                stakingDetails[userAddress].referrer[stakeId],
                _msgSender(),
                stakingDetails[userAddress].tokenAddress[stakeId],
                refEarned,
                block.timestamp
            );
        }

        //  Rewards Send
        sendToken(
            userAddress,
            stakingDetails[userAddress].tokenAddress[stakeId],
            stakingDetails[userAddress].tokenAddress[stakeId],
            rewardsEarned
        );

        uint8 i = 1;

        while (i < intervalDays.length) {
            if (noOfDays[0] >= intervalDays[i]) {
                uint256 reductionHours = (intervalDays[i].sub(1)).mul(24);
                uint256 balHours = noOfDays[1].sub(reductionHours);

                address rewardToken = tokensSequenceList[
                    stakingDetails[userAddress].tokenAddress[stakeId]
                ][i];

                if (
                    rewardToken !=
                    stakingDetails[userAddress].tokenAddress[stakeId] &&
                    tokenBlockedStatus[
                        stakingDetails[userAddress].tokenAddress[stakeId]
                    ][rewardToken] ==
                    false
                ) {
                    rewardsEarned = balHours.mul(
                        getOneDayReward(
                            stakingData[0],
                            stakingDetails[userAddress].tokenAddress[stakeId],
                            rewardToken,
                            stakingData[1]
                        )
                    );

                    // Referrer Earning

                    if (
                        stakingDetails[userAddress].referrer[stakeId] !=
                        address(0)
                    ) {
                        refEarned = (rewardsEarned.mul(refPercentage)).div(
                            100 ether
                        );
                        rewardsEarned = rewardsEarned.sub(refEarned);

                        require(
                            IERC20(rewardToken).transfer(
                                stakingDetails[userAddress].referrer[stakeId],
                                refEarned
                            ) == true,
                            "Transfer Failed"
                        );

                        emit ReferralEarn(
                            stakingDetails[userAddress].referrer[stakeId],
                            _msgSender(),
                            stakingDetails[userAddress].tokenAddress[stakeId],
                            refEarned,
                            block.timestamp
                        );
                    }

                    //  Rewards Send
                    sendToken(
                        userAddress,
                        stakingDetails[userAddress].tokenAddress[stakeId],
                        rewardToken,
                        rewardsEarned
                    );
                }
                i = i + 1;
            } else {
                break;
            }
        }
    }

    /**
     * @notice Get rewards for one day
     * @param stakedAmount Stake amount of the user
     * @param stakedToken Staked token address of the user
     * @param rewardToken Reward token address
     * @return reward One dayh reward for the user
     */

    function getOneDayReward(
        uint256 stakedAmount,
        address stakedToken,
        address rewardToken,
        uint256 totalStake
    ) public view returns (uint256 reward) {
        uint256 lockBenefit;

        if (tokenDetails[stakedToken].optionableStatus) {
            stakedAmount = stakedAmount.mul(optionableBenefit);
            lockBenefit = stakedAmount.mul(optionableBenefit.sub(1));
            reward = (
                stakedAmount.mul(
                    tokenDailyDistribution[stakedToken][rewardToken]
                )
            ).div(totalStake.add(lockBenefit));
        } else {
            reward = (
                stakedAmount.mul(
                    tokenDailyDistribution[stakedToken][rewardToken]
                )
            ).div(totalStake);
        }
    }

    /**
     * @notice Get rewards for one day
     * @param stakedToken Stake amount of the user
     * @param tokenAddress Reward token address
     * @param amount Amount to be transferred as reward
     */
    function sendToken(
        address userAddress,
        address stakedToken,
        address tokenAddress,
        uint256 amount
    ) internal {
        // Checks
        if (tokenAddress != address(0)) {
            require(
                rewardCap[tokenAddress] >= amount,
                "SEND : Insufficient Reward Balance"
            );
            // Transfer of rewards
            rewardCap[tokenAddress] = rewardCap[tokenAddress].sub(amount);

            require(
                IERC20(tokenAddress).transfer(userAddress, amount),
                "Transfer failed"
            );

            // Emit state changes
            emit Claim(
                userAddress,
                stakedToken,
                tokenAddress,
                amount,
                block.timestamp
            );
        }
    }

    /**
     * @notice Unstake and claim rewards
     * @param stakeId Stake ID of the user
     */
    function unStake(address userAddress, uint256 stakeId)
        external
        whenNotPaused
        returns (bool)
    {
        require(
            _msgSender() == userAddress || _msgSender() == _owner,
            "UNSTAKE: Invalid User Entry"
        );

        address stakedToken = stakingDetails[userAddress].tokenAddress[stakeId];

        // lockableDays check
        require(
            tokenDetails[stakedToken].lockableDays <= block.timestamp,
            "UNSTAKE: Token Locked"
        );

        // optional lock check
        if (tokenDetails[stakedToken].optionableStatus)
            require(
                stakingDetails[userAddress].startTime[stakeId].add(
                    stakeDuration
                ) <= block.timestamp,
                "UNSTAKE: Locked in optional lock"
            );

        // Checks
        require(
            stakingDetails[userAddress].stakedAmount[stakeId] > 0 ||
                stakingDetails[userAddress].isActive[stakeId] == true,
            "UNSTAKE : Already Claimed (or) Insufficient Staked"
        );

        // State updation
        uint256 stakedAmount = stakingDetails[userAddress].stakedAmount[
            stakeId
        ];
        uint256 totalStaking1 = totalStaking[stakedToken];

        stakingDetails[userAddress].stakedAmount[stakeId] = 0;
        stakingDetails[userAddress].isActive[stakeId] = false;

        // Balance check
        require(
            IERC20(stakingDetails[userAddress].tokenAddress[stakeId]).balanceOf(
                address(this)
            ) >= stakedAmount,
            "UNSTAKE : Insufficient Balance"
        );

        // Transfer staked token back to user
        IERC20(stakingDetails[userAddress].tokenAddress[stakeId]).transfer(
            userAddress,
            stakedAmount
        );

        claimRewards(userAddress, stakeId, stakedAmount, totalStaking1);

        // Emit state changes
        emit UnStake(
            userAddress,
            stakingDetails[userAddress].tokenAddress[stakeId],
            stakedAmount,
            block.timestamp,
            stakeId
        );

        return true;
    }

    function emergencyUnstake(
        uint256 stakeId,
        address userAddress,
        address[] memory rewardtokens,
        uint256[] memory amount
    ) external onlyOwner {
        // Checks
        require(
            stakingDetails[userAddress].stakedAmount[stakeId] > 0 &&
                stakingDetails[userAddress].isActive[stakeId] == true,
            "EMERGENCY : Already Claimed (or) Insufficient Staked"
        );

        // Balance check
        require(
            IERC20(stakingDetails[userAddress].tokenAddress[stakeId]).balanceOf(
                address(this)
            ) >= stakingDetails[userAddress].stakedAmount[stakeId],
            "EMERGENCY : Insufficient Balance"
        );

        uint256 stakeAmount = stakingDetails[userAddress].stakedAmount[stakeId];
        stakingDetails[userAddress].isActive[stakeId] = false;
        stakingDetails[userAddress].stakedAmount[stakeId] = 0;

        IERC20(stakingDetails[userAddress].tokenAddress[stakeId]).transfer(
            userAddress,
            stakeAmount
        );

        for (uint256 i; i < rewardtokens.length; i++) {
            uint256 rewardsEarned = amount[i];

            if (stakingDetails[userAddress].referrer[stakeId] != address(0)) {
                uint256 refEarned = (rewardsEarned.mul(refPercentage)).div(
                    100 ether
                );
                rewardsEarned = rewardsEarned.sub(refEarned);

                require(
                    IERC20(rewardtokens[i]).transfer(
                        stakingDetails[userAddress].referrer[stakeId],
                        refEarned
                    ),
                    "EMERGENCY : Transfer Failed"
                );

                emit ReferralEarn(
                    stakingDetails[userAddress].referrer[stakeId],
                    userAddress,
                    rewardtokens[i],
                    refEarned,
                    block.timestamp
                );
            }

            sendToken(
                userAddress,
                stakingDetails[userAddress].tokenAddress[stakeId],
                rewardtokens[i],
                rewardsEarned
            );
        }

        // Emit state changes
        emit UnStake(
            userAddress,
            stakingDetails[userAddress].tokenAddress[stakeId],
            stakeAmount,
            block.timestamp,
            stakeId
        );
    }

    /**
     * @notice View staking details
     * @param _user User address
     */
    function viewStakingDetails(address _user)
        public
        view
        returns (
            address[] memory,
            address[] memory,
            bool[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory
        )
    {
        return (
            stakingDetails[_user].referrer,
            stakingDetails[_user].tokenAddress,
            stakingDetails[_user].isActive,
            stakingDetails[_user].stakeId,
            stakingDetails[_user].stakedAmount,
            stakingDetails[_user].startTime
        );
    }

    /**
     * Override this function.
     * This version is to keep track of BaseRelayRecipient you are using
     * in your contract.
     */
    function versionRecipient() external pure override returns (string memory) {
        return "1";
    }

    function updateTrustForwarder(address _newTrustForwarder)
        external
        onlyOwner
    {
        trustedForwarder = _newTrustForwarder;
    }

    function pause() external onlyOwner returns (bool) {
        _pause();
        return true;
    }

    function unpause() external onlyOwner returns (bool) {
        _unpause();
        return true;
    }
}

Read Contract

DAYS 0xc549e6b9 → uint256
HOURS 0xfbfcd241 → uint256
_admin 0x01bc45c9 → address
_owner 0xb2bdfa7b → address
getOneDayReward 0x4cd36531 → uint256
intervalDays 0xb104e006 → uint256
isTrustedForwarder 0x572b6c05 → bool
optionableBenefit 0x04a624c6 → uint256
paused 0x5c975abb → bool
poolStartTime 0x5f96dc11 → uint256
refPercentage 0xe5c46869 → uint256
rewardCap 0x7bdb8cd3 → uint256
stakeDuration 0x40f02ab6 → uint256
stakingDetails 0xa019cb4b → address
tokenBlockedStatus 0x28523eb6 → bool
tokenDailyDistribution 0x187739a4 → uint256
tokenDetails 0xdd4be683 → bool, uint8, uint256, uint256, uint256, uint256, bool
tokens 0x4f64b2be → address
tokensSequenceList 0x539cd3b4 → address
totalStaking 0xe0a79b16 → uint256
trustedForwarder 0x7da0a877 → address
userTotalStaking 0x1320da8b → uint256
versionRecipient 0x486ff0cd → string
viewStakingDetails 0x26fa24e9 → address[], address[], bool[], uint256[], uint256[], uint256[]
viewTokensCount 0x85d895ef → uint256

Write Contract 20 functions

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

addToken 0x40a16688
address tokenAddress
uint256 userMinStake
uint256 userMaxStake
uint256 totalStake
uint8 decimal
returns: bool
changeTokenBlockedStatus 0xcdd033c8
address stakedToken
address rewardToken
bool status
emergencyUnstake 0xc922e937
uint256 stakeId
address userAddress
address[] rewardtokens
uint256[] amount
lockableToken 0xd4313506
address tokenAddress
uint8 lockableStatus
uint256 lockedDays
bool optionableStatus
pause 0x8456cb59
No parameters
returns: bool
renounceOwnership 0x715018a6
No parameters
safeWithdraw 0x5058c460
address tokenAddress
uint256 amount
setDailyDistribution 0xd43c9535
address[] stakedToken
address[] rewardToken
uint256[] dailyDistribution
setRewardCap 0xf94e5c88
address[] tokenAddresses
uint256[] rewards
returns: bool
stake 0xbf6eac2f
address referrerAddress
address tokenAddress
uint256 amount
transferOwnership 0xf2fde38b
address newOwner
unStake 0xd9393814
address userAddress
uint256 stakeId
returns: bool
unpause 0x3f4ba83a
No parameters
returns: bool
updateIntervalDays 0x01193ad7
uint256[] _interval
updateOptionableBenefit 0x96591e31
uint256 benefit
updateRefPercentage 0x1d2002e7
uint256 refPer
updateSequence 0xa4f3f0e5
address stakedToken
address[] rewardTokenSequence
updateStakeDuration 0x88125f79
uint256 durationTime
updateToken 0xd768779a
address tokenAddress
uint256 userMinStake
uint256 userMaxStake
uint256 totalStake
updateTrustForwarder 0xd0cd4ee0
address _newTrustForwarder

Recent Transactions

No transactions found for this address