Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x07E6F2239d6FbE2CE00747fCFb8344ebBf973BcC
Balance 0 ETH
Nonce 1
Code Size 21850 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

21850 bytes
0x608060405234801561001057600080fd5b50600436106105a15760003560e01c806384d3d586116102ed578063d55111c511610191578063f0d33cad116100ee578063f384fe76116100a2578063fb68d53b1161007c578063fb68d53b14610f99578063fe1686b814610fd3578063fe31b2281461100d57600080fd5b8063f384fe7614610f30578063f91159e314610f50578063fad68d1f14610f7957600080fd5b8063f16b41f4116100d3578063f16b41f414610e2a578063f19d684914610ef4578063f2760e9d14610f0757600080fd5b8063f0d33cad14610deb578063f0f4426014610e1757600080fd5b8063e519cf1711610145578063ec6401531161012a578063ec64015314610da2578063f02842a514610db5578063f02d4a4514610dd857600080fd5b8063e519cf1714610d59578063ea425a6d14610d8257600080fd5b8063dad775b111610176578063dad775b114610d0a578063dd2a8b1114610d1d578063e37d47e414610d4657600080fd5b8063d55111c514610cd7578063d6b9243414610cea57600080fd5b8063b54b9c881161024a578063bf811fbc116101fe578063c706fee5116101d8578063c706fee514610c88578063cf717c8c14610cb1578063cfb656a514610cc457600080fd5b8063bf811fbc14610c2c578063c39ccf8814610c3f578063c5ebc2f714610c6857600080fd5b8063ba5771481161022f578063ba57714814610bf3578063beb8314c14610c06578063bf7e214f14610c1957600080fd5b8063b54b9c8814610bb0578063b6740c3b14610bd057600080fd5b80639bfd8d61116102a1578063a55dfa1c11610286578063a55dfa1c14610b77578063a9b2940714610b8a578063aaa78db414610b9d57600080fd5b80639bfd8d6114610b44578063a13d507914610b6457600080fd5b806389d5e38a116102d257806389d5e38a14610b0b578063911ddf0a14610b1e57806396ce362714610b3157600080fd5b806384d3d58614610ad857806387eebaea14610af857600080fd5b80634715f40c116104545780635a5392be116103b157806372aa9d91116103655780637b16c5431161033f5780637b16c54314610a7a5780637bf7f3d314610aa55780637cbfd14414610ab857600080fd5b806372aa9d9114610a3457806378e2816b14610a545780637a9e5e4b14610a6757600080fd5b80635dfa4596116103965780635dfa4596146109d657806361d027b314610a015780636e3c115414610a1457600080fd5b80635a5392be146109a05780635cd3667e146109c357600080fd5b80635385689c116104085780635722dee0116103ed5780635722dee014610931578063580e26a11461095a57806359b0e5901461097d57600080fd5b80635385689c146108e6578063546f2b661461091157600080fd5b80634a912ce5116104395780634a912ce5146108785780634e781513146108ab5780635328c2bf146108be57600080fd5b80634715f40c1461083c5780634774dc931461086557600080fd5b80632bcf161c116105025780633d0132e7116104b6578063404d221a1161049b578063404d221a14610803578063441a3e70146108165780634477c9741461082957600080fd5b80633d0132e7146107a85780633dc60a70146107f057600080fd5b806338c26d18116104e757806338c26d181461072d5780633a46a46d146107655780633ae5713d1461078557600080fd5b80632bcf161c146106f1578063336cada81461071a57600080fd5b8063171f9ce4116105595780631c5122d91161053e5780631c5122d9146106955780631e78e9a2146106be5780631f6514db146106de57600080fd5b8063171f9ce41461065f57806319720be11461067257600080fd5b80630962ef791161058a5780630962ef79146105fe57806310b1843814610613578063151a63491461063657600080fd5b80630399be55146105a657806306811c92146105d0575b600080fd5b6105b96105b4366004615030565b61102d565b6040516105c7929190615097565b60405180910390f35b6105f06105de3660046150c5565b60076020526000908152604090205481565b6040519081526020016105c7565b61061161060c3660046150e9565b611409565b005b6105f06106213660046150e9565b60009081526003602052604090206007015490565b6105f06106443660046150c5565b6001600160a01b031660009081526011602052604090205490565b61061161066d366004615102565b611765565b6105f06106803660046150e9565b60009081526003602052604090206005015490565b6105f06106a33660046150c5565b6001600160a01b031660009081526007602052604090205490565b6105f06106cc3660046150c5565b600a6020526000908152604090205481565b6106116106ec366004615102565b6117f7565b6105f06106ff3660046150c5565b6001600160a01b03166000908152600f602052604090205490565b610611610728366004615102565b611889565b61075361073b3660046150e9565b60009081526003602052604090206008015460ff1690565b60405160ff90911681526020016105c7565b6105f06107733660046150c5565b600b6020526000908152604090205481565b6107536107933660046150c5565b600c6020526000908152604090205460ff1681565b6107bb6107b6366004615030565b61191b565b60408051968752602087019590955260ff909316938501939093526060840152608083019190915260a082015260c0016105c7565b6105f06107fe366004615030565b611984565b610611610811366004615102565b611b79565b610611610824366004615132565b611c0b565b6106116108373660046150e9565b61236d565b6105f061084a3660046150c5565b6001600160a01b031660009081526009602052604090205490565b6105f0610873366004615163565b6125ec565b61089b6108863660046150e9565b60156020526000908152604090205460ff1681565b60405190151581526020016105c7565b6106116108b9366004615132565b612ca6565b6108d16108cc3660046150e9565b6134c9565b604080519283526020830191909152016105c7565b6019546108f9906001600160a01b031681565b6040516001600160a01b0390911681526020016105c7565b6105f061091f3660046150c5565b60096020526000908152604090205481565b6105f061093f3660046150c5565b6001600160a01b031660009081526008602052604090205490565b61089b6109683660046150c5565b60046020526000908152604090205460ff1681565b6105f061098b3660046150e9565b60009081526003602052604090206004015490565b6105f06109ae3660046150e9565b60009081526003602052604090206002015490565b6106116109d1366004615132565b613500565b6105f06109e43660046151a5565b600e60209081526000928352604080842090915290825290205481565b601a546108f9906001600160a01b031681565b6105f0610a223660046150e9565b60009081526013602052604090205490565b6105f0610a423660046150c5565b60056020526000908152604090205481565b610611610a623660046150c5565b61351a565b610611610a753660046150c5565b6135c2565b6105f0610a883660046151a5565b601060209081526000928352604080842090915290825290205481565b610611610ab33660046151e1565b61361e565b6105f0610ac63660046150c5565b60116020526000908152604090205481565b6105f0610ae63660046150c5565b60126020526000908152604090205481565b610611610b06366004615132565b613678565b6105f0610b193660046150c5565b61368b565b610611610b2c36600461520f565b6136e6565b610611610b3f366004615030565b613b6b565b6105f0610b523660046150c5565b600d6020526000908152604090205481565b610611610b72366004615102565b613c4a565b6105f0610b853660046150e9565b613cdc565b6017546108f9906001600160a01b031681565b610611610bab36600461526d565b613d3e565b6105f0610bbe3660046150c5565b60086020526000908152604090205481565b6105f0610bde3660046150e9565b60009081526003602052604090206009015490565b6105f0610c01366004615030565b613d66565b6105f0610c14366004615030565b613d97565b6000546108f9906001600160a01b031681565b610611610c3a3660046150c5565b613f02565b6105f0610c4d3660046150c5565b6001600160a01b031660009081526005602052604090205490565b610c7b610c763660046150c5565b613faa565b6040516105c79190615292565b6105f0610c963660046150c5565b6001600160a01b03166000908152600b602052604090205490565b610611610cbf366004615102565b614016565b610611610cd23660046150c5565b614136565b6018546108f9906001600160a01b031681565b6105f0610cf83660046150c5565b60146020526000908152604090205481565b610611610d18366004615102565b6141de565b6105f0610d2b3660046150c5565b6001600160a01b03166000908152600d602052604090205490565b610611610d54366004615102565b614270565b6105f0610d673660046150c5565b6001600160a01b03166000908152600a602052604090205490565b6105f0610d903660046150c5565b60066020526000908152604090205481565b6105f0610db0366004615030565b614302565b61089b610dc33660046150e9565b60009081526015602052604090205460ff1690565b6105b9610de63660046150c5565b61435f565b610753610df93660046150c5565b6001600160a01b03166000908152600c602052604090205460ff1690565b610611610e253660046150c5565b6146ad565b610e9c610e383660046150e9565b600360208190526000918252604090912080546001820154600283015493830154600484015460058501546006860154600787015460088801546009909801546001600160a01b0397881699969097169795969495939492939192909160ff16908a565b604080516001600160a01b039b8c1681529a90991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015260ff16610100830152610120820152610140016105c7565b610611610f023660046152a5565b614755565b6105f0610f153660046150c5565b6001600160a01b031660009081526012602052604090205490565b6105f0610f3e3660046150c5565b600f6020526000908152604090205481565b6105f0610f5e3660046150c5565b6001600160a01b031660009081526014602052604090205490565b6105f0610f873660046150e9565b60136020526000908152604090205481565b6105f0610fa73660046151a5565b6001600160a01b0380821660009081526010602090815260408083209386168352929052205492915050565b6105f0610fe13660046151a5565b6001600160a01b038082166000908152600e602090815260408083209386168352929052205492915050565b6105f061101b3660046152c3565b60166020526000908152604090205481565b6019546040516370a0823160e01b81526001600160a01b0384811660048301526060928392600092909116906370a0823190602401602060405180830381865afa15801561107f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a391906152e0565b60408051600580825260c082019092529192506020820160a080368337505060408051600580825260c0820190925292955090506020820160a08036833701905050915060005b8181101561140057601954604051632f745c5960e01b81526001600160a01b038881166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015611144573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116891906152e0565b600087815260036020526040908190206005015460195491516319d42f2f60e21b815260048101849052929350916001600160a01b0390911690636750bcbc90602401602060405180830381865afa1580156111c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ec91906152e0565b11156111f857506113ee565b60195460405163032bbfbd60e21b81526004810183905260006024820181905260016044830152916001600160a01b031690630caefef490606401602060405180830381865afa158015611250573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127491906152e0565b60008181526015602052604090205490915060ff166112945750506113ee565b60195460405163032bbfbd60e21b81526004810184905260016024820152600260448201526000916001600160a01b031690630caefef490606401602060405180830381865afa1580156112ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131091906152e0565b61131b90606461530f565b9050600081121561132a575060005b60005b60058110156113e9578781815181106113485761134861533f565b60200260200101518211156113d757600088828151811061136b5761136b61533f565b60200260200101519050828983815181106113885761138861533f565b60200260200101818152505080925060008883815181106113ab576113ab61533f565b60200260200101519050858984815181106113c8576113c861533f565b60209081029190910101529450505b806113e181615355565b91505061132d565b505050505b806113f881615355565b9150506110ea565b50509250929050565b6000818152600360205260409020600101546001600160a01b031633146114855760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b60648201526084015b60405180910390fd5b6000818152600360205260409020600701544210156114e65760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206e6f742070617373656400000000000000000000000000604482015260640161147c565b6000818152600360205260408120600601546115023384613d97565b61150c919061536e565b90506000811161155e5760405162461bcd60e51b815260206004820152601360248201527f596f752068617665206e6f207265776172647300000000000000000000000000604482015260640161147c565b600082815260036020908152604080832060068101849055426004820155546001600160a01b03168084526014835281842054600890935290832054909291906115aa90612710615381565b6115b49085615394565b6115be91906153ab565b905060006115cc8285615381565b9050826001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561162e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165291906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018590526064016020604051808303816000875af11580156116a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c991906153ea565b50600085815260036020526040902080546001909101546116f89184916001600160a01b0391821691166147cc565b6117226117058386615381565b6000878152600360205260409020546001600160a01b031661483a565b604080518381526020810183905233917f02a6a2be713fedf52f113c0a759f1c1a23a113476d9b1b1a2a453c910660de4e91015b60405180910390a25050505050565b61176d61486b565b6001600160a01b0381166117b15760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600b60205260408082208590555184917f62b574cc62ed3db0ae736cb4349346a234832cc8b215c6423fd67505addc2ffa91a35050565b6117ff61486b565b6001600160a01b0381166118435760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600960205260408082208590555184917f1677c34b69a09796446af7a4c75943a1bb36202c16eb82199ef7d37d0ee4b28891a35050565b61189161486b565b6001600160a01b0381166118d55760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600760205260408082208590555184917fef97689adaec5b60041d413c3baef6876d5d01bb6c17b60cc980e2e244ef851791a35050565b60008060008060008061193d8760009081526003602052604090206007015490565b60008881526003602052604090206005810154600890910154919750955060ff169350611969876134c9565b90935091506119788888611984565b90509295509295509295565b600081815260036020818152604080842081516101408101835281546001600160a01b0390811680835260018401548216838701526002840154838601529583015460608301526004808401546080840152600584015460a0840152600684015460c0840152600784015460e0840152600884015460ff1661010084015260099093015461012083015294865260149093528185205460185492516370a0823160e01b81528886169281019290925294929391909116906370a0823190602401602060405180830381865afa158015611a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8591906152e0565b1115611ab25780516001600160a01b0316600090815260096020526040902054611aaf908361536e565b91505b6019546040516370a0823160e01b81526001600160a01b03868116600483015260009216906370a0823190602401602060405180830381865afa158015611afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2191906152e0565b1115611b3e57611b318484614302565b611b3b908361536e565b91505b61010081015160ff1615611b715761010081015160ff16600090815260136020526040902054611b6e908361536e565b91505b505b92915050565b611b8161486b565b6001600160a01b038116611bc55760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600560205260408082208590555184917fef3cb734d88702dbb1c3bc381c52176876be95e70b66d3970d16653ee992a6c291a35050565b600081815260036020526040902060070154421015611c6c5760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206e6f742070617373656400000000000000000000000000604482015260640161147c565b6000818152600360205260409020600101546001600160a01b03163314611ce35760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b600081815260036020526040902060020154821115611d4e5760405162461bcd60e51b815260206004820152602160248201527f43616e2774207769746864726177206d6f7265207468616e20796f75206861766044820152606560f81b606482015260840161147c565b6017546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dba91906152e0565b600082815260036020526040902060090154611dd69084615394565b1115611e4a5760405162461bcd60e51b815260206004820152603760248201527f43616e2774207769746864726177206d6f726520746f6b656e73207468616e2060448201527f74686520636f6c6c61746572616c20796f752068617665000000000000000000606482015260840161147c565b6000611e563383613d97565b905082600360008481526020019081526020016000206002016000828254611e7e9190615381565b909155505060008281526003602052604081204260048201556006018054839290611eaa90849061536e565b90915550506000828152600360209081526040808320546001600160a01b031683526014808352818420546008845291842054925290611eea9082615381565b611ef49086615394565b611efe91906153ab565b90506000611f0c8286615381565b6000858152600360209081526040808320549254815163fbfa77cf60e01b815291519495506001600160a01b03938416948794869463dd62ed3e94919093169263fbfa77cf926004808401938290030181865afa158015611f71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9591906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa158015611fdf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200391906152e0565b10156120a85760405162461bcd60e51b815260206004820152606260248201527f547265617375727920436f6e7472616374206e65656420746f20617070726f7660448201527f65205374616b696e6720436f6e747261637420746f207769746864726177207960648201527f6f757220746f6b656e73202d2d20706c656173652063616c6c20616e2041646d60848201526134b760f11b60a482015260c40161147c565b600085815260036020526040902080546001909101546120d69188916001600160a01b039182169116614942565b6000858152600360209081526040808320546001600160a01b039081168452600c90925280832054601754909216835282205460ff918216929116908183101561212e576121248383615407565b60ff169050612132565b5060005b6017546001600160a01b0316639dc29fac3361214f84600a615504565b60008c81526003602052604090206009015461216b908e615394565b6121759190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156121bb57600080fd5b505af11580156121cf573d6000803e3d6000fd5b50505050836001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612233573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225791906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018990526064016020604051808303816000875af11580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce91906153ea565b50600088815260036020526040902080546001909101546122fd9188916001600160a01b0391821691166147cc565b61232761230a878b615381565b60008a8152600360205260409020546001600160a01b031661483a565b604080518781526020810187905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2505050505050505050565b6000818152600360205260409020600101546001600160a01b031633146123e45760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b6000818152600360205260408120600601546124003384613d97565b61240a919061536e565b90506000811161245c5760405162461bcd60e51b815260206004820152601460248201527f4e6f207265776172647320617661696c61626c65000000000000000000000000604482015260640161147c565b600082815260036020526040812060068101829055600201805483929061248490849061536e565b9091555050600082815260036020526040902042600482015580546001909101546124bd9183916001600160a01b039182169116614ab3565b6000828152600360209081526040808320546001600160a01b039081168452600c90925280832054601754909216835282205460ff91821692911690828211156125155761250b8383615407565b60ff169050612519565b5060005b6017546001600160a01b03166340c10f193361253684600a615504565b6000898152600360205260409020600901546125529089615394565b61255c9190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156125a257600080fd5b505af11580156125b6573d6000803e3d6000fd5b50506040518681523392507f169f1815ebdea059aac3bb00ec9a9594c7a5ffcb64a17e8392b5d84909a145569150602001611756565b60006001600160a01b0382166126325760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b03821660009081526004602052604090205460ff1661269a5760405162461bcd60e51b815260206004820152601460248201527f546f6b656e206e6f7420617574686f72697a6564000000000000000000000000604482015260640161147c565b6001600160a01b0382166000908152600560205260409020548410156127105760405162461bcd60e51b815260206004820152602560248201527f416d6f756e7420736d616c6c6572207468616e206d696e696d696d756d2064656044820152641c1bdcda5d60da1b606482015260840161147c565b6040516370a0823160e01b8152336004820152829085906001600160a01b038316906370a0823190602401602060405180830381865afa158015612758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277c91906152e0565b10156127ca5760405162461bcd60e51b815260206004820152601d60248201527f43616e2774207374616b65206d6f7265207468616e20796f75206f776e000000604482015260640161147c565b604051636eb1769f60e11b815233600482015230602482015285906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa158015612816573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061283a91906152e0565b10156128885760405162461bcd60e51b815260206004820152601160248201527f416c6c6f77616e6365206e6f7420736574000000000000000000000000000000604482015260640161147c565b60038460ff1611156128dc5760405162461bcd60e51b815260206004820152601060248201527f496e76616c69642074696d656c6f636b00000000000000000000000000000000604482015260640161147c565b60006128e760015490565b9050604051806101400160405280856001600160a01b03168152602001336001600160a01b031681526020018781526020016000815260200142815260200142815260200160008152602001601660008860ff1660ff1681526020019081526020016000205442612958919061536e565b815260ff8781166020808401919091526001600160a01b038881166000908152600b8352604080822054958101959095528681526003808452858220875181546001600160a01b0319908116918616919091178255888601516001808401805490931691909616179055878701516002808301919091556060890151928201929092556080880151600482015560a0880151600582015560c0880151600682015560e0880151600782015561010088015160088201805460ff191691909716179095556101209096015160099094019390935533808452948252928220805493840181558252902001829055612a519087908690614ab3565b6001600160a01b038085166000908152600c602052604080822054601754909316825281205460ff92831692169082821115612a9b57612a918383615407565b60ff169050612a9f565b5060005b846001600160a01b03166323b872dd3360008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2491906153cd565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018c90526064016020604051808303816000875af1158015612b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9c91906153ea565b506017546001600160a01b03166340c10f1933612bba84600a615504565b6001600160a01b038b166000908152600b6020526040902054612bdd908e615394565b612be79190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015612c2d57600080fd5b505af1158015612c41573d6000803e3d6000fd5b50505050612c53600180546001019055565b604080516001600160a01b0389168152602081018b9052339186917ff7373f56c201647feae85a62d3cf56286ed3a43d20c5eb7f9883d6ea690ef7c0910160405180910390a35091979650505050505050565b6000818152600360205260409020600101546001600160a01b03163314612d1d5760405162461bcd60e51b815260206004820152602560248201527f596f7520617265206e6f7420746865206f776e6572206f6620746869732064656044820152641c1bdcda5d60da1b606482015260840161147c565b600081815260036020526040902060020154821115612d885760405162461bcd60e51b815260206004820152602160248201527f43616e2774207769746864726177206d6f7265207468616e20796f75206861766044820152606560f81b606482015260840161147c565b6017546040516370a0823160e01b81523360048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df491906152e0565b600082815260036020526040902060090154612e109084615394565b1115612e845760405162461bcd60e51b815260206004820152603760248201527f43616e2774207769746864726177206d6f726520746f6b656e73207468616e2060448201527f74686520636f6c6c61746572616c20796f752068617665000000000000000000606482015260840161147c565b6000818152600360205260409020600701544210612ee45760405162461bcd60e51b815260206004820152601360248201527f54696d656c6f636b206861732070617373656400000000000000000000000000604482015260640161147c565b600081815260036020526040812060070154612f01904290615381565b600083815260036020526040812060058101546007909101549293509091612f299190615381565b90506000612f38826064615394565b6000858152600360209081526040808320546001600160a01b0316835260129091529020548490612f699088615394565b612f739190615394565b612f7d91906153ab565b905084811115612f8a5750835b80600003612fac576064612f9f866001615394565b612fa991906153ab565b90505b6000848152600360209081526040808320546001600160a01b031683526008909152812054612fdb908361536e565b90506000612fe98288615381565b90506000612ff78289615381565b90508760036000898152602001908152602001600020600201600082825461301f9190615381565b909155505060008781526003602090815260408083204260048083019190915590549354825163fbfa77cf60e01b815292516001600160a01b03958616958895879563dd62ed3e95929094169363fbfa77cf938184019390918290030181865afa158015613091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b591906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156130ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312391906152e0565b10156131c85760405162461bcd60e51b815260206004820152606260248201527f547265617375727920436f6e7472616374206e65656420746f20617070726f7660448201527f65205374616b696e6720436f6e747261637420746f207769746864726177207960648201527f6f757220746f6b656e73202d2d20706c656173652063616c6c20616e2041646d60848201526134b760f11b60a482015260c40161147c565b600088815260036020526040902080546001909101546131f6918b916001600160a01b039182169116614942565b6017546001600160a01b039081166000908152600c60208181526040808420548d855260038352818520549095168452919052812054909160ff90811691161015613289576000898152600360209081526040808320546001600160a01b039081168452600c9092528083205460175490921683529091205461327f9160ff9081169116615407565b60ff16905061328d565b5060005b6017546001600160a01b0316639dc29fac336132aa84600a615504565b60008d8152600360205260409020600901546132c6908f615394565b6132d09190615394565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561331657600080fd5b505af115801561332a573d6000803e3d6000fd5b50505050816001600160a01b03166323b872dd60008054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b291906153cd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152336024820152604481018790526064016020604051808303816000875af1158015613405573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061342991906153ea565b50600089815260036020526040902080546001909101546134589186916001600160a01b0391821691166147cc565b613482613465858c615381565b60008b8152600360205260409020546001600160a01b031661483a565b604080518581526020810185905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a250505050505050505050565b600081815260036020526040812060028101546006909101549091906134ef3385613d97565b6134f9919061536e565b9050915091565b61350861486b565b60009182526013602052604090912055565b61352261486b565b6001600160a01b0381166135785760405162461bcd60e51b815260206004820152601e60248201527f466f756e6465727320616464726573732063616e6e6f74206265203078300000604482015260640161147c565b601880546001600160a01b0319166001600160a01b0383169081179091556040517f23008753c65029d55e051a14341d50cf19b808653ba432a5faeb07bd7865e25b90600090a250565b6135ca61486b565b600080546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9060200160405180910390a150565b61362661486b565b6001600160a01b03821661366a5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6136748282614b17565b5050565b6136828282611c0b565b61367481611409565b6000806136978361435f565b50905060005b60058110156136df578181815181106136b8576136b861533f565b6020026020010151836136cb919061536e565b9250806136d781615355565b91505061369d565b5050919050565b6136ee61486b565b6001600160a01b0388166137445760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b600087116137a45760405162461bcd60e51b815260206004820152602760248201527f526577617264732070657220686f7572206d75737420626520677265617465726044820152660207468616e20360cc1b606482015260840161147c565b600086116138065760405162461bcd60e51b815260206004820152602960248201527f436f6d706f756e64206672657175656e6379206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b600085116138645760405162461bcd60e51b815260206004820152602560248201527f5769746864726177616c20666565206d75737420626520677265617465722074604482015264068616e20360dc1b606482015260840161147c565b600084116138c95760405162461bcd60e51b815260206004820152602c60248201527f466f756e646572732072657761726420626f6f7374206d75737420626520677260448201526b06561746572207468616e20360a41b606482015260840161147c565b6000831161392a5760405162461bcd60e51b815260206004820152602860248201527f6b4e46542072657761726420626f6f7374206d75737420626520677265617465604482015267072207468616e20360c41b606482015260840161147c565b6000821161397a5760405162461bcd60e51b815260206004820152601c60248201527f526174696f206d7573742062652067726561746572207468616e203000000000604482015260640161147c565b600081116139d65760405162461bcd60e51b8152602060048201526024808201527f4d696e696d756d207374616b65206d75737420626520677265617465722074686044820152630616e20360e41b606482015260840161147c565b6000886001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a3a91906152e0565b11613a995760405162461bcd60e51b815260206004820152602960248201527f546f6b656e20746f74616c20737570706c79206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b613aa5612710896141de565b613aaf84896117f7565b613ab98389613c4a565b613ac38789611889565b613acd8289611765565b613ad78589614016565b613ae18689614270565b613aeb8189611b79565b613b56886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b509190615510565b89614755565b613b61886001614b17565b5050505050505050565b613b7361486b565b6001600160a01b038216613bb75760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6064811115613c2e5760405162461bcd60e51b815260206004820152602c60248201527f50656e616c74792070657263656e74616765206d75737420626520626574776560448201527f656e203020616e64203130300000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b03909116600090815260126020526040902055565b613c5261486b565b6001600160a01b038116613c965760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600a60205260408082208590555184917f11ef1060a695a1277b08edcbb2c364d43d4eb52f1060daaabf0df445cb6cdfdf91a35050565b6000818152600360209081526040808320600481015490546001600160a01b031684526006909252822054613d11818361536e565b4210613d21575060009392505050565b42613d2c828461536e565b613d369190615381565b949350505050565b613d4661486b565b600091825260156020526040909120805460ff1916911515919091179055565b60026020528160005260406000208181548110613d8257600080fd5b90600052602060002001600091509150505481565b600081815260036020818152604080842081516101408101835281546001600160a01b0390811682526001830154811694820185905260028301549382019390935293810154606085015260048101546080850152600581015460a0850152600681015460c0850152600781015460e0850152600881015460ff1661010085015260090154610120840152851614613e33576000915050611b73565b6000816080015142613e459190615381565b60408084015184516001600160a01b03166000908152600760205291822054929350919063bbf81e00613e788385615394565b613e8a90670de0b6b3a7640000615394565b613e9491906153ab565b90506000670de0b6b3a7640000613eab8387615394565b613eb591906153ab565b90506000613ec38a8a611984565b87516001600160a01b0316600090815260146020526040902054909150613eea8284615394565b613ef491906153ab565b9a9950505050505050505050565b613f0a61486b565b6001600160a01b038116613f605760405162461bcd60e51b815260206004820152601a60248201527f6b4e465420616464726573732063616e6e6f7420626520307830000000000000604482015260640161147c565b601980546001600160a01b0319166001600160a01b0383169081179091556040517fc8e08c5b2fa487609cdc92d5cfcc240f3c8fc73ac5e58fafc5d465d20aaaf31290600090a250565b6001600160a01b03811660009081526002602090815260409182902080548351818402810184019094528084526060939283018282801561400a57602002820191906000526020600020905b815481526020019060010190808311613ff6575b50505050509050919050565b61401e61486b565b6001600160a01b0381166140625760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000908152601460205260409020548211156140f05760405162461bcd60e51b815260206004820152602760248201527f5769746864726177616c206665652063616e6e6f74206265206d6f726520746860448201527f616e203130302500000000000000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b0381166000818152600860205260408082208590555184917f5d5169bb1fbf418e612b1934f181b6ce300a1aad27fdb0e6f6aadbd96f50bb8f91a35050565b61413e61486b565b6001600160a01b0381166141945760405162461bcd60e51b815260206004820152601b60248201527f48656c697820616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b601780546001600160a01b0319166001600160a01b0383169081179091556040517fdcbeffeaf77a19486e34d4b5fc3809913d1e7125a43b8dcdb17944ab2c17579090600090a250565b6141e661486b565b6001600160a01b03811661422a5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152601460205260408082208590555184917f6a437d814668577dce2f82ae56ed67161e12e20b59b9464687859d6a2ce0faa591a35050565b61427861486b565b6001600160a01b0381166142bc5760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b0381166000818152600660205260408082208590555184917fd0d3d840363c3a773f4578f92d7914f6b37985570c79ee2889d69d7d8f12c29591a35050565b60008061430f848461102d565b50905060005b6005811015614357578181815181106143305761433061533f565b602002602001015183614343919061536e565b92508061434f81615355565b915050614315565b505092915050565b6019546040516370a0823160e01b81526001600160a01b0383811660048301526060928392600092909116906370a0823190602401602060405180830381865afa1580156143b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143d591906152e0565b60408051600580825260c082019092529192506020820160a080368337505060408051600580825260c0820190925292955090506020820160a08036833701905050915060005b818110156146a657601954604051632f745c5960e01b81526001600160a01b038781166004830152602482018490526000921690632f745c5990604401602060405180830381865afa158015614476573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061449a91906152e0565b60195460405163032bbfbd60e21b815260048101839052600060248201819052600160448301529293506001600160a01b0390911690630caefef490606401602060405180830381865afa1580156144f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061451a91906152e0565b60008181526015602052604090205490915060ff1661453a575050614694565b60195460405163032bbfbd60e21b81526004810184905260016024820152600260448201526000916001600160a01b031690630caefef490606401602060405180830381865afa158015614592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145b691906152e0565b6145c190606461530f565b905060008112156145d0575060005b60005b600581101561468f578781815181106145ee576145ee61533f565b602002602001015182111561467d5760008882815181106146115761461161533f565b602002602001015190508289838151811061462e5761462e61533f565b60200260200101818152505080925060008883815181106146515761465161533f565b602002602001015190508589848151811061466e5761466e61533f565b60209081029190910101529450505b8061468781615355565b9150506145d3565b505050505b8061469e81615355565b91505061441c565b5050915091565b6146b561486b565b6001600160a01b03811661470b5760405162461bcd60e51b815260206004820152601e60248201527f547265617375727920616464726573732063616e6e6f74206265203078300000604482015260640161147c565b601a80546001600160a01b0319166001600160a01b0383169081179091556040517fafa147634b29e2c7bd53ce194256b9f41cfb9ba3036f2b822fdd1d965beea08690600090a250565b61475d61486b565b6001600160a01b0381166147a15760405162461bcd60e51b8152602060048201526018602482015260008051602061552e833981519152604482015260640161147c565b6001600160a01b03166000908152600c60205260409020805460ff191660ff92909216919091179055565b6001600160a01b0382166000908152600f6020526040812080548592906147f490849061536e565b90915550506001600160a01b0380831660009081526010602090815260408083209385168352929052908120805485929061483090849061536e565b9091555050505050565b6001600160a01b0381166000908152601160205260408120805484929061486290849061536e565b90915550505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156148bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148e091906153cd565b6001600160a01b0316336001600160a01b0316146149405760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015260640161147c565b565b6001600160a01b0382166000908152600d60205260409020548311156149d05760405162461bcd60e51b815260206004820152602560248201527f5374616b696e673a204e6f7420656e6f756768207374616b65642028436f6e7460448201527f7261637429000000000000000000000000000000000000000000000000000000606482015260840161147c565b6001600160a01b038083166000908152600e6020908152604080832093851683529290522054831115614a4f5760405162461bcd60e51b815260206004820152602160248201527f5374616b696e673a204e6f7420656e6f756768207374616b65642028557365726044820152602960f81b606482015260840161147c565b6001600160a01b0382166000908152600d602052604081208054859290614a77908490615381565b90915550506001600160a01b038083166000908152600e6020908152604080832093851683529290529081208054859290614830908490615381565b6001600160a01b0382166000908152600d602052604081208054859290614adb90849061536e565b90915550506001600160a01b038083166000908152600e602090815260408083209385168352929052908120805485929061483090849061536e565b6001600160a01b038216614b6d5760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20616464726573732063616e6e6f74206265203078300000000000604482015260640161147c565b801515600103614fc4576001600160a01b038216600090815260076020526040902054614bec5760405162461bcd60e51b815260206004820152602760248201527f526577617264732070657220686f7572206d75737420626520677265617465726044820152660207468616e20360cc1b606482015260840161147c565b6001600160a01b038216600090815260066020526040902054614c635760405162461bcd60e51b815260206004820152602960248201527f436f6d706f756e64206672657175656e6379206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b6001600160a01b038216600090815260086020526040902054614cd65760405162461bcd60e51b815260206004820152602560248201527f5769746864726177616c20666565206d75737420626520677265617465722074604482015264068616e20360dc1b606482015260840161147c565b6001600160a01b038216600090815260096020526040902054614d505760405162461bcd60e51b815260206004820152602c60248201527f466f756e646572732072657761726420626f6f7374206d75737420626520677260448201526b06561746572207468616e20360a41b606482015260840161147c565b6001600160a01b0382166000908152600a6020526040902054614dc65760405162461bcd60e51b815260206004820152602860248201527f6b4e46542072657761726420626f6f7374206d75737420626520677265617465604482015267072207468616e20360c41b606482015260840161147c565b6001600160a01b0382166000908152600b6020526040902054614e2b5760405162461bcd60e51b815260206004820152601c60248201527f526174696f206d7573742062652067726561746572207468616e203000000000604482015260640161147c565b6001600160a01b038216600090815260056020526040902054614e9c5760405162461bcd60e51b8152602060048201526024808201527f4d696e696d756d207374616b65206d75737420626520677265617465722074686044820152630616e20360e41b606482015260840161147c565b6001600160a01b038216600090815260146020526040902054614f015760405162461bcd60e51b815260206004820152601e60248201527f44697669736f72206d7573742062652067726561746572207468616e20300000604482015260640161147c565b6000826001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f6591906152e0565b11614fc45760405162461bcd60e51b815260206004820152602960248201527f546f6b656e20746f74616c20737570706c79206d75737420626520677265617460448201526806572207468616e20360bc1b606482015260840161147c565b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917f59261974a183535ca20bb33ae77db42c679a079844739a2e10f0b6ecb847379a91a35050565b6001600160a01b038116811461502d57600080fd5b50565b6000806040838503121561504357600080fd5b823561504e81615018565b946020939093013593505050565b600081518084526020808501945080840160005b8381101561508c57815187529582019590820190600101615070565b509495945050505050565b6040815260006150aa604083018561505c565b82810360208401526150bc818561505c565b95945050505050565b6000602082840312156150d757600080fd5b81356150e281615018565b9392505050565b6000602082840312156150fb57600080fd5b5035919050565b6000806040838503121561511557600080fd5b82359150602083013561512781615018565b809150509250929050565b6000806040838503121561514557600080fd5b50508035926020909101359150565b60ff8116811461502d57600080fd5b60008060006060848603121561517857600080fd5b83359250602084013561518a81615154565b9150604084013561519a81615018565b809150509250925092565b600080604083850312156151b857600080fd5b82356151c381615018565b9150602083013561512781615018565b801515811461502d57600080fd5b600080604083850312156151f457600080fd5b82356151ff81615018565b91506020830135615127816151d3565b600080600080600080600080610100898b03121561522c57600080fd5b883561523781615018565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b6000806040838503121561528057600080fd5b823591506020830135615127816151d3565b6020815260006150e2602083018461505c565b600080604083850312156152b857600080fd5b82356151c381615154565b6000602082840312156152d557600080fd5b81356150e281615154565b6000602082840312156152f257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820260008212600160ff1b8414161561532b5761532b6152f9565b8181058314821517611b7357611b736152f9565b634e487b7160e01b600052603260045260246000fd5b600060018201615367576153676152f9565b5060010190565b80820180821115611b7357611b736152f9565b81810381811115611b7357611b736152f9565b8082028115828204841417611b7357611b736152f9565b6000826153c857634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156153df57600080fd5b81516150e281615018565b6000602082840312156153fc57600080fd5b81516150e2816151d3565b60ff8281168282160390811115611b7357611b736152f9565b600181815b8085111561545b578160001904821115615441576154416152f9565b8085161561544e57918102915b93841c9390800290615425565b509250929050565b60008261547257506001611b73565b8161547f57506000611b73565b8160018114615495576002811461549f576154bb565b6001915050611b73565b60ff8411156154b0576154b06152f9565b50506001821b611b73565b5060208310610133831016604e8410600b84101617156154de575081810a611b73565b6154e88383615420565b80600019048211156154fc576154fc6152f9565b029392505050565b60006150e28383615463565b60006020828403121561552257600080fd5b81516150e28161515456fe546f6b656e2061646472657373206973206e6f74207365740000000000000000a164736f6c6343000811000a

