Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x66a0f676479Cee1d7373f3DC2e2952778BfF5bd6
Balance 0 ETH
Nonce 1
Code Size 24195 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

24195 bytes
0x6080604052600436106103bb5760003560e01c806395d89b41116101f2578063c31245251161010d578063dd62ed3e116100a0578063e3073bfb1161006f578063e3073bfb146113aa578063e742806a146113d4578063e7881cda1461140d578063fc527bf51461144c576103c5565b8063dd62ed3e146111ee578063df0618d214611229578063df2d02b1146112a3578063e1d033e9146112eb576103c5565b8063d6565a2d116100dc578063d6565a2d14611149578063d826492014611173578063d8d44a2914611188578063db74559b146111bb576103c5565b8063c312452514611072578063c74c0fac146110ba578063ce8f9f00146110cf578063d1cf9098146110f9576103c5565b8063ae3d1de211610185578063be21ff7011610154578063be21ff7014610f52578063bf58f6d214610f7c578063c172628e14610fc5578063c23d656414611048576103c5565b8063ae3d1de214610ecb578063b381a81114610efe578063b543c4ba14610f13578063bba85e1f14610f28576103c5565b8063a4ed0550116101c1578063a4ed055014610d8e578063a50af89514610e2b578063a9059cbb14610e5f578063a91b19f214610e98576103c5565b806395d89b4114610cc257806399c2def414610cd75780639b57ab1214610d0b5780639e78fb4f14610d79576103c5565b806348e4ccab116102e257806370a08231116102755780638649102b116102445780638649102b14610bb357806387da627414610bfb57806389201d4e14610c105780638a26306014610cad576103c5565b806370a082311461095857806375c3fa4f1461098b578063763241d3146109be578063779e2e1814610b70576103c5565b8063601f37ac116102b1578063601f37ac146108ca57806360e4c651146108fd578063613fc9fd1461092e5780636ba631cf14610943576103c5565b806348e4ccab146107dc5780634dfc7a031461080d5780634f47b16d146108405780635b2023871461087a576103c5565b806320429fac1161035a57806333060d901161032957806333060d90146107035780633697e979146107365780633b58afe71461076457806342966c68146107b0576103c5565b806320429fac146105c357806323672d8a1461060657806323b872dd14610695578063313ce567146106d8576103c5565b8063095ea7b311610396578063095ea7b3146104a457806310748592146104dd57806318160ddd1461054d5780631c0b37e114610562576103c5565b80625ada7f146103ca57806302cbb266146103f157806306fdde031461041a576103c5565b366103c557600080fd5b600080fd5b3480156103d657600080fd5b506103df61157c565b60408051918252519081900360200190f35b3480156103fd57600080fd5b50610406611582565b604080519115158252519081900360200190f35b34801561042657600080fd5b5061042f611592565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610469578181015183820152602001610451565b50505050905090810190601f1680156104965780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104b057600080fd5b50610406600480360360408110156104c757600080fd5b506001600160a01b038135169060200135611626565b3480156104e957600080fd5b506105206004803603604081101561050057600080fd5b5080356001600160a01b031690602001356001600160801b031916611644565b60408051958652602086019490945284840192909252606084015215156080830152519081900360a00190f35b34801561055957600080fd5b506103df6116f2565b6105976004803603604081101561057857600080fd5b5080356001600160401b031690602001356001600160a01b03166116f8565b604080516001600160801b03199485168152602081019390935292168183015290519081900360600190f35b3480156105cf57600080fd5b506103df600480360360408110156105e657600080fd5b5080356001600160a01b031690602001356001600160801b031916611947565b34801561061257600080fd5b506106456004803603606081101561062957600080fd5b506001600160a01b038135169060208101359060400135611964565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610681578181015183820152602001610669565b505050509050019250505060405180910390f35b3480156106a157600080fd5b50610406600480360360608110156106b857600080fd5b506001600160a01b03813581169160208101359091169060400135611ad1565b3480156106e457600080fd5b506106ed611b40565b6040805160ff9092168252519081900360200190f35b34801561070f57600080fd5b506103df6004803603602081101561072657600080fd5b50356001600160a01b0316611b49565b34801561074257600080fd5b5061074b611b5b565b6040805163ffffffff9092168252519081900360200190f35b34801561077057600080fd5b506107976004803603602081101561078757600080fd5b50356001600160a01b0316611b6e565b6040805192835260208301919091528051918290030190f35b3480156107bc57600080fd5b506107da600480360360208110156107d357600080fd5b5035611b87565b005b3480156107e857600080fd5b506107f1611b94565b604080516001600160401b039092168252519081900360200190f35b34801561081957600080fd5b506107da6004803603602081101561083057600080fd5b50356001600160a01b0316611bd9565b34801561084c57600080fd5b506107da6004803603604081101561086357600080fd5b506001600160801b03198135169060200135611c4a565b34801561088657600080fd5b506108ad6004803603602081101561089d57600080fd5b50356001600160a01b0316611c69565b604080516001600160801b03199092168252519081900360200190f35b3480156108d657600080fd5b506103df600480360360208110156108ed57600080fd5b50356001600160a01b0316611cc8565b34801561090957600080fd5b50610912611cda565b604080516001600160a01b039092168252519081900360200190f35b34801561093a57600080fd5b506107da611ce9565b34801561094f57600080fd5b50610912611cf6565b34801561096457600080fd5b506103df6004803603602081101561097b57600080fd5b50356001600160a01b0316611d0c565b34801561099757600080fd5b506108ad600480360360208110156109ae57600080fd5b50356001600160a01b0316611d27565b3480156109ca57600080fd5b506107da600480360360608110156109e157600080fd5b810190602081018135600160201b8111156109fb57600080fd5b820183602082011115610a0d57600080fd5b803590602001918460208302840111600160201b83111715610a2e57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610a7d57600080fd5b820183602082011115610a8f57600080fd5b803590602001918460208302840111600160201b83111715610ab057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610aff57600080fd5b820183602082011115610b1157600080fd5b803590602001918460208302840111600160201b83111715610b3257600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611d79945050505050565b348015610b7c57600080fd5b5061040660048036036040811015610b9357600080fd5b5080356001600160a01b031690602001356001600160801b031916611dda565b348015610bbf57600080fd5b50610bdd60048036036020811015610bd657600080fd5b5035611ebe565b60408051938452602084019290925282820152519081900360600190f35b348015610c0757600080fd5b506107da611edf565b348015610c1c57600080fd5b50610c5360048036036040811015610c3357600080fd5b5080356001600160a01b031690602001356001600160801b03191661214d565b604080516001600160a01b0390991689526001600160801b031990971660208901528787019590955260608701939093529015156080860152151560a0850152151560c0840152151560e083015251908190036101000190f35b348015610cb957600080fd5b5061091261243f565b348015610cce57600080fd5b5061042f61244e565b348015610ce357600080fd5b506103df60048036036020811015610cfa57600080fd5b50356001600160801b0319166124af565b348015610d1757600080fd5b50610d4e60048036036040811015610d2e57600080fd5b5080356001600160801b03191690602001356001600160401b031661270c565b6040805195865260208601949094528484019290925260608401526080830152519081900360a00190f35b348015610d8557600080fd5b506107da612ba0565b348015610d9a57600080fd5b50610dd160048036036040811015610db157600080fd5b5080356001600160a01b031690602001356001600160801b031916612c6a565b604080519b8c5260208c019a909a528a8a019890985260608a0196909652608089019490945260a088019290925260c087015260e08601526101008501521515610120840152151561014083015251908190036101600190f35b348015610e3757600080fd5b506103df60048036036020811015610e4e57600080fd5b50356001600160801b031916612d96565b348015610e6b57600080fd5b5061040660048036036040811015610e8257600080fd5b506001600160a01b038135169060200135612f2b565b348015610ea457600080fd5b506107da60048036036020811015610ebb57600080fd5b50356001600160401b0316612f3f565b348015610ed757600080fd5b506108ad60048036036020811015610eee57600080fd5b50356001600160a01b0316612f99565b348015610f0a57600080fd5b5061074b612feb565b348015610f1f57600080fd5b50610912612ff7565b348015610f3457600080fd5b506103df60048036036020811015610f4b57600080fd5b503561300f565b348015610f5e57600080fd5b506103df60048036036020811015610f7557600080fd5b5035613021565b348015610f8857600080fd5b506108ad60048036036060811015610f9f57600080fd5b5080356001600160a01b031690602081013590604001356001600160f81b031916613033565b348015610fd157600080fd5b5061100860048036036040811015610fe857600080fd5b5080356001600160a01b031690602001356001600160801b03191661308e565b604080516001600160a01b0390961686526001600160801b0319909416602086015284840192909252606084015215156080830152519081900360a00190f35b34801561105457600080fd5b506103df6004803603602081101561106b57600080fd5b50356130da565b34801561107e57600080fd5b506110876130ec565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b3480156110c657600080fd5b50610912613101565b3480156110db57600080fd5b506108ad600480360360208110156110f257600080fd5b5035613119565b34801561110557600080fd5b506105976004803603608081101561111c57600080fd5b506001600160a01b0381358116916020810135916001600160401b03604083013516916060013516613249565b34801561115557600080fd5b50610bdd6004803603602081101561116c57600080fd5b5035613534565b34801561117f57600080fd5b50610912613555565b34801561119457600080fd5b506107da600480360360208110156111ab57600080fd5b50356001600160a01b031661356d565b3480156111c757600080fd5b506103df600480360360208110156111de57600080fd5b50356001600160a01b03166135ad565b3480156111fa57600080fd5b506103df6004803603604081101561121157600080fd5b506001600160a01b03813581169160200135166135bf565b34801561123557600080fd5b5061126c6004803603604081101561124c57600080fd5b5080356001600160a01b031690602001356001600160801b0319166135ea565b6040805195865260208601949094526001600160401b03928316858501529116606084015215156080830152519081900360a00190f35b3480156112af57600080fd5b50610597600480360360608110156112c657600080fd5b5080359060208101356001600160401b031690604001356001600160a01b0316613637565b3480156112f757600080fd5b5061132e6004803603604081101561130e57600080fd5b5080356001600160a01b031690602001356001600160801b0319166139d2565b604080519c8d5260208d019b909b528b8b01999099526001600160401b0397881660608c015295871660808b015293861660a08a01529190941660c088015260e08701939093526101008601929092526101208501919091526001600160a01b0316610140840152151561016083015251908190036101800190f35b3480156113b657600080fd5b50610797600480360360208110156113cd57600080fd5b5035613a5e565b3480156113e057600080fd5b506107da600480360360408110156113f757600080fd5b506001600160a01b038135169060200135613a77565b34801561141957600080fd5b506106456004803603606081101561143057600080fd5b506001600160a01b038135169060208101359060400135613a98565b34801561145857600080fd5b506107da6004803603604081101561146f57600080fd5b810190602081018135600160201b81111561148957600080fd5b82018360208201111561149b57600080fd5b803590602001918460208302840111600160201b831117156114bc57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561150b57600080fd5b82018360208201111561151d57600080fd5b803590602001918460208302840111600160201b8311171561153e57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550613c02945050505050565b600d5481565b600c54600160e01b900460ff1681565b60028054604080516020601f600019610100600187161502019094168590049384018190048102820181019092528281526060939092909183018282801561161b5780601f106115f05761010080835404028352916020019161161b565b820191906000526020600020905b8154815290600101906020018083116115fe57829003601f168201915b505050505090505b90565b600061163a611633613c57565b8484613c5b565b5060015b92915050565b6001600160a01b03821660009081526016602090815260408083206001600160801b0319851684528252808320815160a08101835281548082526001830154948201949094526002909101546001600160401b03808216938301849052600160401b8204166060830152600160801b900460ff1615156080820152909290819081906116cf81613ce3565b6060820151608090920151969995985096506001600160401b0316949392505050565b60055490565b60408051600280825260608201835260009283928392839260208301908036833701905050905073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28160008151811061174157fe5b60200260200101906001600160a01b031690816001600160a01b031681525050308160018151811061176f57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506000737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b0316637ff36ab5346001853342611c20016040518663ffffffff1660e01b81526004018085815260200180602001846001600160a01b03168152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015611828578181015183820152602001611810565b50505050905001955050505050506000604051808303818588803b15801561184f57600080fd5b505af1158015611863573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052602081101561188d57600080fd5b8101908080516040519392919084600160201b8211156118ac57600080fd5b9083019060208201858111156118c157600080fd5b82518660208202830111600160201b821117156118dd57600080fd5b82525081516020918201928201910280838360005b8381101561190a5781810151838201526020016118f2565b5050505090500160405250505090506119388160018151811061192957fe5b60200260200101518888613637565b94509450945050509250925092565b601360209081526000928352604080842090915290825290205481565b60606000808411801561198e57506001600160a01b0385166000908152600f602052604090205484105b6119b0576001600160a01b0385166000908152600f60205260409020546119cd565b6001600160a01b0385166000908152600f60205260409020548490035b9050600080841180156119df57508382115b6119ea5760006119ee565b8382035b905060008183036001600160401b0381118015611a0a57600080fd5b50604051908082528060200260200182016040528015611a34578160200160208202803683370190505b509350825b82811115611ac6576000611a56896000198401600160f81b613033565b6001600160a01b038a1660009081526014602090815260408083206001600160801b03198516845290915290206001015490915015611abc5780868481518110611a9c57fe5b6001600160801b0319909216602092830291909101909101526001909201915b5060001901611a39565b505050509392505050565b6000611b2b84611adf613c57565b6001600160a01b0387166000908152600160205260408120611b2691879190611b06613c57565b6001600160a01b0316815260208101919091526040016000205490613d6b565b613c5b565b611b36848484613d80565b5060019392505050565b60045460ff1690565b600f6020526000908152604090205481565b600c54600160201b900463ffffffff1681565b6012602052600090815260409020805460019091015482565b611b913382613e52565b50565b60007f000000000000000000000000000000000000000000000000000000005fa9d800611bbf613ef6565b1015611bcc576000611bd4565b611bd4613efa565b905090565b601d546001600160a01b03163314611bf057600080fd5b6001600160a01b038116600090815260126020526040902069021e19e0c9bab24000009055611c1d613f0c565b6001600160a01b0390911660009081526012602052604090206001600160401b0391909116600190910155565b611c5a611c55613efa565b613f1e565b611c6533838361423f565b5050565b6001600160a01b03811660009081526010602052604081205415611cc0576001600160a01b038216600090815260106020526040902054611cbb908390611cb1906001613d6b565b600160f91b613033565b61163e565b600092915050565b60116020526000908152604090205481565b601d546001600160a01b031681565b611cf4611c55613efa565b565b600c54600160401b90046001600160a01b031681565b6001600160a01b031660009081526020819052604090205490565b6001600160a01b03811660009081526011602052604081205415611cc0576001600160a01b038216600090815260116020526040902054611cbb908390611d6f906001613d6b565b600360f81b613033565b60005b8351811015611dd457611dc9848281518110611d9457fe5b6020026020010151848381518110611da857fe5b6020026020010151848481518110611dbc57fe5b6020026020010151613637565b505050600101611d7c565b50505050565b6001600160a01b0382811660009081526014602090815260408083206001600160801b03198616845282528083208151610180810183528154815260018201549381019390935260028101549183019190915260038101546001600160401b038082166060850152600160401b820481166080850152600160801b8204811660a0850152600160c01b9091041660c0830152600481015460e08301526005810154610100830152600681015461012083015260070154928316610140820152600160a01b90920460ff16151561016083015290611eb6816145bd565b949350505050565b601b6020526000908152604090208054600182015460029092015490919083565b6000806000600c60089054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611f3257600080fd5b505afa158015611f46573d6000803e3d6000fd5b505050506040513d6060811015611f5c57600080fd5b50805160208083015160409384015184516001600160701b03808616825283169381019390935263ffffffff811683860152935192965094509192507f17057eec9ed80c65db1c29e57a343df0e9f052cf0f5ec6e93bc084533ae9b8c99181900360600190a1600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316600c60089054906101000a90046001600160a01b03166001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561203057600080fd5b505afa158015612044573d6000803e3d6000fd5b505050506040513d602081101561205a57600080fd5b50516001600160a01b0316146120705782612072565b835b6001600160701b0316905060006120876116f2565b156120ad576120a86120976116f2565b6120a28460c861461e565b9061464c565b6120b0565b60005b90506028811080156120cc5750600c54600160e01b900460ff16155b156120d9576120d961466e565b603c811180156120f75750600c54600160e01b900460ff1615156001145b1561210457612104614683565b600c5460408051600160e01b90920460ff1615158252517fbbf65e071e5468fb599b01ba3b914ae6065cf10ad084e0efe2133f7eaa8979bd916020908290030190a15050505050565b6000806000806000806000806000601560008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008b6001600160801b0319166001600160801b03191681526020019081526020016000206040518060a00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a900460801b6001600160801b0319166001600160801b031916815260200160028201548152602001600382015481526020016004820160009054906101000a900460ff16151515158152505090508060000151985080602001519750806080015194506000601460008b6001600160a01b03166001600160a01b0316815260200190815260200160002060008a6001600160801b0319166001600160801b0319168152602001908152602001600020604051806101800160405290816000820154815260200160018201548152602001600282015481526020016003820160009054906101000a90046001600160401b03166001600160401b03166001600160401b031681526020016003820160089054906101000a90046001600160401b03166001600160401b03166001600160401b031681526020016003820160109054906101000a90046001600160401b03166001600160401b03166001600160401b031681526020016003820160189054906101000a90046001600160401b03166001600160401b03166001600160401b031681526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016007820160149054906101000a900460ff16151515158152505090508061012001519750612410816124028385614692565b61240b84614717565b614747565b9650806101600151945061242381614775565b925061242e816145bd565b935050509295985092959890939650565b601e546001600160a01b031681565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561161b5780601f106115f05761010080835404028352916020019161161b565b60006124bc611c55613efa565b6000806124c9338561478e565b6040805161018081018252835480825260018501546020830181905260028601549383019390935260038501546001600160401b038082166060850152600160401b820481166080850152600160801b8204811660a0850152600160c01b9091041660c0830152600485015460e08301526005850154610100830152600685015461012083018190526007909501546001600160a01b038116610140840152600160a01b900460ff16151561016083015290955091935061258c929091906149d9565b6125a78260a001516001600160401b03168360000151614a36565b6125c38260a001516001600160401b0316836101200151614ae9565b6125e582610140015183610100015184606001516001600160401b0316614b9c565b6125f38260c0015182614c41565b61266081836020015111612608576000612610565b818360200151035b3360009081526013602090815260408083206001600160801b03198a16845290915290819020549085015161014086015160808701518751929093019290916001600160401b0390911690614c87565b8161014001516001600160a01b0316336001600160a01b0316856001600160801b0319167f8cc66e48ebd8c008b36e03ee2f7c3f60a313a34a5bf1f3cb988a7936cd47f0d48560200151866000015187610120015188604001518960c001518960405180878152602001868152602001858152602001848152602001836001600160401b03168152602001828152602001965050505050505060405180910390a4506040015192915050565b600080600080600061271f611c55613efa565b3360009081526014602090815260408083206001600160801b03198b168452909152902060070154600160a01b900460ff1661275a57600080fd5b3360009081526014602090815260408083206001600160801b03198b1684528252918290208251610180810184528154815260018201549281019290925260028101549282019290925260038201546001600160401b038082166060840152600160401b820481166080840152600160801b8204811660a0840152600160c01b909104811660c0830152600483015460e0830152600583015461010083015260068301546101208301526007909201546001600160a01b038116610140830152600160a01b900460ff1615156101608201529087166128415761283c81614d90565b61285d565b61285d876001600160401b031661285783614dc6565b90614def565b95508060a001516001600160401b031686116128795785612882565b61288281614d90565b955061289b816000015161289583614dc6565b88614e01565b94506128a6816145bd565b612975576128b381614e47565b93506128c6858533600660020154614ea0565b81519093506128d59084613d6b565b815260a08101516128ef906001600160401b031684614a36565b6101208101511561293d5761290c85856000600660020154614ea0565b61012082015190925061291f9083613d6b565b61012082015260a081015161293d906001600160401b031683614ae9565b612949600084846149d9565b61297081602001518683610140015184608001516001600160401b03168560000151614c87565b6129f0565b3360009081526013602090815260408083206001600160801b03198c1684529091529020546129a49086614def565b3360009081526013602090815260408083206001600160801b03198d1684528252909120829055820151610140830151608084015184516129f09492916001600160401b031690614c87565b60e081018681523360008181526014602090815260408083206001600160801b03198e168452825291829020855181559085015160018201559084015160028201556060840151600382018054608087015160a088015160c089015167ffffffffffffffff199093166001600160401b039586161767ffffffffffffffff60401b1916600160401b928616929092029190911767ffffffffffffffff60801b1916600160801b91851691909102176001600160c01b0316600160c01b93909116929092029190911790559151600483015561010083015160058301556101208301516006830155610140830151600790920180546101608501516001600160a01b03199091166001600160a01b039094169390931760ff60a01b1916600160a01b9315159390930292909217909155612b299086614edf565b336001600160801b031989167f7b5d0995432c9ea1c8033b358af591013d0deff8dec5f4ae49612eba8bfafc0c87898787612b62613efa565b6040805195865260208601949094528484019290925260608401526001600160401b03166080830152519081900360a00190a3509295509295909350565b604080516364e329cb60e11b815273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc260048201523060248201529051735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9163c9c653969160448083019260209291908290030181600087803b158015612c0d57600080fd5b505af1158015612c21573d6000803e3d6000fd5b505050506040513d6020811015612c3757600080fd5b5051600c80546001600160a01b03909216600160401b0268010000000000000000600160e01b0319909216919091179055565b6001600160a01b0382811660009081526014602090815260408083206001600160801b03198616845282528083208151610180810183528154808252600183015494820185905260028301549382019390935260038201546001600160401b0380821660608401819052600160401b8304821660808501819052600160801b8404831660a08601819052600160c01b90940490921660c08501819052600486015460e0860181905260058701546101008701526006870154610120870152600790960154998a16610140860152600160a01b90990460ff161515610160850152979096919590949092909190819081908190612d6581614f7b565b9450612d7081614f9a565b93508061016001519250612d83816145bd565b9150509295989b509295989b9093969950565b6000612da3611c55613efa565b3360009081526016602090815260408083206001600160801b031986168452825291829020825160a08101845281548152600182015492810192909252600201546001600160401b0380821693830193909352600160401b81049092166060820152600160801b90910460ff16151560808201819052612e2257600080fd5b60006080820152612e31613efa565b6001600160401b03166060820152612e4881613ce3565b60208201819052612e5a903390614edf565b600c548151612e7b91600160401b90046001600160a01b0316903390614fc1565b8051600b54612e8991613d6b565b600b553360009081526016602090815260408083206001600160801b0319969096168352948152908490208251815590820151600182018190559382015160029091018054606084015160809094015167ffffffffffffffff199091166001600160401b039384161767ffffffffffffffff60401b1916600160401b93909416929092029290921760ff60801b1916600160801b911515919091021790555090565b600061163a612f38613c57565b8484613d80565b6000816001600160401b0316118015612f705750612f5b613efa565b6001600160401b0316816001600160401b0316105b612f7957600080fd5b6009546001600160401b03821611612f9057600080fd5b611b9181613f1e565b6001600160a01b0381166000908152600f602052604081205415611cc0576001600160a01b0382166000908152600f6020526040902054611cbb908390612fe1906001613d6b565b600160f81b613033565b600c5463ffffffff1681565b739c306cad86550ec80d77668c0a8bee6eb34684b681565b60196020526000908152604090205481565b60186020526000908152604090205481565b604080516bffffffffffffffffffffffff19606086901b16602080830191909152603482018590526001600160f81b0319841660548301528251603581840301815260559092019092528051910120600090611eb690611623565b6015602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401546001600160a01b039093169360809290921b9290919060ff1685565b60176020526000908152604090205481565b600654600754600854600954600a54600b5486565b735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b6000613126611c55613efa565b600c54600160e01b900460ff16151560011461314157600080fd5b600c5461316090600160401b90046001600160a01b03163330856150db565b613168615ce5565b61317133615205565b915061317b613f0c565b6001600160401b0316604082015282815260016080820152600b546131a09084614def565b600b553360008181526016602090815260408083206001600160801b031987168452825291829020845181559084015160018201559083015160029091018054606085015160808601511515600160801b0260ff60801b196001600160401b03928316600160401b0267ffffffffffffffff60401b199390961667ffffffffffffffff19909416939093179190911693909317169190911790556132439061522e565b50919050565b604080516323b872dd60e01b81523360048201523060248201526044810185905290516000918291829188916001600160a01b038316916323b872dd91606480830192602092919082900301818887803b1580156132a657600080fd5b505af11580156132ba573d6000803e3d6000fd5b505050506040513d60208110156132d057600080fd5b50506040805163095ea7b360e01b8152737a250d5630b4cf539739df2c5dacb4c659f2488d60048201526024810189905290516001600160a01b0383169163095ea7b39160448083019260209291908290030181600087803b15801561333557600080fd5b505af1158015613349573d6000803e3d6000fd5b505050506040513d602081101561335f57600080fd5b506000905061336e893061524e565b90506000737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b03166338ed17398a6001853342611c20016040518663ffffffff1660e01b81526004018086815260200185815260200180602001846001600160a01b03168152602001838152602001828103825285818151815260200191508051906020019060200280838360005b8381101561340f5781810151838201526020016133f7565b505050509050019650505050505050600060405180830381600087803b15801561343857600080fd5b505af115801561344c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561347557600080fd5b8101908080516040519392919084600160201b82111561349457600080fd5b9083019060208201858111156134a957600080fd5b82518660208202830111600160201b821117156134c557600080fd5b82525081516020918201928201910280838360005b838110156134f25781810151838201526020016134da565b5050505090500160405250505090506135208160028151811061351157fe5b60200260200101518989613637565b9550955095505050505b9450945094915050565b601a6020526000908152604090208054600182015460029092015490919083565b737a250d5630b4cf539739df2c5dacb4c659f2488d81565b601e546001600160a01b0316331461358457600080fd5b601d80546001600160a01b039092166001600160a01b0319928316179055601e80549091169055565b60106020526000908152604090205481565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60166020908152600092835260408084209091529082529020805460018201546002909201549091906001600160401b0380821691600160401b810490911690600160801b900460ff1685565b6000806000613647611c55613efa565b336001600160a01b03851614801590613664575061366484615314565b61366d57600080fd5b60016001600160401b038616108015906136925750613be26001600160401b03861611155b61369b57600080fd5b620f42408610156136ab57600080fd5b60008060006136bc338a8a8a61531f565b6001600160401b0316925092509250600083610120015111156137b3576136e1615ce5565b3381526001600160801b0319831660208201526001608082015261370488615413565b6001600160a01b0389811660009081526015602090815260408083206001600160801b0319868116855290835292819020865181546001600160a01b031916951694909417845590850151600184018054909316608091821c179092558401516002830155606084015160038301558301516004909101805460ff191691151591909117905594506137958861543c565b6137b18460a001516001600160401b031685610120015161545c565b505b3360008181526014602090815260408083206001600160801b031987168452825291829020865181559086015160018201559085015160028201556060850151600382018054608088015160a089015160c08a015167ffffffffffffffff199093166001600160401b039586161767ffffffffffffffff60401b1916600160401b928616929092029190911767ffffffffffffffff60801b1916600160801b91851691909102176001600160c01b0316600160c01b939091169290920291909117905560e0850151600482015561010085015160058201556101208501516006820155610140850151600790910180546101608701516001600160a01b03199091166001600160a01b039093169290921760ff60a01b1916600160a01b921515929092029190911790556138e69061548b565b6138fe836020015184600001518561012001516154ab565b6139198360a001516001600160401b031684600001516154de565b866001600160a01b0316336001600160a01b0316836001600160801b0319167f6619c8f19b39bf3558af16516f9ca110fcac4a7ab6d846d1b02a17b11f703a338660200151876000015188610120015189606001518a608001518b610100015160405180878152602001868152602001858152602001846001600160401b03168152602001836001600160401b03168152602001828152602001965050505050505060405180910390a490945092505093509350939050565b6014602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600586015460068701546007909701549596949593946001600160401b0380851695600160401b8604821695600160801b8104831695600160c01b909104909216939192906001600160a01b03811690600160a01b900460ff168c565b601c602052600090815260409020805460019091015482565b601d546001600160a01b03163314613a8e57600080fd5b611c658282614edf565b606060008084118015613ac257506001600160a01b03851660009081526010602052604090205484105b613ae4576001600160a01b038516600090815260106020526040902054613b01565b6001600160a01b0385166000908152601060205260409020548490035b905060008084118015613b1357508382115b613b1e576000613b22565b8382035b905060008183036001600160401b0381118015613b3e57600080fd5b50604051908082528060200260200182016040528015613b68578160200160208202803683370190505b509350825b82811115611ac6576000613b8a896000198401600160f91b613033565b6001600160a01b03808b1660009081526015602090815260408083206001600160801b031986168452909152902054919250613bc6911661550d565b15613bf85780868481518110613bd857fe5b6001600160801b0319909216602092830291909101909101526001909201915b5060001901613b6d565b613c0d611c55613efa565b60005b8251811015613c5257613c4a33848381518110613c2957fe5b6020026020010151848481518110613c3d57fe5b602002602001015161423f565b600101613c10565b505050565b3390565b6001600160a01b038316613c6e57600080fd5b6001600160a01b038216613c8157600080fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60008061016d61ffff168360400151016001600160401b0316905060008160066003015410613d125781613d16565b6009545b60408501519091506001600160401b03165b81811015613d63576000818152601c60205260409020600101548551670de0b6b3a76400000281613d5557fe5b049390930192600101613d28565b505050919050565b600082821115613d7a57600080fd5b50900390565b6001600160a01b038316613d9357600080fd5b6001600160a01b038216613da657600080fd5b6001600160a01b038316600090815260208190526040902054613dc99082613d6b565b6001600160a01b038085166000908152602081905260408082209390935590841681522054613df89082614def565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6001600160a01b038216613e6557600080fd5b6001600160a01b038216600090815260208190526040902054613e889082613d6b565b6001600160a01b038316600090815260208190526040902055600554613eae9082613d6b565b6005556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b4290565b6000611bd4613f07613ef6565b61551b565b6000613f16613efa565b600101905090565b613f26611edf565b600654600954600091905b836001600160401b0316811015611dd45760001981016000908152601a602081815260408084206002015485855260178352818520549383529381902081516060810183528154815260019091015492810192909252919092019082018190526007549094508410613fa4576000613fab565b6007548490035b815261406a61405684613fbc6116f2565b60008681526019602090815260409182902054600c5483516330550a4b60e01b815263ffffffff909116600482015292519092739c306cad86550ec80d77668c0a8bee6eb34684b6926330550a4b92602480840193829003018186803b15801561402557600080fd5b505afa158015614039573d6000803e3d6000fd5b505050506040513d602081101561404f57600080fd5b505161554c565b82516120a290670de0b6b3a764000061461e565b60208083019182526000848152601a825260408082208551815593516001808601919091558186015160029586015560001987018352601b80855282842090950154878452601885528284205495855292829020825160608101845281548152910154938101939093529201918101829052600a549195509085106140f05760006140f7565b600a548590035b815261410d614056856141086116f2565b615569565b60208083019182526000858152601b8252604080822085518155935160018086019190915581860151600290950194909455601c83529081902081518083019092529092015490820152600b5481526141fc6140568661416b6116f2565b600c54604080516330550a4b60e01b8152600160201b90920463ffffffff16600483015251739c306cad86550ec80d77668c0a8bee6eb34684b6916330550a4b916024808301926020929190829003018186803b1580156141cb57600080fd5b505afa1580156141df573d6000803e3d6000fd5b505050506040513d60208110156141f557600080fd5b5051615578565b60208083019182526000868152601c90915260409020825181559051600190910155614226615589565b5050600980546001908101909155919091019050613f31565b6001600160a01b0380841660009081526015602090815260408083206001600160801b0319808816855290835292819020815160a08101835281549095168552600180820154608090811b90951693860193909352600281015491850191909152600381015460608501526004015460ff161515918301829052146142c357600080fd5b80516020808301516001600160a01b0380841660009081526014845260408082206001600160801b03198516835285528082208151610180810183528154815260018201549681019690965260028101549186019190915260038101546001600160401b038082166060880152600160401b820481166080880152600160801b8204811660a0880152600160c01b9091041660c0860152600481015460e08601526005810154610100860152600681015461012086015260070154918216610140850152600160a01b90910460ff1615156101608401529091906143a78286614692565b905060006143b483614717565b90506143bf83614775565b15614413576000871180156143dc57506143d98282615670565b87105b156144065760608601516143f09088614def565b60608701526143ff8288614def565b905061440e565b600060808701525b614451565b61442d8261441f613efa565b6001600160401b0316615670565b606087015190975061443f9088614def565b606087015261444e8288614def565b90505b600061445e848484614747565b60408801519091506144709082614def565b87604001818152505086601560008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008b6001600160801b0319166001600160801b031916815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160801b03021916908360801c0217905550604082015181600201556060820151816003015560808201518160040160006101000a81548160ff0219169083151502179055509050506145598a82614edf565b604080516001600160801b03198b811682526020820184905282516001600160a01b03808f1694928a1693908b16927f5d13067bdc9e4d510839580df1e932220b31fb2bc7790b5bd35aae14f0303bed92918290030190a450505050505050505050565b6000808260c001516001600160401b0316116145f9576145db613efa565b6001600160401b03168260a001516001600160401b0316111561163e565b8160c001516001600160401b03168260a001516001600160401b031611159050919050565b60008261462d5750600061163e565b8282028284828161463a57fe5b041461464557600080fd5b9392505050565b600080821161465a57600080fd5b600082848161466557fe5b04949350505050565b600c805460ff60e01b1916600160e01b179055565b600c805460ff60e01b19169055565b6000614645826060015184606001516001600160401b0316601260008761014001516001600160a01b03166001600160a01b0316815260200190815260200160002060010154116146f05784606001516001600160401b0316612857565b6101408501516001600160a01b031660009081526012602052604090206001015490614def565b6000808260c001516001600160401b03161161473657611cbb82614d90565b5060c001516001600160401b031690565b6000614757846101400151615691565b61476b576147668484846156b0565b611eb6565b5060009392505050565b610160810151600090158061163e575061163e826145bd565b6001600160a01b03821660009081526014602090815260408083206001600160801b0319851684529091528120600701548190600160a01b900460ff166147d457600080fd5b6001600160a01b03841660009081526014602090815260408083206001600160801b0319871684529091529020915061480b613efa565b6003830180546001600160c01b0316600160c01b6001600160401b0393841681029190911791829055604080516101808101825286548152600187015460208201526002870154918101919091528284166060820152600160401b830484166080820152600160801b8304841660a0820152910490911660c0820152600483015460e08201526005830154610100820152600683015461012082015260078301546001600160a01b038116610140830152600160a01b900460ff1615156101608201526148d7906156ef565b60028301819055604080516101808101825284548152600185015460208201529081019190915260038301546001600160401b038082166060840152600160401b820481166080840152600160801b8204811660a0840152600160c01b9091041660c0820152600483015460e08201526005830154610100820152600683015461012082015260078301546001600160a01b038116610140830152600160a01b900460ff16151561016082015261498d90614f9a565b60078301805460ff60a01b1916905560018301549091506149c490859083106149b75760006149bf565b828460010154035b614edf565b6149d2848360020154614edf565b9250929050565b60065483106149e95760006149f0565b6006548390035b6006556007548210614a03576000614a0a565b6007548290035b6007558015614a2e57600a548110614a23576000614a2a565b600a548190035b600a555b613c52615710565b614a3f82615767565b15614a87576000828152601760205260409020548110614a60576000614a73565b6000828152601760205260409020548190035b600083815260176020526040902055611c65565b6000614a91615783565b6001600160401b03166000818152601a60205260409020600201549091508210614abc576000614ad2565b6000818152601a60205260409020600201548290035b6000918252601a6020526040909120600201555050565b614af282615767565b15614b3a576000828152601860205260409020548110614b13576000614b26565b6000828152601860205260409020548190035b600083815260186020526040902055611c65565b6000614b44615783565b6001600160401b03166000818152601b60205260409020600201549091508210614b6f576000614b85565b6000818152601b60205260409020600201548290035b6000918252601b6020526040909120600201555050565b614ba581615795565b158015614bb65750614bb68361550d565b15613c52576001600160a01b0383166000908152601260205260409020548210614be1576000614bfe565b6001600160a01b0383166000908152601260205260409020548290035b6001600160a01b038416600090815260126020526040902055614c20836157b1565b6001600160a01b038416600090815260126020526040902060010155505050565b8015611c65576001600160401b038216600090815260196020526040902054614c6a9082614def565b6001600160401b0383166000908152601960205260409020555050565b600081118015614ca757506041614c9c613efa565b6001600160401b0316115b15614d63576000614cbb86868486886157c9565b600854909150811115614d5d57600854614cdd906064906120a290606e61461e565b8110614cfd57600854614cf8906064906120a290606e61461e565b614cff565b805b90507fb52ab4a425c20017539fcd851fc4ddbb50d17546576353cd51a2d483d80a45b881600660020154614d31613efa565b6040805193845260208401929092526001600160401b031682820152519081900360600190a160088190555b50614d89565b6041614d6d613efa565b6001600160401b03161415614d8957670186cc6acd4b00006008555b5050505050565b60006006600301548260a001516001600160401b031611614dbe578160a001516001600160401b031661163e565b505060095490565b60008160e00151600014614dde578160e0015161163e565b50606001516001600160401b031690565b60008282018381101561464557600080fd5b6000825b82811015614e3f576000818152601a6020526040902060010154670de0b6b3a7640000860281614e3157fe5b049190910190600101614e05565b509392505050565b61016081015160009015614e7c57611cbb614e60613efa565b6001600160401b03168360a001516001600160401b0316615670565b61163e8260c001516001600160401b03168360a001516001600160401b0316615670565b6000614eab8361550d565b614ec557614ec08585846402540be400615826565b614ed6565b614ed685858464028fa6ae00615826565b95945050505050565b6001600160a01b038216614ef257600080fd5b600554614eff9082614def565b6005556001600160a01b038216600090815260208190526040902054614f259082614def565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000816101600151614f9157816040015161163e565b61163e82615848565b6000614fa582615860565b80614fb45750614fb4826145bd565b611cc057611cbb826158bf565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b6020831061503d5780518252601f19909201916020918201910161501e565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461509f576040519150601f19603f3d011682016040523d82523d6000602084013e6150a4565b606091505b50915091508180156150d25750805115806150d257508080602001905160208110156150cf57600080fd5b50515b614d8957600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b6020831061515f5780518252601f199092019160209182019101615140565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146151c1576040519150601f19603f3d011682016040523d82523d6000602084013e6151c6565b606091505b50915091508180156151f45750805115806151f457508080602001905160208110156151f157600080fd5b50515b6151fd57600080fd5b505050505050565b6001600160a01b03811660009081526011602052604081205461163e908390600360f81b613033565b6001600160a01b0316600090815260116020526040902080546001019055565b60408051600380825260808201909252606091602082018380368337019050509050828160008151811061527e57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2816001815181106152c057fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081816002815181106152ee57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505092915050565b3b63ffffffff161590565b615327615d13565b6000806153348787613e52565b61533c613f0c565b9050615347876158f5565b6001600160401b0380871660808601819052838216606087015283880190911660a086015260016101608601526020850188905260085491935061538f918891908790614ea0565b835261539961591e565b506020830151600d546153b991670de0b6b3a7640000916120a29161461e565b6101008401526153c88461550d565b1561352a576001600160a01b03841661014084018190526101008401516153ef9190615b0d565b61540386866001600160401b031686615b75565b6101208401529450945094915050565b6001600160a01b03811660009081526010602052604081205461163e908390600160f91b613033565b6001600160a01b0316600090815260106020526040902080546001019055565b6000828152601860205260409020546154759082614def565b6000928352601860205260409092209190915550565b6001600160a01b03166000908152600f6020526040902080546001019055565b6006546154b89084614def565b6006556007546154c89083614def565b6007558015614a2e57600a54614a2a9082614def565b6000828152601760205260409020546154f79082614def565b6000928352601760205260409092209190915550565b6001600160a01b0316151590565b6000620151807f000000000000000000000000000000000000000000000000000000005fa9d80083035b0492915050565b60008282858701612710028161555e57fe5b040195945050505050565b6315dd2ecd9101612710020490565b600081838501612710028161466557fe5b600c54600160e01b900460ff16151560011480156155b95750600c5462019258600160201b90910463ffffffff16105b1561560357600c805463ffffffff1967ffffffff00000000198216600160201b9283900463ffffffff90811660060181169093021790811690821660051901909116179055611cf4565b600c54600160e01b900460ff161580156156295750600c546201925863ffffffff909116105b15611cf457600c805467ffffffff000000001963ffffffff19821663ffffffff928316600601831617908116600160201b9182900483166005190190921602179055611cf4565b6000818311615688576156838284613d6b565b614645565b50600092915050565b6001600160a01b03166000908152601260205260409020600101541590565b6000825b82811015614e3f576000818152601b60205260409020600101548551670de0b6b3a764000002816156e157fe5b0491909101906001016156b4565b600061163e826000015161570284614dc6565b61570b85614d90565b614e01565b600954600754600654600854600a54604080519485526020850193909352838301919091526060830152517fea8ce1d041020595d75f4f48ba3378787b84e61d101465836fa54f1b338a4db59181900360800190a2565b6000615771613efa565b6001600160401b031690911015919050565b6000600161578f613efa565b03905090565b600061579f613efa565b6001600160401b031690911115919050565b60006157bc82615ba6565b611cc057611cbb82615bcd565b6000806157fb846157d98561550d565b6157e8576402540be4006157ef565b64028fa6ae005b64ffffffffff16615c22565b905061581b856120a26305f5e10061581585818d8d614def565b9061461e565b979650505050505050565b6000614ed66402540be4006120a261583e8786615c22565b6158158988615c6c565b600061585382615860565b611cc057611cbb826156ef565b6000808260c001516001600160401b03161161589b5761587e613efa565b6001600160401b031682606001516001600160401b03161161163e565b8160c001516001600160401b031682606001516001600160401b0316119050919050565b60006103e86158cd83615c84565b60016158d885614e47565b0361032002816158e457fe5b046064018360200151028161554557fe5b6001600160a01b0381166000908152600f602052604081205461163e908390600160f81b613033565b6040805163d06ca61f60e01b8152670de0b6b3a76400006004820181815260248301938452600e805460448501819052600095737a250d5630b4cf539739df2c5dacb4c659f2488d9563d06ca61f959492606490910190849080156159ac57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161598e575b5050935050505060006040518083038186803b1580156159cb57600080fd5b505afa925050508015615a8b57506040513d6000823e601f3d908101601f1916820160405260208110156159fe57600080fd5b8101908080516040519392919084600160201b821115615a1d57600080fd5b908301906020820185811115615a3257600080fd5b82518660208202830111600160201b82111715615a4e57600080fd5b82525081516020918201928201910280838360005b83811015615a7b578181015183820152602001615a63565b5050505090500160405250505060015b615ae757615a97615da9565b80615aa25750615aac565b5050600d54611623565b3d808015615ad6576040519150601f19603f3d011682016040523d82523d6000602084013e615adb565b606091505b50600d54915050611623565b80600281518110615af457fe5b6020026020010151600d81905550600d54915050611623565b6001600160a01b038216600090815260126020526040902054615b309082614def565b6001600160a01b038316600090815260126020526040902055615b52826157b1565b6001600160a01b0390921660009081526012602052604090206001019190915550565b6000615b8082615691565b80615b8c575061016d83105b61476b5761476684846006600201546402540be400615826565b6001600160a01b031660009081526012602052604090205469021e19e0c9bab24000001190565b6001600160a01b038116600090815260126020526040812060010154615c0357615bf5613efa565b6001600160401b031661163e565b506001600160a01b031660009081526012602052604090206001015490565b600081615c4f6107218511615c38576000615c3f565b6107201985015b660150b9a52b11286134c1615cba565b615c63856630aad4df397abe610721615cba565b01019392505050565b6000614645826120a285670de0b6b3a764000061461e565b6000600182608001516001600160401b031611615ca2576001615cab565b60018260800151035b6001600160401b031692915050565b6000611eb66402540be400838611615cdb57615cd6868661461e565b6120a2565b6120a2848661461e565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290565b60405180610180016040528060008152602001600081526020016000815260200160006001600160401b0316815260200160006001600160401b0316815260200160006001600160401b0316815260200160006001600160401b0316815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000151581525090565b60e01c90565b600060443d1015615db957611623565b600481823e6308c379a0615dcd8251615da3565b14615dd757611623565b6040513d600319016004823e80513d6001600160401b038160248401118184111715615e065750505050611623565b82840192508251915080821115615e205750505050611623565b503d83016020828401011115615e3857505050611623565b601f01601f191681016020016040529150509056fea264697066735822122077ab368710148891aff560da25363ab814108ed0459319cf37cd25027984ed7964736f6c63430007060033

