Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xACb8D462Ad11374AbFFaDf2C3a1C145D0673ce56
Balance 0 ETH
Nonce 1
Code Size 17529 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

17529 bytes
0x608060405234801561001057600080fd5b50600436106103a45760003560e01c8063766d7cfb116101e9578063d5f9464e1161010f578063e30c3978116100ad578063f6d4c1851161007c578063f6d4c18514610b18578063f7c618c114610b20578063f8cf31cb14610b28578063fecedb6514610b4e576103a4565b8063e30c397814610ace578063e78c1b1b14610ad6578063f24e534314610af3578063f54ac4c114610afb576103a4565b8063d94f11be116100e9578063d94f11be14610a7e578063da38f3af14610a9b578063e0e2f31014610aa3578063e2bbb15814610aab576103a4565b8063d5f9464e14610a27578063d895745c14610a44578063d8fd5a7a14610a61576103a4565b80639b80d28111610187578063bd48cf2211610156578063bd48cf2214610a07578063c0bccbfb14610a0f578063c0db888714610a17578063c1ddfb0014610a1f576103a4565b80639b80d28114610999578063b5bda70d146109a1578063bb872b4a146109be578063bcabf89b146109db576103a4565b80638da5cb5b116101c35780638da5cb5b146108b95780638dbb1e3a146108dd57806393f1a40b1461090057806398969e821461096d576103a4565b8063766d7cfb146108945780638aa28550146103fb5780638ae39cac146108b1576103a4565b806342a9026a116102ce57806352e0371c1161026c578063648b8c6b1161023b578063648b8c6b1461078057806369914d621461079f5780636e2cba99146107c057806373cb07d814610868576103a4565b806352e0371c146106f45780635312ea8e14610730578063630b5ba11461074d57806364482f7914610755576103a4565b8063488a8f58116102a8578063488a8f58146106a157806348cd4cb1146106c75780634e71e0c8146106cf57806351eb05a6146106d7576103a4565b806342a9026a14610644578063441a3e70146106615780634638cef514610684576103a4565b806311ea3264116103465780631eaaa045116103155780631eaaa0451461055d57806321ab46c8146105915780632f380b35146105c257806340be7bec14610621576103a4565b806311ea32641461050957806317caf6f11461052c5780631a249f5c146105345780631aed655314610555576103a4565b80630fa6b3a0116103825780630fa6b3a0146104035780630fc035df146104265780631069f3b51461044957806311aedfbc14610501576103a4565b8063078dfbe7146103a9578063081e3eda146103e157806309cfb6b9146103fb575b600080fd5b6103df600480360360608110156103bf57600080fd5b506001600160a01b03813516906020810135151590604001351515610b56565b005b6103e9610c80565b60408051918252519081900360200190f35b6103e9610c86565b6103df6004803603604081101561041957600080fd5b5080359060200135610c8b565b6103df6004803603604081101561043c57600080fd5b5080359060200135610f39565b6104756004803603604081101561045f57600080fd5b50803590602001356001600160a01b0316611243565b604051808a815260200189815260200188815260200187815260200180602001868152602001858152602001848152602001838152602001828103825287818151815260200191508051906020019060200280838360005b838110156104e55781810151838201526020016104cd565b505050509050019a505050505050505050505060405180910390f35b6103e9611329565b6103df6004803603604081101561051f57600080fd5b508035906020013561132f565b6103e9611580565b6103df6004803603602081101561054a57600080fd5b503561ffff16611586565b6103e96115eb565b6103df6004803603606081101561057357600080fd5b508035906001600160a01b03602082013516906040013515156115f1565b6105ae600480360360208110156105a757600080fd5b50356117bc565b604080519115158252519081900360200190f35b6105df600480360360208110156105d857600080fd5b50356117d1565b604080516001600160a01b0390981688526020880196909652868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b6103df6004803603604081101561063757600080fd5b50803590602001356118d3565b6103df6004803603602081101561065a57600080fd5b50356119fa565b6103df6004803603604081101561067757600080fd5b5080359060200135611b31565b6103df6004803603602081101561069a57600080fd5b5035611dff565b6103df600480360360208110156106b757600080fd5b50356001600160a01b0316611e51565b6103e9611ecb565b6103df611ed1565b6103df600480360360208110156106ed57600080fd5b5035611f93565b6103df6004803603608081101561070a57600080fd5b508035906001600160a01b03602082013581169160408101359091169060600135612054565b6103df6004803603602081101561074657600080fd5b503561230f565b6103df61244c565b6103df6004803603606081101561076b57600080fd5b5080359060208101359060400135151561246f565b61078861252f565b6040805161ffff9092168252519081900360200190f35b6103df600480360360208110156107b557600080fd5b503561ffff1661253f565b6103df600480360360408110156107d657600080fd5b81359190810190604081016020820135600160201b8111156107f757600080fd5b82018360208201111561080957600080fd5b803590602001918460208302840111600160201b8311171561082a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506125ac945050505050565b6103e96004803603604081101561087e57600080fd5b50803590602001356001600160a01b0316612827565b6103df600480360360208110156108aa57600080fd5b5035612974565b6103e96129c6565b6108c16129cc565b604080516001600160a01b039092168252519081900360200190f35b6103e9600480360360408110156108f357600080fd5b50803590602001356129db565b61092c6004803603604081101561091657600080fd5b50803590602001356001600160a01b0316612a41565b604080519889526020890197909752878701959095526060870193909352608086019190915260a085015260c084015260e083015251908190036101000190f35b6103e96004803603604081101561098357600080fd5b50803590602001356001600160a01b0316612a96565b6103e9612bd5565b6103e9600480360360208110156109b757600080fd5b5035612bdb565b6103df600480360360208110156109d457600080fd5b5035612bf0565b6103e9600480360360408110156109f157600080fd5b50803590602001356001600160a01b0316612c42565b6103e9612d50565b6103e9612d56565b6103e9612f16565b6108c16130d8565b6103df60048036036020811015610a3d57600080fd5b50356130ee565b6103df60048036036020811015610a5a57600080fd5b5035613140565b6103df60048036036020811015610a7757600080fd5b5035613192565b6103df60048036036020811015610a9457600080fd5b50356131e4565b6103e9613433565b6103e9613439565b6103df60048036036040811015610ac157600080fd5b508035906020013561343f565b6108c1613627565b6103df60048036036020811015610aec57600080fd5b5035613636565b6108c1613706565b6103df60048036036020811015610b1157600080fd5b5035613715565b610788613767565b6108c1613771565b6103df60048036036020811015610b3e57600080fd5b50356001600160a01b0316613780565b6108c16137ef565b6000546001600160a01b03163314610ba3576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b8115610c5f576001600160a01b038316151580610bbd5750805b610c06576040805162461bcd60e51b81526020600482015260156024820152744f776e61626c653a207a65726f206164647265737360581b604482015290519081900360640190fd5b600080546040516001600160a01b03808716939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b038516179055610c7b565b600180546001600160a01b0319166001600160a01b0385161790555b505050565b60085490565b600a81565b600060088381548110610c9a57fe5b60009182526020808320868452600a825260408085203386529092529220600481015460069092029092019250610cf2576040805162461bcd60e51b8152602060048201526000602482015290519081900360640190fd5b6004810154831115610d25576040805162461bcd60e51b8152602060048201526000602482015290519081900360640190fd5b6004810154610d3385611f93565b610d3d85336137fe565b60015b848111610db357600081830390506000846004018281548110610d5f57fe5b90600052602060002001549050610d768882613967565b84600401805480610d8357fe5b60008281526020812082016000199081019190915590810190915560048701805490910190555050600101610d40565b5042600683015560006007830181905560058301819055858152601260205260409020546004830154610f0a57825460018401819055600084556005850154610dfb91613a50565b60058501556000805b82811015610e52576000888152601260205260409020805482908110610e2657fe5b6000918252602090912001546001600160a01b0316331415610e4a57809150610e52565b600101610e04565b50600087815260126020526040902080546000198401908110610e7157fe5b60009182526020808320909101548983526012909152604090912080546001600160a01b039092169183908110610ea457fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255888152601290915260409020805480610ee657fe5b600082815260209020810160001990810180546001600160a01b0319169055019055505b60155460038501548454610f299291610f239190613a99565b90613af2565b8360020181905550505050505050565b600060088381548110610f4857fe5b60009182526020808320868452600a825260408085203386529092529220600481015460069092029092019250610fa0576040805162461bcd60e51b8152602060048201526000602482015290519081900360640190fd5b6004810154610fae85611f93565b610fb885336137fe565b600080805b83811015610ffa57846004018181548110610fd457fe5b9060005260206000200154871415610ff25780915060019250610ffa565b600101610fbd565b508161104d576040805162461bcd60e51b815260206004820152601960248201527f6e6f7420666f756e6420626f6f7374656420746f6b656e496400000000000000604482015290519081900360640190fd5b6110578787613967565b83600401600184038154811061106957fe5b906000526020600020015484600401828154811061108357fe5b6000918252602090912001556004840180548061109c57fe5b6000828152602080822083016000199081018390559283019093556004808901805490930190925542600688015560078701819055600587018190558981526012909252604090912054908501546112185784546001860181905560008655600587015461110991613a50565b60058701556000805b828110156111605760008a815260126020526040902080548290811061113457fe5b6000918252602090912001546001600160a01b031633141561115857809150611160565b600101611112565b5060008981526012602052604090208054600019840190811061117f57fe5b60009182526020808320909101548b83526012909152604090912080546001600160a01b0390921691839081106111b257fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558a81526012909152604090208054806111f457fe5b600082815260209020810160001990810180546001600160a01b0319169055019055505b601554600387015486546112319291610f239190613a99565b85600201819055505050505050505050565b60008060008060606000806000806000600a60008d815260200190815260200160002060008c6001600160a01b03166001600160a01b03168152602001908152602001600020905080600001548160010154826002015483600301548460040185600501548660060154876007015488600801548480548060200260200160405190810160405280929190818152602001828054801561130257602002820191906000526020600020905b8154815260200190600101908083116112ee575b50505050509450995099509950995099509950995099509950509295985092959850929598565b60115481565b6000828152600a6020908152604080832033845290915290206001810154815401611393576040805162461bcd60e51b815260206004820152600f60248201526e6e6f207374616b6520746f6b656e7360881b604482015290519081900360640190fd5b600f5460048201546201000090910461ffff1690830111156113b457600080fd5b6000600884815481106113c357fe5b600091825260209091206004840154600690920201915061140d5760008481526012602090815260408220805460018101825590835291200180546001600160a01b031916331790555b600f54604080516370a0823160e01b81523360048201529051600092600160201b90046001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561145f57600080fd5b505afa158015611473573d6000803e3d6000fd5b505050506040513d602081101561148957600080fd5b505190508084111561149a57600080fd5b6114a385611f93565b6114ad85336137fe565b60005b8481101561155457600f5460408051632f745c5960e01b815233600482015260006024820181905291519192600160201b90046001600160a01b031691632f745c5991604480820192602092909190829003018186803b15801561151357600080fd5b505afa158015611527573d6000803e3d6000fd5b505050506040513d602081101561153d57600080fd5b5051905061154b8782613b34565b506001016114b0565b506015546003830154845461156e9291610f239190613a99565b60028401555050426006909101555050565b60135481565b6000546001600160a01b031633146115d3576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600f805461ffff191661ffff92909216919091179055565b60065481565b6000546001600160a01b0316331461163e576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b801561164c5761164c61244c565b6000601454431161165f57601454611661565b435b6013549091506116719085613ce8565b6013556040805160c0810182526001600160a01b039485168152602081019586529081019182526000606082018181526080830182815260a0840183815260088054600181018255945293517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3600690940293840180546001600160a01b031916919098161790965595517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee482015591517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee583015593517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee682015591517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee78301555090517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee890910155565b60106020526000908152604090205460ff1681565b600080600080600080600080600889815481106117ea57fe5b60009182526020822060069091020180546003549193506001600160a01b039182169116141561181d5750600954611896565b8154604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b15801561186757600080fd5b505afa15801561187b573d6000803e3d6000fd5b505050506040513d602081101561189157600080fd5b505190505b815460018301546002840154600385015460048601546005909601546001600160a01b039094169e949d50919b5099509750919550909350915050565b6000828152600a6020908152604080832033845290915290206001810154815401611937576040805162461bcd60e51b815260206004820152600f60248201526e6e6f207374616b6520746f6b656e7360881b604482015290519081900360640190fd5b600f5460048201546201000090910461ffff166001909101111561195a57600080fd5b60006008848154811061196957fe5b60009182526020909120600484015460069092020191506119b35760008481526012602090815260408220805460018101825590835291200180546001600160a01b031916331790555b6119bc84611f93565b6119c684336137fe565b6119d08484613b34565b601554600382015483546119e99291610f239190613a99565b600283015550426006909101555050565b6000818152600a6020908152604080832033845290915290206011546006820154420311611a67576040805162461bcd60e51b81526020600482015260156024820152746e6f7420656c696769626c6520746f20636c61696d60581b604482015290519081900360640190fd5b600060088381548110611a7657fe5b90600052602060002090600602019050611a8f83611f93565b611a9983336137fe565b60155460038201548354611ab29291610f239190613a99565b600283015560058201546007830154600091611ace9190613a50565b9050611ada3382613d42565b604080518281529051859133917fabcaf0d72be078b7b459a074ead55fd9690a3d35e84441e246cc038b9e6c84659181900360200190a36005830154611b209082613ce8565b600584015550504260069091015550565b600280541415611b88576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60028081905550600060088381548110611b9e57fe5b60009182526020808320868452600a82526040808520338652909252922060018101548154600690930290930193509101831115611c18576040805162461bcd60e51b81526020600482015260126024820152711dda5d1a191c985dce881b9bdd0819dbdbd960721b604482015290519081900360640190fd5b600c548160030154420311611c74576040805162461bcd60e51b815260206004820152601860248201527f6e6f7420656c696769626c6520746f2077697468647261770000000000000000604482015290519081900360640190fd5b611c7d84611f93565b611c8784336137fe565b805415611cb5578054611c9a9084613a50565b81556005820154611cab9084613a50565b6005830155611cca565b6001810154611cc49084613a50565b60018201555b60155460038301548254611ce39291610f239190613a99565b6002820155600060078201819055600582015542600682015581546003546001600160a01b0390811691161415611d2557600954611d219084613a50565b6009555b8215611da7576004546001600160a01b03166379cc679033611d4886600a613a99565b6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015611d8e57600080fd5b505af1158015611da2573d6000803e3d6000fd5b505050505b8154611dbd906001600160a01b03163385613f04565b604080518481529051859133917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689181900360200190a3505060016002555050565b6000546001600160a01b03163314611e4c576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b601155565b6000546001600160a01b03163314611e9e576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600f80546001600160a01b03909216600160201b02640100000000600160c01b0319909216919091179055565b60145481565b6001546001600160a01b0316338114611f31576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b600060088281548110611fa257fe5b9060005260206000209060060201905080600201544311611fc35750612051565b6005810154611fd85743600290910155612051565b6000611fe88260020154436129db565b90506000612015601354610f23856001015461200f60075487613a9990919063ffffffff16565b90613a99565b90506120426120378460050154610f2360155485613a9990919063ffffffff16565b600385015490613ce8565b60038401555050436002909101555b50565b6002805414156120ab576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600280556004546001600160a01b031633146120c657600080fd5b6000600885815481106120d557fe5b60009182526020808320888452600a80835260408086206001600160a01b038b81168852945280862093891686528520600694909402909101945090929061211e908690613af2565b9050808360010154846000015401101561217f576040805162461bcd60e51b815260206004820152601760248201527f7472616e73666572206578636565647320616d6f756e74000000000000000000604482015290519081900360640190fd5b600c5483600301544203116121db576040805162461bcd60e51b815260206004820152601760248201527f6e6f7420656c696769626c6520746f20756e6474616b65000000000000000000604482015290519081900360640190fd5b6121e488611f93565b6121ee88886137fe565b8254156122085782546122019082613a50565b835561221d565b60018301546122179082613a50565b60018401555b601554600385015484546122369291610f239190613a99565b600284015542600684015560006007840181905560058401819055600383015461225f90613f56565b905060006122738460040180549050613f74565b905081801561227f5750805b1561228e5761228e8a896137fe565b80156122be57600184015484546122b09185916122aa91613ce8565b90613ce8565b8455600060018501556122d3565b60018401546122cd9084613ce8565b60018501555b601554600387015485546122ec9291610f239190613a99565b600280860191909155426006909501949094555050600190915550505050505050565b600280541415612366576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002808190555060006008828154811061237c57fe5b60009182526020808320858452600a825260408085203380875293529093206001810154815460069094029094019450926123cc926123ba91613ce8565b84546001600160a01b03169190613f04565b80546040805191825251849133917fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae05959181900360200190a3805415612421578054600583015461241b91613a50565b60058301555b6000808255600180830182905560028084018390556005840183905560079093019190915590555050565b60085460005b8181101561246b5761246381611f93565b600101612452565b5050565b6000546001600160a01b031633146124bc576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b80156124ca576124ca61244c565b612501826122aa600886815481106124de57fe5b906000526020600020906006020160010154601354613a5090919063ffffffff16565b601381905550816008848154811061251557fe5b906000526020600020906006020160010181905550505050565b600f5462010000900461ffff1681565b6000546001600160a01b0316331461258c576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600f805461ffff909216620100000263ffff000019909216919091179055565b8051806125da576040805162461bcd60e51b8152602060048201526000602482015290519081900360640190fd5b6000838152600a602090815260408083203384529091529020600181015481540161263e576040805162461bcd60e51b815260206004820152600f60248201526e6e6f207374616b6520746f6b656e7360881b604482015290519081900360640190fd5b600f54604080516370a0823160e01b81523360048201529051600092600160201b90046001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561269057600080fd5b505afa1580156126a4573d6000803e3d6000fd5b505050506040513d60208110156126ba57600080fd5b50519050806126ea576040805162461bcd60e51b8152602060048201526000602482015290519081900360640190fd5b6000600886815481106126f957fe5b60009182526020909120600485015460069092020191506127435760008681526012602090815260408220805460018101825590835291200180546001600160a01b031916331790555b6004830154600f5462010000900461ffff1603806127a8576040805162461bcd60e51b815260206004820152601960248201527f6f766572666c6f77206d6178696d756d20626f6f7374696e6700000000000000604482015290519081900360640190fd5b808510156127b35750835b6127bc87611f93565b6127c687336137fe565b60005b818110156127f6576127ee888883815181106127e157fe5b6020026020010151613b34565b6001016127c9565b50601554600383015485546128109291610f239190613a99565b600285015550504260069092019190915550505050565b6000806008848154811061283757fe5b60009182526020808320878452600a825260408085206001600160a01b03891686529092529220600360069092029092019081015460028201549193509043118015612887575060008360050154115b156128f157600061289c8460020154436129db565b905060006128c3601354610f23876001015461200f60075487613a9990919063ffffffff16565b90506128ec6128e58660050154610f2360155485613a9990919063ffffffff16565b8490613ce8565b925050505b600482015460009061290290613f8c565b90506000612931846002015461292b601554610f23878960000154613a9990919063ffffffff16565b90613a50565b905060006129446064610f238585613a99565b9050612965816122aa87600501548860070154613a5090919063ffffffff16565b96505050505050505b92915050565b6000546001600160a01b031633146129c1576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600b55565b60075481565b6000546001600160a01b031681565b600060065482116129fc576129f5600a61200f8486613a50565b905061296e565b6006548310612a0f576129f58284613a50565b6129f5612a2760065484613a5090919063ffffffff16565b6122aa600a61200f87600654613a5090919063ffffffff16565b600a602052816000526040600020602052806000526040600020600091509150508060000154908060010154908060020154908060030154908060050154908060060154908060070154908060080154905088565b60008060088481548110612aa657fe5b60009182526020808320878452600a825260408085206001600160a01b03891686529092529220600360069092029092019081015460028201549193509043118015612af6575060008360050154115b15612b59576000612b0b8460020154436129db565b90506000612b32601354610f23876001015461200f60075487613a9990919063ffffffff16565b9050612b546128e58660050154610f2360155485613a9990919063ffffffff16565b925050505b6004820154600090612b6a90613f8c565b90506000612b93846002015461292b601554610f23878960000154613a9990919063ffffffff16565b90506000612bbf856005015461292b87600701546122aa6064610f23888a613a9990919063ffffffff16565b6008860154909150612965906122aa8484613ce8565b600e5481565b6000818152601260205260409020545b919050565b6000546001600160a01b03163314612c3d576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600755565b60008060088481548110612c5257fe5b60009182526020808320878452600a825260408085206001600160a01b03891686529092529220600360069092029092019081015460028201549193509043118015612ca2575060008360050154115b15612d05576000612cb78460020154436129db565b90506000612cde601354610f23876001015461200f60075487613a9990919063ffffffff16565b9050612d006128e58660050154610f2360155485613a9990919063ffffffff16565b925050505b6000612d2c836002015461292b601554610f23868860000154613a9990919063ffffffff16565b9050612d45836008015482613ce890919063ffffffff16565b979650505050505050565b600b5481565b60008060005b600854811015612f1057600060088281548110612d7557fe5b9060005260206000209060060201905060008160030154905060005b600084815260126020526040902054811015612f05576000848152600a6020908152604080832060129092528220805483919085908110612dce57fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020600285015490915043118015612e0c575060008460050154115b15612e76576000612e218560020154436129db565b90506000612e48601354610f23886001015461200f60075487613a9990919063ffffffff16565b9050612e71612e6a8760050154610f2360155485613a9990919063ffffffff16565b8690613ce8565b945050505b6004810154600090612e8790613f8c565b90506000612eb0836002015461292b601554610f23898860000154613a9990919063ffffffff16565b90506000612ec36064610f238585613a99565b90506000612ee6826122aa87600501548860070154613a5090919063ffffffff16565b9050612ef28a82613ce8565b99505060019094019350612d9192505050565b505050600101612d5c565b50905090565b60008060005b600854811015612f1057600060088281548110612f3557fe5b9060005260206000209060060201905060008160030154905060005b6000848152601260205260409020548110156130cd576000848152600a6020908152604080832060129092528220805483919085908110612f8e57fe5b60009182526020808320909101546001600160a01b03168352820192909252604001902060115460068201549192504291909103106130c457836002015443118015612fde575060008460050154115b15613041576000612ff38560020154436129db565b9050600061301a601354610f23886001015461200f60075487613a9990919063ffffffff16565b905061303c612e6a8760050154610f2360155485613a9990919063ffffffff16565b945050505b600481015460009061305290613f8c565b9050600061307b836002015461292b601554610f23898860000154613a9990919063ffffffff16565b9050600061308e6064610f238585613a99565b905060006130b1826122aa87600501548860070154613a5090919063ffffffff16565b90506130bd8a82613ce8565b9950505050505b50600101612f51565b505050600101612f1c565b600f54600160201b90046001600160a01b031681565b6000546001600160a01b0316331461313b576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600e55565b6000546001600160a01b0316331461318d576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600d55565b6000546001600160a01b031633146131df576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600c55565b6000600882815481106131f357fe5b60009182526020808320858452600a8252604080852033865290925292206004810154600690920290920192508061324c576040805162461bcd60e51b8152602060048201526000602482015290519081900360640190fd5b61325584611f93565b61325f84336137fe565b60005b8181101561329b57600083600401828154811061327b57fe5b906000526020600020015490506132928682613967565b50600101613262565b506132aa6004830160006143a6565b60048084018054839003905542600684015560006007840181905560058401819055858152601260205260409020549083015461340b578254600184018190556000845560058501546132fc91613a50565b60058501556000805b8281101561335357600087815260126020526040902080548290811061332757fe5b6000918252602090912001546001600160a01b031633141561334b57809150613353565b600101613305565b5060008681526012602052604090208054600019840190811061337257fe5b60009182526020808320909101548883526012909152604090912080546001600160a01b0390921691839081106133a557fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558781526012909152604090208054806133e757fe5b600082815260209020810160001990810180546001600160a01b0319169055019055505b601554600385015484546134249291610f239190613a99565b83600201819055505050505050565b600c5481565b600d5481565b60006008838154811061344e57fe5b60009182526020808320868452600a8252604080852033865290925292206006909102909101915061347f84611f93565b600481015460009061349090613f74565b905061349c85336137fe565b82546134b3906001600160a01b0316333087613fdc565b82546003546001600160a01b03908116911614156134dc576009546134d89085613ce8565b6009555b801561351a57600182015482546134f89186916122aa91613ce8565b825560058301546135099085613ce8565b60058401556000600183015561352f565b60018201546135299085613ce8565b60018301555b601554600384015483546135489291610f239190613a99565b600283015583156135e3576004546001600160a01b03166340c10f193361357087600a613a99565b6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156135b657600080fd5b505af11580156135ca573d6000803e3d6000fd5b505050506040513d60208110156135e057600080fd5b50505b426006830155604080518581529051869133917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a35050505050565b6001546001600160a01b031681565b60006008828154811061364557fe5b60009182526020808320858452600a82526040808520338652909252908320600381015460069093029091019350919061367e90613f56565b90506001811515146136cc576040805162461bcd60e51b81526020600482015260126024820152716e6f7420636c61696d20656c696769626c6560701b604482015290519081900360640190fd5b6136d584611f93565b6136df84336137fe565b601554600384015483546136f89291610f239190613a99565b826002018190555050505050565b6003546001600160a01b031681565b6000546001600160a01b03163314613762576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b601555565b600f5461ffff1681565b6005546001600160a01b031681565b6000546001600160a01b031633146137cd576040805162461bcd60e51b815260206004820181905260248201526000805160206143fa833981519152604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6004546001600160a01b031681565b60006008838154811061380d57fe5b60009182526020808320868452600a825260408085206001600160a01b0388168652909252908320600381015460069093029091019350919061384f90613f56565b600384015460048401549192509060009061386990613f8c565b90506000613892856002015461292b601554610f23878a60000154613a9990919063ffffffff16565b905060006138a56064610f238585613a99565b60078701549091506138b79082613ce8565b600787015560008580156138cb5750600083115b156138f85760088701546138e0908490613ce8565b90506138ec8982613d42565b60006008880155613912565b50600886015460009061390c908490613ce8565b60088801555b6040805182815290518b916001600160a01b038c16917f02f5e52fd5bf7180f6e79766027cc92871fbcd14ae61ee25c0ebbc254b3cf92c9181900360200190a342876003018190555050505050505050505050565b60008181526010602052604090205460ff16151560011461398757600080fd5b600f54604080516323b872dd60e01b8152306004820152336024820152604481018490529051600160201b9092046001600160a01b0316916323b872dd9160648082019260009290919082900301818387803b1580156139e657600080fd5b505af11580156139fa573d6000803e3d6000fd5b505050600082815260106020908152604091829020805460ff191690558151848152915185935033927fd9ccb4973c95d201bc1724ce7e7f19f8e0835e571f58bf8b6a0de82084f0574f92908290030190a35050565b6000613a9283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061403c565b9392505050565b600082613aa85750600061296e565b82820282848281613ab557fe5b0414613a925760405162461bcd60e51b81526004018080602001828103825260218152602001806143d96021913960400191505060405180910390fd5b6000613a9283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140d3565b60008181526010602052604090205460ff1615613b8a576040805162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e48189bdbdcdd1959608a1b604482015290519081900360640190fd5b600f54604080516323b872dd60e01b8152336004820152306024820152604481018490529051600160201b9092046001600160a01b0316916323b872dd9160648082019260009290919082900301818387803b158015613be957600080fd5b505af1158015613bfd573d6000803e3d6000fd5b5050506000828152601060205260408120805460ff19166001179055600880549192509084908110613c2b57fe5b60009182526020808320868452600a82526040808520338652909252922060018101546006909202909201925015613c805760018101548082556005830154613c7391613ce8565b6005830155600060018201555b600480820180546001818101835560009283526020928390209091018690559184018054909201909155604080518581529051869233927faadc628cb4fd3bb7a62795eb460290459458bdc6f387ffde727c740f42c18337929081900390910190a350505050565b600082820183811015613a92576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600554604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015613d8d57600080fd5b505afa158015613da1573d6000803e3d6000fd5b505050506040513d6020811015613db757600080fd5b50516005546003549192506001600160a01b0391821691161415613ded57600954811115613de9576009549003613ded565b5060005b80821115613e7d576005546040805163a9059cbb60e01b81526001600160a01b038681166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015613e4b57600080fd5b505af1158015613e5f573d6000803e3d6000fd5b505050506040513d6020811015613e7557600080fd5b50610c7b9050565b6005546040805163a9059cbb60e01b81526001600160a01b038681166004830152602482018690529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015613ed357600080fd5b505af1158015613ee7573d6000803e3d6000fd5b505050506040513d6020811015613efd57600080fd5b5050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610c7b908490614138565b6000600b548242031115613f6c57506001612beb565b506000919050565b600f5460009061ffff168210613f6c57506001612beb565b600f5460009061ffff168211613fa457506000612beb565b600f54600090613fbf90849061ffff90811660010116613a50565b9050613a92600d546122aa600e5484613a9990919063ffffffff16565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052614036908590614138565b50505050565b600081848411156140cb5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614090578181015183820152602001614078565b50505050905090810190601f1680156140bd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836141225760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614090578181015183820152602001614078565b50600083858161412e57fe5b0495945050505050565b606061418d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166141e99092919063ffffffff16565b805190915015610c7b578080602001905160208110156141ac57600080fd5b5051610c7b5760405162461bcd60e51b815260040180806020018281038252602a81526020018061441a602a913960400191505060405180910390fd5b60606141f88484600085614200565b949350505050565b606061420b8561436d565b61425c576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b6020831061429b5780518252601f19909201916020918201910161427c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146142fd576040519150601f19603f3d011682016040523d82523d6000602084013e614302565b606091505b509150915081156143165791506141f89050565b8051156143265780518082602001fd5b60405162461bcd60e51b8152602060048201818152865160248401528651879391928392604401919085019080838360008315614090578181015183820152602001614078565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906141f8575050151592915050565b508054600082559060005260206000209081019061205191905b808211156143d457600081556001016143c0565b509056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220a9081b7793282bba903f53d039cf7e5766ca637d5e33d8084c526a5a2b993ee564736f6c634300060c0033

