Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xB3258E912B88781892489eDb8633C063e5F32cc5
Balance 0 ETH
Nonce 1
Code Size 22307 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

22307 bytes
0x608060405234801561000f575f80fd5b5060043610610393575f3560e01c80637882bd33116101df578063ad7a672f11610109578063d664c0c8116100a9578063f073914711610079578063f0739147146108f2578063f2fde38b146108fa578063fa50c7d01461090d578063fbcbc0f11461092c575f80fd5b8063d664c0c81461085d578063d7b6453f14610890578063d9b26a69146108cc578063dae97c1b146108df575f80fd5b8063ca5b7465116100e4578063ca5b746514610801578063cb43b2dd1461080a578063d5cb06c41461081d578063d5eb911314610855575f80fd5b8063ad7a672f146107bc578063b8522043146107c5578063c54e44eb146107da575f80fd5b806394463e981161017f578063aa5f7e261161014f578063aa5f7e261461073b578063aafd847a1461074e578063ab6ddfa814610776578063ad5c464814610795575f80fd5b806394463e9814610664578063a87430ba14610677578063a8b9d24014610720578063a9c66b1414610733575f80fd5b806385a6b3ae116101ba57806385a6b3ae1461062e578063872b26da146106375780638da5cb5b1461064057806391b89fba14610651575f80fd5b80637882bd33146105ff5780637be1ee9714610612578063814eaeea1461061b575f80fd5b806345d05c42116102c05780636843cd8411610260578063715018a611610230578063715018a6146105c957806371778e7d146105d157806371a0f50e146105d95780637231c394146105ec575f80fd5b80636843cd84146105445780636a4740021461056c5780636f77926b1461057457806370a0823114610598575f80fd5b8063514d8a171161029b578063514d8a17146104ee57806351a8ea6314610515578063583a6c34146105285780635ad31e9914610531575f80fd5b806345d05c42146104d557806348c54b9d146104de5780634e71d92d146104e6575f80fd5b806327ce01471161033657806330bb4cff1161030657806330bb4cff14610494578063315a095d1461049c57806337b90a4f146104af5780633865d2b5146104c2575f80fd5b806327ce0147146104475780632b2e0d5d1461045a5780632d141467146104775780632e29490d1461047f575f80fd5b806317460b1b1161037157806317460b1b146104065780631a2c2e861461040e5780631b90e0e8146104215780631d5d7cc914610434575f80fd5b80630758d9241461039757806308f2f233146103db5780630fc924e3146103fc575b5f80fd5b6103be7f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d81565b6040516001600160a01b0390911681526020015b60405180910390f35b6103ee6103e9366004614d7a565b610969565b6040519081526020016103d2565b610404610b3b565b005b610404610c1e565b61040461041c366004614d93565b610c60565b61040461042f366004614d93565b610c97565b610404610442366004614dc2565b610d34565b6103ee610455366004614d7a565b611338565b6010546104679060ff1681565b60405190151581526020016103d2565b6103ee61139a565b6104876113d7565b6040516103d29190614ddd565b6006546103ee565b6104046104aa366004614d93565b6113e3565b6104046104bd366004614e34565b61188d565b6103ee6104d0366004614d93565b611ea1565b6103ee600c5481565b610404612066565b61040461235b565b6103be7f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e781565b610404610523366004614f37565b61242a565b6103ee600b5481565b61040461053f366004615073565b61265c565b6103ee610552366004614d7a565b6001600160a01b03165f9081526004602052604090205490565b6104046127e5565b610587610582366004614d7a565b6127f1565b6040516103d295949392919061516c565b6103ee6105a6366004614d7a565b6001600160a01b03165f908152601160205260409020546001600160701b031690565b6104046128c2565b6005546103ee565b6103ee6105e7366004614d7a565b612935565b6104046105fa3660046151fc565b612a0c565b61040461060d366004614d93565b612af9565b6103ee600e5481565b61040461062936600461522e565b612b86565b6103ee60065481565b6103ee600f5481565b6007546001600160a01b03166103be565b6103ee61065f366004614d7a565b612efa565b610404610672366004615247565b612f04565b6106d7610685366004614d7a565b60116020525f90815260409020805460018201546002909201546001600160701b0380831693600160701b909304169165ffffffffffff81169160ff600160301b8304811692600160381b9004169086565b604080516001600160701b03978816815296909516602087015265ffffffffffff909316938501939093521515606084015260ff909116608083015260a082015260c0016103d2565b6103ee61072e366004614d7a565b612f96565b610404612fbb565b610404610749366004614d93565b6130af565b6103ee61075c366004614d7a565b6001600160a01b03165f9081526003602052604090205490565b6103ee610784366004614d7a565b60046020525f908152604090205481565b6103be7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6103ee60055481565b6107cd6134c1565b6040516103d291906152aa565b6103be7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec781565b6103ee600d5481565b610404610818366004614d93565b6134cd565b6103ee61082b366004614d7a565b6001600160a01b03165f90815260116020526040902054600160701b90046001600160701b031690565b610404613673565b61087061086b366004614d7a565b61372f565b6040805194855260208501939093529183015260608201526080016103d2565b600f54600c54600d54600e5460105460ff166040805195865260208601949094529284019190915260608301521515608082015260a0016103d2565b6104046108da366004615247565b6137d1565b6104046108ed366004614d93565b613870565b6104046138f0565b610404610908366004614d7a565b6138fa565b6103ee61091b366004614d93565b600a6020525f908152604090205481565b61093f61093a366004614d7a565b61392d565b604080516001600160a01b03909516855260208501939093529183015260608201526080016103d2565b5f8061097483612f96565b604080516003808252608082019092529192505f9190602082016060803683370190505090507f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7815f815181106109cd576109cd6152bc565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110610a2157610a216152bc565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e781600281518110610a7557610a756152bc565b6001600160a01b03928316602091820292909201015260405163d06ca61f60e01b81525f917f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d169063d06ca61f90610ad390869086906004016152d0565b5f60405180830381865afa158015610aed573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610b1491908101906152e8565b905080600281518110610b2957610b296152bc565b60200260200101519350505050919050565b6007546001600160a01b03163314610b6e5760405162461bcd60e51b8152600401610b6590615379565b60405180910390fd5b60105460ff1615610bba5760405162461bcd60e51b81526020600482015260166024820152755265776172647320616c72656164792061637469766560501b6044820152606401610b65565b5f600c5411610c0b5760405162461bcd60e51b815260206004820152601e60248201527f5265776172647320706572207365636f6e64206d7573742062652073657400006044820152606401610b65565b42600d556010805460ff19166001179055565b6007546001600160a01b03163314610c485760405162461bcd60e51b8152600401610b6590615379565b610c50613969565b5f600c556010805460ff19169055565b6007546001600160a01b03163314610c8a5760405162461bcd60e51b8152600401610b6590615379565b610c92613969565b600c55565b6007546001600160a01b03163314610cc15760405162461bcd60e51b8152600401610b6590615379565b610ccc6008826139ca565b610d185760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e6720506572696f6420646f65736e2774206578697374000000006044820152606401610b65565b610d236008826139e4565b505f908152600a6020526040812055565b60025f5403610d555760405162461bcd60e51b8152600401610b65906153ae565b60025f55610d61613673565b335f908152601160209081526040808320815160c08101835281546001600160701b038082168352600160701b9091041693810193909352600181015465ffffffffffff81169284019290925260ff600160301b830481161580156060860152600160381b9093041660808401526002015460a0830152909190610e11576064826080015160ff16835f0151610df791906153f9565b610e01919061542f565b6001600160701b03169050610e38565b600b548251606491610e2b916001600160701b031661545c565b610e359190615473565b90505b81515f90610e509083906001600160701b0316615486565b83519091506001600160701b0316610eaa5760405162461bcd60e51b815260206004820152601760248201527f4e6f20746f6b656e7320776974682077697468647261770000000000000000006044820152606401610b65565b5f84158015610ec2575083516001600160701b031615155b1561101d57610ecf613969565b60a0840151600e54335f90815260046020526040902054610f0c9291610f069164e8d4a5100091610f0091906139ef565b90613a6d565b90613aae565b9050801561101d57600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015610f79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9d9190615499565b610fa79190615486565b811115610fc65760405162461bcd60e51b8152600401610b65906154b0565b610ffa6001600160a01b037f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e7163383613aef565b60405181815233905f805160206156ce8339815191529060200160405180910390a25b835f01516001600160701b0316600f5f82825461103a9190615486565b90915550505f8085526040808601828152602080880184815260a08901858152338087526011909352948490208951815492516001600160701b03908116600160701b026001600160e01b0319909416911617919091178155915160018301805460608b015160808c015160ff16600160381b0260ff60381b19911515600160301b0266ffffffffffffff1990931665ffffffffffff9590951694909417919091171691909117905592516002909101555163a9059cbb60e01b81527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b03169163a9059cbb9161114a919086906004016001600160a01b03929092168252602082015260400190565b6020604051808303815f875af1158015611166573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061118a91906154e7565b508215611242577f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b031663a9059cbb6111d26007546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018690526044016020604051808303815f875af115801561121c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061124091906154e7565b505b61124c335f613b57565b6040516370a0823160e01b81523060048201527f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316906370a0823190602401602060405180830381865afa1580156112ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112d29190615499565b6014556112e0601233613b6c565b156112f2576112f0601233613b8d565b505b604080518381526020810185905233917fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595910160405180910390a2505060015f55505050565b6001600160a01b0381165f908152600260209081526040808320546004909252822054600154600160801b9261138a926113859261137f9161137a91906139ef565b613ba1565b90613baf565b613be9565b6113949190615473565b92915050565b5f42600d5411806113ae575060105460ff16155b156113b857505f90565b600c54600d546113c89042615486565b6113d2919061545c565b905090565b60606113d26008613bfa565b60025f54036114045760405162461bcd60e51b8152600401610b65906153ae565b60025f55611410613673565b335f90815260116020908152604091829020825160c08101845281546001600160701b038082168352600160701b90910416928101839052600182015465ffffffffffff81169482019490945260ff600160301b8504811615156060830152600160381b90940490931660808401526002015460a08301524210156114c35760405162461bcd60e51b8152602060048201526009602482015268546f6f206561726c7960b81b6044820152606401610b65565b80516001600160701b031682111561152c5760405162461bcd60e51b815260206004820152602660248201527f52657175657374696e6720746f20776974686472617720746f6f206d616e7920604482015265746f6b656e7360d01b6064820152608401610b65565b5f611535613969565b60a0820151600e54335f908152600460205260409020546115669291610f069164e8d4a5100091610f0091906139ef565b9050801561167757600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa1580156115d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115f79190615499565b6116019190615486565b8111156116205760405162461bcd60e51b8152600401610b65906154b0565b6116546001600160a01b037f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e7163383613aef565b60405181815233905f805160206156ce8339815191529060200160405180910390a25b82600f5f8282546116889190615486565b909155505081518390839061169e908390615502565b6001600160701b03169052506116b43383613c06565b600e54335f908152600460205260409020546116da9164e8d4a5100091610f00916139ef565b60a08301908152335f8181526011602090815260409182902086518154928801516001600160701b03908116600160701b026001600160e01b031990941691161791909117815581860151600182018054606089015160808a015160ff16600160381b0260ff60381b19911515600160301b0266ffffffffffffff1990931665ffffffffffff9095169490941791909117169190911790559251600290930192909255905163a9059cbb60e01b81527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b03169163a9059cbb916117dd919087906004016001600160a01b03929092168252602082015260400190565b6020604051808303815f875af11580156117f9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061181d91906154e7565b50611829601233613b6c565b801561183d575081516001600160701b0316155b1561184f5761184d601233613b8d565b505b60405183815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a2505060015f5550565b60025f54036118ae5760405162461bcd60e51b8152600401610b65906153ae565b60025f556118ba613673565b335f90815260116020908152604091829020825160c08101845281546001600160701b038082168352600160701b9091041692810192909252600181015465ffffffffffff81169383019390935260ff600160301b8404811615156060840152600160381b909304909216608082015260029091015460a0820152826119705760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8105b5bdd5b9d60aa1b6044820152606401610b65565b611983600865ffffffffffff84166139ca565b61199f5760405162461bcd60e51b8152600401610b6590615521565b8165ffffffffffff16816040015165ffffffffffff1611156119d35760405162461bcd60e51b8152600401610b6590615551565b6119de601233613b6c565b6119ef576119ed601233613ce3565b505b6119f7613969565b80516001600160701b031615611b4d5760a0810151600e54335f908152600460205260408120549092611a3a929091610f069164e8d4a5100091610f00916139ef565b90508015611b4b57600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015611aa7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611acb9190615499565b611ad59190615486565b811115611af45760405162461bcd60e51b8152600401610b65906154b0565b611b286001600160a01b037f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e7163383613aef565b60405181815233905f805160206156ce8339815191529060200160405180910390a25b505b65ffffffffffff82166040820152611b68826201518061559a565b611b7a9065ffffffffffff16426155bb565b65ffffffffffff1660208201526040516370a0823160e01b81523060048201525f9081907f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015611bed573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c119190615499565b6040516323b872dd60e01b8152336004820152306024820152604481018790529091507f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906323b872dd906064016020604051808303815f875af1158015611c84573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ca891906154e7565b506040516370a0823160e01b81523060048201526001600160701b038216907f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015611d16573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d3a9190615499565b611d449190615486565b915081835f01818151611d5791906155ce565b6001600160701b0316905250611d6d3384613c06565b335f90815260046020526040812054600f805491926001600160701b03861692611d989084906155bb565b9091555050600e54611db69064e8d4a5100090610f009084906139ef565b60a08501526040516001600160701b038416815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a25050335f90815260116020908152604080832085518154938701516001600160701b03908116600160701b026001600160e01b0319909516911617929092178255840151600180830180546060880151608089015160ff16600160381b0260ff60381b19911515600160301b0266ffffffffffffff1990931665ffffffffffff9096169590951791909117169290921790915560a09094015160029091015591909155505050565b604080516003808252608082019092525f91829190602082016060803683370190505090507f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7815f81518110611ef957611ef96152bc565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110611f4d57611f4d6152bc565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e781600281518110611fa157611fa16152bc565b6001600160a01b03928316602091820292909201015260405163d06ca61f60e01b81525f917f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d169063d06ca61f90611fff90879086906004016152d0565b5f60405180830381865afa158015612019573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261204091908101906152e8565b905080600281518110612055576120556152bc565b602002602001015192505050919050565b60025f54036120875760405162461bcd60e51b8152600401610b65906153ae565b60025f55612093613673565b335f90815260116020908152604091829020825160c08101845281546001600160701b038082168352600160701b9091041692810192909252600181015465ffffffffffff81169383019390935260ff600160301b8404811615156060840152600160381b909304909216608082015260029091015460a0820152612116613969565b60a0810151600e54335f908152600460205260408120549092612149929091610f069164e8d4a5100091610f00916139ef565b9050801561225a57600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa1580156121b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121da9190615499565b6121e49190615486565b8111156122035760405162461bcd60e51b8152600401610b65906154b0565b6122376001600160a01b037f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e7163383613aef565b60405181815233905f805160206156ce8339815191529060200160405180910390a25b600e54335f908152600460205260409020546122809164e8d4a5100091610f00916139ef565b60a083015260405181815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a250335f90815260116020908152604080832084518154938601516001600160701b03908116600160701b026001600160e01b0319909516911617929092178255830151600180830180546060870151608088015160ff16600160381b0260ff60381b19911515600160301b0266ffffffffffffff1990931665ffffffffffff9096169590951791909117169290921790915560a09093015160029091015555565b60025f540361237c5760405162461bcd60e51b8152600401610b65906153ae565b60025f55612388613673565b6040516370a0823160e01b81523060048201527f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316906370a0823190602401602060405180830381865afa1580156123ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061240e9190615499565b60145561241b335f613cf7565b50612424613969565b60015f55565b6007546001600160a01b031633146124545760405162461bcd60e51b8152600401610b6590615379565b5f5b8351811015612656575f848281518110612472576124726152bc565b6020908102919091018101516001600160a01b0381165f90815260118352604090819020815160c08101835281546001600160701b038082168352600160701b9091041694810194909452600181015465ffffffffffff81169285019290925260ff600160301b8304811615156060860152600160381b90920490911660808401526002015460a083015291508315612599575f858481518110612518576125186152bc565b6020026020010151905060648160ff1611156125855760405162461bcd60e51b815260206004820152602660248201527f43616e6e6f742073657420656d657267656e63792070656e616c7479206f766560448201526572203130302560d01b6064820152608401610b65565b6001606083015260ff1660808201526125a7565b5f6060820181905260808201525b6001600160a01b039091165f9081526011602090815260409182902083518154928501516001600160701b03908116600160701b026001600160e01b031990941691161791909117815590820151600180830180546060860151608087015160ff16600160381b0260ff60381b19911515600160301b0266ffffffffffffff1990931665ffffffffffff9096169590951791909117169290921790915560a09092015160029091015501612456565b50505050565b6007546001600160a01b031633146126865760405162461bcd60e51b8152600401610b6590615379565b5f61268f613969565b5f5b8451811015612728578381815181106126ac576126ac6152bc565b60200260200101516001600160701b0316826126c891906155bb565b91506127208582815181106126df576126df6152bc565b60200260200101518583815181106126f9576126f96152bc565b6020026020010151858481518110612713576127136152bc565b6020026020010151613d63565b600101612691565b507f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b03166323b872dd61276a6007546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303815f875af11580156127ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127de91906154e7565b5050505050565b6127ee33614186565b50565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081018290529080808061282e8661392d565b6001600160a01b039099165f90815260116020908152604091829020825160c08101845281546001600160701b038082168352600160701b9091041692810192909252600181015465ffffffffffff81169383019390935260ff600160301b8404811615156060840152600160381b909304909216608082015260029091015460a082015299929891975095509350915050565b6007546001600160a01b031633146128ec5760405162461bcd60e51b8152600401610b6590615379565b6007546040515f916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600780546001600160a01b0319169055565b6001600160a01b0381165f90815260116020526040812080546001600160701b0316820361296557505f92915050565b600e54600d544211801561297a575060055415155b156129cd575f600d544261298e9190615486565b90505f600c548261299f919061545c565b6005549091506129b48264e8d4a5100061545c565b6129be9190615473565b6129c890846155bb565b925050505b60028201546001600160a01b0385165f90815260046020526040902054612a049190610f069064e8d4a5100090610f0090866139ef565b949350505050565b6007546001600160a01b03163314612a365760405162461bcd60e51b8152600401610b6590615379565b5f5b8151811015612af5575f828281518110612a5457612a546152bc565b6020908102919091018101516001600160a01b0381165f90815260118352604090819020815160c08101835281546001600160701b038082168352600160701b9091041694810194909452600181015465ffffffffffff81169285019290925260ff600160301b8304811615156060860152600160381b90920490911660808401526002015460a08301529150612aeb8282613c06565b5050600101612a38565b5050565b5f8111612b485760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610b65565b612b7d6001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec71633308461424d565b6127ee81614285565b60025f5403612ba75760405162461bcd60e51b8152600401610b65906153ae565b60025f55612bb3613673565b335f90815260116020908152604091829020825160c08101845281546001600160701b038082168352600160701b9091041692810192909252600181015465ffffffffffff8082169484019490945260ff600160301b8204811615156060850152600160381b9091041660808301526002015460a082015290612c3a9060089084166139ca565b612c565760405162461bcd60e51b8152600401610b6590615521565b8165ffffffffffff16816040015165ffffffffffff161115612c8a5760405162461bcd60e51b8152600401610b6590615551565b612c92613969565b80516001600160701b031615612de85760a0810151600e54335f908152600460205260408120549092612cd5929091610f069164e8d4a5100091610f00916139ef565b90508015612de657600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015612d42573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d669190615499565b612d709190615486565b811115612d8f5760405162461bcd60e51b8152600401610b65906154b0565b612dc36001600160a01b037f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e7163383613aef565b60405181815233905f805160206156ce8339815191529060200160405180910390a25b505b65ffffffffffff82166040820152612e03826201518061559a565b612e159065ffffffffffff16426155bb565b65ffffffffffff166020820152612e2c3382613c06565b600e54335f90815260046020526040902054612e529164e8d4a5100091610f00916139ef565b60a08201908152335f90815260116020908152604080832085518154938701516001600160701b03908116600160701b026001600160e01b031990951691161792909217825584015160018083018054606088015160809098015160ff16600160381b0260ff60381b19981515600160301b0266ffffffffffffff1990921665ffffffffffff9095169490941717969096169190911790945591516002909201919091555550565b5f61139482612f96565b6007546001600160a01b03163314612f2e5760405162461bcd60e51b8152600401610b6590615379565b612f396008836139ca565b612f855760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e6720506572696f6420646f65736e2774206578697374000000006044820152606401610b65565b5f918252600a602052604090912055565b6001600160a01b0381165f9081526003602052604081205461139490610f0684611338565b6007546001600160a01b03163314612fe55760405162461bcd60e51b8152600401610b6590615379565b5f612fee6134c1565b90505f5b8151811015612af5575f82828151811061300e5761300e6152bc565b6020908102919091018101516001600160a01b0381165f90815260118352604090819020815160c08101835281546001600160701b038082168352600160701b9091041694810194909452600181015465ffffffffffff81169285019290925260ff600160301b8304811615156060860152600160381b90920490911660808401526002015460a083015291506130a58282613c06565b5050600101612ff2565b60025f54036130d05760405162461bcd60e51b8152600401610b65906153ae565b60025f556130dc613673565b335f818152601160205260408120916130f49061430d565b90508015613289576040516370a0823160e01b81523060048201525f907f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015613160573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131849190615499565b9050613190828561439e565b6040516370a0823160e01b81523060048201525f9082906001600160a01b037f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e716906370a0823190602401602060405180830381865afa1580156131f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061321a9190615499565b6132249190615486565b8454909150819085905f906132439084906001600160701b03166155ce565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550806001600160701b0316600f5f82825461328191906155bb565b909155505050505b60105460ff1680156132a4575081546001600160701b031615155b15613417576132b1613969565b335f908152600460205260408120546002840154600e549192916132e69190610f069064e8d4a5100090610f009087906139ef565b9050801561341457600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015613353573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133779190615499565b6133819190615486565b8111156133a05760405162461bcd60e51b8152600401610b65906154b0565b83546133b69082906001600160701b03166155bb565b84546dffffffffffffffffffffffffffff19166001600160701b0391909116178455600f80548291905f906133ec9084906155bb565b909155505060405181815233905f805160206156ce8339815191529060200160405180910390a25b50505b6040805160c08101825283546001600160701b038082168352600160701b909104166020820152600184015465ffffffffffff81169282019290925260ff600160301b8304811615156060830152600160381b9092049091166080820152600283015460a082015261348a903390613c06565b600e54335f908152600460205260409020546134b09164e8d4a5100091610f00916139ef565b600290920191909155505060015f55565b60606113d26012613bfa565b6007546001600160a01b031633146134f75760405162461bcd60e51b8152600401610b6590615379565b600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa15801561355c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135809190615499565b61358a9190615486565b8111156135e55760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f74207769746864726177206d6f7265207468616e20617661696c61604482015262626c6560e81b6064820152608401610b65565b60405163a9059cbb60e01b8152336004820152602481018290527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b03169063a9059cbb906044016020604051808303815f875af115801561364f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612af591906154e7565b6040516370a0823160e01b81523060048201525f907f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316906370a0823190602401602060405180830381865afa1580156136d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136fb9190615499565b905060145481116137095750565b5f601454826137189190615486565b90508015612af55761372981614285565b50601455565b6001600160a01b0381165f818152601160205260408082208054600282015492516338d07a8760e11b815260048101959095526001600160701b03808216959394600160701b909204169290919030906371a0f50e90602401602060405180830381865afa1580156137a3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137c79190615499565b9150509193509193565b6007546001600160a01b031633146137fb5760405162461bcd60e51b8152600401610b6590615379565b6138066008836139ca565b156138535760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e6720506572696f6420616c7265616479206164646564000000006044820152606401610b65565b61385e600883614584565b505f918252600a602052604090912055565b6007546001600160a01b0316331461389a5760405162461bcd60e51b8152600401610b6590615379565b60328111156138eb5760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f742073657420686967686572207468616e203530250000000000006044820152606401610b65565b600b55565b6138f8613673565b565b6007546001600160a01b031633146139245760405162461bcd60e51b8152600401610b6590615379565b6127ee8161458f565b805f808061393a84612f96565b925061394584611338565b6001600160a01b0385165f9081526004602052604090205494969395509392915050565b600d54421161397457565b6005545f819003613986575042600d55565b5f61398f61139a565b9050805f036139a057505042600d55565b6139bf6139b683610f008464e8d4a510006139ef565b600e549061464f565b600e55505042600d55565b5f81815260018301602052604081205415155b9392505050565b5f6139dd83836146ad565b5f825f036139fe57505f611394565b5f613a09838561545c565b905082613a168583615473565b146139dd5760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b6064820152608401610b65565b5f6139dd83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614797565b5f6139dd83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506147cc565b6040516001600160a01b038316602482015260448101829052613b5290849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526147fb565b505050565b613b6182826148cc565b613b52826001613cf7565b6001600160a01b0381165f90815260018301602052604081205415156139dd565b5f6139dd836001600160a01b0384166146ad565b5f8181811215611394575f80fd5b5f80613bbb83856155ed565b90505f8312158015613bcd5750838112155b80613be157505f83128015613be157508381125b6139dd575f80fd5b5f80821215613bf6575f80fd5b5090565b60605f6139dd83614960565b60408082015165ffffffffffff165f908152600a6020522054613c56908390606490613c3290826155bb565b8451613c4791906001600160701b031661545c565b613c519190615473565b613b57565b6040516370a0823160e01b81523060048201527f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316906370a0823190602401602060405180830381865afa158015613cb8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613cdc9190615499565b6014555050565b5f6139dd836001600160a01b0384166149b9565b5f80613d0284614186565b90508015613d5a57821515846001600160a01b03167fa2c38e2d2fb7e3e1912d937fd1ca11ed6d51864dee4cfa7a7bf02becd7acf09283604051613d4891815260200190565b60405180910390a36001915050611394565b505f9392505050565b6001600160a01b0383165f90815260116020908152604091829020825160c08101845281546001600160701b038082168352600160701b909104811693820193909352600182015465ffffffffffff81169482019490945260ff600160301b8504811615156060830152600160381b90940490931660808401526002015460a08301528316613e225760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8105b5bdd5b9d60aa1b6044820152606401610b65565b613e35600865ffffffffffff84166139ca565b613e515760405162461bcd60e51b8152600401610b6590615521565b613e5c601285613b6c565b613e6d57613e6b601285613ce3565b505b80516001600160701b031615613fda5760a0810151600e546001600160a01b0386165f908152600460205260408120549092613eb9929091610f069164e8d4a5100091610f00916139ef565b90508015613fd857600f546040516370a0823160e01b81523060048201527f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e76001600160a01b0316906370a0823190602401602060405180830381865afa158015613f26573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4a9190615499565b613f549190615486565b811115613f735760405162461bcd60e51b8152600401610b65906154b0565b613fa76001600160a01b037f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e7168683613aef565b846001600160a01b03165f805160206156ce83398151915282604051613fcf91815260200190565b60405180910390a25b505b65ffffffffffff82166040820152613ff5826201518061559a565b6140079065ffffffffffff16426155bb565b65ffffffffffff1660208201528051839082906140259083906155ce565b6001600160701b031690525061403b8482613c06565b600e546001600160a01b0385165f9081526004602052604090205461406a9164e8d4a5100091610f00916139ef565b60a0820152600f80546001600160701b03851691905f9061408c9084906155bb565b90915550506040516001600160701b03841681526001600160a01b038516907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a26001600160a01b039093165f9081526011602090815260409182902085518154928701516001600160701b03908116600160701b026001600160e01b0319909416911617919091178155908401516001820180546060870151608088015160ff16600160381b0260ff60381b19911515600160301b0266ffffffffffffff1990931665ffffffffffff90951694909417919091171691909117905560a0909301516002909301929092555050565b5f8061419183612f96565b90508015614245576001600160a01b0383165f908152600360205260409020546141bb908261464f565b6001600160a01b0384165f81815260036020526040908190209290925590517fee503bee2bb6a87e57bc57db795f98137327401a0e7b7ce42e37926cc1a9ca4d906142099084815260200190565b60405180910390a26113946001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168483613aef565b505f92915050565b6040516001600160a01b03808516602483015283166044820152606481018290526126569085906323b872dd60e01b90608401613b1b565b5f60055411801561429557505f81115b156127ee576005546142c2906142af83600160801b6139ef565b6142b99190615473565b6001549061464f565b60015560405181815233907fa493a9229478c3fcd73f66d2cdeb7f94fd0f341da924d1054236d784541165119060200160405180910390a2600654614307908261464f565b60065550565b5f61431782612f96565b90508015614399576001600160a01b0382165f908152600360205260409020546143429082906155bb565b6001600160a01b0383165f81815260036020526040908190209290925590517fee503bee2bb6a87e57bc57db795f98137327401a0e7b7ce42e37926cc1a9ca4d906143909084815260200190565b60405180910390a25b919050565b604080516003808252608082019092525f91602082016060803683370190505090507f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7815f815181106143f3576143f36152bc565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110614447576144476152bc565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000382ec856c90ef7ed7c936852f6603568ce1984e78160028151811061449b5761449b6152bc565b6001600160a01b0392831660209182029290920101526144fe907f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7167f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d85614a05565b604051635c11d79560e01b81526001600160a01b037f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d1690635c11d795906145529086908690869030904290600401615614565b5f604051808303815f87803b158015614569575f80fd5b505af115801561457b573d5f803e3d5ffd5b50505050505050565b5f6139dd83836149b9565b6001600160a01b0381166145f45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b65565b6007546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3600780546001600160a01b0319166001600160a01b0392909216919091179055565b5f8061465b83856155bb565b9050838110156139dd5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610b65565b5f8181526001830160205260408120548015614787575f6146cf600183615486565b85549091505f906146e290600190615486565b9050818114614741575f865f018281548110614700576147006152bc565b905f5260205f200154905080875f018481548110614720576147206152bc565b5f918252602080832090910192909255918252600188019052604090208390555b85548690806147525761475261564f565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050611394565b5f915050611394565b5092915050565b5f81836147b75760405162461bcd60e51b8152600401610b659190615663565b505f6147c38486615473565b95945050505050565b5f81848411156147ef5760405162461bcd60e51b8152600401610b659190615663565b505f6147c38486615486565b5f61484f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614b189092919063ffffffff16565b805190915015613b52578080602001905181019061486d91906154e7565b613b525760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b65565b6001600160a01b0382165f90815260046020526040902080549082905580821115614925575f6148fc8383613aae565b90506149088482614b26565b8060055f82825461491991906155bb565b90915550613b52915050565b80821015613b52575f6149388284613aae565b90506149448482614b7e565b8060055f8282546149559190615486565b909155505050505050565b6060815f018054806020026020016040519081016040528092919081815260200182805480156149ad57602002820191905f5260205f20905b815481526020019060010190808311614999575b50505050509050919050565b5f8181526001830160205260408120546149fe57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155611394565b505f611394565b801580614a7d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614a57573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614a7b9190615499565b155b614ae85760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610b65565b6040516001600160a01b038316602482015260448101829052613b5290849063095ea7b360e01b90606401613b1b565b6060612a0484845f85614bb7565b614b5f614b4161137a836001546139ef90919063ffffffff16565b6001600160a01b0384165f9081526002602052604090205490614c8e565b6001600160a01b039092165f9081526002602052604090209190915550565b614b5f614b9961137a836001546139ef90919063ffffffff16565b6001600160a01b0384165f9081526002602052604090205490613baf565b606082471015614c185760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b65565b5f80866001600160a01b03168587604051614c339190615698565b5f6040518083038185875af1925050503d805f8114614c6d576040519150601f19603f3d011682016040523d82523d5f602084013e614c72565b606091505b5091509150614c8387838387614cc7565b979650505050505050565b5f80614c9a83856156ae565b90505f8312158015614cac5750838113155b80613be157505f83128015613be157508381136139dd575f80fd5b60608315614d355782515f03614d2e576001600160a01b0385163b614d2e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b65565b5081612a04565b612a048383815115614d4a5781518083602001fd5b8060405162461bcd60e51b8152600401610b659190615663565b80356001600160a01b0381168114614399575f80fd5b5f60208284031215614d8a575f80fd5b6139dd82614d64565b5f60208284031215614da3575f80fd5b5035919050565b80151581146127ee575f80fd5b803561439981614daa565b5f60208284031215614dd2575f80fd5b81356139dd81614daa565b602080825282518282018190525f918401906040840190835b81811015614e14578351835260209384019390920191600101614df6565b509095945050505050565b803565ffffffffffff81168114614399575f80fd5b5f8060408385031215614e45575f80fd5b82359150614e5560208401614e1f565b90509250929050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614e9b57614e9b614e5e565b604052919050565b5f67ffffffffffffffff821115614ebc57614ebc614e5e565b5060051b60200190565b5f82601f830112614ed5575f80fd5b8135614ee8614ee382614ea3565b614e72565b8082825260208201915060208360051b860101925085831115614f09575f80fd5b602085015b83811015614f2d57614f1f81614d64565b835260209283019201614f0e565b5095945050505050565b5f805f60608486031215614f49575f80fd5b833567ffffffffffffffff811115614f5f575f80fd5b614f6b86828701614ec6565b935050602084013567ffffffffffffffff811115614f87575f80fd5b8401601f81018613614f97575f80fd5b8035614fa5614ee382614ea3565b8082825260208201915060208360051b850101925088831115614fc6575f80fd5b6020840193505b82841015614ff657833560ff81168114614fe5575f80fd5b825260209384019390910190614fcd565b94506150089250505060408501614db7565b90509250925092565b5f82601f830112615020575f80fd5b813561502e614ee382614ea3565b8082825260208201915060208360051b86010192508583111561504f575f80fd5b602085015b83811015614f2d5761506581614e1f565b835260209283019201615054565b5f805f60608486031215615085575f80fd5b833567ffffffffffffffff81111561509b575f80fd5b6150a786828701614ec6565b935050602084013567ffffffffffffffff8111156150c3575f80fd5b8401601f810186136150d3575f80fd5b80356150e1614ee382614ea3565b8082825260208201915060208360051b850101925088831115615102575f80fd5b6020840193505b828410156151385783356001600160701b0381168114615127575f80fd5b825260209384019390910190615109565b9450505050604084013567ffffffffffffffff811115615156575f80fd5b61516286828701615011565b9150509250925092565b5f610140820190506001600160701b0387511682526001600160701b03602088015116602083015265ffffffffffff604088015116604083015260608701511515606083015260ff608088015116608083015260a087015160a08301526151de60c08301876001600160a01b03169052565b8460e083015283610100830152826101208301529695505050505050565b5f6020828403121561520c575f80fd5b813567ffffffffffffffff811115615222575f80fd5b612a0484828501614ec6565b5f6020828403121561523e575f80fd5b6139dd82614e1f565b5f8060408385031215615258575f80fd5b50508035926020909101359150565b5f8151808452602084019350602083015f5b828110156152a05781516001600160a01b0316865260209586019590910190600101615279565b5093949350505050565b602081525f6139dd6020830184615267565b634e487b7160e01b5f52603260045260245ffd5b828152604060208201525f612a046040830184615267565b5f602082840312156152f8575f80fd5b815167ffffffffffffffff81111561530e575f80fd5b8201601f8101841361531e575f80fd5b805161532c614ee382614ea3565b8082825260208201915060208360051b85010192508683111561534d575f80fd5b6020840193505b8284101561536f578351825260209384019390910190615354565b9695505050505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b6001600160701b038181168382160290811690818114614790576147906153e5565b634e487b7160e01b5f52601260045260245ffd5b5f6001600160701b038316806154475761544761541b565b806001600160701b0384160491505092915050565b8082028115828204841417611394576113946153e5565b5f826154815761548161541b565b500490565b81810381811115611394576113946153e5565b5f602082840312156154a9575f80fd5b5051919050565b6020808252601a908201527f496e73756666696369656e7420746f6b656e2072657761726473000000000000604082015260600190565b5f602082840312156154f7575f80fd5b81516139dd81614daa565b6001600160701b038281168282160390811115611394576113946153e5565b602080825260169082015275125b9d985b1a59081cdd185ada5b99c81c195c9a5bd960521b604082015260600190565b60208082526029908201527f43616e6e6f74207374616b6520666f7220612073686f7274657220706572696f60408201526864206f662074696d6560b81b606082015260800190565b65ffffffffffff8181168382160290811690818114614790576147906153e5565b80820180821115611394576113946153e5565b6001600160701b038181168382160190811115611394576113946153e5565b8082018281125f83128015821682158216171561560c5761560c6153e5565b505092915050565b85815284602082015260a060408201525f61563260a0830186615267565b6001600160a01b0394909416606083015250608001529392505050565b634e487b7160e01b5f52603160045260245ffd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f82518060208501845e5f920191825250919050565b8181035f831280158383131683831282161715614790576147906153e556fe1e644784312a20029e0b26f09d7855f9c06c5daf598ae7dc9188a367bc3d5560a264697066735822122030264ee90ed4584ef1762f9d6f29c85230987a19867ecc1caa8ee3ca711cd70b64736f6c634300081a0033