Verified Source Code Partial Match

Compiler: v0.7.6+commit.7338295f EVM: istanbul Optimization: Yes (200 runs)
ERC20.sol 324 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

contract Context {

    /**
     * @dev returns address executing the method
     */
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    /**
     * @dev returns data passed into the method
     */
    function _msgData() internal view virtual returns (bytes memory) {
        this;
        return msg.data;
    }
}

contract ERC20 is Context {

    using SafeMath for uint256;

    mapping (address => uint256) private _balances;
    mapping (address => mapping (address => uint256)) private _allowances;

    /**
     * @dev initial private
     */
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev 👻 ghost supply - unclaimable
     */
    uint256 private _totalSupply = 0.404 ether;

    event Transfer(
        address indexed from,
        address indexed to,
        uint256 value
    );

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    constructor (string memory tokenName, string memory tokenSymbol) {
        _name = tokenName;
        _symbol = tokenSymbol;
        _decimals = 18;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the decimals of the token.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @dev Returns the total supply of the token.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev Returns the token balance of specific address.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    function transfer(
        address recipient,
        uint256 amount
    )
        public
        returns (bool)
    {
        _transfer(
            _msgSender(),
            recipient,
            amount
        );

        return true;
    }

    /**
     * @dev Returns approved balance to be spent by another address
     * by using transferFrom method
     */
    function allowance(
        address owner,
        address spender
    )
        public
        view
        returns (uint256)
    {
        return _allowances[owner][spender];
    }

    /**
     * @dev Sets the token allowance to another spender
     */
    function approve(
        address spender,
        uint256 amount
    )
        public
        returns (bool)
    {
        _approve(
            _msgSender(),
            spender,
            amount
        );

        return true;
    }

    /**
     * @dev Allows to transfer tokens on senders behalf
     * based on allowance approved for the executer
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    )
        public
        returns (bool)
    {
        _approve(sender,
            _msgSender(), _allowances[sender][_msgSender()].sub(
                amount
            )
        );

        _transfer(
            sender,
            recipient,
            amount
        );
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * Emits a {Transfer} event.
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    )
        internal
        virtual
    {
        require(
            sender != address(0x0)
        );

        require(
            recipient != address(0x0)
        );

        _balances[sender] =
        _balances[sender].sub(amount);

        _balances[recipient] =
        _balances[recipient].add(amount);

        emit Transfer(
            sender,
            recipient,
            amount
        );
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(
        address account,
        uint256 amount
    )
        internal
        virtual
    {
        require(
            account != address(0x0)
        );

        _totalSupply =
        _totalSupply.add(amount);

        _balances[account] =
        _balances[account].add(amount);

        emit Transfer(
            address(0x0),
            account,
            amount
        );
    }

    /**
     * @dev Allows to burn tokens if token sender
     * wants to reduce totalSupply() of the token
     */
    function burn(
        uint256 amount
    )
        external
    {
        _burn(msg.sender, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(
        address account,
        uint256 amount
    )
        internal
        virtual
    {
        require(
            account != address(0x0)
        );

        _balances[account] =
        _balances[account].sub(amount);

        _totalSupply =
        _totalSupply.sub(amount);

        emit Transfer(
            account,
            address(0x0),
            amount
        );
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    )
        internal
        virtual
    {
        require(
            owner != address(0x0)
        );

        require(
            spender != address(0x0)
        );

        _allowances[owner][spender] = amount;

        emit Approval(
            owner,
            spender,
            amount
        );
    }
}

import "./SafeMath.sol";
Events.sol 72 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

contract Events {

    event StakeStart(
        bytes16 indexed stakeID,
        address indexed stakerAddress,
        address indexed referralAddress,
        uint256 stakedAmount,
        uint256 stakesShares,
        uint256 referralShares,
        uint256 startDay,
        uint256 lockDays,
        uint256 daiEquivalent
    );

    event StakeEnd(
        bytes16 indexed stakeID,
        address indexed stakerAddress,
        address indexed referralAddress,
        uint256 stakedAmount,
        uint256 stakesShares,
        uint256 referralShares,
        uint256 rewardAmount,
        uint256 closeDay,
        uint256 penaltyAmount
    );

    event InterestScraped(
        bytes16 indexed stakeID,
        address indexed stakerAddress,
        uint256 scrapeAmount,
        uint256 scrapeDay,
        uint256 stakersPenalty,
        uint256 referrerPenalty,
        uint256 currentWiseDay
    );

    event ReferralCollected(
        address indexed staker,
        bytes16 indexed stakeID,
        address indexed referrer,
        bytes16 referrerID,
        uint256 rewardAmount
    );

    event NewGlobals(
        uint256 totalShares,
        uint256 totalStaked,
        uint256 shareRate,
        uint256 referrerShares,
        uint256 indexed currentWiseDay
    );

    event NewSharePrice(
        uint256 newSharePrice,
        uint256 oldSharePrice,
        uint64 currentWiseDay
    );

    event UniswapReserves(
        uint112 reserveA,
        uint112 reserveB,
        uint32 blockTimestampLast
    );

    event LiquidityGuardStatus(
        bool isActive
    );
}
Global.sol 86 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./ERC20.sol";
import "./Events.sol";

abstract contract Global is ERC20, Events {

    using SafeMath for uint256;

    struct Globals {
        uint256 totalStaked;
        uint256 totalShares;
        uint256 sharePrice;
        uint256 currentWiseDay;
        uint256 referralShares;
        uint256 liquidityShares;
    }

    Globals public globals;

    constructor() {
        globals.sharePrice = 100E15;
    }

    function _increaseGlobals(
        uint256 _staked,
        uint256 _shares,
        uint256 _rshares
    )
        internal
    {
        globals.totalStaked =
        globals.totalStaked.add(_staked);

        globals.totalShares =
        globals.totalShares.add(_shares);

        if (_rshares > 0) {

            globals.referralShares =
            globals.referralShares.add(_rshares);
        }

        _logGlobals();
    }

    function _decreaseGlobals(
        uint256 _staked,
        uint256 _shares,
        uint256 _rshares
    )
        internal
    {
        globals.totalStaked =
        globals.totalStaked > _staked ?
        globals.totalStaked - _staked : 0;

        globals.totalShares =
        globals.totalShares > _shares ?
        globals.totalShares - _shares : 0;

        if (_rshares > 0) {

            globals.referralShares =
            globals.referralShares > _rshares ?
            globals.referralShares - _rshares : 0;

        }

        _logGlobals();
    }

    function _logGlobals()
        private
    {
        emit NewGlobals(
            globals.totalShares,
            globals.totalStaked,
            globals.sharePrice,
            globals.referralShares,
            globals.currentWiseDay
        );
    }
}
Helper.sol 240 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./Timing.sol";

abstract contract Helper is Timing {

    using SafeMath for uint256;

    function notContract(address _addr) internal view returns (bool) {
        uint32 size;
        assembly {
            size := extcodesize(_addr)
        }
        return (size == 0);
    }

    function toBytes16(uint256 x) internal pure returns (bytes16 b) {
       return bytes16(bytes32(x));
    }

    function generateID(address x, uint256 y, bytes1 z) public pure returns (bytes16 b) {
        b = toBytes16(
            uint256(
                keccak256(
                    abi.encodePacked(x, y, z)
                )
            )
        );
    }

    function generateStakeID(address _staker) internal view returns (bytes16 stakeID) {
        return generateID(_staker, stakeCount[_staker], 0x01);
    }

    function generateReferralID(address _referrer) internal view returns (bytes16 referralID) {
        return generateID(_referrer, referralCount[_referrer], 0x02);
    }

    function generateLiquidityStakeID(address _staker) internal view returns (bytes16 liquidityStakeID) {
        return generateID(_staker, liquidityStakeCount[_staker], 0x03);
    }

    function stakesPagination(
        address _staker,
        uint256 _offset,
        uint256 _length
    )
        external
        view
        returns (bytes16[] memory _stakes)
    {
        uint256 start = _offset > 0 &&
            stakeCount[_staker] > _offset ?
            stakeCount[_staker] - _offset : stakeCount[_staker];

        uint256 finish = _length > 0 &&
            start > _length ?
            start - _length : 0;

        uint256 i;

        _stakes = new bytes16[](start - finish);

        for (uint256 _stakeIndex = start; _stakeIndex > finish; _stakeIndex--) {
            bytes16 _stakeID = generateID(_staker, _stakeIndex - 1, 0x01);
            if (stakes[_staker][_stakeID].stakedAmount > 0) {
                _stakes[i] = _stakeID; i++;
            }
        }
    }

    function referralsPagination(
        address _referrer,
        uint256 _offset,
        uint256 _length
    )
        external
        view
        returns (bytes16[] memory _referrals)
    {
        uint256 start = _offset > 0 &&
            referralCount[_referrer] > _offset ?
            referralCount[_referrer] - _offset : referralCount[_referrer];

        uint256 finish = _length > 0 &&
            start > _length ?
            start - _length : 0;

        uint256 i;

        _referrals = new bytes16[](start - finish);

        for (uint256 _rIndex = start; _rIndex > finish; _rIndex--) {
            bytes16 _rID = generateID(_referrer, _rIndex - 1, 0x02);
            if (_nonZeroAddress(referrerLinks[_referrer][_rID].staker)) {
                _referrals[i] = _rID; i++;
            }
        }
    }

    function latestStakeID(address _staker) external view returns (bytes16) {
        return stakeCount[_staker] == 0 ? bytes16(0) : generateID(_staker, stakeCount[_staker].sub(1), 0x01);
    }

    function latestReferralID(address _referrer) external view returns (bytes16) {
        return referralCount[_referrer] == 0 ? bytes16(0) : generateID(_referrer, referralCount[_referrer].sub(1), 0x02);
    }

    function latestLiquidityStakeID(address _staker) external view returns (bytes16) {
        return liquidityStakeCount[_staker] == 0 ? bytes16(0) : generateID(_staker, liquidityStakeCount[_staker].sub(1), 0x03);
    }

    function _increaseStakeCount(address _staker) internal {
        stakeCount[_staker] = stakeCount[_staker] + 1;
    }

    function _increaseReferralCount(address _referrer) internal {
        referralCount[_referrer] = referralCount[_referrer] + 1;
    }

    function _increaseLiquidityStakeCount(address _staker) internal {
        liquidityStakeCount[_staker] = liquidityStakeCount[_staker] + 1;
    }

    function _isMatureStake(Stake memory _stake) internal view returns (bool) {
        return _stake.closeDay > 0
            ? _stake.finalDay <= _stake.closeDay
            : _stake.finalDay <= _currentWiseDay();
    }

    function _notCriticalMassReferrer(address _referrer) internal view returns (bool) {
        return criticalMass[_referrer].activationDay == 0;
    }

    function _stakeNotStarted(Stake memory _stake) internal view returns (bool) {
        return _stake.closeDay > 0
            ? _stake.startDay > _stake.closeDay
            : _stake.startDay > _currentWiseDay();
    }

    function _stakeEnded(Stake memory _stake) internal view returns (bool) {
        return _stake.isActive == false || _isMatureStake(_stake);
    }

    function _daysLeft(Stake memory _stake) internal view returns (uint256) {
        return _stake.isActive == false
            ? _daysDiff(_stake.closeDay, _stake.finalDay)
            : _daysDiff(_currentWiseDay(), _stake.finalDay);
    }

    function _daysDiff(uint256 _startDate, uint256 _endDate) internal pure returns (uint256) {
        return _startDate > _endDate ? 0 : _endDate.sub(_startDate);
    }

    function _calculationDay(Stake memory _stake) internal view returns (uint256) {
        return _stake.finalDay > globals.currentWiseDay ? globals.currentWiseDay : _stake.finalDay;
    }

    function _startingDay(Stake memory _stake) internal pure returns (uint256) {
        return _stake.scrapeDay == 0 ? _stake.startDay : _stake.scrapeDay;
    }

    function _notFuture(uint256 _day) internal view returns (bool) {
        return _day <= _currentWiseDay();
    }

    function _notPast(uint256 _day) internal view returns (bool) {
        return _day >= _currentWiseDay();
    }

    function _nonZeroAddress(address _address) internal pure returns (bool) {
        return _address != address(0x0);
    }

    function _getLockDays(Stake memory _stake) internal pure returns (uint256) {
        return
            _stake.lockDays > 1 ?
            _stake.lockDays - 1 : 1;
    }

    function _preparePath(
        address _tokenAddress,
        address _wiseAddress
    )
        internal
        pure
        returns (address[] memory _path)
    {
        _path = new address[](3);
        _path[0] = _tokenAddress;
        _path[1] = WETH;
        _path[2] = _wiseAddress;
    }

    function safeTransfer(
        address token,
        address to,
        uint256 value
    )
        internal
    {
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(
                0xa9059cbb,
                to,
                value
            )
        );

        require(
            success && (data.length == 0 || abi.decode(data, (bool)))
            // 'WISE: transfer failed'
        );
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint value
    )
        internal
    {
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(
                0x23b872dd,
                from,
                to,
                value
            )
        );

        require(
            success && (data.length == 0 || abi.decode(data, (bool)))
            // 'WISE: transferFrom failed'
        );
    }
}
Timing.sol 32 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./Declaration.sol";

abstract contract Timing is Declaration {

    function currentWiseDay() public view returns (uint64) {
        return _getNow() >= LAUNCH_TIME ? _currentWiseDay() : 0;
    }

    function _currentWiseDay() internal view returns (uint64) {
        return _wiseDayFromStamp(_getNow());
    }

    function _nextWiseDay() internal view returns (uint64) {
        return _currentWiseDay() + 1;
    }

    function _previousWiseDay() internal view returns (uint64) {
        return _currentWiseDay() - 1;
    }

    function _wiseDayFromStamp(uint256 _timestamp) internal view returns (uint64) {
        return uint64((_timestamp - LAUNCH_TIME) / SECONDS_IN_DAY);
    }

    function _getNow() internal view returns (uint256) {
        return block.timestamp;
    }
}
SafeMath.sol 40 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

library SafeMath {

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;
        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {

        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b);
        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0);
        uint256 c = a / b;
        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}