Verified Source Code Full Match

Compiler: v0.6.12+commit.27d51765 EVM: istanbul Optimization: Yes (200 runs)
StrikeBoostFarm.sol 947 lines
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

import "./interfaces/IBoostToken.sol";
import "./interfaces/IStrikeBoostFarm.sol";
import "./interfaces/IERC721Receiver.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/IVStrike.sol";
import "./libraries/SafeERC20.sol";
import "./libraries/EnumerableSet.sol";
import "./libraries/SafeMath.sol";
import "./libraries/Ownable.sol";
import "./libraries/ReentrancyGuard.sol";

// StrikeFarm is the master of Farm.
//
// Note that it's ownable and the owner wields tremendous power. The ownership
// will be transferred to a governance smart contract once STRIKE is sufficiently
// distributed and the community can show to govern itself.
//
// Have fun reading it. Hopefully it's bug-free. God bless.
contract StrikeBoostFarm is IStrikeBoostFarm, Ownable, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    // Info of each user.
    struct UserInfo {
        uint256 amount; // How many LP tokens the user has provided.
        uint256 pendingAmount; // non-eligible lp amount for reward
        uint256 rewardDebt; // Reward debt. See explanation below.
        uint256 depositedDate; // Latest deposited date
        //
        // We do some fancy math here. Basically, any point in time, the amount of STRIKEs
        // entitled to a user but is pending to be distributed is:
        //
        //   pending reward = (user.amount * pool.accRewardPerShare) - user.rewardDebt
        //
        // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
        //   1. The pool's `accRewardPerShare` (and `lastRewardBlock`) gets updated.
        //   2. User receives the pending reward sent to his/her address.
        //   3. User's `amount` gets updated.
        //   4. User's `rewardDebt` gets updated.
        uint256[] boostFactors;
        uint256 boostRewardDebt; // Boost Reward debt. See explanation below.
        uint256 boostedDate; // Latest boosted date
        uint256 accBoostReward;
        uint256 accBaseReward;
    }
    // Info of each pool.
    struct PoolInfo {
        IERC20 lpToken; // Address of LP token contract.
        uint256 allocPoint; // How many allocation points assigned to this pool. STRIKEs to distribute per block.
        uint256 lastRewardBlock; // Last block number that STRIKEs distribution occurs.
        uint256 accRewardPerShare; // Accumulated STRIKEs per share, times 1e12. See below.
        uint256 totalBoostCount; // Total valid boosted accounts count.
        uint256 rewardEligibleSupply; // total LP supply of users which staked boost token.
    }
    // The STRIKE TOKEN!
    address public strk;
    // The vSTRIKE TOKEN!
    address public vStrk;
    // The Reward TOKEN!
    address public rewardToken;
    // Block number when bonus STRIKE period ends.
    uint256 public bonusEndBlock;
    // STRIKE tokens created per block.
    uint256 public rewardPerBlock;
    // Bonus muliplier for early STRIKEex makers.
    uint256 public constant BONUS_MULTIPLIER = 10;
    // VSTRIKE minting rate
    uint256 public constant VSTRK_RATE = 10;
    // Info of each pool.
    PoolInfo[] private poolInfo;
    // Total STRIKE amount deposited in STRIKE single pool. To reduce tx-fee, not included in struct PoolInfo.
    uint256 private lpSupplyOfStrikePool;
    // Info of each user that stakes LP tokens.
    mapping(uint256 => mapping(address => UserInfo)) public userInfo;
    // claimable time limit for base reward
    uint256 public claimBaseRewardTime = 1 days;
    uint256 public unstakableTime = 2 days;
    uint256 public initialBoostMultiplier = 20;
    uint256 public boostMultiplierFactor = 10;

    // Boosting Part
    // Minimum vaild boost NFT count
    uint16 public minimumValidBoostCount = 1;
    // Maximum boost NFT count
    uint16 public maximumBoostCount = 20;
    // NFT contract for boosting
    IBoostToken public boostFactor;
    // Boosted with NFT or not
    mapping (uint256 => bool) public isBoosted;
    // claimable time limit for boost reward
    uint256 public claimBoostRewardTime = 30 days;
    // boosted user list
    mapping(uint256 => address[]) private boostedUsers;

    // Total allocation poitns. Must be the sum of all allocation points in all pools.
    uint256 public totalAllocPoint = 0;
    // The block number when STRIKE mining starts.
    uint256 public startBlock;
    uint256 private accMulFactor = 1e12;
    event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
    event EmergencyWithdraw(
        address indexed user,
        uint256 indexed pid,
        uint256 amount
    );
    event ClaimBaseRewards(
        address indexed user,
        uint256 indexed pid,
        uint256 amount
    );
    event ClaimBoostRewards(
        address indexed user,
        uint256 indexed pid,
        uint256 amount
    );
    event Boost(address indexed user, uint256 indexed pid, uint256 tokenId);
    event UnBoost(address indexed user, uint256 indexed pid, uint256 tokenId);

    constructor(
        address _strk,
        address _rewardToken,
        address _vStrk,
        address _boost,
        uint256 _rewardPerBlock,
        uint256 _startBlock,
        uint256 _bonusEndBlock
    ) public {
        strk = _strk;
        rewardToken = _rewardToken;
        vStrk = _vStrk;
        boostFactor = IBoostToken(_boost);
        rewardPerBlock = _rewardPerBlock;
        bonusEndBlock = _bonusEndBlock;
        startBlock = _startBlock;
    }

    function poolLength() external view returns (uint256) {
        return poolInfo.length;
    }


    function getPoolInfo(uint _pid) external view returns (
        IERC20 lpToken,
        uint256 lpSupply,
        uint256 allocPoint,
        uint256 lastRewardBlock,
        uint accRewardPerShare,
        uint totalBoostCount,
        uint256 rewardEligibleSupply
    ) {
        PoolInfo storage pool = poolInfo[_pid];
        uint256 amount;
        if (strk == address(pool.lpToken)) {
            amount = lpSupplyOfStrikePool;
        } else {
            amount = pool.lpToken.balanceOf(address(this));
        }
        return (
            pool.lpToken,
            amount,
            pool.allocPoint,
            pool.lastRewardBlock,
            pool.accRewardPerShare,
            pool.totalBoostCount,
            pool.rewardEligibleSupply
        );
    }

    function getUserInfo(uint256 _pid, address _user) external view returns(
        uint256 amount,
        uint256 pendingAmount,
        uint256 rewardDebt,
        uint256 depositedDate,
        uint256[] memory boostFactors,
        uint256 boostRewardDebt,
        uint256 boostedDate,
        uint256 accBoostReward,
        uint256 accBaseReward
    ) {
        UserInfo storage user = userInfo[_pid][_user];

        return (
            user.amount,
            user.pendingAmount,
            user.rewardDebt,
            user.depositedDate,
            user.boostFactors,
            user.boostRewardDebt,
            user.boostedDate,
            user.accBoostReward,
            user.accBaseReward
        );
    }

    // Add a new lp to the pool. Can only be called by the owner.
    // XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.
    function add(
        uint256 _allocPoint,
        IERC20 _lpToken,
        bool _withUpdate
    ) public onlyOwner {
        if (_withUpdate) {
            massUpdatePools();
        }
        uint256 lastRewardBlock =
            block.number > startBlock ? block.number : startBlock;
        totalAllocPoint = totalAllocPoint.add(_allocPoint);
        poolInfo.push(
            PoolInfo({
                lpToken: _lpToken,
                allocPoint: _allocPoint,
                lastRewardBlock: lastRewardBlock,
                accRewardPerShare: 0,
                totalBoostCount: 0,
                rewardEligibleSupply: 0
            })
        );
    }

    // Update the given pool's STRIKE allocation point. Can only be called by the owner.
    function set(
        uint256 _pid,
        uint256 _allocPoint,
        bool _withUpdate
    ) public onlyOwner {
        if (_withUpdate) {
            massUpdatePools();
        }
        totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(
            _allocPoint
        );
        poolInfo[_pid].allocPoint = _allocPoint;
    }

    // Update the given STRIKE per block. Can only be called by the owner.
    function setRewardPerBlock(
        uint256 speed
    ) public onlyOwner {
        rewardPerBlock = speed;
    }

    // Return reward multiplier over the given _from to _to block.
    function getMultiplier(uint256 _from, uint256 _to)
        public
        view
        returns (uint256)
    {
        if (_to <= bonusEndBlock) {
            return _to.sub(_from).mul(BONUS_MULTIPLIER);
        } else if (_from >= bonusEndBlock) {
            return _to.sub(_from);
        } else {
            return
                bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add(
                    _to.sub(bonusEndBlock)
                );
        }
    }

    function getValidBoostFactors(uint256 userBoostFactors) internal view returns (uint256) {
        uint256 validBoostFactors = userBoostFactors > minimumValidBoostCount ? userBoostFactors - minimumValidBoostCount : 0;

        return validBoostFactors;
    }

    function getBoostMultiplier(uint256 boostFactorCount) internal view returns (uint256) {
        if (boostFactorCount <= minimumValidBoostCount) {
            return 0;
        }
        uint256 initBoostCount = boostFactorCount.sub(minimumValidBoostCount + 1);

        return initBoostCount.mul(boostMultiplierFactor).add(initialBoostMultiplier);
    }

    // View function to see pending STRIKEs on frontend.
    function pendingReward(uint256 _pid, address _user)
        external
        view
        returns (uint256)
    {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        uint256 accRewardPerShare = pool.accRewardPerShare;

        if (block.number > pool.lastRewardBlock && pool.rewardEligibleSupply > 0) {
            uint256 multiplier =
                getMultiplier(pool.lastRewardBlock, block.number);
            uint256 reward =
                multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(
                    totalAllocPoint
                );
            accRewardPerShare = accRewardPerShare.add(
                reward.mul(accMulFactor).div(pool.rewardEligibleSupply)
            );
        }
        uint256 boostMultiplier = getBoostMultiplier(user.boostFactors.length);
        uint256 baseReward = user.amount.mul(accRewardPerShare).div(accMulFactor).sub(user.rewardDebt);
        uint256 boostReward = boostMultiplier.mul(baseReward).div(100).add(user.accBoostReward).sub(user.boostRewardDebt);
        return baseReward.add(boostReward).add(user.accBaseReward);
    }

    // View function to see pending STRIKEs on frontend.
    function pendingBaseReward(uint256 _pid, address _user)
        external
        view
        returns (uint256)
    {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        uint256 accRewardPerShare = pool.accRewardPerShare;

        if (block.number > pool.lastRewardBlock && pool.rewardEligibleSupply > 0) {
            uint256 multiplier =
                getMultiplier(pool.lastRewardBlock, block.number);
            uint256 reward =
                multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(
                    totalAllocPoint
                );
            accRewardPerShare = accRewardPerShare.add(
                reward.mul(accMulFactor).div(pool.rewardEligibleSupply)
            );
        }

        uint256 newReward = user.amount.mul(accRewardPerShare).div(accMulFactor).sub(user.rewardDebt);
        return newReward.add(user.accBaseReward);
    }

    // Update reward vairables for all pools. Be careful of gas spending!
    function massUpdatePools() public {
        uint256 length = poolInfo.length;
        for (uint256 pid = 0; pid < length; ++pid) {
            updatePool(pid);
        }
    }

    // Update reward variables of the given pool to be up-to-date.
    function updatePool(uint256 _pid) public {
        PoolInfo storage pool = poolInfo[_pid];
        if (block.number <= pool.lastRewardBlock) {
            return;
        }

        if (pool.rewardEligibleSupply == 0) {
            pool.lastRewardBlock = block.number;
            return;
        }
        uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);
        uint256 reward =
            multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(
                totalAllocPoint
            );
        pool.accRewardPerShare = pool.accRewardPerShare.add(
            reward.mul(accMulFactor).div(pool.rewardEligibleSupply)
        );
        pool.lastRewardBlock = block.number;
    }

    // Check the eligible user or not for reward
    function checkRewardEligible(uint boost) internal view returns(bool) {
        if (boost >= minimumValidBoostCount) {
            return true;
        }

        return false;
    }

    // Check claim eligible
    function checkRewardClaimEligible(uint depositedTime) internal view returns(bool) {
        if (block.timestamp - depositedTime > claimBaseRewardTime) {
            return true;
        }

        return false;
    }

    // Claim base lp reward
    function _claimBaseRewards(uint256 _pid, address _user) internal {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        bool claimEligible = checkRewardClaimEligible(user.depositedDate);

        uint256 accRewardPerShare = pool.accRewardPerShare;
        uint256 boostMultiplier = getBoostMultiplier(user.boostFactors.length);

        uint256 baseReward = user.amount.mul(accRewardPerShare).div(accMulFactor).sub(user.rewardDebt);
        uint256 boostReward = boostMultiplier.mul(baseReward).div(100);
        user.accBoostReward = user.accBoostReward.add(boostReward);
        uint256 rewards;

        if (claimEligible && baseReward > 0) {
            rewards = baseReward.add(user.accBaseReward);
            safeRewardTransfer(_user, rewards);
            user.accBaseReward = 0;
        } else {
            rewards = 0;
            user.accBaseReward = baseReward.add(user.accBaseReward);
        }

        emit ClaimBaseRewards(_user, _pid, rewards);

        user.depositedDate = block.timestamp;
    }

    function claimBaseRewards(uint256 _pid) external {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        bool claimEligible = checkRewardClaimEligible(user.depositedDate);
        require(claimEligible == true, "not claim eligible");
        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
    }

    // Deposit LP tokens to STRIKEswap for STRIKE allocation.
    function deposit(uint256 _pid, uint256 _amount) external {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        updatePool(_pid);
        bool rewardEligible = checkRewardEligible(user.boostFactors.length);

        _claimBaseRewards(_pid, msg.sender);

        pool.lpToken.safeTransferFrom(
            address(msg.sender),
            address(this),
            _amount
        );
        if (strk == address(pool.lpToken)) {
            lpSupplyOfStrikePool = lpSupplyOfStrikePool.add(_amount);
        }
        if (rewardEligible) {
            user.amount = user.amount.add(user.pendingAmount).add(_amount);
            pool.rewardEligibleSupply = pool.rewardEligibleSupply.add(_amount);
            user.pendingAmount = 0;
        } else {
            user.pendingAmount = user.pendingAmount.add(_amount);
        }
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        if (_amount > 0) {
            IVStrike(vStrk).mint(msg.sender, _amount.mul(VSTRK_RATE));
        }
        user.boostedDate = block.timestamp;
        emit Deposit(msg.sender, _pid, _amount);
    }

    // Withdraw LP tokens from STRIKEexFarm.
    function withdraw(uint256 _pid, uint256 _amount) external nonReentrant {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount + user.pendingAmount >= _amount, "withdraw: not good");
        require(block.timestamp - user.depositedDate > unstakableTime, "not eligible to withdraw");
        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);
        if (user.amount > 0) {
            user.amount = user.amount.sub(_amount);
            pool.rewardEligibleSupply = pool.rewardEligibleSupply.sub(_amount);
        } else {
            user.pendingAmount = user.pendingAmount.sub(_amount);
        }
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        // will loose unclaimed boost reward
        user.accBoostReward = 0;
        user.boostRewardDebt = 0;
        user.boostedDate = block.timestamp;
        if (strk == address(pool.lpToken)) {
            lpSupplyOfStrikePool = lpSupplyOfStrikePool.sub(_amount);
        }
        if (_amount > 0) {
            IVStrike(vStrk).burnFrom(msg.sender, _amount.mul(VSTRK_RATE));
        }
        pool.lpToken.safeTransfer(address(msg.sender), _amount);
        emit Withdraw(msg.sender, _pid, _amount);
    }

    // transfer VSTRIKE
    function move(uint256 _pid, address _sender, address _recipient, uint256 _vstrikeAmount) override external nonReentrant {
        require(vStrk == msg.sender);
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage sender = userInfo[_pid][_sender];
        UserInfo storage recipient = userInfo[_pid][_recipient];

        uint256 amount = _vstrikeAmount.div(VSTRK_RATE);

        require(sender.amount + sender.pendingAmount >= amount, "transfer exceeds amount");
        require(block.timestamp - sender.depositedDate > unstakableTime, "not eligible to undtake");
        updatePool(_pid);
        _claimBaseRewards(_pid, _sender);

        if (sender.amount > 0) {
            sender.amount = sender.amount.sub(amount);
        } else {
            sender.pendingAmount = sender.pendingAmount.sub(amount);
        }
        sender.rewardDebt = sender.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        sender.boostedDate = block.timestamp;
        // will loose unclaimed boost reward
        sender.accBoostReward = 0;
        sender.boostRewardDebt = 0;

        bool claimEligible = checkRewardClaimEligible(recipient.depositedDate);
        bool rewardEligible = checkRewardEligible(recipient.boostFactors.length);

        if (claimEligible && rewardEligible) {
            _claimBaseRewards(_pid, _recipient);
        }

        if (rewardEligible) {
            recipient.amount = recipient.amount.add(recipient.pendingAmount).add(amount);
            recipient.pendingAmount = 0;
        } else {
            recipient.pendingAmount = recipient.pendingAmount.add(amount);
        }
        recipient.rewardDebt = recipient.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        recipient.boostedDate = block.timestamp;
    }

    // Withdraw without caring about rewards. EMERGENCY ONLY.
    function emergencyWithdraw(uint256 _pid) external nonReentrant {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        pool.lpToken.safeTransfer(address(msg.sender), user.amount.add(user.pendingAmount));
        emit EmergencyWithdraw(msg.sender, _pid, user.amount);
        if (user.amount > 0) {
            pool.rewardEligibleSupply = pool.rewardEligibleSupply.sub(user.amount);
        }
        user.amount = 0;
        user.pendingAmount = 0;
        user.rewardDebt = 0;
        user.boostRewardDebt = 0;
        user.accBoostReward = 0;
    }

    // Safe rewardToken transfer function, just in case if rounding error causes pool to not have enough STRIKEs.
    function safeRewardTransfer(address _to, uint256 _amount) internal {
        uint256 availableBal = IERC20(rewardToken).balanceOf(address(this));

        // Protect users liquidity
        if (strk == rewardToken) {
            if (availableBal > lpSupplyOfStrikePool) {
                availableBal = availableBal - lpSupplyOfStrikePool;
            } else {
                availableBal = 0;
            }
        }

        if (_amount > availableBal) {
            IERC20(rewardToken).transfer(_to, availableBal);
        } else {
            IERC20(rewardToken).transfer(_to, _amount);
        }
    }

    function setAccMulFactor(uint256 _factor) external onlyOwner {
        accMulFactor = _factor;
    }

    function updateInitialBoostMultiplier(uint _initialBoostMultiplier) external onlyOwner {
        initialBoostMultiplier = _initialBoostMultiplier;
    }

    function updatedBoostMultiplierFactor(uint _boostMultiplierFactor) external onlyOwner {
        boostMultiplierFactor = _boostMultiplierFactor;
    }

    // Update reward token address by owner.
    function updateRewardToken(address _reward) external onlyOwner {
        rewardToken = _reward;
    }

    // Update claimBaseRewardTime
    function updateClaimBaseRewardTime(uint256 _claimBaseRewardTime) external onlyOwner {
        claimBaseRewardTime = _claimBaseRewardTime;
    }

    // Update unstakableTime
    function updateUnstakableTime(uint256 _unstakableTime) external onlyOwner {
        unstakableTime = _unstakableTime;
    }

    // NFT Boosting
    // get boosted users
    function getBoostedUserCount(uint256 _pid) external view returns(uint256) {
        return boostedUsers[_pid].length;
    }

    // View function to see pending STRIKEs on frontend.
    function pendingBoostReward(uint256 _pid, address _user)
        external
        view
        returns (uint256)
    {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        uint256 accRewardPerShare = pool.accRewardPerShare;

        if (block.number > pool.lastRewardBlock && pool.rewardEligibleSupply > 0) {
            uint256 multiplier =
                getMultiplier(pool.lastRewardBlock, block.number);
            uint256 reward =
                multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(
                    totalAllocPoint
                );
            accRewardPerShare = accRewardPerShare.add(
                reward.mul(accMulFactor).div(pool.rewardEligibleSupply)
            );
        }

        uint256 boostMultiplier = getBoostMultiplier(user.boostFactors.length);
        uint256 baseReward = user.amount.mul(accRewardPerShare).div(accMulFactor).sub(user.rewardDebt);
        uint256 boostReward = boostMultiplier.mul(baseReward).div(100);
        return user.accBoostReward.sub(user.boostRewardDebt).add(boostReward);
    }

    // for deposit reward token to contract
    function getTotalPendingBoostRewards() external view returns (uint256) {
        uint256 totalRewards;
        for (uint i; i < poolInfo.length; i++) {
            PoolInfo storage pool = poolInfo[i];
            uint256 accRewardPerShare = pool.accRewardPerShare;

            for (uint j; j < boostedUsers[i].length; j++) {
                UserInfo storage user = userInfo[i][boostedUsers[i][j]];

                if (block.number > pool.lastRewardBlock && pool.rewardEligibleSupply > 0) {
                    uint256 multiplier =
                        getMultiplier(pool.lastRewardBlock, block.number);
                    uint256 reward =
                        multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(
                            totalAllocPoint
                        );
                    accRewardPerShare = accRewardPerShare.add(
                        reward.mul(accMulFactor).div(pool.rewardEligibleSupply)
                    );
                }
                uint256 boostMultiplier = getBoostMultiplier(user.boostFactors.length);
                uint256 baseReward = user.amount.mul(accRewardPerShare).div(accMulFactor).sub(user.rewardDebt);
                uint256 initBoostReward = boostMultiplier.mul(baseReward).div(100);
                uint256 boostReward = user.accBoostReward.sub(user.boostRewardDebt).add(initBoostReward);
                totalRewards = totalRewards.add(boostReward);
            }
        }

        return totalRewards;
    }

    // for deposit reward token to contract
    function getClaimablePendingBoostRewards() external view returns (uint256) {
        uint256 totalRewards;
        for (uint i; i < poolInfo.length; i++) {
            PoolInfo storage pool = poolInfo[i];
            uint256 accRewardPerShare = pool.accRewardPerShare;

            for (uint j; j < boostedUsers[i].length; j++) {
                UserInfo storage user = userInfo[i][boostedUsers[i][j]];

                if (block.timestamp - user.boostedDate >= claimBoostRewardTime) {
                    if (block.number > pool.lastRewardBlock && pool.rewardEligibleSupply > 0) {
                        uint256 multiplier =
                            getMultiplier(pool.lastRewardBlock, block.number);
                        uint256 reward =
                            multiplier.mul(rewardPerBlock).mul(pool.allocPoint).div(
                                totalAllocPoint
                            );
                        accRewardPerShare = accRewardPerShare.add(
                            reward.mul(accMulFactor).div(pool.rewardEligibleSupply)
                        );
                    }
                    uint256 boostMultiplier = getBoostMultiplier(user.boostFactors.length);
                    uint256 baseReward = user.amount.mul(accRewardPerShare).div(accMulFactor).sub(user.rewardDebt);
                    uint256 initBoostReward = boostMultiplier.mul(baseReward).div(100);
                    uint256 boostReward = user.accBoostReward.sub(user.boostRewardDebt).add(initBoostReward);
                    totalRewards = totalRewards.add(boostReward);
                }
            }
        }

        return totalRewards;
    }

    // Claim boost reward
    function claimBoostReward(uint256 _pid) external {
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(block.timestamp - user.boostedDate > claimBoostRewardTime, "not eligible to claim");
        PoolInfo storage pool = poolInfo[_pid];
        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        uint256 boostReward = user.accBoostReward.sub(user.boostRewardDebt);
        safeRewardTransfer(msg.sender, boostReward);
        emit ClaimBoostRewards(msg.sender, _pid, boostReward);
        user.boostRewardDebt = user.boostRewardDebt.add(boostReward);
        user.boostedDate = block.timestamp;
    }

    function _boost(uint256 _pid, uint _tokenId) internal {
        require (isBoosted[_tokenId] == false, "already boosted");

        boostFactor.transferFrom(msg.sender, address(this), _tokenId);
        // boostFactor.updateStakeTime(_tokenId, true);

        isBoosted[_tokenId] = true;

        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        if (user.pendingAmount > 0) {
            user.amount = user.pendingAmount;
            pool.rewardEligibleSupply = pool.rewardEligibleSupply.add(user.amount);
            user.pendingAmount = 0;
        }
        user.boostFactors.push(_tokenId);
        pool.totalBoostCount = pool.totalBoostCount + 1;

        emit Boost(msg.sender, _pid, _tokenId);
    }

    function boost(uint256 _pid, uint _tokenId) external {
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount + user.pendingAmount > 0, "no stake tokens");
        require(user.boostFactors.length + 1 <= maximumBoostCount);
        PoolInfo storage pool = poolInfo[_pid];
        if (user.boostFactors.length == 0) {
            boostedUsers[_pid].push(msg.sender);
        }
        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);

        _boost(_pid, _tokenId);
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        user.boostedDate = block.timestamp;
    }

    function boostPartially(uint _pid, uint tokenAmount) external {
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount + user.pendingAmount > 0, "no stake tokens");
        require(user.boostFactors.length + tokenAmount <= maximumBoostCount);
        PoolInfo storage pool = poolInfo[_pid];
        if (user.boostFactors.length == 0) {
            boostedUsers[_pid].push(msg.sender);
        }
        uint256 ownerTokenCount = boostFactor.balanceOf(msg.sender);
        require(tokenAmount <= ownerTokenCount);
        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);

        for (uint i; i < tokenAmount; i++) {
            uint _tokenId = boostFactor.tokenOfOwnerByIndex(msg.sender, 0);

            _boost(_pid, _tokenId);
        }
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        user.boostedDate = block.timestamp;
    }

    function boostAll(uint _pid, uint256[] memory _tokenIds) external {
        uint256 tokenIdLength = _tokenIds.length;
        require(tokenIdLength > 0, "");
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount + user.pendingAmount > 0, "no stake tokens");
        uint256 ownerTokenCount = boostFactor.balanceOf(msg.sender);
        require(ownerTokenCount > 0, "");
        PoolInfo storage pool = poolInfo[_pid];
        if (user.boostFactors.length == 0) {
            boostedUsers[_pid].push(msg.sender);
        }
        uint256 availableTokenAmount = maximumBoostCount - user.boostFactors.length;
        require(availableTokenAmount > 0, "overflow maximum boosting");

        if (tokenIdLength < availableTokenAmount) {
            availableTokenAmount = tokenIdLength;
        }
        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);

        for (uint256 i; i < availableTokenAmount; i++) {
            _boost(_pid, _tokenIds[i]);
        }
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
        user.boostedDate = block.timestamp;
    }

    function _unBoost(uint _pid, uint _tokenId) internal {
        require (isBoosted[_tokenId] == true);

        boostFactor.transferFrom(address(this), msg.sender, _tokenId);
        // boostFactor.updateStakeTime(_tokenId, false);

        isBoosted[_tokenId] = false;

        emit UnBoost(msg.sender, _pid, _tokenId);
    }

    function unBoost(uint _pid, uint _tokenId) external {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.boostFactors.length > 0, "");
        uint factorLength = user.boostFactors.length;

        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);

        bool found = false;
        uint dfId; // will be deleted factor index
        for (uint j; j < factorLength; j++) {
            if (_tokenId == user.boostFactors[j]) {
                dfId = j;
                found = true;
                break;
            }
        }
        require(found, "not found boosted tokenId");
        _unBoost(_pid, _tokenId);
        user.boostFactors[dfId] = user.boostFactors[factorLength - 1];
        user.boostFactors.pop();
        pool.totalBoostCount = pool.totalBoostCount - 1;

        user.boostedDate = block.timestamp;
        // will loose unclaimed boost reward
        user.accBoostReward = 0;
        user.boostRewardDebt = 0;

        uint boostedUserCount = boostedUsers[_pid].length;
        if (user.boostFactors.length == 0) {
            user.pendingAmount = user.amount;
            user.amount = 0;
            pool.rewardEligibleSupply = pool.rewardEligibleSupply.sub(user.pendingAmount);

            uint index;
            for (uint j; j < boostedUserCount; j++) {
                if (address(msg.sender) == address(boostedUsers[_pid][j])) {
                    index = j;
                    break;
                }
            }
            boostedUsers[_pid][index] = boostedUsers[_pid][boostedUserCount - 1];
            boostedUsers[_pid].pop();
        }
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
    }

    function unBoostPartially(uint _pid, uint tokenAmount) external {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.boostFactors.length > 0, "");
        require(tokenAmount <= user.boostFactors.length, "");
        uint factorLength = user.boostFactors.length;

        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);

        for (uint i = 1; i <= tokenAmount; i++) {
            uint index = factorLength - i;
            uint _tokenId = user.boostFactors[index];

            _unBoost(_pid, _tokenId);
            user.boostFactors.pop();
            pool.totalBoostCount = pool.totalBoostCount - 1;
        }
        user.boostedDate = block.timestamp;
        // will loose unclaimed boost reward
        user.accBoostReward = 0;
        user.boostRewardDebt = 0;

        uint boostedUserCount = boostedUsers[_pid].length;
        if (user.boostFactors.length == 0) {
            user.pendingAmount = user.amount;
            user.amount = 0;
            pool.rewardEligibleSupply = pool.rewardEligibleSupply.sub(user.pendingAmount);

            uint index;
            for (uint j; j < boostedUserCount; j++) {
                if (address(msg.sender) == address(boostedUsers[_pid][j])) {
                    index = j;
                    break;
                }
            }
            boostedUsers[_pid][index] = boostedUsers[_pid][boostedUserCount - 1];
            boostedUsers[_pid].pop();
        }
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
    }

    function unBoostAll(uint _pid) external {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        uint factorLength = user.boostFactors.length;
        require(factorLength > 0, "");

        updatePool(_pid);
        _claimBaseRewards(_pid, msg.sender);

        for (uint i = 0; i < factorLength; i++) {
            uint _tokenId = user.boostFactors[i];
            _unBoost(_pid, _tokenId);
        }
        delete user.boostFactors;
        pool.totalBoostCount = pool.totalBoostCount - factorLength;
        user.boostedDate = block.timestamp;

        // will loose unclaimed boost reward
        user.accBoostReward = 0;
        user.boostRewardDebt = 0;

        uint boostedUserCount = boostedUsers[_pid].length;
        if (user.boostFactors.length == 0) {
            user.pendingAmount = user.amount;
            user.amount = 0;
            pool.rewardEligibleSupply = pool.rewardEligibleSupply.sub(user.pendingAmount);

            uint index;
            for (uint j; j < boostedUserCount; j++) {
                if (address(msg.sender) == address(boostedUsers[_pid][j])) {
                    index = j;
                    break;
                }
            }
            boostedUsers[_pid][index] = boostedUsers[_pid][boostedUserCount - 1];
            boostedUsers[_pid].pop();
        }
        user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(accMulFactor);
    }

    // Update boostFactor address. Can only be called by the owner.
    function setBoostFactor(
        address _address
    ) external onlyOwner {
        boostFactor = IBoostToken(_address);
    }

    // Update claimBoostRewardTime
    function updateClaimBoostRewardTime(uint256 _claimBoostRewardTime) external onlyOwner {
        claimBoostRewardTime = _claimBoostRewardTime;
    }

    // Update minimum valid boost token count. Can only be called by the owner.
    function updateMinimumValidBoostCount(uint16 _count) external onlyOwner {
        minimumValidBoostCount = _count;
    }

    // Update maximum valid boost token count. Can only be called by the owner.
    function updateMaximumBoostCount(uint16 _count) external onlyOwner {
        maximumBoostCount = _count;
    }
}
IERC20.sol 77 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
Address.sol 141 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.2;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
Ownable.sol 64 lines
// SPDX-License-Identifier: MIT
// Audit on 5-Jan-2021 by Keno and BoringCrypto

