Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xAC32ebDBA8cf2907e0b35F4b023b2751b2bd0169
Balance 0 ETH
Nonce 1
Code Size 21772 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

21772 bytes
0x608060405234801561000f575f80fd5b50600436106101f2575f3560e01c806396ce079511610114578063c006cff8116100a9578063dcc19b3911610079578063dcc19b3914610473578063e2bbb15814610486578063f0f4426014610499578063f2fde38b146104ac578063ff657f55146104bf575f80fd5b8063c006cff814610427578063c34902631461043a578063d43462d71461044d578063d72b08c614610460575f80fd5b8063b1b66652116100e4578063b1b66652146103db578063bbcaf3fe146103ee578063be116fcf14610401578063bff1208d14610414575f80fd5b806396ce079514610384578063984d906814610394578063a91cf634146103b5578063ad2cfde0146103c8575f80fd5b806354fd4d501161018a57806364e0e60d1161015a57806364e0e60d1461033b578063715018a61461034e57806385f45250146103565780638da5cb5b14610369575f80fd5b806354fd4d50146102db57806357c81b92146103025780635915d806146103155780636076176414610328575f80fd5b8063389f5763116101c5578063389f57631461027557806344004cc114610295578063441a3e70146102a857806348dec2a7146102bb575f80fd5b806307b18bde146101f65780631068361f1461020b57806324555fb41461021e578063370158ea14610231575b5f80fd5b61020961020436600461471f565b6104d4565b005b610209610219366004614759565b6105c3565b61020961022c3660046147d5565b610b17565b600580545f5460408051808201825293845264312e302e3160d81b60208501525161026c936001600160a01b0393841693909216919061484b565b60405180910390f35b61028861028336600461487f565b611018565b60405161026c9190614896565b6102096102a33660046148e2565b6110b6565b6102096102b6366004614920565b6111c6565b6102ce6102c9366004614940565b6112c4565b60405161026c919061495b565b6040805180820182526005815264312e302e3160d81b6020820152905161026c9190614a71565b61020961031036600461487f565b611790565b610209610323366004614a83565b6117bf565b6102096103363660046147d5565b6118d1565b610209610349366004614a83565b61196f565b610209611a6b565b610209610364366004614920565b611aa0565b6005546040516001600160a01b03909116815260200161026c565b6040516103e8815260200161026c565b6103a76103a2366004614afb565b611bb5565b60405190815260200161026c565b6102096103c3366004614b4d565b6120f8565b6102096103d6366004614b89565b6121be565b6102096103e9366004614a83565b6122b4565b6102096103fc366004614bc2565b6123b0565b61020961040f366004614be5565b612499565b610209610422366004614920565b612617565b610209610435366004614920565b612701565b610209610448366004614920565b6127f3565b61020961045b366004614c3f565b6128dd565b6103a761046e366004614c68565b6129a9565b610209610481366004614920565b612bad565b610209610494366004614920565b612c79565b6102096104a7366004614940565b6132c4565b6102096104ba366004614940565b61330f565b6104c7613357565b60405161026c9190614cc2565b6005546001600160a01b031633146105075760405162461bcd60e51b81526004016104fe90614f0c565b60405180910390fd5b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610550576040519150601f19603f3d011682016040523d82523d5f602084013e610555565b606091505b50509050806105765760405162461bcd60e51b81526004016104fe90614f32565b604080516001600160a01b038516815260208101849052338183015290517f28614ead12a51bcebddb4ac0f25aa61661a6da57f20be72aef8f44ee4d3c68449181900360600190a1505050565b6005546001600160a01b031633146105ed5760405162461bcd60e51b81526004016104fe90614f0c565b6001600160a01b0381166105ff575f80fd5b6001600160a01b0381165f9081526004602052604090205460ff16156106555760405162461bcd60e51b815260206004820152600b60248201526a557365722065786973747360a81b60448201526064016104fe565b6002546001600160a01b0382165f908152600460205260408120805460ff1916600117905561068763ffffffff421690565b6001600160a01b0384165f90815260046020526040812063ffffffff929092166001909201919091555b82811015610a59575f8181526003602090815260408083206001600160a01b0389168452601481019092529091205460ff166106ed5750610a51565b6001600160a01b038681165f8181526014840160209081526040808320805460ff19908116909155948a16808452818420805490961660019081179096556013870180549687018155845282842090950180546001600160a01b03191686179055338352600480835281842088855260039081018452828520549585528184528285208986526002808201865284872080549988528487528588208c89529182018752858820998a5582840187528588205493820187528588209390935581840186528487205493810186528487209390935560058082018652848720549301855283862092909255549095556007909401815283822080548551818402810184019096528086529790930196919392919083018282801561082c57602002820191905f5260205f20905b815481526020019060010190808311610818575b505083519394505f925050505b81811015610986576001600160a01b038981165f9081526004602081815260408084208a855260069081018352818520878652808452828620968f1686529383528185208b8652018252808420868552825283208454815460ff1980821660ff93841615159081178555885464ffffffffff1990931664ffffffff0019909116176101009283900463ffffffff90811690930217808555885468ffffffff0000000000198216600160281b918290048516909102908117865589546cffffffffffffffff00000000001990921663ffffffff60481b1990911617600160481b918290049093160291909117835560018088018054828601556002808a018054918701919091556003808b0180549190970180548616919096161515179094559590945286546cffffffffffffffffffffffffff191690965592849055929091558154909216905501610839565b506001600160a01b038089165f90815260046020818152604080842089855260079081018352818520958d1685529282528084208985529092019052902081546109d09290614562565b506001600160a01b038881165f9081526004602081815260408084208985526008808201845282862054968e1686529383528185208a865290930182528084209490945560079091019052908120610a27916145ae565b5050506001600160a01b0385165f9081526004602090815260408083208484526008019091528120555b6001016106b1565b506001600160a01b0384165f908152600460205260408120805460ff191681556001015580610ab25760405162461bcd60e51b8152602060048201526005602482015264456d70747960d81b60448201526064016104fe565b6001600160a01b038481165f818152600460209081526040808320805460ff19168155600101929092559051918252918516917f844985ce6880ca51e25a6d4ecc8af37a5de880279f2081af96d0e875c42b708291015b60405180910390a250505050565b6005546001600160a01b03163314610b415760405162461bcd60e51b81526004016104fe90614f0c565b5f83815260036020526040902054839060ff16610b705760405162461bcd60e51b81526004016104fe90614f5a565b5f610b7d83850185614fe2565b90508061016001515f1480610b9c575080610140015181610160015110155b610ba4575f80fd5b5f8581526003602052604090206101808201511580610bcc575080600b015482610180015110155b610c0e5760405162461bcd60e51b81526020600482015260136024820152722a37ba30b61039ba30b5b2b2103434b3b432b960691b60448201526064016104fe565b6040820151620186a062ffffff90911611801590610c3a57506060820151620186a062ffffff90911611155b8015610c5457506080820151620186a062ffffff90911611155b8015610c6e575060a0820151620186a062ffffff90911611155b610c8a5760405162461bcd60e51b81526004016104fe906150bd565b6004810154600160601b900460ff1615610cb85760c0820151620186a062ffffff9091161115610cb8575f80fd5b60048101545f90600160801b900460ff168015610ce057506004820154600160881b900460ff165b8015610d05575060e08301516004830154600160901b900463ffffffff908116911614155b8351600184015560408401516004840180546060870151608088015160a089015160c08a015162ffffff96871665ffffffffffff1990951694909417630100000093871693909302929092176bffffffffffff0000000000001916600160301b9186169190910262ffffff60481b191617600160481b918516919091021762ffffff60681b1916600160681b939091169290920291909117905590508015610dd35760e083015160048301805463ffffffff909216600160901b0263ffffffff60901b199092169190911790555b61010083015160048301805463ffffffff909216600160b01b0263ffffffff60b01b19909216919091179055610120830151600683015561014083015160078301556101608301516008830155610180830151600983015560038201546002830154600160281b90046001600160a01b03908116911614610e8c575f836020015162ffffff1611610e62575f80fd5b602083015160038301805462ffffff909216600160b81b0262ffffff60b81b199092169190911790555b8015610fe55760138201545f5b81811015610fe2575f846013018281548110610eb757610eb76150e7565b5f9182526020808320909101546001600160a01b03168083526014880190915260409091205490915060ff16610eed5750610fda565b6001600160a01b0381165f9081526004602090815260408083208d8452600701909152812054905b81811015610fd6575f60045f856001600160a01b03166001600160a01b031681526020019081526020015f206006015f8e81526020019081526020015f205f8381526020019081526020015f2090505f8860040160129054906101000a900463ffffffff1663ffffffff1611610f8b575f610fac565b60048801548154600160481b900463ffffffff908116600160901b90920416015b815463ffffffff91909116600160281b0268ffffffff000000000019909116179055600101610f15565b5050505b600101610e99565b50505b60405187907fecd020be573f4ea369470e09be77de97555097b3017b8029312da9df84cd1806905f90a250505050505050565b5f81815260036020526040902054606090829060ff1661104a5760405162461bcd60e51b81526004016104fe90614f5a565b5f83815260036020908152604091829020601301805483518184028101840190945280845290918301828280156110a857602002820191905f5260205f20905b81546001600160a01b0316815260019091019060200180831161108a575b505050505091505b50919050565b6005546001600160a01b031633146110e05760405162461bcd60e51b81526004016104fe90614f0c565b60405163a9059cbb60e01b81525f906001600160a01b0385169063a9059cbb9061111090869086906004016150fb565b6020604051808303815f875af115801561112c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111509190615114565b90508061116f5760405162461bcd60e51b81526004016104fe90614f32565b604080516001600160a01b038087168252851660208201529081018390523360608201527f2378723624fcc8bcdeaccb21d8cf3dc2c7b9fa6ec78f7c13008a79ac313abfd39060800160405180910390a150505050565b335f8181526004602052604090205460ff166111f45760405162461bcd60e51b81526004016104fe9061512f565b5f83815260036020526040902080548491849160ff166112265760405162461bcd60e51b81526004016104fe90614f5a565b335f908152600460209081526040808320868452600601825280832085845290915290205460ff1661126a5760405162461bcd60e51b81526004016104fe90615155565b5f54600160a01b900460ff16156112935760405162461bcd60e51b81526004016104fe9061517c565b5f805460ff60a01b1916600160a01b1790556112b0338787613838565b50505f805460ff60a01b1916905550505050565b604080518082019091525f8152606060208201526001600160a01b0382165f90815260046020526040902054829060ff166113115760405162461bcd60e51b81526004016104fe9061512f565b6001600160a01b0383165f908152600460205260408120600101548352600254815b81811015611377575f8181526003602090815260408083206001600160a01b038a16845260140190915290205460ff161561136f578260010192505b600101611333565b508167ffffffffffffffff81111561139157611391614f80565b6040519080825280602002602001820160405280156113f657816020015b6113e36040518060c001604052805f81526020015f81526020015f81526020015f81526020015f8152602001606081525090565b8152602001906001900390816113af5790505b5060208501525f805b82811015611786575f8181526003602090815260408083206001600160a01b038b16845260140190915290205460ff161561177e57808660200151838151811061144b5761144b6150e7565b602090810291909101810151919091526001600160a01b0388165f908152600482526040808220848352600201835290205490870151805184908110611493576114936150e7565b6020908102919091018101518101919091526001600160a01b0388165f9081526004825260408082208483526003018352902054908701518051849081106114dd576114dd6150e7565b6020908102919091018101516040908101929092526001600160a01b0389165f9081526004808352838220858352018252919091205490870151805184908110611529576115296150e7565b602090810291909101810151606001919091526001600160a01b0388165f908152600482526040808220848352600501835290205490870151805184908110611574576115746150e7565b602090810291909101810151608001919091526001600160a01b0388165f90815260048252604080822084835260070190925220548067ffffffffffffffff8111156115c2576115c2614f80565b60405190808252806020026020018201604052801561162057816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282525f199092019101816115e05790505b5087602001518481518110611637576116376150e7565b602002602001015160a001819052505f5b81811015611775576001600160a01b0389165f9081526004602090815260408083208684526006018252808320848452825291829020825160e081018452815460ff8082161515835263ffffffff61010083048116848701908152600160281b84048216858901908152600160481b909404821660608087019182526001880154608080890191825260028a015460a0808b019182526003909b0154909716151560c0808b019182528d519081018e5295518716865297518616858c015292519094169983019990995291519781019790975290519086015251151591840191909152908a0151805191929187908110611744576117446150e7565b602002602001015160a001518381518110611761576117616150e7565b602090810291909101015250600101611648565b50826001019250505b6001016113ff565b5050505050919050565b6005546001600160a01b031633146117ba5760405162461bcd60e51b81526004016104fe90614f0c565b600155565b335f8181526004602052604090205460ff166117ed5760405162461bcd60e51b81526004016104fe9061512f565b5f848152600360205260409020805485919060ff1661181e5760405162461bcd60e51b81526004016104fe90614f5a565b6002810154640100000000900460ff1661184a5760405162461bcd60e51b81526004016104fe906151a4565b5f54600160a01b900460ff16156118735760405162461bcd60e51b81526004016104fe9061517c565b5f805460ff60a01b1916600160a01b17815584905b818110156118bb576118b333898989858181106118a7576118a76150e7565b90506020020135613838565b600101611888565b50505f805460ff60a01b19169055505050505050565b6005546001600160a01b031633146118fb5760405162461bcd60e51b81526004016104fe90614f0c565b5f83815260036020526040902054839060ff1661192a5760405162461bcd60e51b81526004016104fe90614f5a565b828260405160200161193d9291906151ce565b604051602081830303815290604052611955906151dd565b5f9485526003602052604090942060010193909355505050565b335f8181526004602052604090205460ff1661199d5760405162461bcd60e51b81526004016104fe9061512f565b5f848152600360205260409020805485919060ff166119ce5760405162461bcd60e51b81526004016104fe90614f5a565b6002810154640100000000900460ff166119fa5760405162461bcd60e51b81526004016104fe906151a4565b5f54600160a01b900460ff1615611a235760405162461bcd60e51b81526004016104fe9061517c565b5f805460ff60a01b1916600160a01b17815584905b818110156118bb57611a633389898985818110611a5757611a576150e7565b90506020020135613ec5565b600101611a38565b6005546001600160a01b03163314611a955760405162461bcd60e51b81526004016104fe90614f0c565b611a9e5f614235565b565b6005546001600160a01b03163314611aca5760405162461bcd60e51b81526004016104fe90614f0c565b5f82815260036020526040902054829060ff16611af95760405162461bcd60e51b81526004016104fe90614f5a565b5f8211611b04575f80fd5b5f8381526003602081905260408083209182015490516323b872dd60e01b8152336004820152306024820152604481018690529192916001600160a01b03909116906323b872dd906064016020604051808303815f875af1158015611b6b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8f9190615114565b905080611bae5760405162461bcd60e51b81526004016104fe90614f32565b5050505050565b6005545f906001600160a01b03163314611be15760405162461bcd60e51b81526004016104fe90614f0c565b5f611bee83850185615200565b60208101519091506001600160a01b03161580611c19575060208101516001600160a01b031661dead145b80611c2f575060408101516001600160a01b0316155b80611c48575060408101516001600160a01b031661dead145b15611c855760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b60448201526064016104fe565b5f816080015162ffffff1611611ccb5760405162461bcd60e51b815260206004820152600b60248201526a496e76616c69642041505960a81b60448201526064016104fe565b5f816060015163ffffffff1611611ce0575f80fd5b6102408101511580611cfc575080610220015181610240015110155b611d04575f80fd5b60c0810151620186a062ffffff90911611801590611d30575060e0810151620186a062ffffff90911611155b8015611d4b5750610100810151620186a062ffffff90911611155b8015611d665750610120810151620186a062ffffff90911611155b611d825760405162461bcd60e51b81526004016104fe906150bd565b80610140015115611da857610160810151620186a062ffffff9091161115611da8575f80fd5b6002545f81815260036020908152604091829020805460ff191660019081178255855190820155918401519084015192945090916001600160a01b03908116911614611df8578160a00151611e05565b611e056103e86064615359565b60038201805462ffffff92909216600160b81b0262ffffff60b81b199092169190911790554263ffffffff16816002015f6101000a81548163ffffffff021916908363ffffffff16021790555081602001518160020160056101000a8154816001600160a01b0302191690836001600160a01b031602179055508160400151816003015f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550816060015181600301601a6101000a81548163ffffffff021916908363ffffffff16021790555081608001518160030160146101000a81548162ffffff021916908362ffffff1602179055508160c00151816004015f6101000a81548162ffffff021916908362ffffff1602179055508160e001518160040160036101000a81548162ffffff021916908362ffffff1602179055508161010001518160040160066101000a81548162ffffff021916908362ffffff1602179055508161012001518160040160096101000a81548162ffffff021916908362ffffff16021790555081610140015181600401600c6101000a81548160ff02191690831515021790555081610160015181600401600d6101000a81548162ffffff021916908362ffffff1602179055508161018001518160040160106101000a81548160ff021916908315150217905550816101a001518160040160116101000a81548160ff021916908315150217905550816101c001518160040160126101000a81548163ffffffff021916908363ffffffff160217905550816101e001518160040160166101000a81548163ffffffff021916908363ffffffff1602179055508161020001518160060181905550816102200151816007018190555081610240015181600801819055508161026001518160090181905550600283908060018154018082558091505060019003905f5260205f20015f9091909190915055827f522b283dfad3650433b41164a9379b13dc60bbf24676affdc6a33c84dd3ac15d60405160405180910390a2505092915050565b6005546001600160a01b031633146121225760405162461bcd60e51b81526004016104fe90614f0c565b5f82815260036020526040902054829060ff166121515760405162461bcd60e51b81526004016104fe90614f5a565b5f83815260036020908152604091829020600401805463ffffffff60b01b1916600160b01b63ffffffff871690810291909117909155915191825284917fa18c8a75e23d740a62065ec340d920da6eaa8d4d978d7ee7bd9c3c984c2b9c00910160405180910390a2505050565b6005546001600160a01b031633146121e85760405162461bcd60e51b81526004016104fe90614f0c565b5f82815260036020526040902054829060ff166122175760405162461bcd60e51b81526004016104fe90614f5a565b5f8381526003602081905260409091209081015460028201546001600160a01b03918216600160281b9091049091160361227c5760405162461bcd60e51b8152602060048201526006602482015265155b9d5cd95960d21b60448201526064016104fe565b5f8362ffffff161161228c575f80fd5b600301805462ffffff909316600160b81b0262ffffff60b81b19909316929092179091555050565b335f8181526004602052604090205460ff166122e25760405162461bcd60e51b81526004016104fe9061512f565b5f848152600360205260409020805485919060ff166123135760405162461bcd60e51b81526004016104fe90614f5a565b6002810154640100000000900460ff1661233f5760405162461bcd60e51b81526004016104fe906151a4565b5f54600160a01b900460ff16156123685760405162461bcd60e51b81526004016104fe9061517c565b5f805460ff60a01b1916600160a01b17815584905b818110156118bb576123a8338989898581811061239c5761239c6150e7565b90506020020135614286565b60010161237d565b6005546001600160a01b031633146123da5760405162461bcd60e51b81526004016104fe90614f0c565b5f82815260036020526040902054829060ff166124095760405162461bcd60e51b81526004016104fe90614f5a565b5f8381526003602052604090206002018054831580156401000000000264ff00000000199092169190911790915561246a5760405183907fdf5eab7aafa65f032281e56b9400db3c1d50c6a02c1c56cf936eb79e5748a9ab905f90a2505050565b60405183907f925a19753e677c9dc36a80e0fc824ca0c5b1afde494872b43daccab9ffeaffd4905f90a2505050565b6005546001600160a01b031633146124c35760405162461bcd60e51b81526004016104fe90614f0c565b5f85815260036020526040902054859060ff166124f25760405162461bcd60e51b81526004016104fe90614f5a565b620186a062ffffff8616118015906125125750620186a062ffffff851611155b80156125265750620186a062ffffff841611155b801561253a5750620186a062ffffff831611155b6125565760405162461bcd60e51b81526004016104fe906150bd565b5f8681526003602090815260409182902060048101805462ffffff8a811665ffffffffffff19909216821763010000008b8316908102919091176bffffffffffff0000000000001916600160301b8b841690810262ffffff60481b191691909117600160481b938b16938402179094558651928352948201949094529384015260608301919091529087907fb54eb3da7684d2563d8b17a37c47244258d7d247453899e36ec6adf96377a44b9060800160405180910390a250505050505050565b335f8181526004602052604090205460ff166126455760405162461bcd60e51b81526004016104fe9061512f565b5f83815260036020526040902080548491849160ff166126775760405162461bcd60e51b81526004016104fe90614f5a565b335f908152600460209081526040808320868452600601825280832085845290915290205460ff166126bb5760405162461bcd60e51b81526004016104fe90615155565b5f54600160a01b900460ff16156126e45760405162461bcd60e51b81526004016104fe9061517c565b5f805460ff60a01b1916600160a01b1790556112b0338787613ec5565b6005546001600160a01b0316331461272b5760405162461bcd60e51b81526004016104fe90614f0c565b5f82815260036020526040902054829060ff1661275a5760405162461bcd60e51b81526004016104fe90614f5a565b5f838152600360205260409020821580612778575080600b01548310155b6127ba5760405162461bcd60e51b81526020600482015260136024820152722a37ba30b61039ba30b5b2b2103434b3b432b960691b60448201526064016104fe565b6009810183905560405183815284907f5def99ddd6102c839dfbaaf9a95f499b5069591d69f95c5dcd5eef4ceb23dbaf90602001610b09565b335f8181526004602052604090205460ff166128215760405162461bcd60e51b81526004016104fe9061512f565b5f83815260036020526040902080548491849160ff166128535760405162461bcd60e51b81526004016104fe90614f5a565b335f908152600460209081526040808320868452600601825280832085845290915290205460ff166128975760405162461bcd60e51b81526004016104fe90615155565b5f54600160a01b900460ff16156128c05760405162461bcd60e51b81526004016104fe9061517c565b5f805460ff60a01b1916600160a01b1790556112b0338787614286565b6005546001600160a01b031633146129075760405162461bcd60e51b81526004016104fe90614f0c565b5f83815260036020526040902054839060ff166129365760405162461bcd60e51b81526004016104fe90614f5a565b81158061294257508282115b61294a575f80fd5b5f84815260036020908152604091829020600781018690556008810185905582518681529182018590529186917f816cd3848cc1dfbfde7fac2337c0eaf390c7fe46b8cd2a912e6c29c698f042a8910160405180910390a25050505050565b6001600160a01b0383165f90815260046020526040812054849060ff166129e25760405162461bcd60e51b81526004016104fe9061512f565b5f84815260036020526040902080548591859160ff16612a145760405162461bcd60e51b81526004016104fe90614f5a565b335f908152600460209081526040808320868452600601825280832085845290915290205460ff16612a585760405162461bcd60e51b81526004016104fe90615155565b5f8781526003602081815260408084206001600160a01b038d168552600483528185208c865260060183528185208b8652835293819020815160e081018352815460ff8082161515835263ffffffff6101008304811696840196909652600160281b8204861694830194909452600160481b9004909316606084015260018101546080840152600281015460a08401529092015490911615801560c0830152612b05575f96505050612ba2565b600382015460608201515f91612b339163ffffffff600160d01b90920482169142160363ffffffff16614550565b9050612b9c6301e185588263ffffffff16612b6f85608001518760030160149054906101000a900462ffffff1662ffffff16620186a091020490565b0281612b7d57612b7d61538c565b600386015491900490600160b81b900462ffffff16620186a091020490565b97505050505b505050509392505050565b6005546001600160a01b03163314612bd75760405162461bcd60e51b81526004016104fe90614f0c565b5f82815260036020526040902054829060ff16612c065760405162461bcd60e51b81526004016104fe90614f5a565b5f838152600360205260409020821580612c24575080600501548310155b612c405760405162461bcd60e51b81526004016104fe906153a0565b6006810183905560405183815284907f57b2b93bd3c690df98cb9f93df3ee46439e48912d61d684c1cfbdfddd1c941df90602001610b09565b5f828152600360205260409020805483919060ff16612caa5760405162461bcd60e51b81526004016104fe90614f5a565b6002810154640100000000900460ff16612cd65760405162461bcd60e51b81526004016104fe906151a4565b5f54600160a01b900460ff1615612cff5760405162461bcd60e51b81526004016104fe9061517c565b5f805460ff60a01b1916600160a01b1781558481526003602052604090206007810154841015612d685760405162461bcd60e51b8152602060048201526014602482015273125b9cdd59999a58da595b9d0819195c1bdcda5d60621b60448201526064016104fe565b60028101546040516323b872dd60e01b8152336004820152306024820152604481018690525f91600160281b90046001600160a01b0316906323b872dd906064016020604051808303815f875af1158015612dc5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612de99190615114565b905080612e085760405162461bcd60e51b81526004016104fe90614f32565b335f9081526004602081815260408084208a8552600701909152909120549083015462ffffff1615612f0d576004830154600e84018054620186a062ffffff90931689029290920491820190555f5496819003966001600160a01b031615612f0b5760028401545f805460405163a9059cbb60e01b815291926001600160a01b03600160281b90910481169263a9059cbb92612eaa92169086906004016150fb565b6020604051808303815f875af1158015612ec6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612eea9190615114565b905080612f095760405162461bcd60e51b81526004016104fe90614f32565b505b505b335f9081526004602052604090205460ff16612f6757335f908152600460205260409020805460ff19166001179055612f4963ffffffff421690565b335f90815260046020526040902063ffffffff919091166001909101555b600883015415612fb3576008830154335f9081526004602090815260408083208b845260030190915290205487011115612fb35760405162461bcd60e51b81526004016104fe906153c6565b600983015415612fe75782600901548684600b0154011115612fe75760405162461bcd60e51b81526004016104fe906153c6565b335f9081526004602090815260408083208a84526008019091529020805460019081019091555415806130385750600154335f9081526004602090815260408083208b845260080190915290205411155b6130545760405162461bcd60e51b81526004016104fe906153a0565b335f9081526004602090815260408083208a845260060182528083208484529091529020805460ff1916600117815561309063ffffffff421690565b81546001830189905563ffffffff60481b1963ffffffff92831661010002166cffffffff00000000ffffffff001990911617600160481b42909216919091021781556004840154600160801b900460ff1680156130fd57506004840154600160901b900463ffffffff1615155b613107575f613128565b6004840154600160901b900463ffffffff1661312663ffffffff421690565b015b815463ffffffff91909116600160281b0268ffffffff000000000019909116178155335f90815260148501602052604090205460ff166132125760058401805460010190556006840154158061318657508360060154846005015411155b6131a25760405162461bcd60e51b81526004016104fe906153a0565b335f8181526014860160209081526040808320805460ff19166001908117909155601389018054918201815584528284200180546001600160a01b03191685179055928252601587019052205460ff1661321257335f9081526015850160205260409020805460ff191660011790555b50335f8181526004602090815260408083208b845260028101835281842080548c01905560038101835281842080548c0190556007018252808320805460018101825590845292829020909201849055600a860180548a019055600b860180548a01905581518481529081018990528992917f36af321ec8d3c75236829c5317affd40ddb308863a1236d2d277a4025cccee1e910160405180910390a350505f805460ff60a01b191690555050505050565b6005546001600160a01b031633146132ee5760405162461bcd60e51b81526004016104fe90614f0c565b5f80546001600160a01b0319166001600160a01b0392909216919091179055565b6005546001600160a01b031633146133395760405162461bcd60e51b81526004016104fe90614f0c565b6001600160a01b03811661334b575f80fd5b61335481614235565b50565b6002546060908067ffffffffffffffff81111561337657613376614f80565b6040519080825280602002602001820160405280156133af57816020015b61339c6145c9565b8152602001906001900390816133945790505b5091505f5b81811015613833575f60035f8381526020019081526020015f2090505f8160020160059054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015613423573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261344a91908101906153e8565b600383015460028401549192505f91600160281b90046001600160a01b039081169116146134ef57826003015f9054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa1580156134c3573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526134ea91908101906153e8565b6134f1565b815b90505f8360020160059054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613547573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061356b9190615493565b600385015460028601549192505f91600160281b90046001600160a01b0390811691161461360e57846003015f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135e5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136099190615493565b613610565b815b6040805161042081018252600288015460ff640100000000820481161515835260018a0154602084015263ffffffff808316848601526001600160a01b03600160281b9093048316606085015260808085018b905288831660a086015260038c015493841660c086015260e085018a9052868316610100860152600160d01b8404821661012086015262ffffff600160a01b85048116610140870152600160b81b90940484166101608601526004808d01548086166101808801526301000000810486166101a0880152600160301b810486166101c0880152600160481b810486166101e0880152600160601b810485161515610200880152600160681b8104909516610220870152600160801b850484161515610240870152600160881b85049093161515610260860152600160901b84048216610280860152600160b01b909304166102a084015260058a01546102c084015260068a01546102e084015260078a015461030084015260088a015461032084015260098a0154610340840152600a8a0154610360840152600b8a0154610380840152600c8a01546103a0840152600d8a01546103c08401528351918201938490529394505f9391926103e0840192600e8b019182845b8154815260200190600101908083116137db57505050505081526020018760120154815250905080898881518110613815576138156150e7565b602002602001018190525050505050505080806001019150506133b4565b505090565b5f8281526003602081815260408084206001600160a01b03881685526004835281852087865260060183528185208686529092529092209081015460ff16156138935760405162461bcd60e51b81526004016104fe906154b3565b6004820154600160801b900460ff1680156138ba57506004820154600160601b900460ff16155b80156138ec57508054600160281b900463ffffffff1615806138ec5750805463ffffffff428116600160281b90920416115b156139225760405162461bcd60e51b8152602060048201526006602482015265131bd8dad95960d21b60448201526064016104fe565b60018101546004830154600160801b900460ff16801561394d57506004830154600160601b900460ff165b801561397f57508154600160281b900463ffffffff16158061397f5750815463ffffffff428116600160281b90920416115b15613a87576004830154600160681b900462ffffff1615613a825760048301545f906139bd908390600160681b900462ffffff16620186a091020490565b601285018054820190555f5492819003929091506001600160a01b031615613a805760028401545f805460405163a9059cbb60e01b815291926001600160a01b03600160281b90910481169263a9059cbb92613a1f92169086906004016150fb565b6020604051808303815f875af1158015613a3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a5f9190615114565b905080613a7e5760405162461bcd60e51b81526004016104fe90614f32565b505b505b613b85565b6004830154600160481b900462ffffff1615613b855760048301545f90613ac0908390600160481b900462ffffff16620186a091020490565b601185018054820190555f5492819003929091506001600160a01b031615613b835760028401545f805460405163a9059cbb60e01b815291926001600160a01b03600160281b90910481169263a9059cbb92613b2292169086906004016150fb565b6020604051808303815f875af1158015613b3e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b629190615114565b905080613b815760405162461bcd60e51b81526004016104fe90614f32565b505b505b5f613b918787876129a9565b60048501549091506301000000900462ffffff1615613c8b5760048401545f90613bcd9083906301000000900462ffffff16620186a091020490565b600f86018054820190555f5492819003929091506001600160a01b031615613c895760038501545f805460405163a9059cbb60e01b815291926001600160a01b039081169263a9059cbb92613c2892169086906004016150fb565b6020604051808303815f875af1158015613c44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c689190615114565b905080613c875760405162461bcd60e51b81526004016104fe90614f32565b505b505b82546cffffffffffffffff00000000001916600160481b63ffffffff421602178355600283018054820190556003808401805460ff191660019081179091558401546001600160a01b0389165f9081526004602081815260408084208c8552958601808352818520805496909603865560058701835281852080548a01905592860182528084208054880190556008909501815293822080545f19019055909252549003613d60576005840180545f190190556001600160a01b0387165f9081526014850160205260409020805460ff191690555b6001830154600b85018054919091039055600d8401805483019055600c8401805482019055600284015460405163a9059cbb60e01b8152600160281b9091046001600160a01b03169063a9059cbb90613dbf908a9086906004016150fb565b6020604051808303815f875af1158015613ddb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613dff9190615114565b50600384015460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90613e34908a9085906004016150fb565b6020604051808303815f875af1158015613e50573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e749190615114565b5050604080518581526020810183905286916001600160a01b038916917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9491015b60405180910390a3505050505050565b5f828152600360208190526040909120908101546002820154600160281b90046001600160a01b03908116911614613f2d5760405162461bcd60e51b815260206004820152600b60248201526a556e617661696c61626c6560a81b60448201526064016104fe565b6001600160a01b0384165f90815260046020908152604080832086845260060182528083208584529091529020600381015460ff1615613f7f5760405162461bcd60e51b81526004016104fe906154b3565b5f613f8b8686866129a9565b6004840154835491925063ffffffff428116600160481b9093048116600160b01b909204811691909101161115613fef5760405162461bcd60e51b815260206004820152600860248201526721b7b7b63237bbb760c11b60448201526064016104fe565b6004830154600160301b900462ffffff16156140e65760048301545f90614028908390600160301b900462ffffff16620186a091020490565b601085018054820190555f5492819003929091506001600160a01b0316156140e45760038401545f805460405163a9059cbb60e01b815291926001600160a01b039081169263a9059cbb9261408392169086906004016150fb565b6020604051808303815f875af115801561409f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906140c39190615114565b9050806140e25760405162461bcd60e51b81526004016104fe90614f32565b505b505b600883015415614132576008830154335f908152600460209081526040808320898452600301909152902054820111156141325760405162461bcd60e51b81526004016104fe906153c6565b6009830154156141665782600901548184600b01540111156141665760405162461bcd60e51b81526004016104fe906153c6565b6001600160a01b0386165f8181526004602081815260408084208a85529283018252808420805487019055600280840183528185208054880190556003909301825292839020805486019055600c8701805486019055600a8701805486019055600b8701805486019055855463ffffffff60481b1916600160481b63ffffffff4216021786556001860180548601905590850180548501905581518781529081018490528792917f1c349721eed47ef3e6aede3963c2597161fbd9d7be47bd891a7ecf27780b804c9101613eb5565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f8281526003602081815260408084206001600160a01b03881685526004835281852087865260060183528185208686529092529092209081015460ff16156142e15760405162461bcd60e51b81526004016104fe906154b3565b5f6142ed8686866129a9565b6004840154835491925063ffffffff428116600160481b9093048116600160b01b9092048116919091011611156143515760405162461bcd60e51b815260206004820152600860248201526721b7b7b63237bbb760c11b60448201526064016104fe565b60048301546301000000900462ffffff16156144485760048301545f9061438a9083906301000000900462ffffff16620186a091020490565b600f85018054820190555f5492819003929091506001600160a01b0316156144465760038401545f805460405163a9059cbb60e01b815291926001600160a01b039081169263a9059cbb926143e592169086906004016150fb565b6020604051808303815f875af1158015614401573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144259190615114565b9050806144445760405162461bcd60e51b81526004016104fe90614f32565b505b505b815463ffffffff60481b1916600160481b63ffffffff421602178255600282018190556001600160a01b038681165f9081526004602081815260408084208a8552830190915291829020805485019055600c86018054850190556003860154915163a9059cbb60e01b8152919092169163a9059cbb916144cc918a918691016150fb565b6020604051808303815f875af11580156144e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061450c9190615114565b50604080518581526020810183905286916001600160a01b038916917f45c072aa05b9853b5a993de7a28bc332ee01404a628cec1a23ce0f659f842ef19101613eb5565b5f8282188284100282185b9392505050565b828054828255905f5260205f2090810192821561459e575f5260205f209182015b8281111561459e578254825591600101919060010190614583565b506145aa9291506146d9565b5090565b5080545f8255905f5260205f209081019061335491906146d9565b60408051610420810182525f8082526020820181905291810182905260608082018390526080820181905260a0820183905260c0820183905260e0820152610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e08101829052610200810182905261022081018290526102408101829052610260810182905261028081018290526102a081018290526102c081018290526102e08101829052610300810182905261032081018290526103408101829052610360810182905261038081018290526103a081018290526103c08101919091526103e081016146cd6146ed565b81526020015f81525090565b5b808211156145aa575f81556001016146da565b60405180608001604052806004906020820280368337509192915050565b6001600160a01b0381168114613354575f80fd5b5f8060408385031215614730575f80fd5b823561473b8161470b565b946020939093013593505050565b80356147548161470b565b919050565b5f806040838503121561476a575f80fd5b82356147758161470b565b915060208301356147858161470b565b809150509250929050565b5f8083601f8401126147a0575f80fd5b50813567ffffffffffffffff8111156147b7575f80fd5b6020830191508360208285010111156147ce575f80fd5b9250929050565b5f805f604084860312156147e7575f80fd5b83359250602084013567ffffffffffffffff811115614804575f80fd5b61481086828701614790565b9497909650939450505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038481168252831660208201526060604082018190525f906148769083018461481d565b95945050505050565b5f6020828403121561488f575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b818110156148d65783516001600160a01b0316835292840192918401916001016148b1565b50909695505050505050565b5f805f606084860312156148f4575f80fd5b83356148ff8161470b565b9250602084013561490f8161470b565b929592945050506040919091013590565b5f8060408385031215614931575f80fd5b50508035926020909101359150565b5f60208284031215614950575f80fd5b813561455b8161470b565b5f6020808352606083018451828501528185015160408081870152828251808552608094508488019150848160051b89010186850194505f5b82811015614a6357898203607f190184528551805183528881015189840152858101518684015260608082015190840152878101518884015260a09081015160c08285018190528151908501819052908a01915f9160e08601905b80841015614a49578451805163ffffffff90811684528e82015181168f8501528b820151168b840152606080820151908401528c8101518d840152830151151583830152938c01936001939093019260c0909101906149ef565b50988b0198968b0196945050506001919091019050614994565b509998505050505050505050565b602081525f61455b602083018461481d565b5f805f60408486031215614a95575f80fd5b83359250602084013567ffffffffffffffff80821115614ab3575f80fd5b818601915086601f830112614ac6575f80fd5b813581811115614ad4575f80fd5b8760208260051b8501011115614ae8575f80fd5b6020830194508093505050509250925092565b5f8060208385031215614b0c575f80fd5b823567ffffffffffffffff811115614b22575f80fd5b614b2e85828601614790565b90969095509350505050565b803563ffffffff81168114614754575f80fd5b5f8060408385031215614b5e575f80fd5b82359150614b6e60208401614b3a565b90509250929050565b803562ffffff81168114614754575f80fd5b5f8060408385031215614b9a575f80fd5b82359150614b6e60208401614b77565b8015158114613354575f80fd5b803561475481614baa565b5f8060408385031215614bd3575f80fd5b82359150602083013561478581614baa565b5f805f805f60a08688031215614bf9575f80fd5b85359450614c0960208701614b77565b9350614c1760408701614b77565b9250614c2560608701614b77565b9150614c3360808701614b77565b90509295509295909350565b5f805f60608486031215614c51575f80fd5b505081359360208301359350604090920135919050565b5f805f60608486031215614c7a575f80fd5b8335614c858161470b565b95602085013595506040909401359392505050565b805f5b6004811015614cbc578151845260209384019390910190600101614c9d565b50505050565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b83811015614efe57603f19898403018552815180511515845287810151888501528681015163ffffffff16878501526060808201516001600160a01b0316908501526080808201516104808287018190529190614d488388018261481d565b9250505060a080830151614d608288018260ff169052565b505060c0828101516001600160a01b03169086015260e08083015186830382880152614d8c838261481d565b9250505061010080830151614da58288018260ff169052565b50506101208281015163ffffffff908116918701919091526101408084015162ffffff9081169188019190915261016080850151821690880152610180808501518216908801526101a0808501518216908801526101c0808501518216908801526101e0808501518216908801526102008085015115159088015261022080850151909116908701526102408084015115159087015261026080840151151590870152610280808401518216908701526102a080840151909116908601526102c080830151908601526102e08083015190860152610300808301519086015261032080830151908601526103408083015190860152610360808301519086015261038080830151908601526103a080830151908601526103c080830151908601526103e080830151614ed982880182614c9a565b5050610400919091015161046094909401939093529386019390860190600101614ce9565b509098975050505050505050565b6020808252600c908201526b155b985d5d1a1bdc9a5e995960a21b604082015260600190565b6020808252600e908201526d2a3930b739b332b91032b93937b960911b604082015260600190565b6020808252600c908201526b155b9adb9bdddb881c1bdbdb60a21b604082015260600190565b634e487b7160e01b5f52604160045260245ffd5b6040516101a0810167ffffffffffffffff81118282101715614fb857614fb8614f80565b60405290565b604051610280810167ffffffffffffffff81118282101715614fb857614fb8614f80565b5f6101a08284031215614ff3575f80fd5b614ffb614f94565b8235815261500b60208401614b77565b602082015261501c60408401614b77565b604082015261502d60608401614b77565b606082015261503e60808401614b77565b608082015261504f60a08401614b77565b60a082015261506060c08401614b77565b60c082015261507160e08401614b3a565b60e0820152610100615084818501614b3a565b90820152610120838101359082015261014080840135908201526101608084013590820152610180928301359281019290925250919050565b60208082526010908201526f5461782065786365656473203130302560801b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b6001600160a01b03929092168252602082015260400190565b5f60208284031215615124575f80fd5b815161455b81614baa565b6020808252600c908201526b2ab735b737bbb7103ab9b2b960a11b604082015260600190565b6020808252600d908201526c556e6b6e6f776e207374616b6560981b604082015260600190565b6020808252600e908201526d4e6f2072652d656e7472616e637960901b604082015260600190565b60208082526010908201526f506f6f6c20756e617661696c61626c6560801b604082015260600190565b818382375f9101908152919050565b805160208083015191908110156110b0575f1960209190910360031b1b16919050565b5f6102808284031215615211575f80fd5b615219614fbe565b8235815261522960208401614749565b602082015261523a60408401614749565b604082015261524b60608401614b3a565b606082015261525c60808401614b77565b608082015261526d60a08401614b77565b60a082015261527e60c08401614b77565b60c082015261528f60e08401614b77565b60e08201526101006152a2818501614b77565b908201526101206152b4848201614b77565b908201526101406152c6848201614bb7565b908201526101606152d8848201614b77565b908201526101806152ea848201614bb7565b908201526101a06152fc848201614bb7565b908201526101c061530e848201614b3a565b908201526101e0615320848201614b3a565b90820152610200838101359082015261022080840135908201526102408084013590820152610260928301359281019290925250919050565b62ffffff81811683821602808216919082811461538457634e487b7160e01b5f52601160045260245ffd5b505092915050565b634e487b7160e01b5f52601260045260245ffd5b6020808252600c908201526b13585e0b881c995858da195960a21b604082015260600190565b602080825260089082015267115e18d95959195960c21b604082015260600190565b5f602082840312156153f8575f80fd5b815167ffffffffffffffff8082111561540f575f80fd5b818401915084601f830112615422575f80fd5b81518181111561543457615434614f80565b604051601f8201601f19908116603f0116810190838211818310171561545c5761545c614f80565b81604052828152876020848701011115615474575f80fd5b8260208601602083015e5f928101602001929092525095945050505050565b5f602082840312156154a3575f80fd5b815160ff8116811461455b575f80fd5b6020808252600990820152682bb4ba34323930bbb760b91b60408201526060019056fea2646970667358221220c1ced2f0b2b0e30065a2abebfbb8ec1791e9a8b88d9fe92ed4e2d5993c5d3f7764736f6c63430008190033