Verified Source Code Partial Match

Compiler: v0.8.17+commit.8df45f5f EVM: london Optimization: Yes (800 runs)
Staking.sol 1367 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./interfaces/ITreasury.sol";
import "./interfaces/IHelix.sol";
import "./interfaces/IKondux.sol";
import "./interfaces/IKonduxERC20.sol";
import "./types/AccessControlled.sol";

contract Staking is AccessControlled {
    using Counters for Counters.Counter;

    Counters.Counter private _depositIds;

    /**
     * @dev Struct representing a staker's information.
     */
    struct Staker {
        // The address of the staked token
        address token;
        // The address of the staker
        address staker;
        // The total amount of tokens deposited by the staker
        uint256 deposited;
        // The total amount of tokens redeemed by the staker
        uint256 redeemed;
        // The timestamp of the last update for this staker's deposit
        uint256 timeOfLastUpdate;
        // The timestamp of the staker's last deposit
        uint256 lastDepositTime;
        // The accumulated, but unclaimed rewards for the staker. These are calculated
        // each time a user writes to the contract
        uint256 unclaimedRewards;
        // The duration of the timelock applied to the staker's deposit
        uint256 timelock;
        // The category of the timelock applied to the staker's deposit
        uint8 timelockCategory;
        // ERC20 Ratio at the time of staking
        uint256 ratioERC20;
    } 

    enum LockingTimes {        
        OneMonth, // 0
        ThreeMonths, // 1
        SixMonths, // 2
        OneYear // 3
    }

    // The deposit IDs associated with a user's address
    mapping(address => uint[]) public userDepositsIds;

    // The Staker struct information associated with a deposit ID
    mapping(uint => Staker) public userDeposits;

    // Indicates whether a specific ERC20 token is authorized for staking
    mapping (address => bool) public authorizedERC20;

    // The minimum amount required to stake for a specific ERC20 token
    mapping (address => uint256) public minStakeERC20;

    // The compound frequency for a specific ERC20 token
    mapping (address => uint256) public compoundFreqERC20;

    // The rewards per hour for a specific ERC20 token
    mapping (address => uint256) public aprERC20;

    // The withdrawal fee for a specific ERC20 token
    mapping (address => uint256) public withdrawalFeeERC20;

    // The founders reward boost for a specific ERC20 token
    mapping (address => uint256) public foundersRewardBoostERC20;

    // The kNFT reward boost for a specific ERC20 token
    mapping (address => uint256) public kNFTRewardBoostERC20;

    // The ratio for a specific ERC20 token
    mapping (address => uint256) public ratioERC20;

    // The decimals of a specific ERC20 token
    mapping (address => uint8) public decimalsERC20;

    // The total amount staked for a specific ERC20 token
    mapping (address => uint256) public totalStaked;

    // The total amount staked by a user for a specific ERC20 token
    mapping (address => mapping (address => uint256)) public userTotalStakedByCoin;

    // The total amount rewarded for a specific ERC20 token
    mapping (address => uint256) public totalRewarded;

    // The total amount rewarded by a user for a specific ERC20 token
    mapping (address => mapping (address => uint256)) public userTotalRewardedByCoin;

    // The total amount paid as a withdrawal fee for a specific ERC20 token
    mapping (address => uint256) public totalWithdrawalFees;

    // The penalty for withdrawing early for a specific ERC20 token
    mapping (address => uint256) public earlyWithdrawalPenalty;

    // The boost for a specific timelock category
    mapping(uint => uint256) public timelockCategoryBoost;

    // The divisor for a specific token
    mapping (address => uint256) public divisorERC20;

    // The allowed dnaVersion for reward boost
    mapping (uint256 => bool) public allowedDnaVersions;

    // Map of timelock durartions
    mapping(uint8 => uint256) public timelockDurations;

    IHelix public helixERC20; // Helix ERC20 Token
    IERC721 public konduxERC721Founders; // Kondux ERC721 Founders Token
    address public konduxERC721kNFT; // Kondux ERC721 kNFT Token
    ITreasury public treasury; // Treasury Contract

    // Events
    // Emitted when a staker withdraws their rewards
    event Withdraw(address indexed user, uint256 liquidAmount, uint256 fees);

    // Emitted when a staker withdraws all their rewards
    event WithdrawAll(address indexed staker, uint256 amount);

    // Emitted when a staker compounds their rewards
    event Compound(address indexed staker, uint256 amount);

    // Emitted when a staker stakes their tokens
    event Stake(uint indexed id, address indexed staker, address token, uint256 amount);

    // Emitted when a staker unstakes their tokens
    event Unstake(address indexed staker, uint256 amount);

    // Emitted when a staker receives a reward
    event Reward(address indexed user, uint256 netRewards, uint256 fees);

    // Emitted when the rewards per hour is updated for a token
    event NewAPR(uint256 indexed amount, address indexed token);

    // Emitted when the minimum stake is updated for a token
    event NewMinStake(uint256 indexed amount, address indexed token);

    // Emitted when the compound frequency is updated for a token
    event NewCompoundFreq(uint256 indexed amount, address indexed token);

    // Emitted when the Helix ERC20 token is updated
    event NewHelixERC20(address indexed helixERC20);

    // Emitted when the Kondux ERC721 Founders token is updated
    event NewKonduxERC721Founders(address indexed konduxERC721Founders);

    // Emitted when the Kondux ERC721 kNFT token is updated
    event NewKonduxERC721kNFT(address indexed konduxERC721kNFT);

    // Emitted when the treasury address is updated
    event NewTreasury(address indexed treasury);

    // Emitted when the withdrawal fee is updated for a token
    event NewWithdrawalFee(uint256 indexed amount, address indexed token);

    // Emitted when the founders reward boost is updated for a token
    event NewFoundersRewardBoost(uint256 indexed amount, address indexed token);

    // Emitted when the kNFT reward boost is updated for a token
    event NewKNFTRewardBoost(uint256 indexed amount, address indexed token);

    // Emitted when a token is authorized or deauthorized for staking
    event NewAuthorizedERC20(address indexed token, bool indexed authorized);

    // Emitted when the ratio is updated for a token
    event NewRatio(uint256 indexed amount, address indexed token);

    // Emitted when a new divisor is set for a token
    event NewDivisorERC20(uint256 indexed amount, address indexed token);
 

    /**
     * @dev Initializes the staking contract with the provided parameters.
     *
     * @param _authority The address of the authority contract.
     * @param _konduxERC20 The address of the Kondux ERC20 token contract.
     * @param _treasury The address of the treasury contract.
     * @param _konduxERC721Founders The address of the Kondux ERC721 Founders token contract.
     * @param _konduxERC721kNFT The address of the Kondux ERC721 kNFT token contract.
     * @param _helixERC20 The address of the Helix ERC20 token contract.
     *
     * The constructor sets up the initial state of the staking contract by initializing contract variables,
     * setting up default staking token parameters, and authorizing the Kondux ERC20 token for staking.
     */
    constructor(
        address _authority,
        address _konduxERC20,
        address _treasury,
        address _konduxERC721Founders,
        address _konduxERC721kNFT,
        address _helixERC20
    ) AccessControlled(IAuthority(_authority)) {
        // Ensure the provided addresses are valid
        require(_konduxERC20 != address(0), "Kondux ERC20 address is not set");
        require(_treasury != address(0), "Treasury address is not set");
        require(_konduxERC721Founders != address(0), "Kondux ERC721 Founders address is not set");
        require(_konduxERC721kNFT != address(0), "Kondux ERC721 kNFT address is not set");
        require(_helixERC20 != address(0), "Helix ERC20 address is not set");

        // Initialize contract variables
        konduxERC721Founders = IERC721(_konduxERC721Founders);
        konduxERC721kNFT = _konduxERC721kNFT;
        helixERC20 = IHelix(_helixERC20);
        treasury = ITreasury(_treasury);

        timelockDurations[0] = 30 days;         // 1 month
        timelockDurations[1] = 90 days;         // 3 months
        timelockDurations[2] = 180 days;        // 6 months
        timelockDurations[3] = 365 days;        // 1 year

        // Set up default staking token parameters
        setDivisorERC20(10_000, _konduxERC20); // 10,000 basis points
        setWithdrawalFee(100, _konduxERC20); // 1% fee on withdrawal or 100 / 10_000
        setFoundersRewardBoost(1_000, _konduxERC20); // 10% boost (=110%) on rewards or 1,000,000/10,000,000
        setkNFTRewardBoost(500, _konduxERC20); // 5% boost on rewards or 500 / 
        setMinStake(10_000_000, _konduxERC20); // 10,000,000 wei
        setAPR(25, _konduxERC20); // 0.00285%/h or 25% APR
        setCompoundFreq(60 * 60 * 24, _konduxERC20); // 24 hours
        setRatio(10_000, _konduxERC20); // 10,000:1 ratio, adjusted for kondux ERC20 decimals
        setEarlyWithdrawalPenalty(_konduxERC20, 10); // 10% penalty
        setTimelockCategoryBoost(1, 100); // 1% boost for 90 days timelock
        setTimelockCategoryBoost(2, 300); // 3% boost for 180 days timelock 
        setTimelockCategoryBoost(3, 900); // 9% boost for 365 days timelock
        setAllowedDnaVersion(1, true); // allow DNA version 1
        setDecimalsERC20(helixERC20.decimals(), _helixERC20); // set decimals for Helix ERC20 token 
        setDecimalsERC20(IKonduxERC20(_konduxERC20).decimals(), _konduxERC20); // set decimals for Kondux ERC20 token

        _setAuthorizedERC20(_konduxERC20, true);
    }

    /**
     * @dev This function allows a user to deposit a specified amount of an authorized token with a selected timelock period.
     *      The function checks the user's token balance, allowance, and the timelock value before proceeding.
     *      It then creates a new deposit record, sets the timelock based on the selected category, and updates the user's
     *      deposit list and total staked amount. The specified amount of tokens is transferred from the user to the vault,
     *      and an equivalent amount of reward tokens is minted for the user.
     * @param _amount The amount of tokens to deposit.
     * @param _timelock The timelock category, represented as an integer (0-4).
     * @param _token The address of the token contract.
     * @return _id The deposit ID assigned to this deposit.
     */
    function deposit(uint256 _amount, uint8 _timelock, address _token) public returns (uint) {
        // Check if the token address is set
        require(_token != address(0), "Token address is not set");
        // Check if the token is authorized for staking
        require(authorizedERC20[_token], "Token not authorized");
        // Check if the deposit amount is greater than or equal to the minimum required stake
        require(_amount >= minStakeERC20[_token], "Amount smaller than minimimum deposit");
        IERC20 konduxERC20 = IERC20(_token);
        // Check if the user has enough balance to stake the specified amount
        require(konduxERC20.balanceOf(msg.sender) >= _amount, "Can't stake more than you own");
        // Check if the user has approved the staking contract to spend the specified amount
        require(konduxERC20.allowance(msg.sender, address(this)) >= _amount, "Allowance not set");
        // Check if the selected timelock category is valid (between 0 and 3)
        require(_timelock <= 3, "Invalid timelock");

        // Get the current deposit ID
        uint _id = _depositIds.current();

        // Create a new deposit record for the user
        userDeposits[_id] = Staker({
            token: _token,
            staker: msg.sender,
            deposited: _amount,
            unclaimedRewards: 0,
            timelock: block.timestamp + timelockDurations[_timelock], // Set the timelock period based on the selected category
            timelockCategory: _timelock,
            timeOfLastUpdate: block.timestamp,
            lastDepositTime: block.timestamp,
            redeemed: 0,
            ratioERC20: ratioERC20[_token]
        });

        // Add the deposit ID to the user's deposit list
        userDepositsIds[msg.sender].push(_id);

        // Update the user's total staked amount
        _addTotalStakedAmount(_amount, _token, msg.sender);
        
        // Mint an equivalent amount of reward tokens for the user
        // Get the decimals of the original staked token and Helix
        uint8 originalTokenDecimals = decimalsERC20[_token];
        uint8 helixDecimals = decimalsERC20[address(helixERC20)];

        // Calculate the decimal difference
        uint decimalDifference;
        if (helixDecimals > originalTokenDecimals) {
            decimalDifference = helixDecimals - originalTokenDecimals;
        } else {
            decimalDifference = 0;
        }

        // Transfer the deposited tokens from the user to the vault
        konduxERC20.transferFrom(msg.sender, authority.vault(), _amount);

        // Mint an equivalent amount of reward tokens for the user, adjusted based on the decimal difference
        helixERC20.mint(msg.sender, _amount * ratioERC20[_token] * (10 ** decimalDifference));

        // Increment the deposit ID counter
        _depositIds.increment();

        // Emit a Stake event
        emit Stake(_id, msg.sender, _token, _amount);

        return _id;
    }

    /**
     * @dev This function allows the owner of a deposit to stake their earned rewards.
     *      It verifies that the caller is the deposit owner and that the compounding is not happening too soon.
     *      The function calculates the rewards, resets the unclaimed rewards to zero, and updates the deposit record.
     *      The total staked amount is updated, and an equivalent amount of reward tokens is minted for the user.
     * @param _depositId The ID of the deposit whose rewards are to be staked.
     */
    function stakeRewards(uint _depositId) public {
        // Verify that the caller is the owner of the deposit
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        // Verify that the user is not trying to compound rewards too soon
        // require(compoundRewardsTimer(_depositId) == 0, "Tried to compound rewards too soon");

        // Calculate the rewards and add any unclaimed rewards
        uint256 rewards = calculateRewards(msg.sender, _depositId) + userDeposits[_depositId].unclaimedRewards;

        // Check if the rewards are non-zero
        require(rewards > 0, "No rewards available");

        // Reset the unclaimed rewards to zero
        userDeposits[_depositId].unclaimedRewards = 0;
        // Update the deposited amount with the compounded rewards
        userDeposits[_depositId].deposited += rewards;
        // Update the time of the last update
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;

        // Update the user's total staked amount
        _addTotalStakedAmount(rewards, userDeposits[_depositId].token, userDeposits[_depositId].staker);

        // Mint an equivalent amount of reward tokens for the user
        // Get the decimals of the original staked token and Helix
        uint8 originalTokenDecimals = decimalsERC20[userDeposits[_depositId].token];
        uint8 helixDecimals = decimalsERC20[address(helixERC20)];

        // Calculate the decimal difference
        uint decimalDifference;
        if (helixDecimals > originalTokenDecimals) {
            decimalDifference = helixDecimals - originalTokenDecimals;
        } else {
            decimalDifference = 0;
        }

        // Mint the calculated rewards for the user, adjusted based on the decimal difference
        helixERC20.mint(msg.sender, rewards * userDeposits[_depositId].ratioERC20 * (10 ** decimalDifference));

        // Emit a Compound event
        emit Compound(msg.sender, rewards);
    }

    /**
     * @dev This function allows the owner of a deposit to claim their earned rewards.
     *      It verifies that the caller is the deposit owner and that the timelock has passed.
     *      The function calculates the rewards, resets the unclaimed rewards to zero, and updates the deposit record.
     *      The reward tokens are burned, and the earned rewards are transferred to the user from the vault.
     *      The function emits a Reward event upon successful execution.
     * @param _depositId The ID of the deposit whose rewards are to be claimed.
     */
    function claimRewards(uint _depositId) public {
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        require(block.timestamp >= userDeposits[_depositId].timelock, "Timelock not passed");

        uint256 rewards = calculateRewards(msg.sender, _depositId) + userDeposits[_depositId].unclaimedRewards;

        require(rewards > 0, "You have no rewards");

        userDeposits[_depositId].unclaimedRewards = 0;
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;

        IERC20 konduxERC20 = IERC20(userDeposits[_depositId].token);

        uint256 netRewards = (rewards * (10_000 - withdrawalFeeERC20[userDeposits[_depositId].token])) / divisorERC20[userDeposits[_depositId].token];
        uint256 fees = rewards - netRewards;

        konduxERC20.transferFrom(authority.vault(), msg.sender, netRewards); 

        _addTotalRewardedAmount(netRewards, userDeposits[_depositId].token, userDeposits[_depositId].staker);
        _addTotalWithdrawalFees(rewards - netRewards, userDeposits[_depositId].token);

        emit Reward(msg.sender, netRewards, fees);
    }

    /**
     * @dev This function allows the owner of a deposit to withdraw a specified amount of their deposited tokens.
     *      It verifies that the timelock has passed, the caller is the deposit owner, and the withdrawal amount
     *      is within the available limits. The function calculates the rewards, updates the deposit record, and
     *      transfers the liquid amount to the user after applying the withdrawal fee. The collateral tokens are burned.
     *      The function emits a Withdraw event upon successful execution.
     * @param _amount The amount of tokens to withdraw.
     * @param _depositId The ID of the deposit from which to withdraw the tokens.
     */
    function withdraw(uint256 _amount, uint _depositId) public {
        // Verify that the timelock has passed
        require(block.timestamp >= userDeposits[_depositId].timelock, "Timelock not passed");
        // Verify that the caller is the owner of the deposit
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        // Verify that the withdrawal amount is within the available limits
        require(userDeposits[_depositId].deposited >= _amount, "Can't withdraw more than you have");
        // Verify that the withdrawal amount is less than or equal to the collateral tokens the user has
        require(_amount * userDeposits[_depositId].ratioERC20 <= helixERC20.balanceOf(msg.sender), "Can't withdraw more tokens than the collateral you have");

        // Calculate the rewards
        uint256 _rewards = calculateRewards(msg.sender, _depositId);
        // Update the deposit record
        userDeposits[_depositId].deposited -= _amount;
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;
        userDeposits[_depositId].unclaimedRewards += _rewards;

        // Calculate the liquid amount to transfer after applying the withdrawal fee
        uint256 _liquid = (_amount * (divisorERC20[userDeposits[_depositId].token] - withdrawalFeeERC20[userDeposits[_depositId].token])) / divisorERC20[userDeposits[_depositId].token];
        uint256 fees = _amount - _liquid;

        // Get the token contract
        IERC20 konduxERC20 = IERC20(userDeposits[_depositId].token);

        // Check if the treasury contract has approved the staking contract to withdraw the tokens
        require(konduxERC20.allowance(authority.vault(), address(this)) >= _liquid, "Treasury Contract need to approve Staking Contract to withdraw your tokens -- please call an Admin");

        // Subtract the staked amount
        _subtractStakedAmount(_amount, userDeposits[_depositId].token, userDeposits[_depositId].staker);

        // Get the decimals of the original staked token and Helix
        uint8 originalTokenDecimals = decimalsERC20[userDeposits[_depositId].token];
        uint8 helixDecimals = decimalsERC20[address(helixERC20)];

        // Calculate the decimal difference
        uint decimalDifference;
        if (originalTokenDecimals < helixDecimals) {
            decimalDifference = helixDecimals - originalTokenDecimals;
        } else {
            decimalDifference = 0;
        }

        // Burn the equivalent amount of collateral tokens, adjusted based on the decimal difference
        helixERC20.burn(msg.sender, _amount * userDeposits[_depositId].ratioERC20 * (10 ** decimalDifference));

        
        // Transfer the liquid amount to the user
        konduxERC20.transferFrom(authority.vault(), msg.sender, _liquid);

        // Update the user's total rewarded amount + total rewarded amount for the token
        _addTotalRewardedAmount(_liquid, userDeposits[_depositId].token, userDeposits[_depositId].staker); 
        _addTotalWithdrawalFees(_amount - _liquid, userDeposits[_depositId].token); 

        // Emit a Withdraw event
        emit Withdraw(msg.sender, _liquid, fees);
    }

    /**
     * @dev This function allows the owner of a deposit to withdraw a specified amount of their deposited tokens
     *      before the timelock has passed. The user is punished by not receiving any reward boosts and paying an extra
     *      fee proportional to the time left until the lock (the closer to the end of the locking time, the smaller the fee,
     *      starting at 10%).
     *      It verifies that the caller is the deposit owner, and the withdrawal amount is within the available limits.
     *      The function calculates the rewards, updates the deposit record, and transfers the liquid amount to the user
     *      after applying the extra fee and withdrawal fee. The collateral tokens are burned.
     *      The function emits a Withdraw event upon successful execution.
     * @param _amount The amount of tokens to withdraw.
     * @param _depositId The ID of the deposit from which to withdraw the tokens.
     */
    function earlyUnstake(uint256 _amount, uint _depositId) public {
        // Verify that the caller is the owner of the deposit
        require(msg.sender == userDeposits[_depositId].staker, "You are not the owner of this deposit");
        // Verify that the withdrawal amount is within the available limits
        require(userDeposits[_depositId].deposited >= _amount, "Can't withdraw more than you have");
        // Verify that the withdrawal amount is less than or equal to the collateral tokens the user has
        require(_amount * userDeposits[_depositId].ratioERC20 <= helixERC20.balanceOf(msg.sender), "Can't withdraw more tokens than the collateral you have");
        // Verify if the timelock has passed
        require(block.timestamp < userDeposits[_depositId].timelock, "Timelock has passed");

        // Calculate the extra fee proportional to the time left until the lock (the closer to the end of the locking time, the smaller the fee)
        uint256 timeLeft = userDeposits[_depositId].timelock - block.timestamp;
        uint256 lockDuration = userDeposits[_depositId].timelock - userDeposits[_depositId].lastDepositTime;
        uint256 extraFee = (_amount * earlyWithdrawalPenalty[userDeposits[_depositId].token] * timeLeft) / (lockDuration * 100);

        // If extra fee is more than the amount, set it to the amount
        if (extraFee > _amount) {
            extraFee = _amount;
        }

        // If extra fee is zero, apply 1% fee
        if (extraFee == 0) {
            extraFee = (_amount * 1) / 100;
        }

        // Calculate the total fee percentage
        uint256 totalFeePercentage = extraFee + withdrawalFeeERC20[userDeposits[_depositId].token];

        // Calculate the liquid amount to transfer after applying the total fee
        uint256 _liquid = (_amount - totalFeePercentage);
        uint256 fees = _amount - _liquid;

        // Update the deposit record
        userDeposits[_depositId].deposited -= _amount;
        userDeposits[_depositId].timeOfLastUpdate = block.timestamp;

        // Get the token contract
        IERC20 konduxERC20 = IERC20(userDeposits[_depositId].token);

        // Check if the treasury contract has approved the staking contract to withdraw the tokens
        require(konduxERC20.allowance(authority.vault(), address(this)) >= _liquid, "Treasury Contract need to approve Staking Contract to withdraw your tokens -- please call an Admin");

        // Subtract the staked amount
        _subtractStakedAmount(_amount, userDeposits[_depositId].token, userDeposits[_depositId].staker);

        // Calculate the decimal difference
        uint decimalDifference;
        if (decimalsERC20[userDeposits[_depositId].token] < decimalsERC20[address(helixERC20)]) {
            decimalDifference = decimalsERC20[address(helixERC20)] - decimalsERC20[userDeposits[_depositId].token];
        } else {
            decimalDifference = 0;
        }

        // Burn the equivalent amount of collateral tokens, adjusted based on the decimal difference
        helixERC20.burn(msg.sender, _amount * userDeposits[_depositId].ratioERC20 * (10 ** decimalDifference));
        
        // Transfer the liquid amount to the user
        konduxERC20.transferFrom(authority.vault(), msg.sender, _liquid);

        // Update the user's total rewarded amount + total rewarded amount for the token
        _addTotalRewardedAmount(_liquid, userDeposits[_depositId].token, userDeposits[_depositId].staker); 
        _addTotalWithdrawalFees(_amount - _liquid, userDeposits[_depositId].token); 

        // Emit a Withdraw event
        emit Withdraw(msg.sender, _liquid, fees);
    }

    /**
     * @dev This function allows the owner of a deposit to withdraw a specified amount of their deposited tokens
     *      and claim their earned rewards in a single transaction. It calls the withdraw and claimRewards functions.
     * @param _amount The amount of tokens to withdraw.
     * @param _depositId The ID of the deposit from which to withdraw the tokens and claim the rewards.
     */
    function withdrawAndClaim(uint256 _amount, uint _depositId) public {
        withdraw(_amount, _depositId);
        claimRewards(_depositId);
    }

    /**
     * @dev This function returns the remaining time until the next allowed compounding action for a given deposit ID.
     *      It calculates the remaining time based on the compound frequency for the deposited token.
     *      If the timer has already passed, it returns 0.
     * @param _depositId The ID of the deposit for which to return the compound timer.
     * @return remainingTime The remaining time until the next allowed compounding action in seconds.
     */
    function compoundRewardsTimer(uint _depositId) public view returns (uint256 remainingTime) {
        uint256 lastUpdateTime = userDeposits[_depositId].timeOfLastUpdate;
        uint256 compoundFrequency = compoundFreqERC20[userDeposits[_depositId].token];

        if (block.timestamp >= lastUpdateTime + compoundFrequency) {
            return 0;
        }

        remainingTime = (lastUpdateTime + compoundFrequency) - block.timestamp;
        return remainingTime;
    }

    /**
     * @dev This function calculates the rewards for a specified staker and deposit ID. The rewards calculation
     *      considers the deposit's elapsed time, staked amount, and a 25% APY compounded hourly.
     *      If the provided staker is not the owner of the deposit, the function returns 0.
     * @param _staker The address of the staker for which to calculate the rewards.
     * @param _depositId The ID of the deposit for which to calculate the rewards.
     * @return rewards The calculated rewards for the specified staker and deposit ID.
     */
    function calculateRewards(address _staker, uint _depositId) public view returns (uint256 rewards) {
        // Retrieve deposit details by _depositId
        Staker memory deposit_ = userDeposits[_depositId];

        // Check if the staker is the owner of the deposit; if not, return 0
        if (deposit_.staker != _staker) {
            return 0;
        }

        // Calculate the elapsed time since the last update
        uint256 elapsedTime = block.timestamp - deposit_.timeOfLastUpdate;
        // Get the deposited amount
        uint256 depositedAmount = deposit_.deposited;

        // Calculate the base reward per second using the token's APR
        uint256 tokenApr = aprERC20[deposit_.token];

        /**
         * @dev This line calculates the reward earned per second by a staker for their deposit, considering the deposit's APR (annual percentage rate).
         *
         * The formula breakdown:
         * 1. depositedAmount: The amount of tokens the staker deposited.
         * 2. tokenApr: The annual percentage rate for the token in question (e.g. 25% APR).
         * 3. 1e18: A scaling factor used to maintain precision in the calculations (10^18 or 1 followed by 18 zeros).
         * 4. 365 * 24 * 3600: The total number of seconds in a year, used to convert the APR to a per-second rate.
         * 5. 100: Used to convert the APR percentage to a decimal (e.g. 25% becomes 0.25).
         *
         * The formula calculates the per-second reward by multiplying the deposited amount and the token's APR, and then scaling it up by 1e18.
         * After that, it divides the result by the total number of seconds in a year and by 100 to adjust for the percentage.
         *
         * Using 1e18 maintains precision in the calculation, avoiding truncation errors due to integer division in Solidity.
         * By scaling up the result and performing the divisions afterward, the calculation maintains precision without truncating intermediate results to zero.
         */
        uint256 rewardPerSecond = (depositedAmount * tokenApr * 1e18) / (365 * 24 * 3600 * 100);
        
        // Calculate the base reward based on elapsed time
        uint256 _reward = elapsedTime * rewardPerSecond / 1e18;

        // Calculate the boost percentage
        uint256 boostPercentage = calculateBoostPercentage(_staker, _depositId);

        // Calculate the final reward by applying the boost percentage
        _reward = (_reward * boostPercentage) / divisorERC20[deposit_.token];

        // Return the calculated reward
        return _reward;
    }      

    // Internal functions:

    /**
     * @dev This internal function calculates the compounded rewards for a given deposited amount and number of elapsed periods.
     *      The function assumes a fixed 25% APR and 8760 periods per year (hourly compounding). It uses exponentiation to calculate
     *      the compounded rewards using the formula A = P * (1 + r/n)^(nt), where:
     *          A: final amount after compounding
     *          P: initial deposited amount
     *          r: annual interest rate (25%)
     *          n: number of periods in a year (8760)
     *          t: number of elapsed periods
     * @param _depositedAmount The initial deposited amount.
     * @param _periodsElapsed The number of elapsed periods (hours) since the deposit.
     * @return compound The calculated compounded rewards for the given deposited amount and elapsed periods.
     */
    function _calculateCompound(uint256 _depositedAmount, uint256 _periodsElapsed) internal pure returns (uint256 compound) {
        uint256 periodsInYear = 8760; // 24 hours * 365 days
        uint256 compoundFactor = 1 + (25 * 1e1 / periodsInYear);

        //Calculate compounded rewards using exponentiation (A = P * (1 + r/n)^(nt))
        compound = _depositedAmount * (compoundFactor ** _periodsElapsed) / (1e1 ** _periodsElapsed);

        return compound;        
    }
        
        
    // Functions for modifying  staking mechanism variables:
    /**
     * @dev This internal function is used to update the total rewarded amount and the total rewarded amount
     *      for a specific user and token. It is called when rewards are distributed or staked.
     * @param _amount The amount of tokens to add to the total rewarded and user's total rewarded.
     * @param _token The address of the token contract.
     * @param _user The address of the user receiving the rewards.
     */
    function _addTotalRewardedAmount(uint256 _amount, address _token, address _user) internal {
        totalRewarded[_token] += _amount;
        userTotalRewardedByCoin[_token][_user] += _amount;
    }


    /**
     * @dev This internal function adds the given amount to the total staked amount for a specified token
     *      and increases the staked amount for the user by the same amount.
     * @param _amount The amount to add to the total staked amount and user's staked amount.
     * @param _token The address of the token for which to update the staked amount.
     * @param _user The address of the user whose staked amount should be increased.
     */
    function _addTotalStakedAmount(uint256 _amount, address _token, address _user) internal {
        totalStaked[_token] += _amount;
        userTotalStakedByCoin[_token][_user] += _amount;
    }

    /**
     * @dev This internal function subtracts the given amount from the total staked amount for a specified token
     *      and decreases the staked amount for the user by the same amount.
     * @param _amount The amount to subtract from the total staked amount and user's staked amount.
     * @param _token The address of the token for which to update the staked amount.
     * @param _user The address of the user whose staked amount should be decreased.
     */
    function _subtractStakedAmount(uint256 _amount,  address _token, address _user) internal {
        // do a underflow check
        require(totalStaked[_token] >= _amount, "Staking: Not enough staked (Contract)");
        require(userTotalStakedByCoin[_token][_user] >= _amount, "Staking: Not enough staked (User)");
        totalStaked[_token] -= _amount;
        userTotalStakedByCoin[_token][_user] -= _amount;
    }

    /**
     * @dev This internal function adds the given amount to the total withdrawal fees for a specified token.
     * @param _amount The amount to add to the total withdrawal fees.
     * @param _token The address of the token for which to update the withdrawal fees.
     */
    function _addTotalWithdrawalFees(uint256 _amount, address _token) internal {
        totalWithdrawalFees[_token] += _amount;
    }
    
    /**
     * @dev This function sets the APR for a specified token.
     * @param _apr The rewards per hour value to be set, as x% APR. (e.g. 25 = 25%)
     * @param _tokenId The address of the token for which to set the rewards per hour.
     */
    function setAPR(uint256 _apr, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        aprERC20[_tokenId] = _apr; 
        emit NewAPR(_apr, _tokenId);
    }

    /**
     * @dev This function sets the minimum staking amount for a specified token.
     * @param _minStake The minimum staking amount to be set, in wei.
     * @param _tokenId The address of the token for which to set the minimum staking amount.
     */
    function setMinStake(uint256 _minStake, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        minStakeERC20[_tokenId] = _minStake;
        emit NewMinStake(_minStake, _tokenId);
    }

    /**
     * @dev This function sets the ratio for a specified ERC20 token.
     * @param _ratio The ratio value to be set.
     * @param _tokenId The address of the token for which to set the ratio.
     */
    function setRatio(uint256 _ratio, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        ratioERC20[_tokenId] = _ratio;
        emit NewRatio(_ratio, _tokenId);
    }

    /**
     * @dev This function sets the address of the Helix ERC20 contract.
     * @param _helix The address of the Helix ERC20 contract.
     */
    function setHelixERC20(address _helix) public onlyGovernor {
        require(_helix != address(0), "Helix address cannot be 0x0");
        helixERC20 = IHelix(_helix);
        emit NewHelixERC20(_helix);
    }

    /**
     * @dev This function sets the address of the konduxERC721Founders contract.
     * @param _konduxERC721Founders The address of the konduxERC721Founders contract.
     */
    function setKonduxERC721Founders(address _konduxERC721Founders) public onlyGovernor {
        require(_konduxERC721Founders != address(0), "Founders address cannot be 0x0");
        konduxERC721Founders = IERC721(_konduxERC721Founders);
        emit NewKonduxERC721Founders(_konduxERC721Founders);
    }

    /**
     * @dev This function sets the address of the konduxERC721kNFT contract.
     * @param _konduxERC721kNFT The address of the konduxERC721kNFT contract.
     */
    function setKonduxERC721kNFT(address _konduxERC721kNFT) public onlyGovernor {
        require(_konduxERC721kNFT != address(0), "kNFT address cannot be 0x0");
        konduxERC721kNFT = _konduxERC721kNFT;
        emit NewKonduxERC721kNFT(_konduxERC721kNFT);
    }

    /**
     * @dev This function sets the address of the Treasury contract.
     * @param _treasury The address of the Treasury contract.
     */
    function setTreasury(address _treasury) public onlyGovernor {
        require(_treasury != address(0), "Treasury address cannot be 0x0");
        treasury = ITreasury(_treasury);
        emit NewTreasury(_treasury);
    }

    /**
     * @dev This function sets the withdrawal fee for a specified token.
     * @param _withdrawalFee The withdrawal fee value to be set.
     * @param _tokenId The address of the token for which to set the withdrawal fee.
     */
    function setWithdrawalFee(uint256 _withdrawalFee, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        require(_withdrawalFee <= divisorERC20[_tokenId], "Withdrawal fee cannot be more than 100%");
        withdrawalFeeERC20[_tokenId] = _withdrawalFee;
        emit NewWithdrawalFee(_withdrawalFee, _tokenId); 
    }

    /**
     * @dev This function sets the founders reward boost for a specified token.
     * @param _foundersRewardBoost The founders reward boost value to be set.
     * @param _tokenId The address of the token for which to set the founders reward boost.
     */
    function setFoundersRewardBoost(uint256 _foundersRewardBoost, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        foundersRewardBoostERC20[_tokenId] = _foundersRewardBoost;
        emit NewFoundersRewardBoost(_foundersRewardBoost, _tokenId);
    }

    /**
     * @dev This function sets the kNFT reward boost for a specified token.
     * @param _kNFTRewardBoost The kNFT reward boost value to be set.
     * @param _tokenId The address of the token for which to set the kNFT reward boost.
     */
    function setkNFTRewardBoost(uint256 _kNFTRewardBoost, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        kNFTRewardBoostERC20[_tokenId] = _kNFTRewardBoost;
        emit NewKNFTRewardBoost(_kNFTRewardBoost, _tokenId); 
    }

    /**
    * @dev This function sets the compound frequency for a specified token.
    * @param _compoundFreq The compound frequency value to be set.
    * @param _tokenId The address of the token for which to set the compound frequency.
    */
    function setCompoundFreq(uint256 _compoundFreq, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        compoundFreqERC20[_tokenId] = _compoundFreq;
        emit NewCompoundFreq(_compoundFreq, _tokenId);
    }

    /**
     * @dev This function sets the penalty percentage for early withdrawal of a specified token.
     * @param _token The address of the token for which to set the penalty percentage.
     * @param penaltyPercentage The penalty percentage value to be set. Must be between 0 and 100. 
     */
    function setEarlyWithdrawalPenalty(address _token, uint256 penaltyPercentage) public onlyGovernor {
        // Check if the token address is set
        require(_token != address(0), "Token address is not set"); 
        require(penaltyPercentage <= 100, "Penalty percentage must be between 0 and 100");
        earlyWithdrawalPenalty[_token] = penaltyPercentage;
    }  

    /**
     * @dev This function sets the timelock category boost for a specified category.
     * @param _category The category for which to set the boost.
     * @param _boost The boost value to be set.
     */
    function setTimelockCategoryBoost(uint _category, uint256 _boost) public onlyGovernor {
        timelockCategoryBoost[_category] = _boost;
    }

    /**
     * @dev This function sets the divisor for a specified token.
     * @param _divisor The divisor value to be set.
     * @param _tokenId The address of the token for which to set the divisor.
     */
    function setDivisorERC20(uint256 _divisor, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        divisorERC20[_tokenId] = _divisor;
        emit NewDivisorERC20(_divisor, _tokenId);
    }

    /**
     * @dev This internal function sets whether an ERC20 token is authorized as a staking currency.
     * Emits a {NewAuthorizedERC20} event.
     * @param _token The address of the token to be authorized or deauthorized.
     * @param _authorized True to authorize the token, false to deauthorize.
     */
    function _setAuthorizedERC20(address _token, bool _authorized) internal {
        require(_token != address(0), "Token address cannot be 0x0");
        if (_authorized == true) {
            require(aprERC20[_token] > 0, "Rewards per hour must be greater than 0");
            require(compoundFreqERC20[_token] > 0, "Compound frequency must be greater than 0");
            require(withdrawalFeeERC20[_token] > 0, "Withdrawal fee must be greater than 0");
            require(foundersRewardBoostERC20[_token] > 0, "Founders reward boost must be greater than 0");
            require(kNFTRewardBoostERC20[_token] > 0, "kNFT reward boost must be greater than 0");
            require(ratioERC20[_token] > 0, "Ratio must be greater than 0");
            require(minStakeERC20[_token] > 0, "Minimum stake must be greater than 0");
            require(divisorERC20[_token] > 0, "Divisor must be greater than 0");
            require(IERC20(_token).totalSupply() > 0, "Token total supply must be greater than 0");
        }
        authorizedERC20[_token] = _authorized;
        emit NewAuthorizedERC20(_token, _authorized);
    }

    /**
     * @dev This function sets whether an ERC20 token is authorized as a staking currency.
     * Emits a {NewAuthorizedERC20} event.
     * @param _token The address of the token to be authorized or deauthorized.
     * @param _authorized True to authorize the token, false to deauthorize.
     */
    function setAuthorizedERC20(address _token, bool _authorized) public onlyGovernor {
        // Check if the token address is set
        require(_token != address(0), "Token address is not set"); 
        _setAuthorizedERC20(_token, _authorized);
    }

    /**
     * @dev This function sets the version of dna that is allowed to be used for reward bonus
     * @param _dnaVersion The dna version to be set.
     * @param _allowed True to allow the dna version, false to disallow.
     */
    function setAllowedDnaVersion(uint256 _dnaVersion, bool _allowed) public onlyGovernor {
        allowedDnaVersions[_dnaVersion] = _allowed;
    }

    /**
     * @dev This function sets the decimals of a specified token.
     * @param _decimals The decimals value to be set.
     * @param _tokenId The address of the token for which to set the decimals.
     */
    function setDecimalsERC20(uint8 _decimals, address _tokenId) public onlyGovernor {
        // Check if the token address is set
        require(_tokenId != address(0), "Token address is not set"); 
        decimalsERC20[_tokenId] = _decimals;
    }

    /**
     * @dev This function adds a new staking token with its parameters.
     * Emits various events based on the setter functions called during token addition.
     * Emits a {NewAuthorizedERC20} event at the end.
     * @param _token The address of the new staking token.
     * @param _apr The rewards per hour for the new staking token.
     * @param _compoundFreq The compound frequency for the new staking token.
     * @param _withdrawalFee The withdrawal fee for the new staking token.
     * @param _foundersRewardBoost The founders reward boost for the new staking token.
     * @param _kNFTRewardBoost The kNFT reward boost for the new staking token.
     * @param _ratio The ratio for the new staking token.
     * @param _minStake The minimum stake for the new staking token.
     */ 
    function addNewStakingToken(address _token, uint256 _apr, uint256 _compoundFreq, uint256 _withdrawalFee, uint256 _foundersRewardBoost, uint256 _kNFTRewardBoost, uint256 _ratio, uint256 _minStake) public onlyGovernor {
        require(_token != address(0), "Token address cannot be 0x0");
        require(_apr > 0, "Rewards per hour must be greater than 0"); 
        require(_compoundFreq > 0, "Compound frequency must be greater than 0");
        require(_withdrawalFee > 0, "Withdrawal fee must be greater than 0");
        require(_foundersRewardBoost > 0, "Founders reward boost must be greater than 0");
        require(_kNFTRewardBoost > 0, "kNFT reward boost must be greater than 0");
        require(_ratio > 0, "Ratio must be greater than 0");
        require(_minStake > 0, "Minimum stake must be greater than 0");
        require(IERC20(_token).totalSupply() > 0, "Token total supply must be greater than 0");

        setDivisorERC20(10_000, _token);
        setFoundersRewardBoost(_foundersRewardBoost, _token);
        setkNFTRewardBoost(_kNFTRewardBoost, _token);
        setAPR(_apr, _token); 
        setRatio(_ratio, _token);
        setWithdrawalFee(_withdrawalFee, _token);
        setCompoundFreq(_compoundFreq, _token);
        setMinStake(_minStake, _token);
        setDecimalsERC20(IERC20Metadata(_token).decimals(), _token);

        _setAuthorizedERC20(_token, true); 
    }


    // Functions for getting staking mechanism variables:

    /**
     * @dev This function returns the time of the last update for the specified deposit ID.
     * @param _depositId The ID of the deposit for which the time of the last update is requested.
     * @return _timeOfLastUpdate The time of the last update for the specified deposit ID.
     */
    function getTimeOfLastUpdate(uint _depositId) public view returns (uint256 _timeOfLastUpdate) {
        return userDeposits[_depositId].timeOfLastUpdate;
    }

    /**
     * @dev This function returns the staked amount for the specified deposit ID.
     * @param _depositId The ID of the deposit for which the staked amount is requested.
     * @return _deposited The staked amount for the specified deposit ID.
     */
    function getStakedAmount(uint _depositId) public view returns (uint256 _deposited) {
        return userDeposits[_depositId].deposited;
    }

    /**
     * @dev This function returns the APR for the specified token.
     * @param _tokenId The address o...

// [truncated — 67992 bytes total]
IHelix.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IHelix is IERC20, IERC20Metadata {
    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
    function burn(address _to, uint256 _amount) external;
    function mint(address _to, uint256 _amount) external; 
}
IKondux.sol 21 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

interface IKondux {
    function changeDenominator(uint96 _denominator) external returns (uint96);
    function setDefaultRoyalty(address receiver, uint96 feeNumerator) external;
    function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) external;
    function setBaseURI(string memory _newURI) external returns (string memory);
    function tokenURI(uint256 tokenId) external view returns (string memory);
    function pause() external;
    function unpause() external;
    function safeMint(address to, uint256 dna) external returns (uint256);
    function setDna(uint256 _tokenID, uint256 _dna) external;
    function getDna(uint256 _tokenID) external view returns (uint256);
    function readGen(uint256 _tokenID, uint8 startIndex, uint8 endIndex) external view returns (int256);
    function writeGen(uint256 _tokenID, uint256 inputValue, uint8 startIndex, uint8 endIndex) external;
    function getTransferDate(uint256 _tokenID) external view returns (uint256);
}
ITreasury.sol 26 lines
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;

interface ITreasury {
    function deposit(
        uint256 _amount,
        address _token
    ) external;

    function depositEther() external payable;

    function withdraw(
        uint256 _amount,
        address _token
    ) external;

    function withdrawTo(
        uint256 _amount,
        address _token,
        address _to
    ) external;

    function withdrawEther(
        uint256 _amount
    ) external;
}
IAuthority.sol 30 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.9;

interface IAuthority {
    /* ========== EVENTS ========== */

    event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event RolePushed(address indexed account, bytes32 _role);

    event GovernorPulled(address indexed from, address indexed to);
    event GuardianPulled(address indexed from, address indexed to);
    event PolicyPulled(address indexed from, address indexed to);
    event VaultPulled(address indexed from, address indexed to);

    /* ========== VIEW ========== */

    function governor() external view returns (address);

    function guardian() external view returns (address);

    function policy() external view returns (address);

    function vault() external view returns (address);

    function roles(address _addr) external view returns (bytes32);

}
AccessControlled.sol 90 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "../interfaces/IAuthority.sol";