// P1 - P3: OK
pragma solidity 0.6.12;

// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol
// Edited by BoringCrypto

// T1 - T4: OK
contract OwnableData {
    // V1 - V5: OK
    address public owner;
    // V1 - V5: OK
    address public pendingOwner;
}

// T1 - T4: OK
contract Ownable is OwnableData {
    // E1: OK
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor () internal {
        owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }

    // F1 - F9: OK
    // C1 - C21: OK
    function transferOwnership(address newOwner, bool direct, bool renounce) public onlyOwner {
        if (direct) {
            // Checks
            require(newOwner != address(0) || renounce, "Ownable: zero address");

            // Effects
            emit OwnershipTransferred(owner, newOwner);
            owner = newOwner;
        } else {
            // Effects
            pendingOwner = newOwner;
        }
    }

    // F1 - F9: OK
    // C1 - C21: OK
    function claimOwnership() public {
        address _pendingOwner = pendingOwner;

        // Checks
        require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");

        // Effects
        emit OwnershipTransferred(owner, _pendingOwner);
        owner = _pendingOwner;
        pendingOwner = address(0);
    }

    // M1 - M5: OK
    // C1 - C21: OK
    modifier onlyOwner() {
        require(msg.sender == owner, "Ownable: caller is not the owner");
        _;
    }
}
IERC165.sol 24 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

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