Verified Source Code Full Match

Compiler: v0.8.25+commit.b61c2a91 EVM: cancun Optimization: Yes (200 runs)
IERC20.sol 12 lines
// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

interface IERC20 {
  function symbol() external view returns (string memory);
  function decimals() external view returns (uint8);
  function balanceOf(address account) external view returns (uint256);
  function allowance(address owner, address spender) external view returns (uint256);
  function transfer(address to, uint256 amount) external returns (bool);
  function transferFrom(address from, address to, uint256 value) external returns (bool);
}
CF_Common.sol 234 lines
// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

import "./IERC20.sol";

abstract contract CF_Common {
  string internal constant _version = "1.0.1";

  address internal _treasury;

  bool internal locked;
  uint24 internal constant _denominator = 1_000;
  uint256 internal _maxStakePerUser = 25;

  struct Stake {
    bool exists;
    uint32 created;
    uint32 lockedUntil;
    uint32 lastAction;
    uint256 amount;
    uint256 claimed;
    bool withdrawn;
  }

  struct User {
    bool exists;
    uint256 created;
    mapping(uint256 => uint256) totalDeposited;
    mapping(uint256 => uint256) totalStaked;
    mapping(uint256 => uint256) totalRewardsClaimed;
    mapping(uint256 => uint256) totalWithdrawn;
    mapping(uint256 => mapping(uint256 => Stake)) pool;
    mapping(uint256 => uint256[]) list;
    mapping(uint256 => uint256) active;
  }

  struct userView {
    uint256 created;
    userPoolView[] pool;
  }

  struct userPoolView {
    uint256 id;
    uint256 totalDeposited;
    uint256 totalStaked;
    uint256 totalRewardsClaimed;
    uint256 totalWithdrawn;
    userStakeView[] stake;
  }

  struct userStakeView {
    uint32 created;
    uint32 lockedUntil;
    uint32 lastAction;
    uint256 amount;
    uint256 claimed;
    bool withdrawn;
  }

  struct newPoolConfig {
    bytes32 label;
    address stakedToken;
    address rewardToken;
    uint32 rewardPeriod;
    uint24 apy;
    uint24 ratio;
    uint24 taxDeposit;
    uint24 taxClaim;
    uint24 taxCompound;
    uint24 taxWithdraw;
    bool allowEarlyUnstake;
    uint24 earlyUnstakePenalty;
    bool lockupEnabled;
    bool allowLockupPeriodChange;
    uint32 lockupPeriod;
    uint32 cooldownPeriod;
    uint256 maxUsers;
    uint256 minStake;
    uint256 maxStake;
    uint256 maxTotalStaked;
  }

  struct setPoolConfig {
    bytes32 label;
    uint24 ratio;
    uint24 taxDeposit;
    uint24 taxClaim;
    uint24 taxCompound;
    uint24 taxWithdraw;
    uint24 earlyUnstakePenalty;
    uint32 lockupPeriod;
    uint32 cooldownPeriod;
    uint256 maxUsers;
    uint256 minStake;
    uint256 maxStake;
    uint256 maxTotalStaked;
  }

  struct Pool {
    bool exists;
    bytes32 label;
    uint32 created;
    bool open;
    IERC20 stakedToken;
    IERC20 rewardToken;
    uint24 apy;
    uint24 ratio;
    uint32 rewardPeriod;
    uint24 taxDeposit;
    uint24 taxClaim;
    uint24 taxCompound;
    uint24 taxWithdraw;
    bool allowEarlyUnstake;
    uint24 earlyUnstakePenalty;
    bool lockupEnabled;
    bool allowLockupPeriodChange;
    uint32 lockupPeriod;
    uint32 cooldownPeriod;
    uint256 activeUsers;
    uint256 maxUsers;
    uint256 minStake;
    uint256 maxStake;
    uint256 maxTotalStaked;
    uint256 totalDeposited;
    uint256 totalStaked;
    uint256 totalRewardsClaimed;
    uint256 totalWithdrawn;
    uint256[4] collectedTaxes;
    uint256 collectedPenalties;
    address[] users;
    mapping(address => bool) activeUser;
    mapping(address => bool) user;
  }

  struct PoolView {
    bool open;
    bytes32 label;
    uint32 created;
    address stakedToken;
    string stakedTokenSymbol;
    uint8 stakedTokenDecimals;
    address rewardToken;
    string rewardTokenSymbol;
    uint8 rewardTokenDecimals;
    uint32 rewardPeriod;
    uint24 apy;
    uint24 ratio;
    uint24 taxDeposit;
    uint24 taxClaim;
    uint24 taxCompound;
    uint24 taxWithdraw;
    bool allowEarlyUnstake;
    uint24 earlyUnstakePenalty;
    bool lockupEnabled;
    bool allowLockupPeriodChange;
    uint32 lockupPeriod;
    uint32 cooldownPeriod;
    uint256 activeUsers;
    uint256 maxUsers;
    uint256 minStake;
    uint256 maxStake;
    uint256 maxTotalStaked;
    uint256 totalDeposited;
    uint256 totalStaked;
    uint256 totalRewardsClaimed;
    uint256 totalWithdrawn;
    uint256[4] collectedTaxes;
    uint256 collectedPenalties;
  }

  uint256[] internal _pools;

  mapping(uint256 => Pool) internal _pool;
  mapping(address => User) internal _user;

  modifier nonReEntrant() {
    require(!locked, "No re-entrancy");

    locked = true;
    _;
    locked = false;
  }

  modifier isUser(address user) {
    require(_user[user].exists, "Unknown user");

    _;
  }

  modifier isPool(uint256 poolId) {
    require(_pool[poolId].exists, "Unknown pool");

    _;
  }

  modifier isPoolOpen(uint256 poolId) {
    Pool storage pool = _pool[poolId];

    require(pool.exists, "Unknown pool");
    require(pool.open, "Pool unavailable");

    _;
  }

  modifier isStake(uint256 poolId, uint256 stakeId) {
    Pool storage pool = _pool[poolId];

    require(pool.exists, "Unknown pool");
    require(_user[msg.sender].pool[poolId][stakeId].exists, "Unknown stake");

    _;
  }

  function _percentage(uint256 amount, uint256 bps) internal pure returns (uint256) {
    unchecked {
      return (amount * bps) / (100 * uint256(_denominator));
    }
  }

  function _timestamp() internal view returns (uint32) {
    unchecked {
      return uint32(block.timestamp % 2**32);
    }
  }

  function denominator() external pure returns (uint24) {
    return _denominator;
  }

  function version() external pure returns (string memory) {
    return _version;
  }
}
CF_Ownable.sol 36 lines
// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