Snapshot.sol 255 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./Helper.sol";

abstract contract Snapshot is Helper {

    using SafeMath for uint;

    // regular shares
    struct SnapShot {
        uint256 totalShares;
        uint256 inflationAmount;
        uint256 scheduledToEnd;
    }

    // referral shares
    struct rSnapShot {
        uint256 totalShares;
        uint256 inflationAmount;
        uint256 scheduledToEnd;
    }

    // liquidity shares
    struct lSnapShot {
        uint256 totalShares;
        uint256 inflationAmount;
    }

    mapping(uint256 => SnapShot) public snapshots;
    mapping(uint256 => rSnapShot) public rsnapshots;
    mapping(uint256 => lSnapShot) public lsnapshots;

    modifier snapshotTrigger() {
        _dailySnapshotPoint(_currentWiseDay());
        _;
    }

    /**
     * @notice allows to activate/deactivate
     * liquidity guard manually based on the
     * liquidity in UNISWAP pair contract
     */
    function liquidityGuardTrigger() public {

        (
            uint112 reserveA,
            uint112 reserveB,
            uint32 blockTimestampLast
        ) = UNISWAP_PAIR.getReserves();

        emit UniswapReserves(
            reserveA,
            reserveB,
            blockTimestampLast
        );

        uint256 onUniswap = UNISWAP_PAIR.token1() == WETH
            ? reserveA
            : reserveB;

        uint256 ratio = totalSupply() == 0
            ? 0
            : onUniswap
                .mul(200)
                .div(totalSupply());

        if (ratio < 40 && isLiquidityGuardActive == false) enableLiquidityGuard();
        if (ratio > 60 && isLiquidityGuardActive == true) disableLiquidityGuard();

        emit LiquidityGuardStatus(
            isLiquidityGuardActive
        );
    }

    function enableLiquidityGuard() private {
        isLiquidityGuardActive = true;
    }

    function disableLiquidityGuard() private {
        isLiquidityGuardActive = false;
    }

    /**
     * @notice allows volunteer to offload snapshots
     * to save on gas during next start/end stake
     */
    function manualDailySnapshot()
        external
    {
        _dailySnapshotPoint(_currentWiseDay());
    }

    /**
     * @notice allows volunteer to offload snapshots
     * to save on gas during next start/end stake
     * in case manualDailySnapshot reach block limit
     */
    function manualDailySnapshotPoint(
        uint64 _updateDay
    )
        external
    {
        require(
            _updateDay > 0 &&
            _updateDay < _currentWiseDay()
            // 'WISE: snapshot day does not exist yet'
        );

        require(
            _updateDay > globals.currentWiseDay
            // 'WISE: snapshot already taken for that day'
        );

        _dailySnapshotPoint(_updateDay);
    }

    /**
     * @notice internal function that offloads
     * global values to daily snapshots
     * updates globals.currentWiseDay
     */
    function _dailySnapshotPoint(
        uint64 _updateDay
    )
        private
    {
        liquidityGuardTrigger();

        uint256 scheduledToEndToday;
        uint256 totalStakedToday = globals.totalStaked;

        for (uint256 _day = globals.currentWiseDay; _day < _updateDay; _day++) {

            // ------------------------------------
            // prepare snapshot for regular shares
            // reusing scheduledToEndToday variable

            scheduledToEndToday = scheduledToEnd[_day] + snapshots[_day - 1].scheduledToEnd;

            SnapShot memory snapshot = snapshots[_day];
            snapshot.scheduledToEnd = scheduledToEndToday;

            snapshot.totalShares =
                globals.totalShares > scheduledToEndToday ?
                globals.totalShares - scheduledToEndToday : 0;

            snapshot.inflationAmount =  snapshot.totalShares
                .mul(PRECISION_RATE)
                .div(
                    _inflationAmount(
                        totalStakedToday,
                        totalSupply(),
                        totalPenalties[_day],
                        LIQUIDITY_GUARD.getInflation(
                            INFLATION_RATE
                        )
                    )
                );

            // store regular snapshot
            snapshots[_day] = snapshot;


            // ------------------------------------
            // prepare snapshot for referrer shares
            // reusing scheduledToEndToday variable

            scheduledToEndToday = referralSharesToEnd[_day] + rsnapshots[_day - 1].scheduledToEnd;

            rSnapShot memory rsnapshot = rsnapshots[_day];
            rsnapshot.scheduledToEnd = scheduledToEndToday;

            rsnapshot.totalShares =
                globals.referralShares > scheduledToEndToday ?
                globals.referralShares - scheduledToEndToday : 0;

            rsnapshot.inflationAmount = rsnapshot.totalShares
                .mul(PRECISION_RATE)
                .div(
                    _referralInflation(
                        totalStakedToday,
                        totalSupply()
                    )
                );

            // store referral snapshot
            rsnapshots[_day] = rsnapshot;


            // ------------------------------------
            // prepare snapshot for liquidity shares
            // reusing scheduledToEndToday variable

            lSnapShot memory lsnapshot = lsnapshots[_day];
            lsnapshot.totalShares = globals.liquidityShares;

            lsnapshot.inflationAmount = lsnapshot.totalShares
                .mul(PRECISION_RATE).div(
                    _liquidityInflation(
                        totalStakedToday,
                        totalSupply(),
                        LIQUIDITY_GUARD.getInflation(
                            LIQUIDITY_RATE
                        )
                    )
                );

            // store liquidity snapshot
            lsnapshots[_day] = lsnapshot;

            adjustLiquidityRates();
            globals.currentWiseDay++;
        }
    }

    /**
     * @notice moves inflation up and down by 0.006%
     * from regular shares to liquidity shares
     * if the liquidityGuard is active (visa-versa)
     */
    function adjustLiquidityRates() private {
        if (
            isLiquidityGuardActive ==  true &&
            LIQUIDITY_RATE < INFLATION_RATE_MAX
            )
        {
            LIQUIDITY_RATE = LIQUIDITY_RATE + 6;
            INFLATION_RATE = INFLATION_RATE - 6;
            return;
        }
        if (
            isLiquidityGuardActive == false &&
            INFLATION_RATE < INFLATION_RATE_MAX
            )
        {
            INFLATION_RATE = INFLATION_RATE + 6;
            LIQUIDITY_RATE = LIQUIDITY_RATE - 6;
            return;
        }
    }

    function _inflationAmount(uint256 _totalStaked, uint256 _totalSupply, uint256 _totalPenalties, uint256 _INFLATION_RATE) private pure returns (uint256) {
        return (_totalStaked + _totalSupply) * 10000 / _INFLATION_RATE + _totalPenalties;
    }

    function _referralInflation(uint256 _totalStaked, uint256 _totalSupply) private pure returns (uint256) {
        return (_totalStaked + _totalSupply) * 10000 / REFERRALS_RATE;
    }

    function _liquidityInflation(uint256 _totalStaked, uint256 _totalSupply, uint256 _LIQUIDITY_RATE) private pure returns (uint256) {
        return (_totalStaked + _totalSupply) * 10000 / _LIQUIDITY_RATE;
    }
}
WiseToken.sol 168 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./LiquidityToken.sol";