Verified Source Code Full Match

Compiler: v0.8.26+commit.8a97fa7a EVM: cancun Optimization: Yes (200 runs)
VoxStaking.sol 1930 lines
//SPDX-License-Identifier: MIT

pragma solidity 0.8.26;


library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

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

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

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

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

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

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

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

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

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

            return true;
        } else {
            return false;
        }
    }

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

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

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

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

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }
}

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

/**
 * @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`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

interface IDexRouter {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);
    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, 'SafeMath: addition overflow');

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, 'SafeMath: subtraction overflow');
    }

    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

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

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, 'SafeMath: division by zero');
    }

    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, 'SafeMath: modulo by zero');
    }

    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x < y ? x : y;
    }

    function sqrt(uint256 y) internal pure returns (uint256 z) {
        if (y > 3) {
            z = y;
            uint256 x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
}

library SafeMathInt {
    int256 private constant MIN_INT256 = int256(1) << 255;
    int256 private constant MAX_INT256 = ~(int256(1) << 255);

    /**
     * @dev Multiplies two int256 variables and fails on overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a * b;

        // Detect overflow when multiplying MIN_INT256 with -1
        require(c != MIN_INT256 || (a & MIN_INT256) != (b & MIN_INT256));
        require((b == 0) || (c / b == a));
        return c;
    }

    /**
     * @dev Division of two int256 variables and fails on overflow.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        // Prevent overflow when dividing MIN_INT256 by -1
        require(b != -1 || a != MIN_INT256);

        // Solidity already throws when dividing by 0.
        return a / b;
    }

    /**
     * @dev Subtracts two int256 variables and fails on overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a));
        return c;
    }

    /**
     * @dev Adds two int256 variables and fails on overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a));
        return c;
    }

    /**
     * @dev Converts to absolute value, and fails on overflow.
     */
    function abs(int256 a) internal pure returns (int256) {
        require(a != MIN_INT256);
        return a < 0 ? -a : a;
    }


    function toUint256Safe(int256 a) internal pure returns (uint256) {
        require(a >= 0);
        return uint256(a);
    }
}