abstract contract CF_Ownable {
  address internal _owner;

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

  modifier onlyOwner() {
    require(_owner == msg.sender, "Unauthorized");

    _;
  }

  function owner() external view returns (address) {
    return _owner;
  }

  function renounceOwnership() external onlyOwner {
    _transferOwnership(address(0));
  }

  function transferOwnership(address newOwner) external onlyOwner {
    require(newOwner != address(0));

    _transferOwnership(newOwner);
  }

  function _transferOwnership(address newOwner) internal {
    address oldOwner = _owner;
    _owner = newOwner;

    emit OwnershipTransferred(oldOwner, newOwner);
  }
}
BIG_ECOSYSTEM_Staking_by_ChianFactory.sol 819 lines
/*

        ____ _____ _____             
       |  _ \_   _/ ____|            
       | |_) || || |  __             
       |  _ < | || | |_ |            
       | |_) || || |__| |            
   ____|____/_____\_____|            
  / ____| |      | |/ (_)            
 | (___ | |_ __ _|  / _ _ __   __ _ 
  \___ \| __/ _` |  < | | _ \ / _` |
  ____) | || (_| | . \| | | | | (_| |
 |_____/ \__\__,_|_|\_\_|_| |_|\__, |
                                __/ |
                               |___/ 

  
Web: https://bigecosystem.com
X: https://x.com/BigEcosystem
Telegram: https://t.me/BigEcosystemOfficial                                   
                                                                                                                            


*/