pragma solidity ^0.6.2;

import "./IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transfered from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

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

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

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

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

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

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

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

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IVStrike {
    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Mint} event.
     */
    function mint(address recipient, uint256 amount) external returns (bool);
    function burnFrom(address account, uint256 amount) external;
}
SafeERC20.sol 75 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "../interfaces/IERC20.sol";
import "../libraries/SafeMath.sol";
import "../libraries/Address.sol";

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

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

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

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

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

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

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}
IBoostToken.sol 11 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.2;

import "./IERC721Enumerable.sol";

interface IBoostToken is IERC721Enumerable {
    function updateStakeTime(uint tokenId, bool isStake) external;

    function getTokenOwner(uint tokenId) external view returns(address);
}
EnumerableSet.sol 243 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
 * (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

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

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

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

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

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

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

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

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

            return true;
        } else {
            return false;
        }
    }

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

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

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

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

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

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

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

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

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


    // UintSet

    struct UintSet {
        Set _inner;
    }

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

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

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

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

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

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}
IERC721Receiver.sol 22 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)
    external returns (bytes4);
}
IStrikeBoostFarm.sol 10 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IStrikeBoostFarm {
    function move(uint256 pid, address sender, address recipient, uint256 amount) external;
}
IERC721Enumerable.sol 29 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.2;