/// @dev Reasoning for this contract = modifiers literaly copy code
/// instead of pointing towards the logic to execute. Over many
/// functions this bloats contract size unnecessarily.
/// imho modifiers are a meme.
abstract contract AccessControlled {
    /* ========== EVENTS ========== */

    event AuthorityUpdated(IAuthority authority);

    /* ========== STATE VARIABLES ========== */

    IAuthority public authority;

    /* ========== Constructor ========== */

    constructor(IAuthority _authority) {
        require(address(_authority) != address(0), "Authority cannot be zero address");
        authority = _authority;
        emit AuthorityUpdated(_authority);
    }

    /* ========== "MODIFIERS" ========== */

    modifier onlyGovernor {
        _onlyGovernor();
        _;
    }

    modifier onlyGuardian {
        _onlyGuardian();
        _;
    }

    modifier onlyPolicy {
        _onlyPolicy();
        _;
    }

    modifier onlyVault {
        _onlyVault();
        _;
    }

    modifier onlyGlobalRole(bytes32 _role){
        _onlyRole(_role);
        _;
    }

    /* ========== GOV ONLY ========== */

    function initializeAuthority(IAuthority _newAuthority) internal {
        require(authority == IAuthority(address(0)), "AUTHORITY_INITIALIZED");
        authority = _newAuthority;
        emit AuthorityUpdated(_newAuthority);
    }

    function setAuthority(IAuthority _newAuthority) external {
        _onlyGovernor();
        authority = _newAuthority;
        emit AuthorityUpdated(_newAuthority);
    }

    /* ========== INTERNAL CHECKS ========== */

    function _onlyGovernor() internal view {
        require(msg.sender == authority.governor(), "UNAUTHORIZED");
    }

    function _onlyGuardian() internal view {
        require(msg.sender == authority.guardian(), "UNAUTHORIZED");
    }

    function _onlyPolicy() internal view {
        require(msg.sender == authority.policy(), "UNAUTHORIZED");        
    }

    function _onlyVault() internal view {
        require(msg.sender == authority.vault(), "UNAUTHORIZED");                
    }

    function _onlyRole(bytes32 _role) internal view {
        require(authority.roles(msg.sender) == _role, "UNAUTHORIZED");
    }
  
}
IKonduxERC20.sol 45 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IKonduxERC20 is IERC20 {
    function excludedFromFees(address) external view returns (bool);
    function tradingOpen() external view returns (bool);
    function taxSwapMin() external view returns (uint256);
    function taxSwapMax() external view returns (uint256);
    function _isLiqPool(address) external view returns (bool);
    function taxRateBuy() external view returns (uint8);
    function taxRateSell() external view returns (uint8);
    function antiBotEnabled() external view returns (bool);
    function excludedFromAntiBot(address) external view returns (bool);
    function _lastSwapBlock(address) external view returns (uint256);
    function taxWallet() external view returns (address);

    event TokensAirdropped(uint256 totalWallets, uint256 totalTokens);
    event TokensBurned(address indexed burnedByWallet, uint256 tokenAmount);
    event TaxWalletChanged(address newTaxWallet);
    event TaxRateChanged(uint8 newBuyTax, uint8 newSellTax);

    function initLP() external;
    function enableTrading() external;
    function burnTokens(uint256 amount) external;
    function enableAntiBot(bool isEnabled) external;
    function excludeFromAntiBot(address wallet, bool isExcluded) external;
    function excludeFromFees(address wallet, bool isExcluded) external;
    function adjustTaxRate(uint8 newBuyTax, uint8 newSellTax) external;
    function setTaxWallet(address newTaxWallet) external;
    function taxSwapSettings(uint32 minValue, uint32 minDivider, uint32 maxValue, uint32 maxDivider) external;

    function totalSupply() external view returns (uint256);
	function decimals() external view returns (uint8);
	function symbol() external view returns (string memory);
	function name() external view returns (string memory);
	function getOwner() external view returns (address);
	function balanceOf(address account) external view returns (uint256);
	function transfer(address recipient, uint256 amount) external returns (bool);
	function allowance(address _owner, address spender) external view returns (uint256);
	function approve(address spender, uint256 amount) external returns (bool);
	function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
Counters.sol 43 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}
IERC20.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}
IERC721.sol 145 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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);
}
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);
}
IERC20Metadata.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
IERC721Enumerable.sol 29 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