contract WiseToken is LiquidityToken {

    address public LIQUIDITY_TRANSFORMER;
    address public transformerGateKeeper;

    constructor() ERC20("Wise Token", "WISE") {
        transformerGateKeeper = msg.sender;
    }

    receive() external payable {
        revert();
    }

    /**
     * @notice ability to define liquidity transformer contract
     * @dev this method renounce transformerGateKeeper access
     * @param _immutableTransformer contract address
     */
    function setLiquidityTransfomer(
        address _immutableTransformer
    )
        external
    {
        require(
            transformerGateKeeper == msg.sender
            // 'WISE: transformer defined'
        );
        LIQUIDITY_TRANSFORMER = _immutableTransformer;
        transformerGateKeeper = address(0x0);
    }

    /**
     * @notice allows liquidityTransformer to mint supply
     * @dev executed from liquidityTransformer upon UNISWAP transfer
     * and during reservation payout to contributors and referrers
     * @param _investorAddress address for minting WISE tokens
     * @param _amount of tokens to mint for _investorAddress
     */
    function mintSupply(
        address _investorAddress,
        uint256 _amount
    )
        external
    {
        require(
            msg.sender == LIQUIDITY_TRANSFORMER
            // 'WISE: wrong transformer'
        );

        _mint(
            _investorAddress,
            _amount
        );
    }

    /**
     * @notice allows to grant permission to CM referrer status
     * @dev called from liquidityTransformer if user referred 50 ETH
     * @param _referrer - address that becomes a CM reffer
     */
    function giveStatus(
        address _referrer
    )
        external
    {
        require(
            msg.sender == LIQUIDITY_TRANSFORMER
            // 'WISE: wrong transformer'
        );
        criticalMass[_referrer].totalAmount = THRESHOLD_LIMIT;
        criticalMass[_referrer].activationDay = _nextWiseDay();
    }

    /**
     * @notice allows to create stake directly with ETH
     * if you don't have WISE tokens method will convert
     * and use amount returned from UNISWAP to open a stake
     * @param _lockDays amount of days it is locked for.
     * @param _referrer referrer address for +10% bonus
     */
    function createStakeWithETH(
        uint64 _lockDays,
        address _referrer
    )
        external
        payable
        returns (bytes16, uint256, bytes16 referralID)
    {
        address[] memory path = new address[](2);
            path[0] = WETH;
            path[1] = address(this);

        uint256[] memory amounts =
        UNISWAP_ROUTER.swapExactETHForTokens{value: msg.value}(
            1,
            path,
            msg.sender,
            block.timestamp + 2 hours
        );

        return createStake(
            amounts[1],
            _lockDays,
            _referrer
        );
    }

    /**
     * @notice allows to create stake with another token
     * if you don't have WISE tokens method will convert
     * and use amount returned from UNISWAP to open a stake
     * @dev the token must have WETH pair on UNISWAP
     * @param _tokenAddress any ERC20 token address
     * @param _tokenAmount amount to be converted to WISE
     * @param _lockDays amount of days it is locked for.
     * @param _referrer referrer address for +10% bonus
     */
    function createStakeWithToken(
        address _tokenAddress,
        uint256 _tokenAmount,
        uint64 _lockDays,
        address _referrer
    )
        external
        returns (bytes16, uint256, bytes16 referralID)
    {
        ERC20TokenI token = ERC20TokenI(
            _tokenAddress
        );

        token.transferFrom(
            msg.sender,
            address(this),
            _tokenAmount
        );

        token.approve(
            address(UNISWAP_ROUTER),
            _tokenAmount
        );

        address[] memory path = _preparePath(
            _tokenAddress,
            address(this)
        );

        uint256[] memory amounts =
        UNISWAP_ROUTER.swapExactTokensForTokens(
            _tokenAmount,
            1,
            path,
            msg.sender,
            block.timestamp + 2 hours
        );

        return createStake(
            amounts[2],
            _lockDays,
            _referrer
        );
    }
}
Declaration.sol 190 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./Global.sol";