// SPDX-License-Identifier: MIT

pragma solidity 0.8.25;

import "./IERC20.sol";
import "./CF_Common.sol";
import "./CF_Ownable.sol";

library Math {
  function toUint(bool b) internal pure returns (uint256 u) {
    assembly ("memory-safe") {
      u := iszero(iszero(b))
    }
  }

  function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
    unchecked {
      return b ^ ((a ^ b) * toUint(condition));
    }
  }

  function min(uint256 a, uint256 b) internal pure returns (uint256) {
    return ternary(a < b, a, b);
  }

  function max(uint256 a, uint256 b) internal pure returns (uint256) {
    return ternary(a > b, a, b);
  }
}

contract BIG_ECOSYSTEM_Staking_by_ChianFactory is CF_Common, CF_Ownable {
  event Deposit(address indexed user, uint256 indexed poolId, uint256 stakeId, uint256 amount);
  event Claim(address indexed user, uint256 indexed poolId, uint256 stakeId, uint256 amount);
  event Compound(address indexed user, uint256 indexed poolId, uint256 stakeId, uint256 amount);
  event Withdraw(address indexed user, uint256 indexed poolId, uint256 stakeId, uint256 amount);
  event Migrated(address indexed newUser, address oldUser);
  event PoolAdded(uint256 indexed poolId);
  event PoolOpened(uint256 indexed poolId);
  event PoolClosed(uint256 indexed poolId);
  event PoolConfigChanged(uint256 indexed poolId);
  event TaxesChanged(uint256 indexed poolId, uint24 taxDeposit, uint24 taxClaim, uint24 taxCompound, uint24 taxWithdraw);
  event CooldownPeriodChanged(uint256 indexed poolId, uint32 time);
  event StakeAmountChanged(uint256 indexed poolId, uint256 minStake, uint256 maxStake);
  event MaxUsersChanged(uint256 indexed poolId, uint256 maxUsers);
  event MaxTotalStakedChanged(uint256 indexed poolId, uint256 value);
  event WithdrawnNative(address to, uint256 amount, address executor);
  event WithdrawnERC20(address token, address to, uint256 amount, address executor);

  constructor() payable {
    _transferOwnership(0xC897DA2881887B352668B5A99bb02588bE8F1C54);
  }

  /// @notice Retrieve data for a specific user
  /// @param user Address of the user
  function userDetails(address user) external view isUser(user) returns (userView memory data) {
    data.created = _user[user].created;

    uint256 activePoolCount;
    uint256 cnt = _pools.length;

    unchecked {
      for (uint256 i; i < cnt; i++) {
        if (!_pool[i].activeUser[user]) { continue; }

        ++activePoolCount;
      }
    }

    data.pool = new userPoolView[](activePoolCount);
    uint256 index;

    unchecked {
      for (uint256 i; i < cnt; i++) {
        if (!_pool[i].activeUser[user]) { continue; }

        data.pool[index].id = i;
        data.pool[index].totalDeposited = _user[user].totalDeposited[i];
        data.pool[index].totalStaked = _user[user].totalStaked[i];
        data.pool[index].totalRewardsClaimed = _user[user].totalRewardsClaimed[i];
        data.pool[index].totalWithdrawn = _user[user].totalWithdrawn[i];

        uint256 stakes = _user[user].list[i].length;

        data.pool[index].stake = new userStakeView[](stakes);

        for (uint256 s; s < stakes; s++) {
          Stake memory stake = _user[user].pool[i][s];

          data.pool[index].stake[s] = userStakeView({
            created: stake.created,
            lockedUntil: stake.lockedUntil,
            lastAction: stake.lastAction,
            amount: stake.amount,
            claimed: stake.claimed,
            withdrawn: stake.withdrawn
          });
        }

        ++index;
      }
    }

    return data;
  }

  /// @notice Deposit and create a new stake
  /// @param poolId ID of the pool
  /// @param amount Desired amount to deposit
  function deposit(uint256 poolId, uint256 amount) external isPoolOpen(poolId) nonReEntrant {
    Pool storage pool = _pool[poolId];

    require(amount >= pool.minStake, "Insufficient deposit");

    bool txDeposit = pool.stakedToken.transferFrom(msg.sender, address(this), amount);
    require(txDeposit, "Transfer error");

    uint256 stakeId = _user[msg.sender].list[poolId].length;

    unchecked {
      if (pool.taxDeposit > 0) {
        uint256 tax = _percentage(amount, uint256(pool.taxDeposit));

        amount -= tax;
        pool.collectedTaxes[0] += tax;

        if (_treasury != address(0)) {
          bool txFee = pool.stakedToken.transfer(_treasury, tax);
          require(txFee, "Transfer error");
        }
      }

      if (!_user[msg.sender].exists) {
        _user[msg.sender].exists = true;
        _user[msg.sender].created = _timestamp();
      }

      if (pool.maxStake > 0) { require(_user[msg.sender].totalStaked[poolId] + amount <= pool.maxStake, "Exceeded"); }
      if (pool.maxTotalStaked > 0) { require(pool.totalStaked + amount <= pool.maxTotalStaked, "Exceeded"); }

      ++_user[msg.sender].active[poolId];

      require(_maxStakePerUser == 0 || _user[msg.sender].active[poolId] <= _maxStakePerUser, "Max. reached");

      Stake storage stake = _user[msg.sender].pool[poolId][stakeId];

      stake.exists = true;
      stake.created = _timestamp();
      stake.amount = amount;
      stake.lastAction = _timestamp();
      stake.lockedUntil = pool.lockupEnabled && pool.lockupPeriod > 0 ? _timestamp() + pool.lockupPeriod : 0;

      if (!pool.activeUser[msg.sender]) {
        ++pool.activeUsers;

        require(pool.maxUsers == 0 || pool.activeUsers <= pool.maxUsers, "Max. reached");

        pool.activeUser[msg.sender] = true;
        pool.users.push(msg.sender);

        if (!pool.user[msg.sender]) { pool.user[msg.sender] = true; }
      }

      _user[msg.sender].totalDeposited[poolId] += amount;
      _user[msg.sender].totalStaked[poolId] += amount;
      _user[msg.sender].list[poolId].push(stakeId);

      pool.totalDeposited += amount;
      pool.totalStaked += amount;
    }

    emit Deposit(msg.sender, poolId, stakeId, amount);
  }

  function _claim(address user, uint256 poolId, uint256 stakeId) private {
    Pool storage pool = _pool[poolId];
    Stake storage stake = _user[user].pool[poolId][stakeId];

    require(!stake.withdrawn, "Withdrawn");

    uint256 rewards = calculateRewards(user, poolId, stakeId);

    unchecked {
      require(stake.lastAction + pool.cooldownPeriod <= _timestamp(), "Cooldown");

      if (pool.taxClaim > 0) {
        uint256 tax = _percentage(rewards, uint256(pool.taxClaim));

        rewards -= tax;
        pool.collectedTaxes[1] += tax;

        if (_treasury != address(0)) {
          bool txFee = pool.rewardToken.transfer(_treasury, tax);
          require(txFee, "Transfer error");
        }
      }

      stake.lastAction = _timestamp();
      stake.claimed = rewards;

      _user[user].totalRewardsClaimed[poolId] += rewards;

      pool.totalRewardsClaimed += rewards;
      pool.rewardToken.transfer(user, rewards);
    }

    emit Claim(user, poolId, stakeId, rewards);
  }

  /// @notice Claim the rewards generated
  /// @param poolId ID of the pool
  /// @param stakeId ID of the stake
  function claim(uint256 poolId, uint256 stakeId) external isUser(msg.sender) isStake(poolId, stakeId) nonReEntrant {
    _claim(msg.sender, poolId, stakeId);
  }

  /// @notice Compound the rewards generated
  /// @param poolId ID of the pool
  /// @param stakeIds List of stake IDs
  function claim(uint256 poolId, uint256[] calldata stakeIds) external isUser(msg.sender) isPoolOpen(poolId) nonReEntrant {
    uint256 cnt = stakeIds.length;

    unchecked {
      for (uint256 i; i < cnt; i++) { _claim(msg.sender, poolId, stakeIds[i]); }
    }
  }

  function _compound(address user, uint256 poolId, uint256 stakeId) private {
    Pool storage pool = _pool[poolId];

    require(address(pool.stakedToken) == address(pool.rewardToken), "Unavailable");

    Stake storage stake = _user[user].pool[poolId][stakeId];

    require(!stake.withdrawn, "Withdrawn");

    uint256 rewards = calculateRewards(user, poolId, stakeId);

    unchecked {
      require(stake.lastAction + pool.cooldownPeriod <= _timestamp(), "Cooldown");

      if (pool.taxCompound > 0) {
        uint256 tax = _percentage(rewards, uint256(pool.taxCompound));

        rewards -= tax;
        pool.collectedTaxes[2] += tax;

        if (_treasury != address(0)) {
          bool txFee = pool.rewardToken.transfer(_treasury, tax);
          require(txFee, "Transfer error");
        }
      }

      if (pool.maxStake > 0) { require(_user[msg.sender].totalStaked[poolId] + rewards <= pool.maxStake, "Exceeded"); }
      if (pool.maxTotalStaked > 0) { require(pool.totalStaked + rewards <= pool.maxTotalStaked, "Exceeded"); }

      _user[user].totalRewardsClaimed[poolId] += rewards;
      _user[user].totalDeposited[poolId] += rewards;
      _user[user].totalStaked[poolId] += rewards;

      pool.totalRewardsClaimed += rewards;
      pool.totalDeposited += rewards;
      pool.totalStaked += rewards;

      stake.lastAction = _timestamp();
      stake.amount += rewards;
      stake.claimed += rewards;
    }

    emit Compound(user, poolId, stakeId, rewards);
  }

  /// @notice Compound the rewards generated
  /// @param poolId ID of the pool
  /// @param stakeId ID of the stake
  function compound(uint256 poolId, uint256 stakeId) external isUser(msg.sender) isStake(poolId, stakeId) nonReEntrant {
    _compound(msg.sender, poolId, stakeId);
  }

  /// @notice Compound the rewards generated
  /// @param poolId ID of the pool
  /// @param stakeIds List of stake IDs
  function compound(uint256 poolId, uint256[] calldata stakeIds) external isUser(msg.sender) isPoolOpen(poolId) nonReEntrant {
    uint256 cnt = stakeIds.length;

    unchecked {
      for (uint256 i; i < cnt; i++) { _compound(msg.sender, poolId, stakeIds[i]); }
    }
  }

  function _withdraw(address user, uint256 poolId, uint256 stakeId) private {
    Pool storage pool = _pool[poolId];
    Stake storage stake = _user[user].pool[poolId][stakeId];

    require(!stake.withdrawn, "Withdrawn");

    if (pool.lockupEnabled && !pool.allowEarlyUnstake && (stake.lockedUntil == 0 || stake.lockedUntil > _timestamp())) { revert("Locked"); }

    uint256 amount = stake.amount;

    unchecked {
      if (pool.lockupEnabled && pool.allowEarlyUnstake && (stake.lockedUntil == 0 || stake.lockedUntil > _timestamp())) {
        if (pool.earlyUnstakePenalty > 0) {
          uint256 penalty = _percentage(amount, uint256(pool.earlyUnstakePenalty));

          amount -= penalty;
          pool.collectedPenalties += penalty;

          if (_treasury != address(0)) {
            bool txPenalty = pool.stakedToken.transfer(_treasury, penalty);
            require(txPenalty, "Transfer error");
          }
        }
      } else {
        if (pool.taxWithdraw > 0) {
          uint256 taxWithdraw = _percentage(amount, uint256(pool.taxWithdraw));

          amount -= taxWithdraw;
          pool.collectedTaxes[3] += taxWithdraw;

          if (_treasury != address(0)) {
            bool txTaxWithdraw = pool.stakedToken.transfer(_treasury, taxWithdraw);
            require(txTaxWithdraw, "Transfer error");
          }
        }
      }

      uint256 rewards = calculateRewards(user, poolId, stakeId);

      if (pool.taxClaim > 0) {
        uint256 taxClaim = _percentage(rewards, uint256(pool.taxClaim));

        rewards -= taxClaim;
        pool.collectedTaxes[1] += taxClaim;

        if (_treasury != address(0)) {
          bool txTaxClaim = pool.rewardToken.transfer(_treasury, taxClaim);
          require(txTaxClaim, "Transfer error");
        }
      }

      stake.lockedUntil = 0;
      stake.lastAction = _timestamp();
      stake.claimed += rewards;
      stake.withdrawn = true;

      _user[user].totalStaked[poolId] -= stake.amount;
      _user[user].totalWithdrawn[poolId] += amount;
      _user[user].totalRewardsClaimed[poolId] += rewards;
      --_user[user].active[poolId];

      if (_user[user].totalStaked[poolId] == 0) {
        --pool.activeUsers;
        pool.activeUser[user] = false;
      }

      pool.totalStaked -= stake.amount;
      pool.totalWithdrawn += amount;
      pool.totalRewardsClaimed += rewards;

      pool.stakedToken.transfer(user, amount);
      pool.rewardToken.transfer(user, rewards);
    }

    emit Withdraw(user, poolId, stakeId, amount);
  }

  /// @notice Withdraw a stake
  /// @param poolId ID of the pool
  /// @param stakeId ID of the stake
  function withdraw(uint256 poolId, uint256 stakeId) external isUser(msg.sender) isStake(poolId, stakeId) nonReEntrant {
    _withdraw(msg.sender, poolId, stakeId);
  }

  /// @notice Withdraw multiple stakes
  /// @param poolId ID of the pool
  /// @param stakeIds List of stake IDs
  function withdraw(uint256 poolId, uint256[] calldata stakeIds) external isUser(msg.sender) isPoolOpen(poolId) nonReEntrant {
    uint256 cnt = stakeIds.length;

    unchecked {
      for (uint256 i; i < cnt; i++) { _withdraw(msg.sender, poolId, stakeIds[i]); }
    }
  }

  /// @notice Migrates an account to another address
  /// @param oldUser Address of the current user
  /// @param newUser Address of the target user
  function migrate(address oldUser, address newUser) external onlyOwner {
    require(newUser != address(0));
    require(!_user[newUser].exists, "User exists");

    uint256 cnt = _pools.length;
    uint256 totalStaked;

    _user[newUser].exists = true;
    _user[newUser].created = _timestamp();

    unchecked {
      for (uint256 i; i < cnt; i++) {
        Pool storage pool = _pool[i];

        if (!pool.activeUser[oldUser]) { continue; }

        pool.activeUser[oldUser] = false;
        pool.activeUser[newUser] = true;
        pool.users.push(newUser);

        totalStaked += _user[msg.sender].totalStaked[i];

        _user[newUser].totalDeposited[i] = _user[oldUser].totalDeposited[i];
        _user[newUser].totalStaked[i] = _user[oldUser].totalStaked[i];
        _user[newUser].totalRewardsClaimed[i] = _user[oldUser].totalRewardsClaimed[i];
        _user[newUser].totalWithdrawn[i] = _user[oldUser].totalWithdrawn[i];
        _user[newUser].totalDeposited[i] = _user[oldUser].totalDeposited[i];

        uint256[] memory list = _user[oldUser].list[i];
        uint256 scnt = list.length;

        for (uint256 s; s < scnt; s++) {
          _user[newUser].pool[i][s] = _user[oldUser].pool[i][s];

          delete _user[oldUser].pool[i][s];
        }

        _user[newUser].list[i] = _user[oldUser].list[i];
        _user[newUser].active[i] = _user[oldUser].active[i];

        delete _user[oldUser].list[i];
        delete _user[oldUser].active[i];
      }

      delete _user[oldUser];
    }

    require(totalStaked > 0, "Empty");

    delete _user[oldUser];

    emit Migrated(newUser, oldUser);
  }

  /// @notice Returns the current amount of rewards
  /// @param user Address of the user
  /// @param poolId ID of the pool
  /// @param stakeId ID of the stake
  function calculateRewards(address user, uint256 poolId, uint256 stakeId) public view isUser(user) isStake(poolId, stakeId) returns (uint256 rewards) {
    Pool storage pool = _pool[poolId];
    Stake memory stake = _user[user].pool[poolId][stakeId];

    if (stake.withdrawn) { return 0; }

    unchecked {
      uint32 timeElapsed = uint32(Math.min(pool.rewardPeriod, _timestamp() - stake.lastAction));

      rewards = _percentage(_percentage(stake.amount, uint256(pool.apy)) * uint256(timeElapsed) / 31556952, uint256(pool.ratio));
    }
  }

  /// @notice Returns the list of available pools
  function poolList() external view returns (PoolView[] memory list) {
    uint256 cnt = _pools.length;
    list = new PoolView[](cnt);

    unchecked {
      for (uint256 i; i < cnt; i++) {
        Pool storage pool = _pool[i];

        string memory stakedTokenSymbol = pool.stakedToken.symbol();
        string memory rewardTokenSymbol = address(pool.stakedToken) == address(pool.rewardToken) ? stakedTokenSymbol : pool.rewardToken.symbol();

        uint8 stakedTokenDecimals = pool.stakedToken.decimals();
        uint8 rewardTokenDecimals = address(pool.stakedToken) == address(pool.rewardToken) ? stakedTokenDecimals : pool.rewardToken.decimals();

        PoolView memory data = PoolView({
          open: pool.open,
          label: pool.label,
          created: pool.created,
          stakedToken: address(pool.stakedToken),
          stakedTokenSymbol: stakedTokenSymbol,
          stakedTokenDecimals: stakedTokenDecimals,
          rewardToken: address(pool.rewardToken),
          rewardTokenSymbol: rewardTokenSymbol,
          rewardTokenDecimals:rewardTokenDecimals,
          rewardPeriod: pool.rewardPeriod,
          apy: pool.apy,
          ratio: pool.ratio,
          taxDeposit: pool.taxDeposit,
          taxClaim: pool.taxClaim,
          taxCompound: pool.taxCompound,
          taxWithdraw: pool.taxWithdraw,
          allowEarlyUnstake: pool.allowEarlyUnstake,
          earlyUnstakePenalty: pool.earlyUnstakePenalty,
          lockupEnabled: pool.lockupEnabled,
          allowLockupPeriodChange: pool.allowLockupPeriodChange,
          lockupPeriod: pool.lockupPeriod,
          cooldownPeriod: pool.cooldownPeriod,
          activeUsers: pool.activeUsers,
          maxUsers: pool.maxUsers,
          minStake: pool.minStake,
          maxStake: pool.maxStake,
          maxTotalStaked: pool.maxTotalStaked,
          totalDeposited: pool.totalDeposited,
          totalStaked: pool.totalStaked,
          totalRewardsClaimed: pool.totalRewardsClaimed,
          totalWithdrawn: pool.totalWithdrawn,
          collectedTaxes: pool.collectedTaxes,
          collectedPenalties: pool.collectedPenalties
        });

        list[i] = data;
      }
    }
  }

  /// @notice Returns the list of users of a pool
  /// @param poolId ID of the pool
  function listPoolUsers(uint256 poolId) external view isPool(poolId) returns (address[] memory) {
    return _pool[poolId].users;
  }

  /// @notice Creates a new pool
  /// @dev Refer to the CF_Common.newPoolConfig struct
  /// @param _config ABI-encoded parameters
  function newPool(bytes calldata _config) external onlyOwner returns (uint256 poolId) {
    (newPoolConfig memory config) = abi.decode(_config, (newPoolConfig));

    if (config.stakedToken == address(0) || config.stakedToken == address(0xdEaD) || config.rewardToken == address(0) || config.rewardToken == address(0xdEaD)) { revert("Invalid token"); }

    require(config.apy > 0, "Invalid APY");
    require(config.rewardPeriod > 0);
    require(config.maxStake == 0 || config.maxStake >= config.minStake);

    unchecked {
      require(config.taxDeposit <= 100 * _denominator && config.taxClaim <= 100 * _denominator && config.taxCompound <= 100 * _denominator && config.taxWithdraw <= 100 * _denominator, "Tax exceeds 100%");

      if (config.allowEarlyUnstake) { require(config.earlyUnstakePenalty <= 100 * _denominator); }
    }

    poolId = _pools.length;

    Pool storage pool = _pool[poolId];
    pool.exists = true;
    pool.label = config.label;
    pool.ratio = config.stakedToken == config.rewardToken ? uint24(100 * _denominator) : config.ratio;
    pool.created = _timestamp();
    pool.stakedToken = IERC20(config.stakedToken);
    pool.rewardToken = IERC20(config.rewardToken);
    pool.rewardPeriod = config.rewardPeriod;
    pool.apy = config.apy;
    pool.taxDeposit = config.taxDeposit;
    pool.taxClaim = config.taxClaim;
    pool.taxCompound = config.taxCompound;
    pool.taxWithdraw = config.taxWithdraw;
    pool.allowEarlyUnstake = config.allowEarlyUnstake;
    pool.earlyUnstakePenalty = config.earlyUnstakePenalty;
    pool.lockupEnabled = config.lockupEnabled;
    pool.allowLockupPeriodChange = config.allowLockupPeriodChange;
    pool.lockupPeriod = config.lockupPeriod;
    pool.cooldownPeriod = config.cooldownPeriod;
    pool.maxUsers = config.maxUsers;
    pool.minStake = config.minStake;
    pool.maxStake = config.maxStake;
    pool.maxTotalStaked = config.maxTotalStaked;

    _pools.push(poolId);

    emit PoolAdded(poolId);
  }

  /// @notice Changes the configuration of an existing pool
  /// @dev Refer to the CF_Common.setPoolConfig struct
  /// @param poolId ID of the pool
  /// @param _config ABI-encoded parameters
  function setPool(uint256 poolId, bytes calldata _config) external onlyOwner isPool(poolId) {
    (setPoolConfig memory config) = abi.decode(_config, (setPoolConfig));

    require(config.maxStake == 0 || config.maxStake >= config.minStake);

    Pool storage pool = _pool[poolId];

    require(config.maxTotalStaked == 0 || config.maxTotalStaked >= pool.totalStaked, "Total staked higher");

    unchecked {
      require(config.taxDeposit <= 100 * _denominator && config.taxClaim <= 100 * _denominator && config.taxCompound <= 100 * _denominator && config.taxWithdraw <= 100 * _denominator, "Tax exceeds 100%");

      if (pool.allowEarlyUnstake) { require(config.earlyUnstakePenalty <= 100 * _denominator); }
    }

    bool updatePoolStakesLockupPeriod = pool.lockupEnabled && pool.allowLockupPeriodChange && pool.lockupPeriod != config.lockupPeriod;

    pool.label = config.label;
    pool.taxDeposit = config.taxDeposit;
    pool.taxClaim = config.taxClaim;
    pool.taxCompound = config.taxCompound;
    pool.taxWithdraw = config.taxWithdraw;
    pool.earlyUnstakePenalty = config.earlyUnstakePenalty;

    if (updatePoolStakesLockupPeriod) { pool.lockupPeriod = config.lockupPeriod; }

    pool.cooldownPeriod = config.cooldownPeriod;
    pool.maxUsers = config.maxUsers;
    pool.minStake = config.minStake;
    pool.maxStake = config.maxStake;
    pool.maxTotalStaked = config.maxTotalStaked;

    if (address(pool.stakedToken) != address(pool.rewardToken)) {
      require(config.ratio > 0);

      pool.ratio = config.ratio;
    }

    if (updatePoolStakesLockupPeriod) {
      unchecked {
        uint256 ucnt = pool.users.length;

        for (uint256 u; u < ucnt; u++) {
          address user = pool.users[u];

          if (!pool.activeUser[user]) { continue; }

          uint256 stakes = _user[user].list[poolId].length;

          for (uint256 s; s < stakes; s++) {
            Stake storage stake = _user[user].pool[poolId][s];

            stake.lockedUntil = pool.lockupPeriod > 0 ? stake.lastAction + pool.lockupPeriod : 0;
          }
        }
      }
    }

    emit PoolConfigChanged(poolId);
  }

  /// @notice Defines the label of a specific pool
  /// @param poolId ID of the pool
  /// @param label Label to be displayed
  function setPoolLabel(uint256 poolId, string calldata label) external onlyOwner isPool(poolId) {
    _pool[poolId].label = bytes32(abi.encodePacked(label));
  }

  /// @notice Defines the status of a specific pool
  /// @param poolId ID of the pool
  /// @param open True for open, False for closed
  function setPoolStatus(uint256 poolId, bool open) external onlyOwner isPool(poolId) {
    _pool[poolId].open = open;

    if (open) {
      emit PoolOpened(poolId);
    } else {
      emit PoolClosed(poolId);
    }
  }

  /// @notice Defines the ratio between staked and reward token
  /// @param poolId ID of the pool
  /// @param ratio Desired percentage to apply
  function setPoolTokenRatio(uint256 poolId, uint24 ratio) external onlyOwner isPool(poolId) {
    Pool storage pool = _pool[poolId];

    require(address(pool.stakedToken) != address(pool.rewardToken), "Unused");
    require(ratio > 0);

    pool.ratio = ratio;
  }

  /// @notice Defines the applied taxes of a specific pool
  /// @dev Percentages must be multiplied by denominator
  /// @param poolId ID of the pool
  /// @param taxDeposit Desired percentage to apply to deposits
  /// @param taxClaim Desired percentage to apply to claims
  /// @param taxCompound Desired percentage to apply to compounds
  /// @param taxWithdraw Desired percentage to apply to withdrawals
  function setPoolTaxes(uint256 poolId, uint24 taxDeposit, uint24 taxClaim, uint24 taxCompound, uint24 taxWithdraw) external onlyOwner isPool(poolId) {
    unchecked {
      require(taxDeposit <= 100 * _denominator && taxClaim <= 100 * _denominator && taxCompound <= 100 * _denominator && taxWithdraw <= 100 * _denominator, "Tax exceeds 100%");
    }

    Pool storage pool = _pool[poolId];

    pool.taxDeposit = taxDeposit;
    pool.taxClaim = taxClaim;
    pool.taxCompound = taxCompound;
    pool.taxWithdraw = taxWithdraw;

    emit TaxesChanged(poolId, taxDeposit, taxClaim, taxCompound, taxWithdraw);
  }

  /// @notice Defines the time the user has to wait between each claim/compound
  /// @param poolId ID of the pool
  /// @param time Time to wait between each claim/compound (in seconds)
  function setPoolCooldownPeriod(uint256 poolId, uint32 time) external onlyOwner isPool(poolId) {
    _pool[poolId].cooldownPeriod = time;

    emit CooldownPeriodChanged(poolId, time);
  }

  /// @notice Defines the min. and max. amounts per stake
  /// @param poolId ID of the pool
  /// @param minStake Min. amount per stake
  /// @param maxStake Max. amount per stake (0 for unlimited)
  function setPoolStakeAmount(uint256 poolId, uint256 minStake, uint256 maxStake) external onlyOwner isPool(poolId) {
    require(maxStake == 0 || maxStake > minStake);

    Pool storage pool = _pool[poolId];

    pool.minStake = minStake;
    pool.maxStake = maxStake;

    emit StakeAmountChanged(poolId, minStake, maxStake);
  }

  /// @notice Defines a limit of users
  /// @param poolId ID of the pool
  /// @param maxUsers Max. allowed users (0 for unlimited)
  function setPoolMaxUsers(uint256 poolId, uint256 maxUsers) external onlyOwner isPool(poolId) {
    Pool storage pool = _pool[poolId];

    require(maxUsers == 0 || maxUsers >= pool.activeUsers, "Max. reached");

    pool.maxUsers = maxUsers;

    emit MaxUsersChanged(poolId, maxUsers);
  }

  /// @notice Defines a limit on the total amount staked
  /// @param poolId ID of the pool
  /// @param value Max. total amount (0 for unlimited)
  function setPoolMaxTotalStaked(uint256 poolId, uint256 value) external onlyOwner isPool(poolId) {
    Pool storage pool = _pool[poolId];

    require(value == 0 || value >= pool.totalStaked, "Total staked higher");

    pool.maxTotalStaked = value;

    emit MaxTotalStakedChanged(poolId, value);
  }

  /// @notice Defines the address of the treasury where to receive taxes
  /// @param treasury Address of the treasury
  function setTreasury(address treasury) external onlyOwner {
    _treasury = treasury;
  }

  /// @notice Defines the maximum number of stakes per user
  /// @dev Specify 25 to 50 to avoid possible gas limits in the future
  /// @param stakes Max. number of stakes per user
  function setMaxStakePerUser(uint256 stakes) external onlyOwner {
    _maxStakePerUser = stakes;
  }

  /// @notice Injects funds to a specific pool
  /// @dev Amount to be deposited must be approved previously
  /// @param poolId ID of the pool
  /// @param amount Amount to be deposited
  function addFunds(uint256 poolId, uint256 amount) external onlyOwner isPool(poolId) {
    require(amount > 0);

    Pool storage pool = _pool[poolId];

    bool txFund = IERC20(pool.rewardToken).transferFrom(msg.sender, address(this), amount);
    require(txFund, "Transfer error");
  }

  /// @notice Recovers a misplaced amount of native tokens sitting in the contract balance
  /// @param to Recipient
  /// @param amount Amount of native tokens to be transferred
  function withdrawNative(address payable to, uint256 amount) external onlyOwner {
    (bool success, ) = to.call{ value: amount }("");
    require(success, "Transfer error");

    emit WithdrawnNative(to, amount, msg.sender);
  }

  /// @notice Recovers a misplaced amount of an ERC-20 token sitting in the contract balance
  /// @dev Beware of scam tokens!
  /// @dev Note that recovery of amounts allocated to specific pools could prevent users from claiming/withdrawing their rewards
  /// @param token Address of the ERC-20 token
  /// @param to Recipient
  /// @param amount Amount to be transferred
  function withdrawERC20(address token, address to, uint256 amount) external onlyOwner {
    bool success = IERC20(token).transfer(to, amount);
    require(success, "Transfer error");

    emit WithdrawnERC20(token, to, amount, msg.sender);
  }

  /// @notice Returns basic information about this Smart-Contract
  function info() external view returns (address owner, address treasury, string memory version) {
    return (_owner, _treasury, _version);
  }
}