import "./IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {

    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

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

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

Read Contract

BONUS_MULTIPLIER 0x8aa28550 → uint256
VSTRK_RATE 0x09cfb6b9 → uint256
bonusEndBlock 0x1aed6553 → uint256
boostFactor 0xc1ddfb00 → address
boostMultiplierFactor 0x9b80d281 → uint256
claimBaseRewardTime 0xbd48cf22 → uint256
claimBoostRewardTime 0x11aedfbc → uint256
getBoostedUserCount 0xb5bda70d → uint256
getClaimablePendingBoostRewards 0xc0db8887 → uint256
getMultiplier 0x8dbb1e3a → uint256
getPoolInfo 0x2f380b35 → address, uint256, uint256, uint256, uint256, uint256, uint256
getTotalPendingBoostRewards 0xc0bccbfb → uint256
getUserInfo 0x1069f3b5 → uint256, uint256, uint256, uint256, uint256[], uint256, uint256, uint256, uint256
initialBoostMultiplier 0xe0e2f310 → uint256
isBoosted 0x21ab46c8 → bool
maximumBoostCount 0x648b8c6b → uint16
minimumValidBoostCount 0xf6d4c185 → uint16
owner 0x8da5cb5b → address
pendingBaseReward 0xbcabf89b → uint256
pendingBoostReward 0x73cb07d8 → uint256
pendingOwner 0xe30c3978 → address
pendingReward 0x98969e82 → uint256
poolLength 0x081e3eda → uint256
rewardPerBlock 0x8ae39cac → uint256
rewardToken 0xf7c618c1 → address
startBlock 0x48cd4cb1 → uint256
strk 0xf24e5343 → address
totalAllocPoint 0x17caf6f1 → uint256
unstakableTime 0xda38f3af → uint256
userInfo 0x93f1a40b → uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
vStrk 0xfecedb65 → address