interface IUniswapV2Factory {

    function createPair(
        address tokenA,
        address tokenB
    ) external returns (
        address pair
    );
}

interface IUniswapRouterV2 {

    function getAmountsOut(
        uint amountIn,
        address[] calldata path
    ) external view returns (
        uint[] memory amounts
    );

    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (
        uint[] memory amounts
    );

    function swapExactETHForTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable returns (
        uint[] memory amounts
    );
}

interface IUniswapV2Pair {

    function getReserves() external view returns (
        uint112 reserve0,
        uint112 reserve1,
        uint32 blockTimestampLast
    );

    function token1() external view returns (address);
}

interface ILiquidityGuard {
    function getInflation(uint32 _amount) external view returns (uint256);
}

interface ERC20TokenI {

    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    )  external returns (
        bool success
    );

    function approve(
        address _spender,
        uint256 _value
    )  external returns (
        bool success
    );
}

abstract contract Declaration is Global {

    uint256 constant _decimals = 18;
    uint256 constant YODAS_PER_WISE = 10 ** _decimals;

    uint32 constant SECONDS_IN_DAY = 86400 seconds;
    uint16 constant MIN_LOCK_DAYS = 1;
    uint16 constant FORMULA_DAY = 65;
    uint16 constant MAX_LOCK_DAYS = 15330; // 42 years
    uint16 constant MAX_BONUS_DAYS_A = 1825; // 5 years
    uint16 constant MAX_BONUS_DAYS_B = 13505; // 37 years
    uint16 constant MIN_REFERRAL_DAYS = 365;

    uint32 constant MIN_STAKE_AMOUNT = 1000000;
    uint32 constant REFERRALS_RATE = 366816973; // 1.000% (direct value, can be used right away)
    uint32 constant INFLATION_RATE_MAX = 103000; // 3.000% (indirect -> checks throgh LiquidityGuard)

    uint32 public INFLATION_RATE = 103000; // 3.000% (indirect -> checks throgh LiquidityGuard)
    uint32 public LIQUIDITY_RATE = 100006; // 0.006% (indirect -> checks throgh LiquidityGuard)

    uint64 constant PRECISION_RATE = 1E18;

    uint96 constant THRESHOLD_LIMIT = 10000E18; // $10,000 DAI

    uint96 constant DAILY_BONUS_A = 13698630136986302; // 25%:1825 = 0.01369863013 per day;
    uint96 constant DAILY_BONUS_B = 370233246945576;   // 5%:13505 = 0.00037023324 per day;

    uint256 immutable LAUNCH_TIME;

    address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
    address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    IUniswapRouterV2 public constant UNISWAP_ROUTER = IUniswapRouterV2(
        0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
    );

    IUniswapV2Factory public constant UNISWAP_FACTORY = IUniswapV2Factory(
        0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
    );

    ILiquidityGuard public constant LIQUIDITY_GUARD = ILiquidityGuard(
        0x9C306CaD86550EC80D77668c0A8bEE6eB34684B6
    );

    IUniswapV2Pair public UNISWAP_PAIR;
    bool public isLiquidityGuardActive;

    uint256 public latestDaiEquivalent;
    address[] internal _path = [address(this), WETH, DAI];

    constructor() {
        LAUNCH_TIME = 1604966400; // (10th November 2020 @00:00 GMT == day 0)
    }

    function createPair() external {
        UNISWAP_PAIR = IUniswapV2Pair(
            UNISWAP_FACTORY.createPair(
                WETH, address(this)
            )
        );
    }

    struct Stake {
        uint256 stakesShares;
        uint256 stakedAmount;
        uint256 rewardAmount;
        uint64 startDay;
        uint64 lockDays;
        uint64 finalDay;
        uint64 closeDay;
        uint256 scrapeDay;
        uint256 daiEquivalent;
        uint256 referrerShares;
        address referrer;
        bool isActive;
    }

    struct ReferrerLink {
        address staker;
        bytes16 stakeID;
        uint256 rewardAmount;
        uint256 processedDays;
        bool isActive;
    }

    struct LiquidityStake {
        uint256 stakedAmount;
        uint256 rewardAmount;
        uint64 startDay;
        uint64 closeDay;
        bool isActive;
    }

    struct CriticalMass {
        uint256 totalAmount;
        uint256 activationDay;
    }

    mapping(address => uint256) public stakeCount;
    mapping(address => uint256) public referralCount;
    mapping(address => uint256) public liquidityStakeCount;

    mapping(address => CriticalMass) public criticalMass;
    mapping(address => mapping(bytes16 => uint256)) public scrapes;
    mapping(address => mapping(bytes16 => Stake)) public stakes;
    mapping(address => mapping(bytes16 => ReferrerLink)) public referrerLinks;
    mapping(address => mapping(bytes16 => LiquidityStake)) public liquidityStakes;

    mapping(uint256 => uint256) public scheduledToEnd;
    mapping(uint256 => uint256) public referralSharesToEnd;
    mapping(uint256 => uint256) public totalPenalties;
}
StakingToken.sol 724 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./ReferralToken.sol";