Read Contract

allowedDnaVersions 0x4a912ce5 → bool
aprERC20 0x06811c92 → uint256
authority 0xbf7e214f → address
authorizedERC20 0x580e26a1 → bool
calculateBoostPercentage 0x3dc60a70 → uint256
calculateKNFTBoostPercentage 0xec640153 → uint256
calculateMaxKNFTBoostPercentage 0x89d5e38a → uint256
calculateRewards 0xbeb8314c → uint256
compoundFreqERC20 0xea425a6d → uint256
compoundRewardsTimer 0xa55dfa1c → uint256
decimalsERC20 0x3ae5713d → uint8
divisorERC20 0xd6b92434 → uint256
earlyWithdrawalPenalty 0x84d3d586 → uint256
foundersRewardBoostERC20 0x546f2b66 → uint256
getAPR 0x1c5122d9 → uint256
getAllowedDnaVersion 0xf02842a5 → bool
getDecimalsERC20 0xf0d33cad → uint8
getDepositDetails 0x3d0132e7 → uint256, uint256, uint8, uint256, uint256, uint256
getDepositIds 0xc5ebc2f7 → uint256[]
getDepositInfo 0x5328c2bf → uint256, uint256
getDepositRatioERC20 0xb6740c3b → uint256
getDepositTimestamp 0x19720be1 → uint256
getDivisorERC20 0xf91159e3 → uint256
getEarlyWithdrawalPenalty 0xf2760e9d → uint256
getFoundersRewardBoost 0x4715f40c → uint256
getMaxTop5BonusesAndIds 0xf02d4a45 → uint256[], uint256[]
getMinStake 0xc39ccf88 → uint256
getRatioERC20 0xc706fee5 → uint256
getStakedAmount 0x5a5392be → uint256
getTimeOfLastUpdate 0x59b0e590 → uint256
getTimelock 0x10b18438 → uint256
getTimelockCategory 0x38c26d18 → uint8
getTimelockCategoryBoost 0x6e3c1154 → uint256
getTop5BonusesAndIds 0x0399be55 → uint256[], uint256[]
getTotalRewards 0x2bcf161c → uint256
getTotalStaked 0xdd2a8b11 → uint256
getTotalWithdrawalFees 0x151a6349 → uint256
getUserTotalRewardsByCoin 0xfb68d53b → uint256
getUserTotalStakedByCoin 0xfe1686b8 → uint256
getWithdrawalFee 0x5722dee0 → uint256
getkNFTRewardBoost 0xe519cf17 → uint256
helixERC20 0xa9b29407 → address
kNFTRewardBoostERC20 0x1e78e9a2 → uint256
konduxERC721Founders 0xd55111c5 → address
konduxERC721kNFT 0x5385689c → address
minStakeERC20 0x72aa9d91 → uint256
ratioERC20 0x3a46a46d → uint256
timelockCategoryBoost 0xfad68d1f → uint256
timelockDurations 0xfe31b228 → uint256
totalRewarded 0xf384fe76 → uint256
totalStaked 0x9bfd8d61 → uint256
totalWithdrawalFees 0x7cbfd144 → uint256
treasury 0x61d027b3 → address
userDeposits 0xf16b41f4 → address, address, uint256, uint256, uint256, uint256, uint256, uint256, uint8, uint256
userDepositsIds 0xba577148 → uint256
userTotalRewardedByCoin 0x7b16c543 → uint256
userTotalStakedByCoin 0x5dfa4596 → uint256
withdrawalFeeERC20 0xb54b9c88 → uint256