library SafeMathUint {
  function toInt256Safe(uint256 a) internal pure returns (int256) {
    int256 b = int256(a);
    require(b >= 0);
    return b;
  }
}

library Address {
    function isContract(address account) internal view returns (bool) {
        return account.code.length > 0;
    }

    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

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

library SafeERC20 {
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

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

interface IERC20 {
    function totalSupply() external view returns (uint256);
    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);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

interface DividendPayingContractOptionalInterface {
  function withdrawableDividendOf(address _owner) external view returns(uint256);
  function withdrawnDividendOf(address _owner) external view returns(uint256);
  function accumulativeDividendOf(address _owner) external view returns(uint256);
}

interface DividendPayingContractInterface {
  function dividendOf(address _owner) external view returns(uint256);
  function withdrawDividend() external;
  event DividendsDistributed(
    address indexed from,
    uint256 usdtAmount
  );
  event DividendWithdrawn(
    address indexed to,
    uint256 usdtAmount
  );
}

contract DividendPayingContract is DividendPayingContractInterface, DividendPayingContractOptionalInterface {
  using SafeMath for uint256;
  using SafeMathUint for uint256;
  using SafeMathInt for int256;
  using SafeERC20 for IERC20;

  uint256 constant internal magnitude = 2**128;

  uint256 internal magnifiedDividendPerShare;
                                                                         
  mapping(address => int256) internal magnifiedDividendCorrections;
  mapping(address => uint256) internal withdrawnDividends;
  
  mapping (address => uint256) public holderBalance;
  uint256 public totalBalance;
  IERC20 public immutable USDT;

  uint256 public totalDividendsDistributed;

  function distributeDividends(uint256 amount) internal {
    if(totalBalance > 0 && amount > 0){
        magnifiedDividendPerShare = magnifiedDividendPerShare.add(
            (amount).mul(magnitude) / totalBalance
        );
        emit DividendsDistributed(msg.sender, amount);

        totalDividendsDistributed = totalDividendsDistributed.add(amount);
    }
  }

  function withdrawDividend() external virtual override {
    _withdrawDividendOfUser(payable(msg.sender));
  }

  function _withdrawDividendOfUser(address payable user) internal returns (uint256) {
    uint256 _withdrawableDividend = withdrawableDividendOf(user);
    if (_withdrawableDividend > 0) {
      withdrawnDividends[user] = withdrawnDividends[user].add(_withdrawableDividend);

      emit DividendWithdrawn(user, _withdrawableDividend);
      
      USDT.safeTransfer(user, _withdrawableDividend);

      return _withdrawableDividend;
    }

    return 0;
  }

  function dividendOf(address _owner) external view override returns(uint256) {
    return withdrawableDividendOf(_owner);
  }

  function withdrawableDividendOf(address _owner) public view override returns(uint256) {
    return accumulativeDividendOf(_owner).sub(withdrawnDividends[_owner]);
  }

  function withdrawnDividendOf(address _owner) external view override returns(uint256) {
    return withdrawnDividends[_owner];
  }

  function accumulativeDividendOf(address _owner) public view override returns(uint256) {
    return magnifiedDividendPerShare.mul(holderBalance[_owner]).toInt256Safe()
      .add(magnifiedDividendCorrections[_owner]).toUint256Safe() / magnitude;
  }

  function _increase(address account, uint256 value) internal {
    magnifiedDividendCorrections[account] = magnifiedDividendCorrections[account]
      .sub( (magnifiedDividendPerShare.mul(value)).toInt256Safe() );
  }

  function _reduce(address account, uint256 value) internal {
    magnifiedDividendCorrections[account] = magnifiedDividendCorrections[account]
      .add( (magnifiedDividendPerShare.mul(value)).toInt256Safe() );
  }

  function _setBalance(address account, uint256 newBalance) internal {
    uint256 currentBalance = holderBalance[account];
    holderBalance[account] = newBalance;
    if(newBalance > currentBalance) {
      uint256 increaseAmount = newBalance.sub(currentBalance);
      _increase(account, increaseAmount);
      totalBalance += increaseAmount;
    } else if(newBalance < currentBalance) {
      uint256 reduceAmount = currentBalance.sub(newBalance);
      _reduce(account, reduceAmount);
      totalBalance -= reduceAmount;
    }
  }
}


contract DividendTracker is DividendPayingContract {

    event Claim(address indexed account, uint256 amount, bool indexed automatic);

    constructor() {}

    function getAccount(address _account)
        public view returns (
            address account,
            uint256 withdrawableDividends,
            uint256 totalDividends,
            uint256 balance) {
        account = _account;

        withdrawableDividends = withdrawableDividendOf(account);
        totalDividends = accumulativeDividendOf(account);

        balance = holderBalance[account];
    }

    function setBalance(address payable account, uint256 newBalance) internal {

        _setBalance(account, newBalance);

    	processAccount(account, true);
    }
    
    function processAccount(address payable account, bool automatic) internal returns (bool) {
        uint256 amount = _withdrawDividendOfUser(account);

    	if(amount > 0) {
            emit Claim(account, amount, automatic);
    		return true;
    	}

    	return false;
    }

    function getTotalDividendsDistributed() external view returns (uint256) {
        return totalDividendsDistributed;
    }

	function dividendTokenBalanceOf(address account) public view returns (uint256) {
		return holderBalance[account];
	}

    function getNumberOfDividends() external view returns(uint256) {
        return totalBalance;
    }


}

abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}

contract Context {
    constructor() {}

    function _msgSender() internal view returns (address payable) {
        return payable(msg.sender);
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

contract Ownable is Context {
    address private _owner;

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

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

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

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

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), 'Ownable: new owner is the zero address');
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

/**
 * @title VoxStaking
 * @notice Unified staking contract for VOX tokens with dual reward system
 * @dev Users stake VOX tokens and earn both USDT dividends and additional VOX token rewards
 *      Features time-locked staking with boost multipliers, emergency withdrawal, and compounding
 */
contract VoxStaking is ReentrancyGuard, DividendTracker, Ownable {

    /// @notice The VOX token contract (immutable)
    IERC20 public immutable voxToken;
    
    /// @notice The WETH token contract for DEX operations (immutable)
    IERC20 public immutable WETH;
    
    /// @notice The DEX router for token swapping during compound operations (immutable)
    IDexRouter public immutable dexRouter;
    
    using EnumerableSet for EnumerableSet.UintSet;
    using EnumerableSet for EnumerableSet.AddressSet;
    using SafeERC20 for IERC20;
    using SafeMath for uint256;

    /// @notice Set of valid staking periods in days
    EnumerableSet.UintSet private stakingPeriodsInDays;
    
    /// @notice Mapping of staking period (days) to boost percentage (e.g., 100 = 100% boost = 2x multiplier)
    mapping (uint256 => uint256) public stakingPeriodBoost;
    
    /// @notice Default emergency withdrawal penalty percentage (e.g., 50 = 50%)
    uint256 public emergencyWithdrawPenalty;

    // ═══════════════════════════════════════════════════════════════════════════════
    // TOKEN EMISSIONS STAKING VARIABLES
    // ═══════════════════════════════════════════════════════════════════════════════
    
    /// @notice VOX tokens distributed per second to all stakers
    uint256 public tokenRewardsPerSecond;
    
    /// @notice Last timestamp when token pool rewards were updated
    uint256 public tokenLastRewardTimestamp;
    
    /// @notice Accumulated VOX tokens per share, scaled by 1e12 for precision
    uint256 public tokenAccTokensPerShare;
    
    /// @notice Total amount of VOX tokens currently staked (raw amount, not boosted)
    uint256 public tokenTotalStaked;
    
    /// @notice Whether token emission rewards are currently active
    bool public tokenRewardsActive;

    // ═══════════════════════════════════════════════════════════════════════════════
    // USER DATA STRUCTURE
    // ═══════════════════════════════════════════════════════════════════════════════
    
    /**
     * @notice User staking information combining both USDT dividend and VOX token reward tracking
     * @dev Optimized struct packing to minimize storage costs
     */
    struct User {
        /// @notice Base amount of VOX tokens staked (before boost multiplier)
        uint112 baseTokensStaked;
        
        /// @notice Timestamp when tokens can be withdrawn (unlock time)
        uint112 holderUnlockTime;
        
        /// @notice Duration of staking period in days (30, 90, or 180)
        uint48 stakingDuration;
        
        /// @notice Whether user has a custom emergency withdrawal penalty
        bool hasCustomEmergencyWithdrawPenalty;
        
        /// @notice Custom emergency withdrawal penalty percentage (0-100)
        uint8 customEmergencyWithdrawPenalty;
        
        /// @notice Reward debt for VOX token emissions (prevents double-claiming)
        uint256 tokenRewardDebt;
    }

    /// @notice Mapping of user addresses to their staking information
    mapping (address => User) public users;
    
    /// @notice Set of all users who have ever staked (for iteration)
    EnumerableSet.AddressSet private userList;
    
    /// @notice Last known USDT balance for automatic dividend detection
    uint256 private lastKnownUsdtBalance;

    // ═══════════════════════════════════════════════════════════════════════════════
    // EVENTS
    // ═══════════════════════════════════════════════════════════════════════════════
    
    /// @notice Emitted when a user deposits VOX tokens
    event Deposit(address indexed user, uint256 amount);
    
    /// @notice Emitted when a user withdraws VOX tokens
    event Withdraw(address indexed user, uint256 amount);
    
    /// @notice Emitted when a user performs emergency withdrawal
    event EmergencyWithdraw(address indexed user, uint256 amountForUser, uint256 amountForPenalty);
    
    /// @notice Emitted when VOX token rewards are paid to a user
    event TokenRewardsPaid(address indexed user, uint256 amount);

    /// @notice Emitted when VOX token rewards are paid to a user
    event Claim(address indexed user, uint256 amount);

    /**
     * @notice Initializes the VoxStaking contract
     * @dev Sets up staking periods, boost multipliers, and chain-specific token addresses
     * @param _voxToken Address of the VOX token contract
     */
    constructor(address _voxToken) {
        require(_voxToken != address(0), "cannot be 0 address");
        voxToken = IERC20(_voxToken);

        // Initialize staking periods and their corresponding boost multipliers
        // 30 days = 0% boost (1x multiplier)
        // 90 days = 100% boost (2x multiplier) 
        // 180 days = 200% boost (3x multiplier)
        stakingPeriodsInDays.add(30);
        stakingPeriodsInDays.add(90);
        stakingPeriodsInDays.add(180);
        stakingPeriodBoost[30] = 0;
        stakingPeriodBoost[90] = 100;
        stakingPeriodBoost[180] = 200;

        // Initialize token emissions staking with disabled state
        tokenRewardsPerSecond = 0;
        tokenLastRewardTimestamp = 99999999999; // Far future timestamp
        tokenAccTokensPerShare = 0;
        tokenTotalStaked = 0;
        tokenRewardsActive = false;

        // Set up chain-specific contract addresses for DEX operations
        address _v2Router;
        address _USDT;
        address _WETH;

        // Configure addresses based on the deployed chain
        if(block.chainid == 1){ // Ethereum Mainnet
            _v2Router = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; // Uniswap V2 Router
            _USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;     // USDT
            _WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;     // WETH
        } else if(block.chainid == 8453){ // Base Mainnet
            _v2Router = 0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24; // Base DEX Router
            _USDT = 0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2;     // USDT on Base
            _WETH = 0x4200000000000000000000000000000000000006;     // WETH on Base
        } else {
            revert("Chain not configured");
        }

        dexRouter = IDexRouter(_v2Router);
        USDT = IERC20(_USDT);
        WETH = IERC20(_WETH);
        
        // Set default emergency withdrawal penalty to 50%
        emergencyWithdrawPenalty = 50;
    }

    // ═══════════════════════════════════════════════════════════════════════════════
    // TOKEN EMISSIONS STAKING FUNCTIONS
    // ═══════════════════════════════════════════════════════════════════════════════

    /**
     * @notice Starts the token rewards distribution system
     * @dev Can only be called by the contract owner. Requires rewards per second to be set first.
     */
    function startTokenRewards() external onlyOwner {
        require(!tokenRewardsActive, "Rewards already active");
        require(tokenRewardsPerSecond > 0, "Rewards per second must be set");
        tokenLastRewardTimestamp = block.timestamp;
        tokenRewardsActive = true;
    }

    /**
     * @notice Stops the token rewards distribution system
     * @dev Can only be called by the contract owner. Updates pool before stopping.
     */
    function stopTokenRewards() external onlyOwner {
        updateTokenPool();
        tokenRewardsPerSecond = 0;
        tokenRewardsActive = false;
    }

    /**
     * @notice Sets the rate of VOX token rewards distributed per second
     * @dev Can only be called by the contract owner. Updates pool before changing rate.
     * @param newRewardsPerSecond New reward rate in VOX tokens per second (in wei)
     */
    function setTokenRewardsPerSecond(uint256 newRewardsPerSecond) external onlyOwner {
        updateTokenPool();
        tokenRewardsPerSecond = newRewardsPerSecond;
    }

    /**
     * @notice Updates the token reward pool with new accumulated rewards
     * @dev Internal function called before any staking state changes to ensure accurate reward calculations
     */
    function updateTokenPool() internal {
        if (block.timestamp <= tokenLastRewardTimestamp) {
            return;
        }
        uint256 lpSupply = totalBalance;
        if (lpSupply == 0) {
            tokenLastRewardTimestamp = block.timestamp;
            return;
        }
        uint256 tokenReward = calculateTokenNewRewards();

        if (tokenReward == 0) {
            tokenLastRewardTimestamp = block.timestamp;
            return;
        }
        tokenAccTokensPerShare = tokenAccTokensPerShare.add(
            tokenReward.mul(1e12).div(lpSupply)
        );
        tokenLastRewardTimestamp = block.timestamp;
    }

    /**
     * @notice Calculates the amount of new VOX token rewards since last update
     * @dev Public view function that can be used to preview pending rewards
     * @return Amount of new VOX token rewards in wei
     */
    function calculateTokenNewRewards() public view returns (uint256) {
        if (tokenLastRewardTimestamp > block.timestamp || !tokenRewardsActive) {
            return 0;
        }
        return ((block.timestamp - tokenLastRewardTimestamp) * tokenRewardsPerSecond);
    }

    /**
     * @notice Calculates pending VOX token rewards for a specific user
     * @dev Uses the user's boosted balance for reward calculations
     * @param _user Address of the user to check pending rewards for
     * @return Amount of pending VOX token rewards in wei
     */
    function pendingTokenReward(address _user) external view returns (uint256) {
        User storage user = users[_user];
        if (user.baseTokensStaked == 0) {
            return 0;
        }
        uint256 accTokensPerShare = tokenAccTokensPerShare;
        if (block.timestamp > tokenLastRewardTimestamp && totalBalance != 0) {
            uint256 multiplier = block.timestamp - tokenLastRewardTimestamp;
            uint256 rewards = multiplier * tokenRewardsPerSecond;
            accTokensPerShare = accTokensPerShare + (rewards * 1e12 / totalBalance);
        }
        return holderBalance[_user].mul(accTokensPerShare).div(1e12).sub(user.tokenRewardDebt);
    }

    /**
     * @notice Gets comprehensive token staking information for a specific user
     * @dev Returns all relevant data for token reward tracking
     * @param _user Address of the user to query
     * @return amount Base amount of VOX tokens staked (before boost)
     * @return rewardDebt Current reward debt for preventing double-claiming
     * @return unlockTime Timestamp when tokens can be withdrawn
     * @return pendingReward Current pending VOX token rewards
     */
    function getTokenUserInfo(address _user) external view returns (
        uint256 amount,
        uint256 rewardDebt,
        uint256 unlockTime,
        uint256 pendingReward
    ) {
        User storage user = users[_user];
        amount = user.baseTokensStaked;
        rewardDebt = user.tokenRewardDebt;
        unlockTime = user.holderUnlockTime;
        pendingReward = this.pendingTokenReward(_user);
    }

    /**
     * @notice Gets comprehensive information about the token staking pool
     * @dev Returns all relevant pool statistics and parameters
     * @return totalStaked Total amount of VOX tokens currently staked
     * @return rewardsPerSecond Current reward distribution rate
     * @return lastRewardTimestamp Last time rewards were calculated
     * @return accTokensPerShare Accumulated tokens per share (scaled by 1e12)
     * @return rewardsActive Whether token rewards are currently active
     */
    function getTokenPoolInfo() external view returns (
        uint256 totalStaked,
        uint256 rewardsPerSecond,
        uint256 lastRewardTimestamp,
        uint256 accTokensPerShare,
        bool rewardsActive
    ) {
        totalStaked = tokenTotalStaked;
        rewardsPerSecond = tokenRewardsPerSecond;
        lastRewardTimestamp = tokenLastRewardTimestamp;
        accTokensPerShare = tokenAccTokensPerShare;
        rewardsActive = tokenRewardsActive;
    }

    // Owner functions

    // @dev Sets custom emergency withdraw penalties by wallet
    function setCustomEmergencyWithdrawPenalty(address[] memory _addresses, uint8[] memory _customEmergencyWithdrawPenalty, bool _hasCustomEmergencyWithdrawPenalty) external onlyOwner {
        for(uint256 i = 0; i < _addresses.length; i++){
            address addy = _addresses[i];
            User memory user = users[addy];
            if(_hasCustomEmergencyWithdrawPenalty){
                uint8 customEmergencyWithdrawPenalty = _customEmergencyWithdrawPenalty[i];
                require(customEmergencyWithdrawPenalty <= 100, "Cannot set emergency penalty over 100%");
                user.hasCustomEmergencyWithdrawPenalty = true;
                us...

// [truncated — 77111 bytes total]

Read Contract

USDT 0xc54e44eb → address
WETH 0xad5c4648 → address
accumulativeDividendOf 0x27ce0147 → uint256
balanceOf 0x70a08231 → uint256
calculateTokenNewRewards 0x2d141467 → uint256
dexRouter 0x0758d924 → address
dividendOf 0x91b89fba → uint256
dividendTokenBalanceOf 0x6843cd84 → uint256
emergencyWithdrawPenalty 0x583a6c34 → uint256
getAccount 0xfbcbc0f1 → address, uint256, uint256, uint256
getExpectedCompoundOutputByUsdtAmount 0x3865d2b5 → uint256
getExpectedCompoundOutputByWallet 0x08f2f233 → uint256
getLockPeriodEnd 0xd5cb06c4 → uint256
getNumberOfDividends 0x71778e7d → uint256
getTokenPoolInfo 0xd7b6453f → uint256, uint256, uint256, uint256, bool
getTokenUserInfo 0xd664c0c8 → uint256, uint256, uint256, uint256
getTotalDividendsDistributed 0x30bb4cff → uint256
getUser 0x6f77926b → tuple, address, uint256, uint256, uint256
getUserList 0xb8522043 → address[]
getValidStakingDurations 0x2e29490d → uint256[]
holderBalance 0xab6ddfa8 → uint256
owner 0x8da5cb5b → address
pendingTokenReward 0x71a0f50e → uint256
stakingPeriodBoost 0xfa50c7d0 → uint256
tokenAccTokensPerShare 0x7be1ee97 → uint256
tokenLastRewardTimestamp 0xca5b7465 → uint256
tokenRewardsActive 0x2b2e0d5d → bool
tokenRewardsPerSecond 0x45d05c42 → uint256
tokenTotalStaked 0x872b26da → uint256
totalBalance 0xad7a672f → uint256
totalDividendsDistributed 0x85a6b3ae → uint256
users 0xa87430ba → uint112, uint112, uint48, bool, uint8, uint256
voxToken 0x514d8a17 → address
withdrawableDividendOf 0xa8b9d240 → uint256
withdrawnDividendOf 0xaafd847a → uint256

Write Contract 25 functions

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

addStakingPeriod 0xd9b26a69
uint256 _newStakingPeriod
uint256 _newStakingBoost
allocateStake 0x5ad31e99
address[] _addresses
uint112[] _amounts
uint48[] _durations
autoDistributeUsdtDividends 0xd5eb9113
No parameters
checkAndDistributeUsdt 0xf0739147
No parameters
claim 0x4e71d92d
No parameters
claimTokens 0x48c54b9d
No parameters
compound 0xaa5f7e26
uint256 minOutput
deposit 0x37b90a4f
uint256 _amount
uint48 _stakingDurationInDays
emergencyWithdrawTokens 0x1d5d7cc9
bool ignoreRewards
extendLock 0x814eaeea
uint48 _stakingDurationInDays
forceUpdate 0x7231c394
address[] _addresses
forceUpdateAll 0xa9c66b14
No parameters
receiveUsdtAndDistribute 0x7882bd33
uint256 amount
removeStakingPeriod 0x1b90e0e8
uint256 _newStakingPeriod
renounceOwnership 0x715018a6
No parameters
setCustomEmergencyWithdrawPenalty 0x51a8ea63
address[] _addresses
uint8[] _customEmergencyWithdrawPenalty
bool _hasCustomEmergencyWithdrawPenalty
setTokenRewardsPerSecond 0x1a2c2e86
uint256 newRewardsPerSecond
startTokenRewards 0x0fc924e3
No parameters
stopTokenRewards 0x17460b1b
No parameters
transferOwnership 0xf2fde38b
address newOwner
updateEmergencyWithdrawPenalty 0xdae97c1b
uint256 _newPerc
updateStakingBoost 0x94463e98
uint256 _stakingPeriod
uint256 _newStakingBoost
withdrawDividend 0x6a474002
No parameters
withdrawRewardTokens 0xcb43b2dd
uint256 _amount
withdrawTokens 0x315a095d
uint256 _amount

Recent Transactions

No transactions found for this address