abstract contract StakingToken is ReferralToken {

    using SafeMath for uint256;

    /**
     * @notice A method for a staker to create multiple stakes
     * @param _stakedAmount amount of WISE staked.
     * @param _lockDays amount of days it is locked for.
     * @param _referrer address of the referrer
     */
    function createStakeBulk(
        uint256[] memory _stakedAmount,
        uint64[] memory _lockDays,
        address[] memory _referrer
    )
        external
    {
        for(uint256 i = 0; i < _stakedAmount.length; i++) {
            createStake(
                _stakedAmount[i],
                _lockDays[i],
                _referrer[i]
            );
        }
    }

    /**
     * @notice A method for a staker to create a stake
     * @param _stakedAmount amount of WISE staked.
     * @param _lockDays amount of days it is locked for.
     * @param _referrer address of the referrer
     */
    function createStake(
        uint256 _stakedAmount,
        uint64 _lockDays,
        address _referrer
    )
        snapshotTrigger
        public
        returns (bytes16, uint256, bytes16 referralID)
    {
        require(
            msg.sender != _referrer &&
            notContract(_referrer)
            // 'WISE: invalid referrer'
        );

        require(
            _lockDays >= MIN_LOCK_DAYS &&
            _lockDays <= MAX_LOCK_DAYS
            // 'WISE: stake is not in range'
        );

        require(
            _stakedAmount >= MIN_STAKE_AMOUNT
            // 'WISE: stake is not large enough'
        );

        (
            Stake memory newStake,
            bytes16 stakeID,
            uint256 _startDay
        ) =

        _createStake(msg.sender, _stakedAmount, _lockDays, _referrer);

        if (newStake.referrerShares > 0) {

            ReferrerLink memory referrerLink;

            referrerLink.staker = msg.sender;
            referrerLink.stakeID = stakeID;
            referrerLink.isActive = true;

            referralID = generateReferralID(_referrer);
            referrerLinks[_referrer][referralID] = referrerLink;

            _increaseReferralCount(
                _referrer
            );

            _addReferrerSharesToEnd(
                newStake.finalDay,
                newStake.referrerShares
            );
        }

        stakes[msg.sender][stakeID] = newStake;

        _increaseStakeCount(
            msg.sender
        );

        _increaseGlobals(
            newStake.stakedAmount,
            newStake.stakesShares,
            newStake.referrerShares
        );

        _addScheduledShares(
            newStake.finalDay,
            newStake.stakesShares
        );

        emit StakeStart(
            stakeID,
            msg.sender,
            _referrer,
            newStake.stakedAmount,
            newStake.stakesShares,
            newStake.referrerShares,
            newStake.startDay,
            newStake.lockDays,
            newStake.daiEquivalent
        );

        return (stakeID, _startDay, referralID);
    }

    /**
    * @notice A method for a staker to start a stake
    * @param _staker ...
    * @param _stakedAmount ...
    * @param _lockDays ...
    */
    function _createStake(
        address _staker,
        uint256 _stakedAmount,
        uint64 _lockDays,
        address _referrer
    )
        private
        returns (
            Stake memory _newStake,
            bytes16 _stakeID,
            uint64 _startDay
        )
    {
        _burn(
            _staker,
            _stakedAmount
        );

        _startDay = _nextWiseDay();
        _stakeID = generateStakeID(_staker);

        _newStake.lockDays = _lockDays;
        _newStake.startDay = _startDay;
        _newStake.finalDay = _startDay + _lockDays;
        _newStake.isActive = true;

        _newStake.stakedAmount = _stakedAmount;
        _newStake.stakesShares = _stakesShares(
            _stakedAmount,
            _lockDays,
            _referrer,
            globals.sharePrice
        );

        _updateDaiEquivalent();

        _newStake.daiEquivalent = latestDaiEquivalent
            .mul(_newStake.stakedAmount)
            .div(YODAS_PER_WISE);

        if (_nonZeroAddress(_referrer)) {

            _newStake.referrer = _referrer;

            _addCriticalMass(
                _newStake.referrer,
                _newStake.daiEquivalent
            );

            _newStake.referrerShares = _referrerShares(
                _stakedAmount,
                _lockDays,
                _referrer
            );
        }
    }

    /**
    * @notice A method for a staker to remove a stake
    * belonging to his address by providing ID of a stake.
    * @param _stakeID unique bytes sequence reference to the stake
    */
    function endStake(
        bytes16 _stakeID
    )
        snapshotTrigger
        external
        returns (uint256)
    {
        (
            Stake memory endedStake,
            uint256 penaltyAmount
        ) =

        _endStake(
            msg.sender,
            _stakeID
        );

        _decreaseGlobals(
            endedStake.stakedAmount,
            endedStake.stakesShares,
            endedStake.referrerShares
        );

        _removeScheduledShares(
            endedStake.finalDay,
            endedStake.stakesShares
        );

        _removeReferrerSharesToEnd(
            endedStake.finalDay,
            endedStake.referrerShares
        );

        _removeCriticalMass(
            endedStake.referrer,
            endedStake.daiEquivalent,
            endedStake.startDay
        );

        _storePenalty(
            endedStake.closeDay,
            penaltyAmount
        );

        _sharePriceUpdate(
            endedStake.stakedAmount > penaltyAmount ?
            endedStake.stakedAmount - penaltyAmount : 0,
            endedStake.rewardAmount + scrapes[msg.sender][_stakeID],
            endedStake.referrer,
            endedStake.lockDays,
            endedStake.stakesShares
        );

        emit StakeEnd(
            _stakeID,
            msg.sender,
            endedStake.referrer,
            endedStake.stakedAmount,
            endedStake.stakesShares,
            endedStake.referrerShares,
            endedStake.rewardAmount,
            endedStake.closeDay,
            penaltyAmount
        );

        return endedStake.rewardAmount;
    }

    function _endStake(
        address _staker,
        bytes16 _stakeID
    )
        private
        returns (
            Stake storage _stake,
            uint256 _penalty
        )
    {
        require(
            stakes[_staker][_stakeID].isActive
            // 'WISE: not an active stake'
        );

        _stake = stakes[_staker][_stakeID];
        _stake.closeDay = _currentWiseDay();
        _stake.rewardAmount = _calculateRewardAmount(_stake);
        _penalty = _calculatePenaltyAmount(_stake);

        _stake.isActive = false;

        _mint(
            _staker,
            _stake.stakedAmount > _penalty ?
            _stake.stakedAmount - _penalty : 0
        );

        _mint(
            _staker,
            _stake.rewardAmount
        );
    }

    /**
    * @notice alloes to scrape interest from active stake
    * @param _stakeID unique bytes sequence reference to the stake
    * @param _scrapeDays amount of days to proccess, 0 = all
    */
    function scrapeInterest(
        bytes16 _stakeID,
        uint64 _scrapeDays
    )
        external
        snapshotTrigger
        returns (
            uint256 scrapeDay,
            uint256 scrapeAmount,
            uint256 remainingDays,
            uint256 stakersPenalty,
            uint256 referrerPenalty
        )
    {
        require(
            stakes[msg.sender][_stakeID].isActive
            // 'WISE: not an active stake'
        );

        Stake memory stake = stakes[msg.sender][_stakeID];

        scrapeDay = _scrapeDays > 0
            ? _startingDay(stake).add(_scrapeDays)
            : _calculationDay(stake);

        scrapeDay = scrapeDay > stake.finalDay
            ? _calculationDay(stake)
            : scrapeDay;

        scrapeAmount = _loopRewardAmount(
            stake.stakesShares,
            _startingDay(stake),
            scrapeDay
        );

        if (_isMatureStake(stake) == false) {

            remainingDays = _daysLeft(stake);

            stakersPenalty = _stakesShares(
                scrapeAmount,
                remainingDays,
                msg.sender,
                globals.sharePrice
            );

            stake.stakesShares =
            stake.stakesShares.sub(stakersPenalty);

            _removeScheduledShares(
                stake.finalDay,
                stakersPenalty
            );

            if (stake.referrerShares > 0) {

                referrerPenalty = _stakesShares(
                    scrapeAmount,
                    remainingDays,
                    address(0x0),
                    globals.sharePrice
                );

                stake.referrerShares =
                stake.referrerShares.sub(referrerPenalty);

                _removeReferrerSharesToEnd(
                    stake.finalDay,
                    referrerPenalty
                );
            }

            _decreaseGlobals(
                0,
                stakersPenalty,
                referrerPenalty
            );

            _sharePriceUpdate(
                stake.stakedAmount,
                scrapeAmount,
                stake.referrer,
                stake.lockDays,
                stake.stakesShares
            );
        }
        else {
            scrapes[msg.sender][_stakeID] =
            scrapes[msg.sender][_stakeID].add(scrapeAmount);

            _sharePriceUpdate(
                stake.stakedAmount,
                scrapes[msg.sender][_stakeID],
                stake.referrer,
                stake.lockDays,
                stake.stakesShares
            );
        }

        stake.scrapeDay = scrapeDay;
        stakes[msg.sender][_stakeID] = stake;

        _mint(
            msg.sender,
            scrapeAmount
        );

        emit InterestScraped(
            _stakeID,
            msg.sender,
            scrapeAmount,
            scrapeDay,
            stakersPenalty,
            referrerPenalty,
            _currentWiseDay()
        );
    }

    function _addScheduledShares(
        uint256 _finalDay,
        uint256 _shares
    )
        internal
    {
        scheduledToEnd[_finalDay] =
        scheduledToEnd[_finalDay].add(_shares);
    }

    function _removeScheduledShares(
        uint256 _finalDay,
        uint256 _shares
    )
        internal
    {
        if (_notPast(_finalDay)) {

            scheduledToEnd[_finalDay] =
            scheduledToEnd[_finalDay] > _shares ?
            scheduledToEnd[_finalDay] - _shares : 0;

        } else {

            uint256 _day = _previousWiseDay();
            snapshots[_day].scheduledToEnd =
            snapshots[_day].scheduledToEnd > _shares ?
            snapshots[_day].scheduledToEnd - _shares : 0;
        }
    }

    function _sharePriceUpdate(
        uint256 _stakedAmount,
        uint256 _rewardAmount,
        address _referrer,
        uint256 _lockDays,
        uint256 _stakeShares
    )
        private
    {
        if (_stakeShares > 0 && _currentWiseDay() > FORMULA_DAY) {

            uint256 newSharePrice = _getNewSharePrice(
                _stakedAmount,
                _rewardAmount,
                _stakeShares,
                _lockDays,
                _referrer
            );

            if (newSharePrice > globals.sharePrice) {

                newSharePrice =
                    newSharePrice < globals.sharePrice.mul(110).div(100) ?
                    newSharePrice : globals.sharePrice.mul(110).div(100);

                emit NewSharePrice(
                    newSharePrice,
                    globals.sharePrice,
                    _currentWiseDay()
                );

                globals.sharePrice = newSharePrice;
            }

            return;
        }

        if (_currentWiseDay() == FORMULA_DAY) {
            globals.sharePrice = 110E15;
        }
    }

    function _getNewSharePrice(
        uint256 _stakedAmount,
        uint256 _rewardAmount,
        uint256 _stakeShares,
        uint256 _lockDays,
        address _referrer
    )
        private
        pure
        returns (uint256)
    {

        uint256 _bonusAmount = _getBonus(
            _lockDays, _nonZeroAddress(_referrer) ? 11E9 : 10E9
        );

        return
            _stakedAmount
                .add(_rewardAmount)
                .mul(_bonusAmount)
                .mul(1E8)
                .div(_stakeShares);
    }

    function checkMatureStake(
        address _staker,
        bytes16 _stakeID
    )
        external
        view
        returns (bool isMature)
    {
        Stake memory stake = stakes[_staker][_stakeID];
        isMature = _isMatureStake(stake);
    }

    function checkStakeByID(
        address _staker,
        bytes16 _stakeID
    )
        external
        view
        returns (
            uint256 startDay,
            uint256 lockDays,
            uint256 finalDay,
            uint256 closeDay,
            uint256 scrapeDay,
            uint256 stakedAmount,
            uint256 stakesShares,
            uint256 rewardAmount,
            uint256 penaltyAmount,
            bool isActive,
            bool isMature
        )
    {
        Stake memory stake = stakes[_staker][_stakeID];
        startDay = stake.startDay;
        lockDays = stake.lockDays;
        finalDay = stake.finalDay;
        closeDay = stake.closeDay;
        scrapeDay = stake.scrapeDay;
        stakedAmount = stake.stakedAmount;
        stakesShares = stake.stakesShares;
        rewardAmount = _checkRewardAmount(stake);
        penaltyAmount = _calculatePenaltyAmount(stake);
        isActive = stake.isActive;
        isMature = _isMatureStake(stake);
    }

    function _stakesShares(
        uint256 _stakedAmount,
        uint256 _lockDays,
        address _referrer,
        uint256 _sharePrice
    )
        private
        pure
        returns (uint256)
    {
        return _nonZeroAddress(_referrer)
            ? _sharesAmount(_stakedAmount, _lockDays, _sharePrice, 11E9)
            : _sharesAmount(_stakedAmount, _lockDays, _sharePrice, 10E9);
    }

    function _sharesAmount(
        uint256 _stakedAmount,
        uint256 _lockDays,
        uint256 _sharePrice,
        uint256 _extraBonus
    )
        private
        pure
        returns (uint256)
    {
        return _baseAmount(_stakedAmount, _sharePrice)
            .mul(_getBonus(_lockDays, _extraBonus))
            .div(10E9);
    }

    function _getBonus(
        uint256 _lockDays,
        uint256 _extraBonus
    )
        private
        pure
        returns (uint256)
    {
        return
            _regularBonus(_lockDays, DAILY_BONUS_A, MAX_BONUS_DAYS_A) +
            _regularBonus(
                _lockDays > MAX_BONUS_DAYS_A ?
                _lockDays - MAX_BONUS_DAYS_A : 0, DAILY_BONUS_B, MAX_BONUS_DAYS_B
            ) + _extraBonus;
    }

    function _regularBonus(
        uint256 _lockDays,
        uint256 _daily,
        uint256 _maxDays
    )
        private
        pure
        returns (uint256)
    {
        return (
            _lockDays > _maxDays
                ? _maxDays.mul(_daily)
                : _lockDays.mul(_daily)
            ).div(10E9);
    }

    function _baseAmount(
        uint256 _stakedAmount,
        uint256 _sharePrice
    )
        private
        pure
        returns (uint256)
    {
        return
            _stakedAmount
                .mul(PRECISION_RATE)
                .div(_sharePrice);
    }

    function _referrerShares(
        uint256 _stakedAmount,
        uint256 _lockDays,
        address _referrer
    )
        private
        view
        returns (uint256)
    {
        return
            _notCriticalMassReferrer(_referrer) ||
            _lockDays < MIN_REFERRAL_DAYS
                ? 0
                : _sharesAmount(
                    _stakedAmount,
                    _lockDays,
                    globals.sharePrice,
                    10E9
                );
    }

    function _checkRewardAmount(Stake memory _stake) private view returns (uint256) {
        return _stake.isActive ? _detectReward(_stake) : _stake.rewardAmount;
    }

    function _detectReward(Stake memory _stake) private view returns (uint256) {
        return _stakeNotStarted(_stake) ? 0 : _calculateRewardAmount(_stake);
    }

    function _storePenalty(
        uint64 _storeDay,
        uint256 _penalty
    )
        private
    {
        if (_penalty > 0) {
            totalPenalties[_storeDay] =
            totalPenalties[_storeDay].add(_penalty);
        }
    }

    function _calculatePenaltyAmount(
        Stake memory _stake
    )
        private
        view
        returns (uint256)
    {
        return _stakeNotStarted(_stake) || _isMatureStake(_stake) ? 0 : _getPenalties(_stake);
    }

    function _getPenalties(Stake memory _stake)
        private
        view
        returns (uint256)
    {
        return _stake.stakedAmount * (100 + (800 * (_daysLeft(_stake) - 1) / (_getLockDays(_stake)))) / 1000;
    }

    function _calculateRewardAmount(
        Stake memory _stake
    )
        private
        view
        returns (uint256)
    {
        return _loopRewardAmount(
            _stake.stakesShares,
            _startingDay(_stake),
            _calculationDay(_stake)
        );
    }

    function _loopRewardAmount(
        uint256 _stakeShares,
        uint256 _startDay,
        uint256 _finalDay
    )
        private
        view
        returns (uint256 _rewardAmount)
    {
        for (uint256 _day = _startDay; _day < _finalDay; _day++) {
            _rewardAmount += _stakeShares * PRECISION_RATE / snapshots[_day].inflationAmount;
        }
    }
}
ReferralToken.sol 291 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./Snapshot.sol";