Write Contract 25 functions

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

addNewStakingToken 0x911ddf0a
address _token
uint256 _apr
uint256 _compoundFreq
uint256 _withdrawalFee
uint256 _foundersRewardBoost
uint256 _kNFTRewardBoost
uint256 _ratio
uint256 _minStake
claimRewards 0x0962ef79
uint256 _depositId
deposit 0x4774dc93
uint256 _amount
uint8 _timelock
address _token
returns: uint256
earlyUnstake 0x4e781513
uint256 _amount
uint256 _depositId
setAPR 0x336cada8
uint256 _apr
address _tokenId
setAllowedDnaVersion 0xaaa78db4
uint256 _dnaVersion
bool _allowed
setAuthority 0x7a9e5e4b
address _newAuthority
setAuthorizedERC20 0x7bf7f3d3
address _token
bool _authorized
setCompoundFreq 0xe37d47e4
uint256 _compoundFreq
address _tokenId
setDecimalsERC20 0xf19d6849
uint8 _decimals
address _tokenId
setDivisorERC20 0xdad775b1
uint256 _divisor
address _tokenId
setEarlyWithdrawalPenalty 0x96ce3627
address _token
uint256 penaltyPercentage
setFoundersRewardBoost 0x1f6514db
uint256 _foundersRewardBoost
address _tokenId
setHelixERC20 0xcfb656a5
address _helix
setKonduxERC721Founders 0x78e2816b
address _konduxERC721Founders
setKonduxERC721kNFT 0xbf811fbc
address _konduxERC721kNFT
setMinStake 0x404d221a
uint256 _minStake
address _tokenId
setRatio 0x171f9ce4
uint256 _ratio
address _tokenId
setTimelockCategoryBoost 0x5cd3667e
uint256 _category
uint256 _boost
setTreasury 0xf0f44260
address _treasury
setWithdrawalFee 0xcf717c8c
uint256 _withdrawalFee
address _tokenId
setkNFTRewardBoost 0xa13d5079
uint256 _kNFTRewardBoost
address _tokenId
stakeRewards 0x4477c974
uint256 _depositId
withdraw 0x441a3e70
uint256 _amount
uint256 _depositId
withdrawAndClaim 0x87eebaea
uint256 _amount
uint256 _depositId

Recent Transactions

No transactions found for this address