Write Contract 29 functions

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

add 0x1eaaa045
uint256 _allocPoint
address _lpToken
bool _withUpdate
boost 0x40be7bec
uint256 _pid
uint256 _tokenId
boostAll 0x6e2cba99
uint256 _pid
uint256[] _tokenIds
boostPartially 0x11ea3264
uint256 _pid
uint256 tokenAmount
claimBaseRewards 0xe78c1b1b
uint256 _pid
claimBoostReward 0x42a9026a
uint256 _pid
claimOwnership 0x4e71e0c8
No parameters
deposit 0xe2bbb158
uint256 _pid
uint256 _amount
emergencyWithdraw 0x5312ea8e
uint256 _pid
massUpdatePools 0x630b5ba1
No parameters
move 0x52e0371c
uint256 _pid
address _sender
address _recipient
uint256 _vstrikeAmount
set 0x64482f79
uint256 _pid
uint256 _allocPoint
bool _withUpdate
setAccMulFactor 0xf54ac4c1
uint256 _factor
setBoostFactor 0x488a8f58
address _address
setRewardPerBlock 0xbb872b4a
uint256 speed
transferOwnership 0x078dfbe7
address newOwner
bool direct
bool renounce
unBoost 0x0fc035df
uint256 _pid
uint256 _tokenId
unBoostAll 0xd94f11be
uint256 _pid
unBoostPartially 0x0fa6b3a0
uint256 _pid
uint256 tokenAmount
updateClaimBaseRewardTime 0x766d7cfb
uint256 _claimBaseRewardTime
updateClaimBoostRewardTime 0x4638cef5
uint256 _claimBoostRewardTime
updateInitialBoostMultiplier 0xd895745c
uint256 _initialBoostMultiplier
updateMaximumBoostCount 0x69914d62
uint16 _count
updateMinimumValidBoostCount 0x1a249f5c
uint16 _count
updatePool 0x51eb05a6
uint256 _pid
updateRewardToken 0xf8cf31cb
address _reward
updateUnstakableTime 0xd8fd5a7a
uint256 _unstakableTime
updatedBoostMultiplierFactor 0xd5f9464e
uint256 _boostMultiplierFactor
withdraw 0x441a3e70
uint256 _pid
uint256 _amount

Recent Transactions

No transactions found for this address