Read Contract

calculateRewards 0xd72b08c6 → uint256
denominator 0x96ce0795 → uint24
info 0x370158ea → address, address, string
listPoolUsers 0x389f5763 → address[]
owner 0x8da5cb5b → address
poolList 0xff657f55 → tuple[]
userDetails 0x48dec2a7 → tuple
version 0x54fd4d50 → string

Write Contract 25 functions

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

addFunds 0x85f45250
uint256 poolId
uint256 amount
claim 0xb1b66652
uint256 poolId
uint256[] stakeIds
claim 0xc3490263
uint256 poolId
uint256 stakeId
compound 0x64e0e60d
uint256 poolId
uint256[] stakeIds
compound 0xbff1208d
uint256 poolId
uint256 stakeId
deposit 0xe2bbb158
uint256 poolId
uint256 amount
migrate 0x1068361f
address oldUser
address newUser
newPool 0x984d9068
bytes _config
returns: uint256
renounceOwnership 0x715018a6
No parameters
setMaxStakePerUser 0x57c81b92
uint256 stakes
setPool 0x24555fb4
uint256 poolId
bytes _config
setPoolCooldownPeriod 0xa91cf634
uint256 poolId
uint32 time
setPoolLabel 0x60761764
uint256 poolId
string label
setPoolMaxTotalStaked 0xc006cff8
uint256 poolId
uint256 value
setPoolMaxUsers 0xdcc19b39
uint256 poolId
uint256 maxUsers
setPoolStakeAmount 0xd43462d7
uint256 poolId
uint256 minStake
uint256 maxStake
setPoolStatus 0xbbcaf3fe
uint256 poolId
bool open
setPoolTaxes 0xbe116fcf
uint256 poolId
uint24 taxDeposit
uint24 taxClaim
uint24 taxCompound
uint24 taxWithdraw
setPoolTokenRatio 0xad2cfde0
uint256 poolId
uint24 ratio
setTreasury 0xf0f44260
address treasury
transferOwnership 0xf2fde38b
address newOwner
withdraw 0x441a3e70
uint256 poolId
uint256 stakeId
withdraw 0x5915d806
uint256 poolId
uint256[] stakeIds
withdrawERC20 0x44004cc1
address token
address to
uint256 amount
withdrawNative 0x07b18bde
address to
uint256 amount

Recent Transactions

No transactions found for this address