abstract contract ReferralToken is Snapshot {

    using SafeMath for uint256;

    function _addReferrerSharesToEnd(
        uint256 _finalDay,
        uint256 _shares
    )
        internal
    {
        referralSharesToEnd[_finalDay] =
        referralSharesToEnd[_finalDay].add(_shares);
    }

    function _removeReferrerSharesToEnd(
        uint256 _finalDay,
        uint256 _shares
    )
        internal
    {
        if (_notPast(_finalDay)) {

            referralSharesToEnd[_finalDay] =
            referralSharesToEnd[_finalDay] > _shares ?
            referralSharesToEnd[_finalDay] - _shares : 0;

        } else {

            uint256 _day = _previousWiseDay();
            rsnapshots[_day].scheduledToEnd =
            rsnapshots[_day].scheduledToEnd > _shares ?
            rsnapshots[_day].scheduledToEnd - _shares : 0;
        }
    }

    function _belowThresholdLevel(
        address _referrer
    )
        private
        view
        returns (bool)
    {
        return criticalMass[_referrer].totalAmount < THRESHOLD_LIMIT;
    }

    function _addCriticalMass(
        address _referrer,
        uint256 _daiEquivalent
    )
        internal
    {
        criticalMass[_referrer].totalAmount =
        criticalMass[_referrer].totalAmount.add(_daiEquivalent);
        criticalMass[_referrer].activationDay = _determineActivationDay(_referrer);
    }

    function _removeCriticalMass(
        address _referrer,
        uint256 _daiEquivalent,
        uint256 _startDay
    )
        internal
    {
        if (
            _notFuture(_startDay) == false &&
            _nonZeroAddress(_referrer)
        ) {
            criticalMass[_referrer].totalAmount =
            criticalMass[_referrer].totalAmount > _daiEquivalent ?
            criticalMass[_referrer].totalAmount - _daiEquivalent : 0;
            criticalMass[_referrer].activationDay = _determineActivationDay(_referrer);
        }
    }

    function _determineActivationDay(
        address _referrer
    )
        private
        view
        returns (uint256)
    {
        return _belowThresholdLevel(_referrer) ? 0 : _activationDay(_referrer);
    }

    function _activationDay(
        address _referrer
    )
        private
        view
        returns (uint256)
    {
        return
            criticalMass[_referrer].activationDay > 0 ?
            criticalMass[_referrer].activationDay : _currentWiseDay();
    }

    function _updateDaiEquivalent()
        internal
        returns (uint256)
    {
        try UNISWAP_ROUTER.getAmountsOut(
            YODAS_PER_WISE, _path
        ) returns (uint256[] memory results) {
            latestDaiEquivalent = results[2];
            return latestDaiEquivalent;
        } catch Error(string memory) {
            return latestDaiEquivalent;
        } catch (bytes memory) {
            return latestDaiEquivalent;
        }
    }

    function referrerInterest(
        bytes16 _referralID,
        uint256 _scrapeDays
    )
        external
        snapshotTrigger
    {
        _referrerInterest(
            msg.sender,
            _referralID,
            _scrapeDays
        );
    }

    function referrerInterestBulk(
        bytes16[] memory _referralIDs,
        uint256[] memory _scrapeDays
    )
        external
        snapshotTrigger
    {
        for(uint256 i = 0; i < _referralIDs.length; i++) {
            _referrerInterest(
                msg.sender,
                _referralIDs[i],
                _scrapeDays[i]
            );
        }
    }

    function _referrerInterest(
        address _referrer,
        bytes16 _referralID,
        uint256 _processDays
    )
        internal
    {
        ReferrerLink memory link =
        referrerLinks[_referrer][_referralID];

        require(
            link.isActive == true
        );

        address staker = link.staker;
        bytes16 stakeID = link.stakeID;

        Stake memory stake = stakes[staker][stakeID];

        uint256 startDay = _determineStartDay(stake, link);
        uint256 finalDay = _determineFinalDay(stake);

        if (_stakeEnded(stake)) {

            if (
                _processDays > 0 &&
                _processDays < _daysDiff(startDay, finalDay)
                )
            {

                link.processedDays =
                link.processedDays.add(_processDays);

                finalDay =
                startDay.add(_processDays);

            } else {

                link.isActive = false;
            }

        } else {

            _processDays = _daysDiff(startDay, _currentWiseDay());

            link.processedDays =
            link.processedDays.add(_processDays);

            finalDay =
            startDay.add(_processDays);
        }

        uint256 referralInterest = _checkReferralInterest(
            stake,
            startDay,
            finalDay
        );

        link.rewardAmount =
        link.rewardAmount.add(referralInterest);

        referrerLinks[_referrer][_referralID] = link;

        _mint(
            _referrer,
            referralInterest
        );

        emit ReferralCollected(
            staker,
            stakeID,
            _referrer,
            _referralID,
            referralInterest
        );
    }

    function checkReferralsByID(
        address _referrer,
        bytes16 _referralID
    )
        external
        view
        returns (
            address staker,
            bytes16 stakeID,
            uint256 referrerShares,
            uint256 referralInterest,
            bool isActiveReferral,
            bool isActiveStake,
            bool isMatureStake,
            bool isEndedStake
        )
    {
        ReferrerLink memory link = referrerLinks[_referrer][_referralID];

        staker = link.staker;
        stakeID = link.stakeID;
        isActiveReferral = link.isActive;

        Stake memory stake = stakes[staker][stakeID];
        referrerShares = stake.referrerShares;

        referralInterest = _checkReferralInterest(
            stake,
            _determineStartDay(stake, link),
            _determineFinalDay(stake)
        );

        isActiveStake = stake.isActive;
        isEndedStake = _stakeEnded(stake);
        isMatureStake = _isMatureStake(stake);
    }

    function _checkReferralInterest(Stake memory _stake, uint256 _startDay, uint256 _finalDay) internal view returns (uint256 _referralInterest) {
        return _notCriticalMassReferrer(_stake.referrer) ? 0 : _getReferralInterest(_stake, _startDay, _finalDay);
    }

    function _getReferralInterest(Stake memory _stake, uint256 _startDay, uint256 _finalDay) private view returns (uint256 _referralInterest) {
        for (uint256 _day = _startDay; _day < _finalDay; _day++) {
            _referralInterest += _stake.stakesShares * PRECISION_RATE / rsnapshots[_day].inflationAmount;
        }
    }

    function _determineStartDay(Stake memory _stake, ReferrerLink memory _link) internal view returns (uint256) {
        return (
            criticalMass[_stake.referrer].activationDay > _stake.startDay ?
            criticalMass[_stake.referrer].activationDay : _stake.startDay
        ).add(_link.processedDays);
    }

    function _determineFinalDay(
        Stake memory _stake
    )
        internal
        view
        returns (uint256)
    {
        return
            _stake.closeDay > 0 ?
            _stake.closeDay : _calculationDay(_stake);
    }
}
LiquidityToken.sol 147 lines
// SPDX-License-Identifier: --🦉--

pragma solidity =0.7.6;

import "./StakingToken.sol";

abstract contract LiquidityToken is StakingToken {

    using SafeMath for uint;

    /**
     * @notice A method for a staker to create a liquidity stake
     * @param _liquidityTokens amount of UNI-WISE staked.
     */
    function createLiquidityStake(
        uint256 _liquidityTokens
    )
        snapshotTrigger
        external
        returns (bytes16 liquidityStakeID)
    {
        require(
            isLiquidityGuardActive == true
            // WISE: LiquidityGuard is not active
        );

        safeTransferFrom(
            address(UNISWAP_PAIR),
            msg.sender,
            address(this),
            _liquidityTokens
        );

        LiquidityStake memory newLiquidityStake;

        liquidityStakeID = generateLiquidityStakeID(
            msg.sender
        );

        newLiquidityStake.startDay = _nextWiseDay();
        newLiquidityStake.stakedAmount = _liquidityTokens;
        newLiquidityStake.isActive = true;

        globals.liquidityShares =
        globals.liquidityShares.add(_liquidityTokens);

        liquidityStakes[msg.sender][liquidityStakeID] = newLiquidityStake;

        _increaseLiquidityStakeCount(
            msg.sender
        );
    }

    /**
     * @notice A method for a staker to end a liquidity stake
     * @param _liquidityStakeID - identification number
     */
    function endLiquidityStake(
        bytes16 _liquidityStakeID
    )
        snapshotTrigger
        external
        returns (uint256)
    {
        LiquidityStake memory liquidityStake =
        liquidityStakes[msg.sender][_liquidityStakeID];

        require(
            liquidityStake.isActive
            // 'WISE: not an active stake'
        );

        liquidityStake.isActive = false;
        liquidityStake.closeDay = _currentWiseDay();

        liquidityStake.rewardAmount = _calculateRewardAmount(
            liquidityStake
        );

        _mint(
            msg.sender,
            liquidityStake.rewardAmount
        );

        safeTransfer(
            address(UNISWAP_PAIR),
            msg.sender,
            liquidityStake.stakedAmount
        );

        globals.liquidityShares =
        globals.liquidityShares.sub(liquidityStake.stakedAmount);

        liquidityStakes[msg.sender][_liquidityStakeID] = liquidityStake;

        return liquidityStake.rewardAmount;
    }

    /**
     * @notice returns full view and details of
     * a liquidity stake belonging to caller
     * @param _liquidityStakeID - stakeID
     */
    function checkLiquidityStakeByID(
        address _staker,
        bytes16 _liquidityStakeID
    )
        external
        view
        returns (
            uint256 startDay,
            uint256 stakedAmount,
            uint256 rewardAmount,
            uint256 closeDay,
            bool isActive
        )
    {
        LiquidityStake memory stake = liquidityStakes[_staker][_liquidityStakeID];
        startDay = stake.startDay;
        stakedAmount = stake.stakedAmount;
        rewardAmount = _calculateRewardAmount(stake);
        closeDay = stake.closeDay;
        isActive = stake.isActive;
    }

    /**
     * @notice calculates reward when closing liquidity stake
     * @param _liquidityStake - stake instance
     */
    function _calculateRewardAmount(
        LiquidityStake memory _liquidityStake
    )
        private
        view
        returns (uint256 _rewardAmount)
    {
        uint256 maxCalculationDay = _liquidityStake.startDay + MIN_REFERRAL_DAYS;

        uint256 calculationDay =
            globals.currentWiseDay < maxCalculationDay ?
            globals.currentWiseDay : maxCalculationDay;

        for (uint256 _day = _liquidityStake.startDay; _day < calculationDay; _day++) {
            _rewardAmount += _liquidityStake.stakedAmount * PRECISION_RATE / lsnapshots[_day].inflationAmount;
        }
    }
}

Read Contract

INFLATION_RATE 0xb381a811 → uint32
LIQUIDITY_GUARD 0xb543c4ba → address
LIQUIDITY_RATE 0x3697e979 → uint32
LIQUIDITY_TRANSFORMER 0x60e4c651 → address
UNISWAP_FACTORY 0xc74c0fac → address
UNISWAP_PAIR 0x6ba631cf → address
UNISWAP_ROUTER 0xd8264920 → address
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
checkLiquidityStakeByID 0x10748592 → uint256, uint256, uint256, uint256, bool
checkMatureStake 0x779e2e18 → bool
checkReferralsByID 0x89201d4e → address, bytes16, uint256, uint256, bool, bool, bool, bool
checkStakeByID 0xa4ed0550 → uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, bool, bool
criticalMass 0x3b58afe7 → uint256, uint256
currentWiseDay 0x48e4ccab → uint64
decimals 0x313ce567 → uint8
generateID 0xbf58f6d2 → bytes16
globals 0xc3124525 → uint256, uint256, uint256, uint256, uint256, uint256
isLiquidityGuardActive 0x02cbb266 → bool
latestDaiEquivalent 0x005ada7f → uint256
latestLiquidityStakeID 0x75c3fa4f → bytes16
latestReferralID 0x5b202387 → bytes16
latestStakeID 0xae3d1de2 → bytes16
liquidityStakeCount 0x601f37ac → uint256
liquidityStakes 0xdf0618d2 → uint256, uint256, uint64, uint64, bool
lsnapshots 0xe3073bfb → uint256, uint256
name 0x06fdde03 → string
referralCount 0xdb74559b → uint256
referralSharesToEnd 0xbe21ff70 → uint256
referralsPagination 0xe7881cda → bytes16[]
referrerLinks 0xc172628e → address, bytes16, uint256, uint256, bool
rsnapshots 0x8649102b → uint256, uint256, uint256
scheduledToEnd 0xc23d6564 → uint256
scrapes 0x20429fac → uint256
snapshots 0xd6565a2d → uint256, uint256, uint256
stakeCount 0x33060d90 → uint256
stakes 0xe1d033e9 → uint256, uint256, uint256, uint64, uint64, uint64, uint64, uint256, uint256, uint256, address, bool
stakesPagination 0x23672d8a → bytes16[]
symbol 0x95d89b41 → string
totalPenalties 0xbba85e1f → uint256
totalSupply 0x18160ddd → uint256
transformerGateKeeper 0x8a263060 → address

Write Contract 21 functions

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

approve 0x095ea7b3
address spender
uint256 amount
returns: bool
burn 0x42966c68
uint256 amount
createLiquidityStake 0xce8f9f00
uint256 _liquidityTokens
returns: bytes16
createPair 0x9e78fb4f
No parameters
createStake 0xdf2d02b1
uint256 _stakedAmount
uint64 _lockDays
address _referrer
returns: bytes16, uint256, bytes16
createStakeBulk 0x763241d3
uint256[] _stakedAmount
uint64[] _lockDays
address[] _referrer
createStakeWithETH 0x1c0b37e1
uint64 _lockDays
address _referrer
returns: bytes16, uint256, bytes16
createStakeWithToken 0xd1cf9098
address _tokenAddress
uint256 _tokenAmount
uint64 _lockDays
address _referrer
returns: bytes16, uint256, bytes16
endLiquidityStake 0xa50af895
bytes16 _liquidityStakeID
returns: uint256
endStake 0x99c2def4
bytes16 _stakeID
returns: uint256
giveStatus 0x4dfc7a03
address _referrer
liquidityGuardTrigger 0x87da6274
No parameters
manualDailySnapshot 0x613fc9fd
No parameters
manualDailySnapshotPoint 0xa91b19f2
uint64 _updateDay
mintSupply 0xe742806a
address _investorAddress
uint256 _amount
referrerInterest 0x4f47b16d
bytes16 _referralID
uint256 _scrapeDays
referrerInterestBulk 0xfc527bf5
bytes16[] _referralIDs
uint256[] _scrapeDays
scrapeInterest 0x9b57ab12
bytes16 _stakeID
uint64 _scrapeDays
returns: uint256, uint256, uint256, uint256, uint256
setLiquidityTransfomer 0xd8d44a29
address _immutableTransformer
transfer 0xa9059cbb
address recipient
uint256 amount
returns: bool
transferFrom 0x23b872dd
address sender
address recipient
uint256 amount
returns: bool

Recent Transactions

No transactions found for this address