Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x835b1C24462B6A8D433ce1f8B3e22bbcE5682F8b
Balance 0 ETH
Nonce 2
Code Size 16019 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

16019 bytes
0x60806040526004361061021d575f3560e01c806380ae2e5c1161011d57806380ae2e5c1461059b5780638d8f3730146105ce57806398ae1f52146105e35780639c823f37146106165780639f08e497146106355780639fc4973414610654578063a6c3ef8b14610682578063b5ed298a146106a1578063bc25cf77146106c0578063c8a7caac146106df578063caf44bd6146106fe578063d3573a331461071d578063d5ca79701461073c578063d64c34fc14610751578063d682e30a14610765578063d850e31914610779578063df61427e14610798578063e3b9bac8146107b7578063e5e933d3146107d6578063ee97f7f3146107ea578063f2bf69f614610808578063f61c266b14610834578063fcbc1d6014610848575f80fd5b8062445e4b14610268578063019dbb631461028957806304b473bd146102be57806310d2b492146102dd578063170c95b71461030957806317f8abb014610349578063241d8afe146103685780633684a72b1461039c5780633f6f34de146103bb5780633f828600146103e8578063438e55a0146104075780634e71e0c8146104265780635c388ca61461043a5780635d99ba831461044e5780636109cdbf1461046d57806366b2d8f91461048c5780636797d24c146104b8578063698766ee146104ec578063715018a61461050b578063765d8b2e1461051f57806378b7d4551461053e5780637aeaa75d1461055d5780637afcdc3c1461057c575f80fd5b366102645761022a61087b565b604080513481523360208201527f49109bdae8e3bbdcbeb7fe5b25b1c75a6bc84fd3f27c6ee0633d41fe197f2aba910160405180910390a1005b5f80fd5b348015610273575f80fd5b506102876102823660046133a7565b6108ac565b005b348015610294575f80fd5b506001546102a990600160a01b900460ff1681565b60405190151581526020015b60405180910390f35b3480156102c9575f80fd5b506102876102d8366004613402565b61095c565b3480156102e8575f80fd5b506102fc6102f736600461342c565b610a05565b6040516102b59190613447565b348015610314575f80fd5b5061033c7f00000000000000000000000044087e105137a5095c008aab6a6530182821f2f081565b6040516102b59190613493565b348015610354575f80fd5b50610287610363366004613402565b610a7b565b348015610373575f80fd5b5061033c61038236600461342c565b60036020525f90815260409020546001600160a01b031681565b3480156103a7575f80fd5b506102876103b63660046134b4565b610b16565b3480156103c6575f80fd5b506103da6103d53660046134ff565b610b59565b6040519081526020016102b5565b3480156103f3575f80fd5b5061028761040236600461342c565b610d7f565b348015610412575f80fd5b5061028761042136600461354f565b610dc8565b348015610431575f80fd5b50610287610e0b565b348015610445575f80fd5b506103da610e26565b348015610459575f80fd5b5061028761046836600461342c565b610fd2565b348015610478575f80fd5b506102876104873660046133a7565b61104c565b348015610497575f80fd5b506104ab6104a636600461342c565b611113565b6040516102b59190613566565b3480156104c3575f80fd5b506104d76104d2366004613402565b6111ae565b604080519283526020830191909152016102b5565b3480156104f7575f80fd5b506102876105063660046135a6565b61133f565b348015610516575f80fd5b50610287611460565b34801561052a575f80fd5b5060085461033c906001600160a01b031681565b348015610549575f80fd5b506103da61055836600461360c565b6114ac565b348015610568575f80fd5b5061028761057736600461364a565b6117ff565b348015610587575f80fd5b50610287610596366004613737565b611a78565b3480156105a6575f80fd5b5061033c7f0000000000000000000000008c237520a8e14d658170a633d96f8e80764433b981565b3480156105d9575f80fd5b506103da60075481565b3480156105ee575f80fd5b5061033c7f0000000000000000000000007bb12bcac1108ff996a3794ed6a77dac5565fec881565b348015610621575f80fd5b506102876106303660046134b4565b611e11565b348015610640575f80fd5b506102a961064f36600461342c565b611e4d565b34801561065f575f80fd5b506102a961066e36600461342c565b60056020525f908152604090205460ff1681565b34801561068d575f80fd5b5061028761069c36600461360c565b611ed7565b3480156106ac575f80fd5b506102876106bb36600461342c565b611f3f565b3480156106cb575f80fd5b506103da6106da36600461342c565b611fb9565b3480156106ea575f80fd5b506102876106f9366004613402565b612129565b348015610709575f80fd5b506102876107183660046137b5565b6121db565b348015610728575f80fd5b5060015461033c906001600160a01b031681565b348015610747575f80fd5b506103da60025481565b34801561075c575f80fd5b506103da61227f565b348015610770575f80fd5b506006546103da565b348015610784575f80fd5b5061033c61079336600461354f565b61228d565b3480156107a3575f80fd5b506102876107b2366004613402565b6122b5565b3480156107c2575f80fd5b506102876107d1366004613894565b612307565b3480156107e1575f80fd5b50610287612518565b3480156107f5575f80fd5b505f5461033c906001600160a01b031681565b348015610813575f80fd5b5061082761082236600461342c565b61259e565b6040516102b59190613973565b34801561083f575f80fd5b506103da612606565b348015610853575f80fd5b5061033c7f0000000000000000000000004f30a9d41b80ecc5b94306ab4364951ae317021081565b60018054600160a01b900460ff16151590036108aa5760405163012a9bc160e01b815260040160405180910390fd5b565b6108b461260f565b6008545f54604051630f44fe1d60e21b81526001600160a01b0392831692633d13f874926108ed929116908790879087906004016139da565b5f604051808303815f87803b158015610904575f80fd5b505af1158015610916573d5f803e3d5ffd5b505050507ff50d70ea1da361101e246009eff066a75f0618b780f16e1314d100b0d324b37f8383834260405161094f9493929190613a01565b60405180910390a1505050565b8161096681612631565b6001600160a01b0383165f9081526004602052604090206002810180546109b39186918690811061099957610999613a2b565b5f918252602090912001546001600160a01b03163061266d565b8160010184815481106109c8576109c8613a2b565b905f5260205f2090600291828204019190066010026101000a8154816001600160801b0302191690836001600160801b0316021790555050505050565b6001600160a01b0381165f90815260046020908152604091829020600201805483518184028101840190945280845260609392830182828015610a6f57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610a51575b50505050509050919050565b610a83612682565b6001600160a01b038083165f908152600360205260409020541680610abb57604051630d23cf4160e11b815260040160405180910390fd5b604051638caad7b560e01b8152600481018390526001600160a01b03821690638caad7b5906024015b5f604051808303815f87803b158015610afb575f80fd5b505af1158015610b0d573d5f803e3d5ffd5b50505050505050565b610b1e612682565b5f610b28836126ae565b604051633951707760e01b815283151560048201529091506001600160a01b03821690633951707790602401610ae4565b5f610b62612682565b610b6a612518565b5f610b736126eb565b90505f83610b8957610b8486612707565b610b8b565b815b905081816001600160801b03161015610bb757604051636badcecf60e01b815260040160405180910390fd5b8615610c3d57610c087f000000000000000000000000808507121b80c02388fad14726482e061b8da8277f0000000000000000000000004f30a9d41b80ecc5b94306ab4364951ae317021089612741565b8415155f03610c3d57610c3d7f000000000000000000000000808507121b80c02388fad14726482e061b8da82733308a6127aa565b6040516364090f6160e11b81526001600160801b038089166004830152821660248201527f0000000000000000000000004f30a9d41b80ecc5b94306ab4364951ae31702106001600160a01b03169063c8121ec2906044016020604051808303815f875af1158015610cb1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cd59190613a3f565b6001600160801b03169250610ce8612518565b8415155f03610cf8575050610d77565b8615610d15578660025f828254610d0f9190613a6e565b90915550505b604080518881526001600160801b0383166020820152908101849052851515606082015284151560808201524260a08201527f81c3ffd68d2582ce8b110372b88b1620a58f73a45fb2fa70a32000c1f411037b9060c00160405180910390a150505b949350505050565b80610d8981612631565b6001600160a01b0382165f908152600460205260408120600201545b80821015610dc257610db7848361095c565b816001019150610da5565b50505050565b610dd0612682565b60078190556040518181527f3ee3809877d53d55716573bfb8d95c61d9bbd6eb4785bf652ede115adb0f87c19060200160405180910390a150565b610e136127e9565b5f80546001600160a01b03191633179055565b5f610e2f612682565b7f000000000000000000000000000000000000000000000000000000000000000115155f03610ed45750600280545f918290559054610e99907f000000000000000000000000808507121b80c02388fad14726482e061b8da827906001600160a01b031683612816565b604080518281524260208201527ffb86642c6ff183cbd0d7b3c84eff3ef09ab5f598dcf85a45790297f3e5072817910160405180910390a190565b42610edd6126eb565b1115610efc5760405163d0404f8560e01b815260040160405180910390fd5b610f04612518565b7f0000000000000000000000004f30a9d41b80ecc5b94306ab4364951ae31702106001600160a01b0316633ccfd60b6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015610f61573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f859190613a3f565b5f546001600160801b03919091169150610fca907f000000000000000000000000808507121b80c02388fad14726482e061b8da827906001600160a01b031683612816565b610e99612518565b80610fdc81612631565b6001600160a01b0382165f90815260046020526040902060028101546001600160401b0381111561100f5761100f613681565b604051908082528060200260200182016040528015611038578160200160208202803683370190505b508051610dc2918391602090910190613200565b6040516253f6a760e41b81526001600160a01b037f0000000000000000000000008c237520a8e14d658170a633d96f8e80764433b9169063053f6a709061109d9030908790879087906004016139da565b6020604051808303815f875af11580156110b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110dd9190613a81565b507f7dae5ae135d483810fba324b0121ba1b97bd34e06e2c8449ba001c42df198db18383834260405161094f9493929190613a01565b6001600160a01b0381165f90815260046020908152604091829020600101805483518184028101840190945280845260609392830182828015610a6f57602002820191905f5260205f20905f905b82829054906101000a90046001600160801b03166001600160801b031681526020019060100190602082600f01049283019260010382029150808411611161575094979650505050505050565b5f80836111ba81612835565b835f036111da57604051639811e0c760e01b815260040160405180910390fd5b6001600160a01b038086165f908152600360205260408120549091169061122a7f000000000000000000000000808507121b80c02388fad14726482e061b8da82761122584896128b7565b61294f565b90508060025f82825461123d9190613a98565b9091555061126f90507f000000000000000000000000808507121b80c02388fad14726482e061b8da8273330846127aa565b604051633e87f6d560e11b8152600481018790525f906001600160a01b03841690637d0fedaa906024016020604051808303815f875af11580156112b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112d99190613a81565b90506112e6883383612816565b60408051888152602081018490529081018290526001600160a01b038916907f049425cdb07b8722657d13dbc0cdaa252f471025bd8fd8455486016e71df972e9060600160405180910390a29097909650945050505050565b611347612682565b8083146113675760405163251f56a160e21b815260040160405180910390fd5b5f81815b818310156113af5784848481811061138557611385613a2b565b905060200201602081019061139a9190613ac1565b6001909301926001600160401b03160161136b565b670de0b6b3a76400008111156113d85760405163940addc760e01b815260040160405180910390fd5b6040516334c3b37760e11b81526001600160a01b037f00000000000000000000000044087e105137a5095c008aab6a6530182821f2f0169063698766ee9061142a908a908a908a908a90600401613ada565b5f604051808303815f87803b158015611441575f80fd5b505af1158015611453573d5f803e3d5ffd5b5050505050505050505050565b611468612682565b5f80546001600160a01b0319908116825560018054909116905560405133917f6172baf984ea013d88b784409f46655b96ba7f2ff91bca1ac9bcd27b113e6eb091a2565b5f836114b781612835565b6001600160a01b0385165f908152600460209081526040808320815181546080948102820185019093526060810183815290939192849284919084018282801561151e57602002820191905f5260205f20905b81548152602001906001019080831161150a575b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156115a557602002820191905f5260205f20905f905b82829054906101000a90046001600160801b03166001600160801b031681526020019060100190602082600f010492830192600103820291508084116115625790505b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561160557602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116115e7575b50505050508152505090505f61161f8260400151876129ac565b905084825f0151828151811061163757611637613a2b565b6020026020010151101561165e57604051632d23af9d60e21b815260040160405180910390fd5b5f61166d8861122589896128b7565b905085835f0151838151811061168557611685613a2b565b602002602001018181516116999190613a6e565b9052506001600160a01b0388165f9081526004602090815260409091208451805186936116ca928492910190613200565b5060208281015180516116e39260018501920190613249565b50604082015180516116ff9160028401916020909101906132f9565b5090505061170f883330846127aa565b6001600160a01b038881165f9081526003602052604090819020549051636ae55c3f60e01b815260048101849052911690636ae55c3f906024015f604051808303815f87803b158015611760575f80fd5b505af1158015611772573d5f803e3d5ffd5b5050505061179e8360400151838151811061178f5761178f613a2b565b60200260200101513388612816565b866001600160a01b0316886001600160a01b03167f7497b44341cf7a330eb32a7dedfb6e54b3e0ba937271da2d52025bd49667135488846040516117ec929190918252602082015260400190565b60405180910390a3979650505050505050565b8261180981612631565b6001600160a01b0384165f908152600460209081526040808320815181546080948102820185019093526060810183815290939192849284919084018282801561187057602002820191905f5260205f20905b81548152602001906001019080831161185c575b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156118f757602002820191905f5260205f20905f905b82829054906101000a90046001600160801b03166001600160801b031681526020019060100190602082600f010492830192600103820291508084116118b45790505b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561195757602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611939575b50505050508152505090505f8082604001515190505b808210156119c55785858381811061198757611987613a2b565b90506020020135835f015183815181106119a3576119a3613a2b565b602002602001018181516119b79190613a98565b90525060019091019061196d565b6001600160a01b0387165f9081526004602090815260409091208451805186936119f3928492910190613200565b506020828101518051611a0c9260018501920190613249565b5060408201518051611a289160028401916020909101906132f9565b50905050866001600160a01b03167f501c57a5a0f2fe1ea61d8d78bca856d5aa22562392484491e7c297941464b34f8787604051611a67929190613b6d565b60405180910390a250505050505050565b611a80612682565b6001600160a01b038481165f908152600360205260409020541615611ab85760405163a741a04560e01b815260040160405180910390fd5b602a611ac360065490565b03611ae0576040516274618b60e51b815260040160405180910390fd5b6001600160a01b038416611b0757604051630d23cf4160e11b815260040160405180910390fd5b6040516304fda39f60e21b81525f906001600160a01b037f0000000000000000000000007bb12bcac1108ff996a3794ed6a77dac5565fec816906313f68e7c90611b5b908890889088908890600401613bcd565b6020604051808303815f875af1158015611b77573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b9b9190613c18565b6001600160a01b038681165f90815260036020526040902080546001600160a01b0319169183169190911790559050611bdc85611bd781612a19565b612a7d565b6001600160a01b0385165f9081526004602052604090206002810154806001600160401b03811115611c1057611c10613681565b604051908082528060200260200182016040528015611c39578160200160208202803683370190505b508051611c50916001850191602090910190613249565b50806001600160401b03811115611c6957611c69613681565b604051908082528060200260200182016040528015611c92578160200160208202803683370190505b508051611ca6918491602090910190613200565b505f5b81811015611d66575f836002018281548110611cc757611cc7613a2b565b5f918252602090912001546001600160a01b03169050611ce889823061266d565b846001018381548110611cfd57611cfd613a2b565b905f5260205f2090600291828204019190066010026101000a8154816001600160801b0302191690836001600160801b031602179055505f845f018381548110611d4957611d49613a2b565b5f91825260209091200155611d5d81612ab0565b50600101611ca9565b611d6f88612ab0565b60068054600180820183555f929092527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b0319166001600160a01b038b16179055611dc790899030906121db565b836001600160a01b0316886001600160a01b03167fa832978fceae1f879475bdadef75ee695f5ab7d0d2635bed35d2e9282595352e60405160405180910390a35050505050505050565b611e19612682565b5f611e23836126ae565b6001600160a01b03165f908152600560205260409020805460ff1916921515929092179091555050565b5f81611e5881612631565b5f611e6284612a19565b9050611e6e8482612b64565b1515600103611e80575f925050611ed1565b611e8a8482612a7d565b836001600160a01b03167f096e937b1b3283a0a67ea594d71f0c599b007cc6330f6eb1cfe70e3c455791e782604051611ec39190613447565b60405180910390a260019250505b50919050565b82611ee181612631565b611eec848484612816565b826001600160a01b0316846001600160a01b03167f31947ad95728f2ef65a83a94d3cba12bdc654e728f65f4e91bca53ea5586085f84604051611f3191815260200190565b60405180910390a350505050565b611f47612682565b6001600160a01b038116611f6e5760405163f2365b5b60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907f322fd6444c59daffa82e4689b7685b6fafc6109a1eff8a6ca10c5a8e3206cda1905f90a350565b6001600160a01b038082165f9081526003602052604081205490911680611ff357604051630d23cf4160e11b815260040160405180910390fd5b6040516370a0823160e01b81525f906001600160a01b038516906370a0823190612021903090600401613493565b602060405180830381865afa15801561203c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120609190613a81565b90505f826001600160a01b0316630cd107da6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561209f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120c39190613a81565b90506120d0816001613a98565b8210156120f0576040516316ed654560e31b815260040160405180910390fd5b5f6120fb8284613a6e565b612106906001613a98565b5f549091506121209087906001600160a01b031683612816565b95945050505050565b612131612682565b5f61213b836126ae565b60405163e929d66960e01b8152600481018490529091506001600160a01b0382169063e929d669906024015f604051808303815f87803b15801561217d575f80fd5b505af115801561218f573d5f803e3d5ffd5b50505050826001600160a01b03167f93093390567ab17f0424ef1af14d90a4e2d60ed10df4054eadbd61a400e269c0836040516121ce91815260200190565b60405180910390a2505050565b6121e3612682565b6001600160a01b038084165f90815260036020526040902054168061221b57604051630d23cf4160e11b815260040160405180910390fd5b60405163112d197560e11b81526001600160a01b038481166004830152831515602483015282169063225a32ea906044015f604051808303815f87803b158015612263575f80fd5b505af1158015612275573d5f803e3d5ffd5b5050505050505050565b5f612288612bd6565b905090565b6006818154811061229c575f80fd5b5f918252602090912001546001600160a01b0316905081565b6122bd612682565b60018054600160a01b900460ff16151590036122ec5760405163012a9bc160e01b815260040160405180910390fd5b6122f68282612bef565b50506001805460ff60a01b19169055565b61230f612682565b8151815181146123325760405163251f56a160e21b815260040160405180910390fd5b5f61233b612ca3565b90505f805b838210156124e95784828151811061235a5761235a613a2b565b602002602001015190505f6001600160a01b0316816001600160a01b0316036123965760405163d92e233d60e01b815260040160405180910390fd5b306001600160a01b038216036123bf57604051633f89638160e11b815260040160405180910390fd5b60048683815181106123d3576123d3613a2b565b60200260200101515110156124025760405163b5b4301960e01b81526004810183905260240160405180910390fd5b61242486838151811061241757612417613a2b565b6020026020010151612ded565b15156001036124465760405163853e38d360e01b815260040160405180910390fd5b5f816001600160a01b031687848151811061246357612463613a2b565b60200260200101516040516124789190613c33565b5f604051808303815f865af19150503d805f81146124b1576040519150601f19603f3d011682016040523d82523d5f602084013e6124b6565b606091505b50909150508015155f036124dd57604051630d04919960e11b815260040160405180910390fd5b82600101925050612340565b826124f2612ca3565b1461251057604051632b582cb960e21b815260040160405180910390fd5b505050505050565b6006545f905b8082101561259a575f6006838154811061253a5761253a613a2b565b5f9182526020808320909101546001600160a01b0390811680845260038352604080852054909216845260059092529091205460019485019491925060ff16151514151560010361258b575061251e565b61259481612835565b5061251e565b5050565b6001600160a01b0381165f90815260046020908152604091829020805483518184028101840190945280845260609392830182828015610a6f57602002820191905f5260205f20905b8154815260200190600101908083116125e75750505050509050919050565b5f6122886126eb565b61a4b146146108aa576040516323a7aa6760e11b815260040160405180910390fd5b6001600160a01b038181165f9081526003602052604090205416331461266a57604051631eb49d6d60e11b815260040160405180910390fd5b50565b5f612679848484612e36565b51949350505050565b5f546001600160a01b0316330361269557565b604051635a7617f960e11b815260040160405180910390fd5b6001600160a01b038082165f9081526003602052604090205416806126e657604051630d23cf4160e11b815260040160405180910390fd5b919050565b5f6126f530612eb6565b602001516001600160801b0316905090565b5f8062093a806127178142613c4e565b6127219190613c6d565b905061273062093a8084613c84565b61273a9082613caf565b9392505050565b6001600160a01b03821661275457505050565b610dc28363095ea7b360e01b8484604051602401612773929190613cd6565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f51565b6040516001600160a01b03808516602483015283166044820152606481018290526127e29085906323b872dd60e01b90608401612773565b5050505050565b6001546001600160a01b031633036127fd57565b6040516379543eaf60e11b815260040160405180910390fd5b610dc28363a9059cbb60e01b8484604051602401612773929190613cd6565b6001600160a01b038082165f90815260036020526040902054168061286d57604051630d23cf4160e11b815260040160405180910390fd5b806001600160a01b031663753d02a16040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156128a5575f80fd5b505af1158015612510573d5f803e3d5ffd5b604051630e8f811d60e41b81525f906001600160a01b037f000000000000000000000000896fc8ffc11cda80cf40c373afa9a22d6e05f2d3169063e8f811d0906129079086908690600401613cd6565b602060405180830381865afa158015612922573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129469190613a81565b90505b92915050565b5f80620f4240600754620f42406129669190613a6e565b6129709085613c6d565b61297a9190613c4e565b90506402540be4008110156129a257604051639a721da360e01b815260040160405180910390fd5b610d778482613006565b81515f9081905b80821015612a0057836001600160a01b03168583815181106129d7576129d7613a2b565b60200260200101516001600160a01b0316036129f557509050612949565b8160010191506129b3565b60405163c5723b5160e01b815260040160405180910390fd5b6060816001600160a01b031663c4f59f9b6040518163ffffffff1660e01b81526004015f60405180830381865afa158015612a56573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526129499190810190613cef565b6001600160a01b0382165f9081526004602090815260409091208251612aab926002909201918401906132f9565b505050565b604051630fea45cd60e11b81525f907f000000000000000000000000896fc8ffc11cda80cf40c373afa9a22d6e05f2d36001600160a01b031690631fd48b9a90612afe908590600401613493565b602060405180830381865afa158015612b19573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b3d9190613c18565b6001600160a01b03160361266a57604051630d23cf4160e11b815260040160405180910390fd5b6001600160a01b0382165f9081526004602090815260408083209051612b909260029092019101613d83565b6040516020818303038152906040528051906020012082604051602001612bb79190613447565b6040516020818303038152906040528051906020012014905092915050565b5f612be030612eb6565b516001600160801b0316919050565b80471015612c105760405163617ab12d60e11b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b1790556040515f906001600160a01b0384169083908381818185875af1925050503d805f8114612c6b576040519150601f19603f3d011682016040523d82523d5f602084013e612c70565b606091505b50506001805460ff60a01b1916905590508015155f03612aab5760405163120086e360e11b815260040160405180910390fd5b5f807f000000000000000000000000808507121b80c02388fad14726482e061b8da8276001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612cf19190613493565b602060405180830381865afa158015612d0c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d309190613a81565b6040515f602082018190526034820181905291925060540160408051601f19818403018152828252805160209182012090830152810183905260600160408051601f1981840301815291905280516020909101206006549091505f9081905b80831015612de35760068381548110612daa57612daa613a2b565b5f918252602090912001546001600160a01b03169150612dca8285613056565b9350612dd68483613163565b9350826001019250612d8f565b5091949350505050565b60208101515f9063f6a1584d60e01b6001600160e01b0319821601612e155750600192915050565b632afa533160e01b6001600160e01b0319821601611ed15750600192915050565b6040805180820182525f8082526020820152905163172eb6f960e21b81526001600160a01b0384811660048301528381166024830152851690635cbadbe4906044016040805180830381865afa158015612e92573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d779190613e28565b6040805180820182525f808252602082015290516332dad3cf60e21b81527f0000000000000000000000004f30a9d41b80ecc5b94306ab4364951ae31702106001600160a01b03169063cb6b4f3c90612f13908590600401613493565b6040805180830381865afa158015612f2d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129499190613e28565b5f805f846001600160a01b031684604051612f6c9190613c33565b5f604051808303815f865af19150503d805f8114612fa5576040519150601f19603f3d011682016040523d82523d5f602084013e612faa565b606091505b50915091505f81515f1480612fce575081806020019051810190612fce9190613e42565b90508215155f03612fdd575f80fd5b828015612fe75750805b8015612ffc57505f866001600160a01b03163b115b9695505050505050565b6040516326a7a5ed60e21b81525f906001600160a01b037f000000000000000000000000896fc8ffc11cda80cf40c373afa9a22d6e05f2d31690639a9e97b4906129079086908690600401613cd6565b6001600160a01b0382165f908152600460209081526040808320600201805482518185028101850190935280835284938301828280156130bd57602002820191905f5260205f20905b81546001600160a01b0316815260019091019060200180831161309f575b505083519394505f925050505b81811015613159577f000000000000000000000000808507121b80c02388fad14726482e061b8da8276001600160a01b031683828151811061310e5761310e613a2b565b60200260200101516001600160a01b03160361312c576001016130ca565b61314f8584838151811061314257613142613a2b565b6020026020010151613163565b94506001016130ca565b5092949350505050565b5f82826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016131919190613493565b602060405180830381865afa1580156131ac573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131d09190613a81565b60408051602081019390935282015260600160405160208183030381529060405280519060200120905092915050565b828054828255905f5260205f20908101928215613239579160200282015b8281111561323957825182559160200191906001019061321e565b5061324592915061334c565b5090565b828054828255905f5260205f2090600101600290048101928215613239579160200282015f5b838211156132b957835183826101000a8154816001600160801b0302191690836001600160801b031602179055509260200192601001602081600f0104928301926001030261326f565b80156132ec5782816101000a8154906001600160801b030219169055601001602081600f010492830192600103026132b9565b505061324592915061334c565b828054828255905f5260205f20908101928215613239579160200282015b8281111561323957825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613317565b5b80821115613245575f815560010161334d565b5f8083601f840112613370575f80fd5b5081356001600160401b03811115613386575f80fd5b6020830191508360208260051b85010111156133a0575f80fd5b9250929050565b5f805f604084860312156133b9575f80fd5b8335925060208401356001600160401b038111156133d5575f80fd5b6133e186828701613360565b9497909650939450505050565b6001600160a01b038116811461266a575f80fd5b5f8060408385031215613413575f80fd5b823561341e816133ee565b946020939093013593505050565b5f6020828403121561343c575f80fd5b813561273a816133ee565b602080825282518282018190525f9190848201906040850190845b818110156134875783516001600160a01b031683529284019291840191600101613462565b50909695505050505050565b6001600160a01b0391909116815260200190565b801515811461266a575f80fd5b5f80604083850312156134c5575f80fd5b82356134d0816133ee565b915060208301356134e0816134a7565b809150509250929050565b6001600160801b038116811461266a575f80fd5b5f805f8060808587031215613512575f80fd5b843593506020850135613524816134eb565b92506040850135613534816134a7565b91506060850135613544816134a7565b939692955090935050565b5f6020828403121561355f575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b818110156134875783516001600160801b031683529284019291840191600101613581565b5f805f80604085870312156135b9575f80fd5b84356001600160401b03808211156135cf575f80fd5b6135db88838901613360565b909650945060208701359150808211156135f3575f80fd5b5061360087828801613360565b95989497509550505050565b5f805f6060848603121561361e575f80fd5b8335613629816133ee565b92506020840135613639816133ee565b929592945050506040919091013590565b5f805f6040848603121561365c575f80fd5b8335613667816133ee565b925060208401356001600160401b038111156133d5575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156136bd576136bd613681565b604052919050565b5f6001600160401b038311156136dd576136dd613681565b6136f0601f8401601f1916602001613695565b9050828152838383011115613703575f80fd5b828260208301375f602084830101529392505050565b5f82601f830112613728575f80fd5b612946838335602085016136c5565b5f805f806080858703121561374a575f80fd5b8435613755816133ee565b935060208501356001600160401b0380821115613770575f80fd5b61377c88838901613719565b94506040870135915080821115613791575f80fd5b5061379e87828801613719565b925050606085013561ffff81168114613544575f80fd5b5f805f606084860312156137c7575f80fd5b83356137d2816133ee565b925060208401356137e2816133ee565b915060408401356137f2816134a7565b809150509250925092565b5f6001600160401b0382111561381557613815613681565b5060051b60200190565b5f82601f83011261382e575f80fd5b8135602061384361383e836137fd565b613695565b8083825260208201915060208460051b870101935086841115613864575f80fd5b602086015b8481101561388957803561387c816133ee565b8352918301918301613869565b509695505050505050565b5f8060408084860312156138a6575f80fd5b83356001600160401b03808211156138bc575f80fd5b818601915086601f8301126138cf575f80fd5b813560206138df61383e836137fd565b82815260059290921b8401810191818101908a8411156138fd575f80fd5b8286015b8481101561394557803586811115613917575f80fd5b8701603f81018d13613927575f80fd5b6139378d868301358b84016136c5565b845250918301918301613901565b509750508701359350508083111561395b575f80fd5b50506139698582860161381f565b9150509250929050565b602080825282518282018190525f9190848201906040850190845b818110156134875783518352928401929184019160010161398e565b8183525f6001600160fb1b038311156139c1575f80fd5b8260051b80836020870137939093016020019392505050565b60018060a01b0385168152836020820152606060408201525f612ffc6060830184866139aa565b848152606060208201525f613a1a6060830185876139aa565b905082604083015295945050505050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613a4f575f80fd5b815161273a816134eb565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561294957612949613a5a565b5f60208284031215613a91575f80fd5b5051919050565b8082018082111561294957612949613a5a565b80356001600160401b03811681146126e6575f80fd5b5f60208284031215613ad1575f80fd5b61294682613aab565b604080825281018490525f8560608301825b87811015613b1c578235613aff816133ee565b6001600160a01b0316825260209283019290910190600101613aec565b508381036020858101919091528582529150859082015f5b86811015613b60576001600160401b03613b4d84613aab565b1682529183019190830190600101613b34565b5098975050505050505050565b602081525f610d776020830184866139aa565b5f5b83811015613b9a578181015183820152602001613b82565b50505f910152565b5f8151808452613bb9816020860160208601613b80565b601f01601f19169290920160200192915050565b6001600160a01b03851681526080602082018190525f90613bf090830186613ba2565b8281036040840152613c028186613ba2565b91505061ffff8316606083015295945050505050565b5f60208284031215613c28575f80fd5b815161273a816133ee565b5f8251613c44818460208701613b80565b9190910192915050565b5f82613c6857634e487b7160e01b5f52601260045260245ffd5b500490565b808202811582820484141761294957612949613a5a565b6001600160801b03818116838216028082169190828114613ca757613ca7613a5a565b505092915050565b6001600160801b03818116838216019080821115613ccf57613ccf613a5a565b5092915050565b6001600160a01b03929092168252602082015260400190565b5f6020808385031215613d00575f80fd5b82516001600160401b03811115613d15575f80fd5b8301601f81018513613d25575f80fd5b8051613d3361383e826137fd565b81815260059190911b82018301908381019087831115613d51575f80fd5b928401925b82841015613d78578351613d69816133ee565b82529284019290840190613d56565b979650505050505050565b602080825282548282018190525f8481528281209092916040850190845b818110156134875783546001600160a01b031683526001938401939285019201613da1565b5f60408284031215613dd6575f80fd5b604051604081018181106001600160401b0382111715613df857613df8613681565b80604052508091508251613e0b816134eb565b81526020830151613e1b816134eb565b6020919091015292915050565b5f60408284031215613e38575f80fd5b6129468383613dc6565b5f60208284031215613e52575f80fd5b815161273a816134a756fea2646970667358221220fd69f09e97dec70526f29ea18411f9171b2c9ec771961a602b4a3978a15d023164736f6c63430008190033

Verified Source Code Full Match

Compiler: v0.8.25+commit.b61c2a91 EVM: shanghai Optimization: Yes (20 runs)
OwnableMaster.sol 114 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

error NoValue();
error NotMaster();
error NotProposed();

contract OwnableMaster {

    address public master;
    address public proposedMaster;

    address internal constant ZERO_ADDRESS = address(0x0);

    modifier onlyProposed() {
        _onlyProposed();
        _;
    }

    function _onlyMaster()
        private
        view
    {
        if (msg.sender == master) {
            return;
        }

        revert NotMaster();
    }

    modifier onlyMaster() {
        _onlyMaster();
        _;
    }

    function _onlyProposed()
        private
        view
    {
        if (msg.sender == proposedMaster) {
            return;
        }

        revert NotProposed();
    }

    event MasterProposed(
        address indexed proposer,
        address indexed proposedMaster
    );

    event RenouncedOwnership(
        address indexed previousMaster
    );

    constructor(
        address _master
    ) {
        if (_master == ZERO_ADDRESS) {
            revert NoValue();
        }
        master = _master;
    }

    /**
     * @dev Allows to propose next master.
     * Must be claimed by proposer.
     */
    function proposeOwner(
        address _proposedOwner
    )
        external
        onlyMaster
    {
        if (_proposedOwner == ZERO_ADDRESS) {
            revert NoValue();
        }

        proposedMaster = _proposedOwner;

        emit MasterProposed(
            msg.sender,
            _proposedOwner
        );
    }

    /**
     * @dev Allows to claim master role.
     * Must be called by proposer.
     */
    function claimOwnership()
        external
        onlyProposed
    {
        master = msg.sender;
    }

    /**
     * @dev Removes master role.
     * No ability to be in control.
     */
    function renounceOwnership()
        external
        onlyMaster
    {
        master = ZERO_ADDRESS;
        proposedMaster = ZERO_ADDRESS;

        emit RenouncedOwnership(
            msg.sender
        );
    }
}
IERC20.sol 75 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

interface IERC20 {

    function totalSupply()
        external
        view
        returns (uint256);

    function balanceOf(
        address _account
    )
        external
        view
        returns (uint256);

    function transferFrom(
        address _sender,
        address _recipient,
        uint256 _amount
    )
        external
        returns (bool);

    function transfer(
        address _recipient,
        uint256 _amount
    )
        external
        returns (bool);

    function allowance(
        address owner,
        address spender
    )
        external
        view
        returns (uint256);

    function approve(
        address _spender,
        uint256 _amount
    )
        external
        returns (bool);

    function decimals()
        external
        view
        returns (uint8);

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

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

    event  Deposit(
        address indexed dst,
        uint wad
    );

    event  Withdrawal(
        address indexed src,
        uint wad
    );
}
IPendle.sol 619 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import {IERC20 as IERC20A} from "./IERC20.sol";

struct Order {
    uint256 salt;
    uint256 expiry;
    uint256 nonce;
    IPLimitOrderType.OrderType orderType;
    address token;
    address YT;
    address maker;
    address receiver;
    uint256 makingAmount;
    uint256 lnImpliedRate;
    uint256 failSafeRate;
    bytes permit;
}

struct FillOrderParams {
    Order order;
    bytes signature;
    uint256 makingAmount;
}

struct TokenOutput {
    // TOKEN DATA
    address tokenOut;
    uint256 minTokenOut;
    address tokenRedeemSy;
    // AGGREGATOR DATA
    address pendleSwap;
    SwapData swapData;
}

struct LimitOrderData {
    address limitRouter;
    uint256 epsSkipMarket; // only used for swap
        // operations, will be ignored otherwise
    FillOrderParams[] normalFills;
    FillOrderParams[] flashFills;
    bytes optData;
}

struct TokenInput {
    // TOKEN DATA
    address tokenIn;
    uint256 netTokenIn;
    address tokenMintSy;
    // AGGREGATOR DATA
    address pendleSwap;
    SwapData swapData;
}

enum SwapType {
    NONE,
    KYBERSWAP,
    ONE_INCH,
    // ETH_WETH not used in Aggregator
    ETH_WETH
}

struct SwapData {
    SwapType swapType;
    address extRouter;
    bytes extCalldata;
    bool needScale;
}

struct MarketStorage {
    int128 totalPt;
    int128 totalSy;
    uint96 lastLnImpliedRate;
    uint16 observationIndex;
    uint16 observationCardinality;
    uint16 observationCardinalityNext;
}

struct FillResults {
    uint256 totalMaking;
    uint256 totalTaking;
    uint256 totalFee;
    uint256 totalNotionalVolume;
    uint256[] netMakings;
    uint256[] netTakings;
    uint256[] netFees;
    uint256[] notionalVolumes;
}

struct MarketState {
    int256 totalPt;
    int256 totalSy;
    int256 totalLp;
    address treasury;
    int256 scalarRoot;
    uint256 expiry;
    uint256 lnFeeRateRoot;
    uint256 reserveFeePercent;
    uint256 lastLnImpliedRate;
}

struct LockedPosition {
    uint128 amount;
    uint128 expiry;
}

struct UserReward {
    uint128 index;
    uint128 accrued;
}

struct ApproxParams {
    uint256 guessMin;
    uint256 guessMax;
    uint256 guessOffchain;
    uint256 maxIteration;
    uint256 eps;
}

interface IPendleSy {

    function decimals()
        external
        view
        returns (uint8);

    function previewDeposit(
        address _tokenIn,
        uint256 _amountTokenToDeposit
    )
        external
        view
        returns (uint256 sharesAmount);

    function deposit(
        address _receiver,
        address _tokenIn,
        uint256 _amountTokenToDeposit,
        uint256 _minSharesOut
    )
        external
        returns (uint256 sharesAmount);

    function exchangeRate()
        external
        view
        returns (uint256);

    function redeem(
        address _receiver,
        uint256 _amountSharesToRedeem,
        address _tokenOut,
        uint256 _minTokenOut,
        bool _burnFromInternalBalance
    )
        external
        returns (uint256 amountTokenOut);
}

interface IPendleYt {

    function mintPY(
        address _receiverPT,
        address _receiverYT
    )
        external
        returns (uint256 pyAmount);

    function redeemPY(
        address _receiver
    )
        external
        returns (uint256);

    function redeemDueInterestAndRewards(
        address _user,
        bool _redeemInterest,
        bool _redeemRewards
    )
        external
        returns (
            uint256 interestOut,
            uint256[] memory rewardsOut
        );

    function getRewardTokens()
        external
        view
        returns (address[] memory);

    function userReward(
        address _token,
        address _user
    )
        external
        view
        returns (UserReward memory);

    function userInterest(
        address user
    )
        external
        view
        returns (
            uint128 lastPYIndex,
            uint128 accruedInterest
        );

    function pyIndexStored()
        external
        view
        returns (uint256);
}

interface IPendleMarket {

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    )
        external;

    function readTokens()
        external
        view
        returns (
            address SY,
            address PT,
            address YT
        );

    function activeBalance(
        address _user
    )
        external
        view
        returns (uint256);

    function transferFrom(
        address _from,
        address _to,
        uint256 _amount
    )
        external;

    function balanceOf(
        address _user
    )
        external
        view
        returns (uint256);

    function isExpired()
        external
        view
        returns (bool);

    function decimals()
        external
        view
        returns (uint8);

    function increaseObservationsCardinalityNext(
        uint16 _newObservationCardinalityNext
    )
        external;

    function swapExactPtForSy(
        address receiver,
        uint256 exactPtIn,
        bytes calldata data
    )
        external
        returns (
            uint256 netSyOut,
            uint256 netSyFee
        );

    function _storage()
        external
        view
        returns (MarketStorage memory);

    function getRewardTokens()
        external
        view
        returns (address[] memory);

    function readState(
        address _router
    )
        external
        view
        returns (MarketState memory marketState);

    function mint(
        address _receiver,
        uint256 _netSyDesired,
        uint256 _netPtDesired
    )
        external
        returns (uint256[3] memory);

    function burn(
        address _receiverAddressSy,
        address _receiverAddressPt,
        uint256 _lpToBurn
    )
        external
        returns (
            uint256 syOut,
            uint256 ptOut
        );

    function redeemRewards(
        address _user
    )
        external
        returns (uint256[] memory);

    function totalSupply()
        external
        view
        returns (uint256);

    function userReward(
        address _token,
        address _user
    )
        external
        view
        returns (UserReward memory);
}

interface IPendleChild {

    function underlyingLpAssetsCurrent()
        external
        view
        returns (uint256);

    function totalLpAssets()
        external
        view
        returns (uint256);

    function totalSupply()
        external
        view
        returns (uint256);

    function previewUnderlyingLpAssets()
        external
        view
        returns (uint256);

    function previewMintShares(
        uint256 _underlyingAssetAmount,
        uint256 _underlyingLpAssetsCurrent
    )
        external
        view
        returns (uint256);

    function previewAmountWithdrawShares(
        uint256 _shares,
        uint256 _underlyingLpAssetsCurrent
    )
        external
        view
        returns (uint256);

    function previewBurnShares(
        uint256 _underlyingAssetAmount,
        uint256 _underlyingLpAssetsCurrent
    )
        external
        view
        returns (uint256);

    function depositExactAmount(
        uint256 _amount
    )
        external
        returns (
            uint256,
            uint256
        );

    function withdrawExactShares(
        uint256 _shares
    )
        external
        returns (uint256);
}

interface IPendleLock {

    function increaseLockPosition(
        uint128 _additionalAmountToLock,
        uint128 _newExpiry
    )
        external
        returns (uint128 newVeBalance);

    function withdraw()
        external
        returns (uint128);

    function positionData(
        address _user
    )
        external
        view
        returns (LockedPosition memory);

    function getBroadcastPositionFee(
        uint256[] calldata _chainIds
    )
        external
        view
        returns (uint256);
}

interface IPendleVoteRewards {
    function claimRetail(
        address _user,
        uint256 _amount,
        bytes32[] calldata _merkleProof
    )
        external
        returns (uint256);
}

interface IPendleVoter {
    function vote(
        address[] memory _pools,
        uint64[] memory _weights
    )
        external;
}

interface IPLimitOrderType {

    enum OrderType {
        SY_FOR_PT,
        PT_FOR_SY,
        SY_FOR_YT,
        YT_FOR_SY
    }

    // Fixed-size order part with core information
    struct StaticOrder {
        uint256 salt;
        uint256 expiry;
        uint256 nonce;
        OrderType orderType;
        address token;
        address YT;
        address maker;
        address receiver;
        uint256 makingAmount;
        uint256 lnImpliedRate;
        uint256 failSafeRate;
    }
}

interface IPendleRouter {

    function removeLiquiditySingleToken(
        address receiver,
        address market,
        uint256 netLpToRemove,
        TokenOutput calldata output,
        LimitOrderData calldata limit
    )
        external
        returns (
            uint256 netTokenOut,
            uint256 netSyFee,
            uint256 netSyInterm
        );

    function swapTokenToToken(
        address receiver,
        uint256 minTokenOut,
        TokenInput memory inp
    )
        external
        payable
        returns (uint256 netTokenOut);

    function addLiquiditySingleToken(
        address receiver,
        address market,
        uint256 minLpOut,
        ApproxParams memory guessPtReceivedFromSy,
        TokenInput memory input,
        LimitOrderData memory limit
    )
        external
        payable
        returns (
            uint256 netLpOut,
            uint256 netSyFee,
            uint256 netSyInterm
        );

    function swapSyForExactYt(
        address _receiver,
        address _market,
        uint256 _exactYtOut,
        uint256 _maxSyIn
    )
        external
        returns (
            uint256 netSyIn,
            uint256 netSyFee
        );

    function swapExactSyForYt(
        address _receiver,
        address _market,
        uint256 _exactSyIn,
        uint256 _minYtOut
    )
        external
        returns (
            uint256 netYtOut,
            uint256 netSyFee
        );

    function swapSyForExactPt(
        address _receiver,
        address _market,
        uint256 _exactPtOut,
        uint256 _maxSyIn
    )
        external
        returns (
            uint256 netSyIn,
            uint256 netSyFee
        );

    function swapExactSyForPt(
        address _receiver,
        address _market,
        uint256 _exactSyIn,
        uint256 _minPtOut
    )
        external
        returns (
            uint256 netPtOut,
            uint256 netSyFee
        );

    function removeLiquiditySingleSy(
        address _receiver,
        address _market,
        uint256 _netLpToRemove,
        uint256 _minSyOut
    )
        external
        returns (
            uint256 netSyOut,
            uint256 netSyFee
        );

    function addLiquiditySingleSy(
        address _receiver,
        address _market,
        uint256 _netSyIn,
        uint256 _minLpOut,
        ApproxParams calldata _guessPtReceivedFromSy
    )
        external
        returns (
            uint256 netLpOut,
            uint256 netSyFee
        );
}

interface IPendleRouterStatic {

    function addLiquiditySingleSyStatic(
        address _market,
        uint256 _netSyIn
    )
        external
        view
        returns (
            uint256 netLpOut,
            uint256 netPtFromSwap,
            uint256 netSyFee,
            uint256 priceImpact,
            uint256 exchangeRateAfter,
            uint256 netSyToSwap
        );

    function swapExactPtForSyStatic(
        address _market,
        uint256 _exactPtIn
    )
        external
        view
        returns (
            uint256 netSyOut,
            uint256 netSyFee,
            uint256 priceImpact,
            uint256 exchangeRateAfter
        );
}
ApprovalHelper.sol 33 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "./CallOptionalReturn.sol";

contract ApprovalHelper is CallOptionalReturn {

    /**
     * @dev
     * Allows to execute safe approve for a token
     */
    function _safeApprove(
        address _token,
        address _spender,
        uint256 _value
    )
        internal
    {
        if (_spender == address(0)) {
            return;
        }

        _callOptionalReturn(
            _token,
            abi.encodeWithSelector(
                IERC20.approve.selector,
                _spender,
                _value
            )
        );
    }
}
TransferHelper.sol 52 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "./CallOptionalReturn.sol";

contract TransferHelper is CallOptionalReturn {

    /**
     * @dev
     * Allows to execute safe transfer for a token
     */
    function _safeTransfer(
        address _token,
        address _to,
        uint256 _value
    )
        internal
    {
        _callOptionalReturn(
            _token,
            abi.encodeWithSelector(
                IERC20.transfer.selector,
                _to,
                _value
            )
        );
    }

    /**
     * @dev
     * Allows to execute safe transferFrom for a token
     */
    function _safeTransferFrom(
        address _token,
        address _from,
        address _to,
        uint256 _value
    )
        internal
    {
        _callOptionalReturn(
            _token,
            abi.encodeWithSelector(
                IERC20.transferFrom.selector,
                _from,
                _to,
                _value
            )
        );
    }
}
IWiseOracleHub.sol 104 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

interface IWiseOracleHub {

    function getTokensPriceFromUSD(
        address _tokenAddress,
        uint256 _usdValue
    )
        external
        view
        returns (uint256);

    function getTokensPriceInUSD(
        address _tokenAddress,
        uint256 _tokenAmount
    )
        external
        view
        returns (uint256);

    function latestResolver(
        address _tokenAddress
    )
        external
        view
        returns (uint256);

    function latestResolverTwap(
        address _tokenAddress
    )
        external
        view
        returns (uint256);

    function getTokensFromUSD(
        address _tokenAddress,
        uint256 _usdValue
    )
        external
        view
        returns (uint256);

    function getTokensFromETH(
        address _tokenAddress,
        uint256 _ethValue
    )
        external
        view
        returns (uint256);

    function getTokensInUSD(
        address _tokenAddress,
        uint256 _amount
    )
        external
        view
        returns (uint256);

    function getTokensInETH(
        address _tokenAddress,
        uint256 _tokenAmount
    )
        external
        view
        returns (uint256);

    function chainLinkIsDead(
        address _tokenAddress
    )
        external
        view
        returns (bool);

    function decimalsUSD()
        external
        pure
        returns (uint8);

    function addOracle(
        address _tokenAddress,
        address _priceFeedAddress,
        address[] calldata _underlyingFeedTokens
    )
        external;

    function recalibrate(
        address _tokenAddress
    )
        external;

    function WETH_ADDRESS()
        external
        view
        returns (address);

    function priceFeed(
        address _tokenAddress
    )
        external
        view
        returns (address);
}
SendValueHelper.sol 37 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

error AmountTooSmall();
error SendValueFailed();

contract SendValueHelper {

    bool public sendingProgress;

    function _sendValue(
        address _recipient,
        uint256 _amount
    )
        internal
    {
        if (address(this).balance < _amount) {
            revert AmountTooSmall();
        }

        sendingProgress = true;

        (
            bool success
            ,
        ) = payable(_recipient).call{
            value: _amount
        }("");

        sendingProgress = false;

        if (success == false) {
            revert SendValueFailed();
        }
    }
}
IPendleController.sol 68 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

interface IPendleController {

    struct compoundStruct {
        uint256[] reservedForCompound;
        uint128[] lastIndex;
        address[] rewardTokens;
    }

    function withdrawLp(
        address _pendleMarket,
        address _to,
        uint256 _amount
    )
        external;

    function increaseReservedForCompound(
        address _pendleMarket,
        uint256[] memory _amounts
    )
        external;

    function pendleChildCompoundInfoReservedForCompound(
        address _pendleMarket
    )
        external
        view
        returns (uint256[] memory);

    function pendleChildCompoundInfoLastIndex(
        address _pendleMarket
    )
        external
        view
        returns (uint128[] memory);

    function pendleChildCompoundInfoRewardTokens(
        address _pendleMarket
    )
        external
        view
        returns (address[] memory);

    function updateRewardTokens(
        address _pendleMarket
    )
        external
        returns (bool);

    function overWriteIndexAll(
        address _pendleMarket
    )
        external;

    function overWriteIndex(
        address _pendleMarket,
        uint256 _index
    )
        external;

    function overWriteAmounts(
        address _pendleMarket
    )
        external;
}
CallOptionalReturn.sol 39 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "../InterfaceHub/IERC20.sol";

contract CallOptionalReturn {

    /**
     * @dev Helper function to do low-level call
     */
    function _callOptionalReturn(
        address token,
        bytes memory data
    )
        internal
        returns (bool call)
    {
        (
            bool success,
            bytes memory returndata
        ) = token.call(
            data
        );

        bool results = returndata.length == 0 || abi.decode(
            returndata,
            (bool)
        );

        if (success == false) {
            revert();
        }

        call = success
            && results
            && token.code.length > 0;
    }
}
IArbRewardsClaimer.sol 12 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

interface IArbRewardsClaimer{
    function claim(
        address _receiver,
        uint256 _accrued,
        bytes32[] calldata _proof
    )
        external;
}
IPendlePowerFarmToken.sol 112 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

interface IPendlePowerFarmToken {

    function changeGrowthCheckState(
        bool _state
    )
        external;

    function changeMinDepositAmount(
        uint256 _newMinDepositAmount
    )
        external;

    function changeCompoundRoleState(
        address _roleReceiver,
        bool _state
    )
        external;

    function changeMintFee(
        uint256 _newFee
    )
        external;

    function manualSync()
        external;

    function addCompoundRewards(
        uint256 _amount
    )
        external;

    function withdrawExactShares(
        uint256 _shares
    )
        external
        returns (uint256);

    function totalLpAssets()
        external
        view
        returns (uint256);

    function totalSupply()
        external
        view
        returns (uint256);

    function previewUnderlyingLpAssets()
        external
        view
        returns (uint256);

    function previewMintShares(
        uint256 _underlyingAssetAmount,
        uint256 _underlyingLpAssetsCurrent
    )
        external
        view
        returns (uint256);

    function previewAmountWithdrawShares(
        uint256 _shares,
        uint256 _underlyingLpAssetsCurrent
    )
        external
        view
        returns (uint256);

    function previewBurnShares(
        uint256 _underlyingAssetAmount,
        uint256 _underlyingLpAssetsCurrent
    )
        external
        view
        returns (uint256);

    function balanceOf(
        address _account
    )
        external
        view
        returns (uint256);

    function withdrawExactAmount(
        uint256 _underlyingLpAssetAmount
    )
        external
        returns (uint256);

    function depositExactAmount(
        uint256 _underlyingLpAssetAmount
    )
        external
        returns (
            uint256,
            uint256
        );

    function underlyingLpAssetsCurrent()
        external
        view
        returns (uint256);

    function totalLpAssetsToDistribute()
        external
        view
        returns (uint256);
}
IPendlePowerFarmTokenFactory.sol 14 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

interface IPendlePowerFarmTokenFactory {
    function deploy(
        address _underlyingPendleMarket,
        string memory _tokenName,
        string memory _symbolName,
        uint16 _maxCardinality
    )
        external
        returns (address);
}
SimpleERC20Clone.sol 333 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

error AllowanceBelowZero();
error ApproveWithZeroAddress();
error BurnExceedsBalance();
error BurnFromZeroAddress();
error InsufficientAllowance();
error MintToZeroAddress();
error TransferAmountExceedsBalance();
error TransferZeroAddress();

contract SimpleERC20 {

    string internal _name;
    string internal _symbol;

    uint8 internal _decimals;
    uint256 internal _totalSupply;

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

    // Miscellaneous constants
    uint256 internal constant UINT256_MAX = type(uint256).max;
    address internal constant ZERO_ADDRESS = address(0);

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

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

    function name()
        external
        view
        returns (string memory)
    {
        return _name;
    }

    function symbol()
        external
        view
        returns (string memory)
    {
        return _symbol;
    }

    function decimals()
        external
        view
        returns (uint8)
    {
        return _decimals;
    }

    function totalSupply()
        public
        view
        returns (uint256)
    {
        return _totalSupply;
    }

    function balanceOf(
        address _account
    )
        public
        view
        returns (uint256)
    {
        return _balances[_account];
    }

    function _transfer(
        address _from,
        address _to,
        uint256 _amount
    )
        internal
    {
        if (_from == ZERO_ADDRESS || _to == ZERO_ADDRESS) {
            revert TransferZeroAddress();
        }

        uint256 fromBalance = _balances[_from];

        if (fromBalance < _amount) {
            revert TransferAmountExceedsBalance();
        }

        unchecked {
            _balances[_from] = fromBalance - _amount;
            _balances[_to] += _amount;
        }

        emit Transfer(
            _from,
            _to,
            _amount
        );
    }

    function _mint(
        address _account,
        uint256 _amount
    )
        internal
    {
        if (_account == ZERO_ADDRESS) {
            revert MintToZeroAddress();
        }

        _totalSupply += _amount;

        unchecked {
            _balances[_account] += _amount;
        }

        emit Transfer(
            ZERO_ADDRESS,
            _account,
            _amount
        );
    }

    function _burn(
        address _account,
        uint256 _amount
    )
        internal
    {
        if (_account == ZERO_ADDRESS) {
            revert BurnFromZeroAddress();
        }

        uint256 accountBalance = _balances[
            _account
        ];

        if (accountBalance < _amount) {
            revert BurnExceedsBalance();
        }

        unchecked {
            _balances[_account] = accountBalance - _amount;
            _totalSupply -= _amount;
        }

        emit Transfer(
            _account,
            ZERO_ADDRESS,
            _amount
        );
    }

    function transfer(
        address _to,
        uint256 _amount
    )
        external
        returns (bool)
    {
        _transfer(
            _msgSender(),
            _to,
            _amount
        );

        return true;
    }

    function allowance(
        address _owner,
        address _spender
    )
        public
        view
        returns (uint256)
    {
        return _allowances[_owner][_spender];
    }

    function approve(
        address _spender,
        uint256 _amount
    )
        external
        returns (bool)
    {
        _approve(
            _msgSender(),
            _spender,
            _amount
        );

        return true;
    }

    function transferFrom(
        address _from,
        address _to,
        uint256 _amount
    )
        external
        returns (bool)
    {
        _spendAllowance(
            _from,
            _msgSender(),
            _amount
        );

        _transfer(
            _from,
            _to,
            _amount
        );

        return true;
    }

    function increaseAllowance(
        address _spender,
        uint256 _addedValue
    )
        external
        returns (bool)
    {
        address owner = _msgSender();

        _approve(
            owner,
            _spender,
            allowance(owner, _spender) + _addedValue
        );

        return true;
    }

    function decreaseAllowance(
        address _spender,
        uint256 _subtractedValue
    )
        external
        returns (bool)
    {
        address owner = _msgSender();

        uint256 currentAllowance = allowance(
            owner,
            _spender
        );

        if (currentAllowance < _subtractedValue) {
            revert AllowanceBelowZero();
        }

        unchecked {
            _approve(
                owner,
                _spender,
                currentAllowance - _subtractedValue
            );
        }

        return true;
    }

    function _approve(
        address _owner,
        address _spender,
        uint256 _amount
    )
        internal
    {
        if (_owner == ZERO_ADDRESS || _spender == ZERO_ADDRESS) {
            revert ApproveWithZeroAddress();
        }

        _allowances[_owner][_spender] = _amount;

        emit Approval(
            _owner,
            _spender,
            _amount
        );
    }

    function _spendAllowance(
        address _owner,
        address _spender,
        uint256 _amount
    )
        internal
    {
        uint256 currentAllowance = allowance(
            _owner,
            _spender
        );

        if (currentAllowance != UINT256_MAX) {

            if (currentAllowance < _amount) {
                revert InsufficientAllowance();
            }

            unchecked {
                _approve(
                    _owner,
                    _spender,
                    currentAllowance - _amount
                );
            }
        }
    }

    function _msgSender()
        internal
        view
        returns (address)
    {
        return msg.sender;
    }
}
PendlePowerFarmToken.sol 800 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "./SimpleERC20Clone.sol";

import "../../InterfaceHub/IPendle.sol";
import "../../InterfaceHub/IPendleController.sol";

import "../../TransferHub/TransferHelper.sol";

error MarketExpired();
error NotController();
error ZeroFee();
error TooMuchFee();
error NotEnoughLpAssetsTransferred();
error InsufficientShares();
error ZeroAmount();
error FeeTooHigh();
error NotEnoughShares();
error InvalidSharePriceGrowth();
error InvalidSharePrice();
error AlreadyInitialized();
error compoundRoleNotApproved();
error AmountBelowMinDeposit();

contract PendlePowerFarmToken is SimpleERC20, TransferHelper {

    // Pendle - LP token address
    address public UNDERLYING_PENDLE_MARKET;
    address public PENDLE_POWER_FARM_CONTROLLER;

    // Total balance of LPs backing at current compound distribution
    uint256 public underlyingLpAssetsCurrent;

    // Lp assets from compound left to distribute
    uint256 public totalLpAssetsToDistribute;

    // Interface Object for underlying Market
    IPendleMarket public PENDLE_MARKET;

    // InterfaceObject for pendle Sy
    IPendleSy public PENDLE_SY;

    // Interface for Pendle Controller
    IPendleController public PENDLE_CONTROLLER;

    // sharePrice growth check
    bool public growthCheckNecessary;

    // Max cardinality of Pendle Market
    uint16 public MAX_CARDINALITY;

    uint256 public mintFee;
    uint256 public lastInteraction;

    uint256 private constant ONE_WEEK = 7 days;
    uint256 internal constant ONE_YEAR = 365 days;
    uint256 private constant MAX_MINT_FEE = 10000;

    uint256 private constant PRECISION_FACTOR_E6 = 1E6;
    uint256 private constant PRECISION_FACTOR_E18 = 1E18;
    uint256 internal constant PRECISION_FACTOR_E36 = PRECISION_FACTOR_E18 * PRECISION_FACTOR_E18;
    uint256 internal constant PRECISION_FACTOR_YEAR = PRECISION_FACTOR_E18 * ONE_YEAR;

    uint256 MIN_DEPOSIT_AMOUNT = 1E6;

    uint256 private INITIAL_TIME_STAMP;

    uint256 internal constant RESTRICTION_FACTOR = 10
        * PRECISION_FACTOR_E36
        / PRECISION_FACTOR_YEAR;

    mapping (address => bool) public compoundRole;

    modifier onlyController() {
        _onlyController();
        _;
    }

    function _onlyController()
        private
        view
    {
        if (msg.sender != PENDLE_POWER_FARM_CONTROLLER) {
            revert NotController();
        }
    }

    modifier syncSupply()
    {
        _triggerIndexUpdate();
        _overWriteCheck();
        _syncSupply();
        _updateRewards();
        _setLastInteraction();
        _increaseCardinalityNext();
        uint256 sharePriceBefore = _getSharePrice();
        _;
        _validateSharePriceGrowth(
            _validateSharePrice(
                sharePriceBefore
            )
        );
    }

    modifier onlyCompoundRole()
    {
        _onlyCompoundRole();
        _;
    }

    function _onlyCompoundRole()
        private
        view
    {
        if (compoundRole[msg.sender] == false) {
            revert compoundRoleNotApproved();
        }
    }

    function _validateSharePrice(
        uint256 _sharePriceBefore
    )
        private
        view
        returns (uint256)
    {
        uint256 sharePricenNow = _getSharePrice();

        if (sharePricenNow < _sharePriceBefore) {
            revert InvalidSharePrice();
        }

        return sharePricenNow;
    }

    function changeGrowthCheckState(
        bool _state
    )
        external
        onlyController
    {
        growthCheckNecessary = _state;
    }

    function _validateSharePriceGrowth(
        uint256 _sharePriceNow
    )
        private
        view
    {
        if (growthCheckNecessary == false) {
            return;
        }

        uint256 timeDifference = block.timestamp
            - INITIAL_TIME_STAMP;

        uint256 maximum = timeDifference
            * RESTRICTION_FACTOR
            + PRECISION_FACTOR_E18;

        if (_sharePriceNow > maximum) {
            revert InvalidSharePriceGrowth();
        }
    }

    function _overWriteCheck()
        internal
    {
        _wrapOverWrites(
            _updateRewardTokens()
        );
    }

    function _triggerIndexUpdate()
        internal
    {
        _withdrawLp(
            UNDERLYING_PENDLE_MARKET,
            0
        );
    }

    function _wrapOverWrites(
        bool _overWritten
    )
        internal
    {
        if (_overWritten == true) {
            _overWriteIndexAll();
            _overWriteAmounts();
        }
    }

    function _updateRewardTokens()
        private
        returns (bool)
    {
        return PENDLE_CONTROLLER.updateRewardTokens(
            UNDERLYING_PENDLE_MARKET
        );
    }

    function _overWriteIndexAll()
        private
    {
        PENDLE_CONTROLLER.overWriteIndexAll(
            UNDERLYING_PENDLE_MARKET
        );
    }

    function _overWriteIndex(
        uint256 _index
    )
        private
    {
        PENDLE_CONTROLLER.overWriteIndex(
            UNDERLYING_PENDLE_MARKET,
            _index
        );
    }

    function _overWriteAmounts()
        private
    {
        PENDLE_CONTROLLER.overWriteAmounts(
            UNDERLYING_PENDLE_MARKET
        );
    }

    function _updateRewards()
        private
    {
        uint256[] memory rewardsOutsideArray = _calculateRewardsClaimedOutside();

        uint256 i;
        uint256 l = rewardsOutsideArray.length;

        while (i < l) {
            if (rewardsOutsideArray[i] > 0) {
                PENDLE_CONTROLLER.increaseReservedForCompound(
                    UNDERLYING_PENDLE_MARKET,
                    rewardsOutsideArray
                );
                break;
            }
            unchecked {
                ++i;
            }
        }
    }

    function _calculateRewardsClaimedOutside()
        internal
        returns (uint256[] memory)
    {
        IPendleController PENDLE_CONTROLLER_INSTANCE = PENDLE_CONTROLLER;
        address UNDERLYING_PENDLE_MARKET_ADDRESS = UNDERLYING_PENDLE_MARKET;

        address[] memory rewardTokens = PENDLE_CONTROLLER_INSTANCE.pendleChildCompoundInfoRewardTokens(
            UNDERLYING_PENDLE_MARKET_ADDRESS
        );

        uint128[] memory lastIndex = PENDLE_CONTROLLER_INSTANCE.pendleChildCompoundInfoLastIndex(
            UNDERLYING_PENDLE_MARKET_ADDRESS
        );

        uint256 l = rewardTokens.length;
        uint256[] memory rewardsOutsideArray = new uint256[](l);

        uint256 i;
        uint128 index;

        uint256 activeBalance = _getActiveBalance();
        uint256 totalLpAssetsCurrent = totalLpAssets();
        uint256 lpBalanceController = _getBalanceLpBalanceController();

        address PENDLE_POWER_FARM_CONTROLLER_ADDRESS = PENDLE_POWER_FARM_CONTROLLER;
        IPendleMarket PENDLE_MARKET_INSTANCE = PENDLE_MARKET;

        while (i < l) {
            UserReward memory userReward = _getUserReward(
                rewardTokens[i],
                PENDLE_POWER_FARM_CONTROLLER_ADDRESS
            );

            if (userReward.accrued > 0) {
                PENDLE_MARKET_INSTANCE.redeemRewards(
                    PENDLE_POWER_FARM_CONTROLLER_ADDRESS
                );

                userReward = _getUserReward(
                    rewardTokens[i],
                    PENDLE_POWER_FARM_CONTROLLER_ADDRESS
                );
            }

            index = userReward.index;

            if (lastIndex[i] == 0 && index > 0) {
                rewardsOutsideArray[i] = 0;
                _overWriteIndex(
                    i
                );
                unchecked {
                    ++i;
                }
                continue;
            }

            if (index == lastIndex[i]) {
                rewardsOutsideArray[i] = 0;
                unchecked {
                    ++i;
                }
                continue;
            }

            uint256 indexDiff = index
                - lastIndex[i];

            bool scaleNecessary = totalLpAssetsCurrent < lpBalanceController;

            rewardsOutsideArray[i] = scaleNecessary
                ? indexDiff
                    * activeBalance
                    * totalLpAssetsCurrent
                    / lpBalanceController
                    / PRECISION_FACTOR_E18
                : indexDiff
                    * activeBalance
                    / PRECISION_FACTOR_E18;

            _overWriteIndex(
                i
            );

            unchecked {
                ++i;
            }
        }

        return rewardsOutsideArray;
    }

    function _getBalanceLpBalanceController()
        private
        view
        returns (uint256)
    {
        return PENDLE_MARKET.balanceOf(
            PENDLE_POWER_FARM_CONTROLLER
        );
    }

    function _getActiveBalance()
        private
        view
        returns (uint256)
    {
        return PENDLE_MARKET.activeBalance(
            PENDLE_POWER_FARM_CONTROLLER
        );
    }

    function _getSharePrice()
        private
        view
        returns (uint256)
    {
        return previewUnderlyingLpAssets() * PRECISION_FACTOR_E18
            / totalSupply();
    }

    function _syncSupply()
        private
    {
        uint256 additonalAssets = previewDistribution();

        if (additonalAssets == 0) {
            return;
        }

        underlyingLpAssetsCurrent += additonalAssets;
        totalLpAssetsToDistribute -= additonalAssets;
    }

    function _increaseCardinalityNext()
        internal
    {
        MarketStorage memory storageMarket = PENDLE_MARKET._storage();

        if (storageMarket.observationCardinalityNext < MAX_CARDINALITY) {
            PENDLE_MARKET.increaseObservationsCardinalityNext(
                storageMarket.observationCardinalityNext + 1
            );
        }
    }

    function _withdrawLp(
        address _to,
        uint256 _amount
    )
        internal
    {
        PENDLE_CONTROLLER.withdrawLp(
            UNDERLYING_PENDLE_MARKET,
            _to,
            _amount
        );
    }

    function _getUserReward(
        address _rewardToken,
        address _user
    )
        internal
        view
        returns (UserReward memory)
    {
        return PENDLE_MARKET.userReward(
            _rewardToken,
            _user
        );
    }

    function previewDistribution()
        public
        view
        returns (uint256)
    {
        uint256 lastInteractioCached = lastInteraction;

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

        if (block.timestamp == lastInteractioCached) {
            return 0;
        }

        if (totalLpAssetsToDistribute < ONE_WEEK) {
            return totalLpAssetsToDistribute;
        }

        uint256 currentRate = totalLpAssetsToDistribute
            / ONE_WEEK;

        uint256 additonalAssets = currentRate
            * (block.timestamp - lastInteractioCached);

        if (additonalAssets > totalLpAssetsToDistribute) {
            return totalLpAssetsToDistribute;
        }

        return additonalAssets;
    }

    function _setLastInteraction()
        private
    {
        lastInteraction = block.timestamp;
    }

    function _applyMintFee(
        uint256 _amount
    )
        internal
        view
        returns (uint256)
    {
        return _amount
            * (PRECISION_FACTOR_E6 - mintFee)
            / PRECISION_FACTOR_E6;
    }

    function totalLpAssets()
        public
        view
        returns (uint256)
    {
        return underlyingLpAssetsCurrent
            + totalLpAssetsToDistribute;
    }

    function previewUnderlyingLpAssets()
        public
        view
        returns (uint256)
    {
        return previewDistribution()
            + underlyingLpAssetsCurrent;
    }

    function previewMintShares(
        uint256 _underlyingAssetAmount,
        uint256 _underlyingLpAssetsCurrent
    )
        public
        view
        returns (uint256)
    {
        return _underlyingAssetAmount
            * totalSupply()
            / _underlyingLpAssetsCurrent;
    }

    function previewAmountWithdrawShares(
        uint256 _shares,
        uint256 _underlyingLpAssetsCurrent
    )
        public
        view
        returns (uint256)
    {
        return _shares
            * _underlyingLpAssetsCurrent
            / totalSupply();
    }

    function previewBurnShares(
        uint256 _underlyingAssetAmount,
        uint256 _underlyingLpAssetsCurrent
    )
        public
        view
        returns (uint256)
    {
        uint256 product = _underlyingAssetAmount
            * totalSupply();

        return product % _underlyingLpAssetsCurrent == 0
            ? product / _underlyingLpAssetsCurrent
            : product / _underlyingLpAssetsCurrent + 1;
    }

    function changeCompoundRoleState(
        address _compoundRole,
        bool _state
    )
        external
        onlyController
    {
        compoundRole[_compoundRole] = _state;
    }

    function changeMinDepositAmount(
        uint256 _newMinDepositAmount
    )
        external
        onlyController
    {
        MIN_DEPOSIT_AMOUNT = _newMinDepositAmount;
    }

    function manualSync()
        external
        syncSupply
        returns (bool)
    {
        return true;
    }

    function addCompoundRewards(
        uint256 _amount
    )
        external
        syncSupply
        onlyCompoundRole
    {
        if (_amount == 0) {
            revert ZeroAmount();
        }

        totalLpAssetsToDistribute += _amount;

        if (msg.sender == PENDLE_POWER_FARM_CONTROLLER) {
            return;
        }

        _safeTransferFrom(
            UNDERLYING_PENDLE_MARKET,
            msg.sender,
            PENDLE_POWER_FARM_CONTROLLER,
            _amount
        );
    }

    /**
     * @dev External wrapper for mint function.
     */
    function depositExactAmount(
        uint256 _underlyingLpAssetAmount
    )
        external
        syncSupply
        returns (
            uint256,
            uint256
        )
    {
        if (_underlyingLpAssetAmount < MIN_DEPOSIT_AMOUNT) {
            revert AmountBelowMinDeposit();
        }

        uint256 shares = previewMintShares(
            _underlyingLpAssetAmount,
            underlyingLpAssetsCurrent
        );

        if (shares == 0) {
            revert NotEnoughLpAssetsTransferred();
        }

        uint256 reducedShares = _applyMintFee(
            shares
        );

        uint256 feeShares = shares
            - reducedShares;

        if (feeShares == 0) {
            revert ZeroFee();
        }

        if (reducedShares == feeShares) {
            revert TooMuchFee();
        }

        _mint(
            msg.sender,
            reducedShares
        );

        _mint(
            PENDLE_POWER_FARM_CONTROLLER,
            feeShares
        );

        underlyingLpAssetsCurrent += _underlyingLpAssetAmount;

        _safeTransferFrom(
            UNDERLYING_PENDLE_MARKET,
            msg.sender,
            PENDLE_POWER_FARM_CONTROLLER,
            _underlyingLpAssetAmount
        );

        return (
            reducedShares,
            feeShares
        );
    }

    function changeMintFee(
        uint256 _newFee
    )
        external
        onlyController
    {
        if (_newFee > MAX_MINT_FEE) {
            revert FeeTooHigh();
        }

        mintFee = _newFee;
    }

    /**
     * @dev External wrapper for burn function.
     */
    function withdrawExactShares(
        uint256 _shares
    )
        external
        syncSupply
        returns (uint256)
    {
        if (_shares == 0) {
            revert ZeroAmount();
        }

        if (_shares > balanceOf(msg.sender)) {
            revert InsufficientShares();
        }

        uint256 tokenAmount = previewAmountWithdrawShares(
            _shares,
            underlyingLpAssetsCurrent
        );

        underlyingLpAssetsCurrent -= tokenAmount;

        _burn(
            msg.sender,
            _shares
        );

        if (msg.sender == PENDLE_POWER_FARM_CONTROLLER) {
            return tokenAmount;
        }

        _withdrawLp(
            msg.sender,
            tokenAmount
        );

        return tokenAmount;
    }

    function withdrawExactAmount(
        uint256 _underlyingLpAssetAmount
    )
        external
        syncSupply
        returns (uint256)
    {
        if (_underlyingLpAssetAmount == 0) {
            revert ZeroAmount();
        }

        uint256 shares = previewBurnShares(
            _underlyingLpAssetAmount,
            underlyingLpAssetsCurrent
        );

        if (shares > balanceOf(msg.sender)) {
            revert NotEnoughShares();
        }

        _burn(
            msg.sender,
            shares
        );

        underlyingLpAssetsCurrent -= _underlyingLpAssetAmount;

        _withdrawLp(
            msg.sender,
            _underlyingLpAssetAmount
        );

        return shares;
    }

    function initialize(
        address _underlyingPendleMarket,
        address _pendleController,
        string memory _tokenName,
        string memory _symbolName,
        uint16 _maxCardinality
    )
        external
    {
        if (address(PENDLE_MARKET) != address(0)) {
            revert AlreadyInitialized();
        }

        growthCheckNecessary = true;

        PENDLE_MARKET = IPendleMarket(
            _underlyingPendleMarket
        );

        if (PENDLE_MARKET.isExpired() == true) {
            revert MarketExpired();
        }

        PENDLE_CONTROLLER = IPendleController(
            _pendleController
        );

        MAX_CARDINALITY = _maxCardinality;

        _name = _tokenName;
        _symbol = _symbolName;

        PENDLE_POWER_FARM_CONTROLLER = _pendleController;
        UNDERLYING_PENDLE_MARKET = _underlyingPendleMarket;

        (
            address pendleSyAddress,
            ,
        ) = PENDLE_MARKET.readTokens();

        PENDLE_SY = IPendleSy(
            pendleSyAddress
        );

        _decimals = PENDLE_SY.decimals();

        lastInteraction = block.timestamp;

        _totalSupply = 1;
        underlyingLpAssetsCurrent = 1;
        mintFee = 3000;
        INITIAL_TIME_STAMP = block.timestamp;
    }
}
PendlePowerFarmController.sol 810 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "./PendlePowerFarmTokenFactory.sol";
import "./PendlePowerFarmControllerHelper.sol";

contract PendlePowerFarmController is PendlePowerFarmControllerHelper {

    PendlePowerFarmTokenFactory public immutable PENDLE_POWER_FARM_TOKEN_FACTORY;

    constructor(
        address _vePendle,
        address _pendleToken,
        address _voterContract,
        address _voterRewardsClaimerAddress,
        address _wiseOracleHub
    )
        PendlePowerFarmControllerBase(
            _vePendle,
            _pendleToken,
            _voterContract,
            _voterRewardsClaimerAddress,
            _wiseOracleHub
        )
    {
        PENDLE_POWER_FARM_TOKEN_FACTORY = new PendlePowerFarmTokenFactory(
            address(this)
        );
    }

    function withdrawLp(
        address _pendleMarket,
        address _to,
        uint256 _amount
    )
        external
        onlyChildContract(_pendleMarket)
    {
        _safeTransfer(
            _pendleMarket,
            _to,
            _amount
        );

        emit WithdrawLp(
            _pendleMarket,
            _to,
            _amount
        );
    }

    function exchangeRewardsForCompoundingWithIncentive(
        address _pendleMarket,
        address _rewardToken,
        uint256 _rewardAmount
    )
        external
        syncSupply(_pendleMarket)
        returns (uint256)
    {
        CompoundStruct memory childInfo = pendleChildCompoundInfo[
            _pendleMarket
        ];

        uint256 index = _findIndex(
            childInfo.rewardTokens,
            _rewardToken
        );

        if (childInfo.reservedForCompound[index] < _rewardAmount) {
            revert NotEnoughCompound();
        }

        uint256 sendingAmount = _getAmountToSend(
            _pendleMarket,
            _getTokensInETH(
                _rewardToken,
                _rewardAmount
            )
        );

        childInfo.reservedForCompound[index] -= _rewardAmount;
        pendleChildCompoundInfo[_pendleMarket] = childInfo;

        _safeTransferFrom(
            _pendleMarket,
            msg.sender,
            address(this),
            sendingAmount
        );

        IPendlePowerFarmToken(pendleChildAddress[_pendleMarket]).addCompoundRewards(
            sendingAmount
        );

        _safeTransfer(
            childInfo.rewardTokens[index],
            msg.sender,
            _rewardAmount
        );

        emit ExchangeRewardsForCompounding(
            _pendleMarket,
            _rewardToken,
            _rewardAmount,
            sendingAmount
        );

        return sendingAmount;
    }

    function exchangeLpFeesForPendleWithIncentive(
        address _pendleMarket,
        uint256 _pendleChildShares
    )
        external
        syncSupply(_pendleMarket)
        returns (
            uint256,
            uint256
        )
    {
        if (_pendleChildShares == 0) {
            revert ZeroShares();
        }

        address pendleChild = pendleChildAddress[
            _pendleMarket
        ];

        uint256 tokenAmountSend = _getAmountToSend(
            PENDLE_TOKEN_ADDRESS,
            _getTokensInETH(
                pendleChild,
                _pendleChildShares
            )
        );

        reservedPendleForLocking += tokenAmountSend;

        _safeTransferFrom(
            PENDLE_TOKEN_ADDRESS,
            msg.sender,
            address(this),
            tokenAmountSend
        );

        uint256 withdrawnAmount = IPendlePowerFarmToken(pendleChild).withdrawExactShares(
            _pendleChildShares
        );

        _safeTransfer(
            _pendleMarket,
            msg.sender,
            withdrawnAmount
        );

        emit ExchangeLpFeesForPendle(
            _pendleMarket,
            _pendleChildShares,
            tokenAmountSend,
            withdrawnAmount
        );

        return(
            tokenAmountSend,
            withdrawnAmount
        );
    }

    function skim(
        address _pendleMarket
    )
        external
        returns (uint256)
    {
        address childMarket = pendleChildAddress[
            _pendleMarket
        ];

        if (childMarket == ZERO_ADDRESS) {
            revert WrongAddress();
        }

        uint256 balance = IPendleMarket(_pendleMarket).balanceOf(
            address(this)
        );

        uint256 totalAssets = IPendlePowerFarmToken(
            childMarket
        ).totalLpAssets();

        if (balance < totalAssets + 1) {
            revert NothingToSkim();
        }

        uint256 difference = balance
            - totalAssets
            + 1;

        _safeTransfer(
            _pendleMarket,
            master,
            difference
        );

        return difference;
    }

    function changeCompoundRoleState(
        address _pendleMarket,
        address _roleReceiver,
        bool _state
    )
        public
        onlyMaster
    {
        address pendleChild = pendleChildAddress[
            _pendleMarket
        ];

        if (pendleChild == ZERO_ADDRESS) {
            revert WrongAddress();
        }

        IPendlePowerFarmToken(pendleChild).changeCompoundRoleState(
            _roleReceiver,
            _state
        );
    }

    function changeMinDepositAmount(
        address _pendleMarket,
        uint256 _newAmount
    )
        external
        onlyMaster
    {
        address pendleChild = pendleChildAddress[
            _pendleMarket
        ];

        if (pendleChild == ZERO_ADDRESS) {
            revert WrongAddress();
        }

        IPendlePowerFarmToken(pendleChild).changeMinDepositAmount(
            _newAmount
        );
    }

    function claimAirdropSafe(
        bytes[] memory _calldataArray,
        address[] memory _contractAddresses
    )
        external
        onlyMaster
    {
        uint256 callDataLength = _calldataArray.length;

        if (callDataLength != _contractAddresses.length) {
            revert InvalidLength();
        }

        bytes32 initialHashChainResult = _getHashChainResult();

        uint256 i;

        address currentAddress;

        while (i < callDataLength) {
            currentAddress = _contractAddresses[i];

            if (currentAddress == ZERO_ADDRESS) {
                revert ZeroAddress();
            }

            if (currentAddress == address(this)) {
                revert SelfCallNotAllowed();
            }

            if (_calldataArray[i].length < 4) {
                revert CallDataTooShort(i);
            }

            if (_forbiddenSelector(_calldataArray[i]) == true) {
                revert ForbiddenSelector();
            }

            (
                bool success
                ,
            ) = currentAddress.call(
                _calldataArray[i]
            );

            if (success == false) {
                revert AirdropFailed();
            }

            unchecked {
                ++i;
            }
        }

        if (_getHashChainResult() != initialHashChainResult) {
            revert HashChainManipulated();
        }
    }

    function addPendleMarket(
        address _pendleMarket,
        string memory _tokenName,
        string memory _symbolName,
        uint16 _maxCardinality
    )
        external
        onlyMaster
    {
        if (pendleChildAddress[_pendleMarket] > ZERO_ADDRESS) {
            revert AlreadySet();
        }

        if (activePendleMarketsLength() == MAX_PENDLE_MARKETS) {
            revert MaxPendleMarketsReached();
        }

        if (_pendleMarket == ZERO_ADDRESS) {
            revert WrongAddress();
        }

        address pendleChild = PENDLE_POWER_FARM_TOKEN_FACTORY.deploy(
            _pendleMarket,
            _tokenName,
            _symbolName,
            _maxCardinality
        );

        pendleChildAddress[_pendleMarket] = pendleChild;

        _setRewardTokens(
            _pendleMarket,
            _getRewardTokens(
                _pendleMarket
            )
        );

        CompoundStruct storage childInfo = pendleChildCompoundInfo[
            _pendleMarket
        ];

        uint256 rewardTokensLength = childInfo
            .rewardTokens
            .length;

        childInfo.lastIndex = new uint128[](
            rewardTokensLength
        );

        childInfo.reservedForCompound = new uint256[](
            rewardTokensLength
        );

        uint256 i;

        while (i < rewardTokensLength) {

            address token = childInfo.rewardTokens[i];

            childInfo.lastIndex[i] = _getUserRewardIndex(
                _pendleMarket,
                token,
                address(this)
            );

            childInfo.reservedForCompound[i] = 0;

            _checkFeed(
                token
            );

            unchecked {
                ++i;
            }
        }

        _checkFeed(
            _pendleMarket
        );

        activePendleMarkets.push(
            _pendleMarket
        );

        changeCompoundRoleState({
            _pendleMarket: _pendleMarket,
            _roleReceiver: address(this),
            _state: true
        });

        emit AddPendleMarket(
            _pendleMarket,
            pendleChild
        );
    }

    function updateRewardTokens(
        address _pendleMarket
    )
        external
        onlyChildContract(_pendleMarket)
        returns (bool)
    {
        address[] memory rewardTokens = _getRewardTokens(
            _pendleMarket
        );

        if (_compareHashes(_pendleMarket, rewardTokens) == true) {
            return false;
        }

        _setRewardTokens(
            _pendleMarket,
            rewardTokens
        );

        emit UpdateRewardTokens(
            _pendleMarket,
            rewardTokens
        );

        return true;
    }

    function changeExchangeIncentive(
        uint256 _newExchangeIncentive
    )
        external
        onlyMaster
    {
        exchangeIncentive = _newExchangeIncentive;

        emit ChangeExchangeIncentive(
            _newExchangeIncentive
        );
    }

    function changeSyncCheck(
        address _pendleMarket,
        bool _state
    )
        external
        onlyMaster
    {
        address child = _checkChildExistence(
            _pendleMarket
        );

        syncNotNecessary[child] = _state;
    }

    function changeGrowthCheckState(
        address _pendleMarket,
        bool _state
    )
        external
        onlyMaster
    {
        address child = _checkChildExistence(
            _pendleMarket
        );

        IPendlePowerFarmToken(
            child
        ).changeGrowthCheckState(
            _state
        );
    }

    function changeMintFee(
        address _pendleMarket,
        uint256 _newFee
    )
        external
        onlyMaster
    {
        address child = _checkChildExistence(
            _pendleMarket
        );

        IPendlePowerFarmToken(
            child
        ).changeMintFee(
            _newFee
        );

        emit ChangeMintFee(
            _pendleMarket,
            _newFee
        );
    }

    function _checkChildExistence(
        address _pendleMarket
    )
        private
        view
        returns (address child)
    {
        child = pendleChildAddress[
            _pendleMarket
        ];

        if (child == ZERO_ADDRESS) {
            revert WrongAddress();
        }
    }

    /**
     * @dev Can also be used to extend existing lock.
     */
    function lockPendle(
        uint256 _amount,
        uint128 _weeks,
        bool _fromInside,
        bool _sameExpiry
    )
        external
        onlyMaster
        returns (uint256 newVeBalance)
    {
        syncAllSupply();

        uint256 currentExpiry = _getExpiry();

        uint128 expiry = _sameExpiry
            ? uint128(currentExpiry)
            : _calcExpiry(
                _weeks
            );

        if (uint256(expiry) < currentExpiry) {
            revert LockTimeTooShort();
        }

        if (_amount > 0) {

            _safeApprove(
                PENDLE_TOKEN_ADDRESS,
                VE_PENDLE_CONTRACT_ADDRESS,
                _amount
            );

            if (_fromInside == false) {
                _safeTransferFrom(
                    PENDLE_TOKEN_ADDRESS,
                    msg.sender,
                    address(this),
                    _amount
                );
            }
        }

        newVeBalance = PENDLE_LOCK.increaseLockPosition(
            uint128(_amount),
            expiry
        );

        syncAllSupply();

        if (_fromInside == false) {
            return newVeBalance;
        }

        if (_amount > 0) {
            reservedPendleForLocking -= _amount;
        }

        emit LockPendle(
            _amount,
            expiry,
            newVeBalance,
            _fromInside,
            _sameExpiry,
            block.timestamp
        );
    }

    function claimArb(
        uint256 _accrued,
        bytes32[] calldata _proof
    )
        external
        onlyArbitrum
    {
        ARB_REWARDS.claim(
            master,
            _accrued,
            _proof
        );

        emit ClaimArb(
            _accrued,
            _proof,
            block.timestamp
        );
    }

    function withdrawLock()
        external
        onlyMaster
        returns (uint256 amount)
    {
        if (IS_ETH_MAIN == false) {

            amount = reservedPendleForLocking;
            reservedPendleForLocking = 0;

            _safeTransfer(
                PENDLE_TOKEN_ADDRESS,
                master,
                amount
            );

            emit WithdrawLock(
                amount,
                block.timestamp
            );

            return amount;
        }

        if (_getExpiry() > block.timestamp) {
            revert NotExpired();
        }

        syncAllSupply();

        amount = PENDLE_LOCK.withdraw();

        _safeTransfer(
            PENDLE_TOKEN_ADDRESS,
            master,
            amount
        );

        syncAllSupply();

        emit WithdrawLock(
            amount,
            block.timestamp
        );
    }

    function increaseReservedForCompound(
        address _pendleMarket,
        uint256[] calldata _amounts
    )
        external
        onlyChildContract(_pendleMarket)
    {
        CompoundStruct memory childInfo = pendleChildCompoundInfo[
            _pendleMarket
        ];

        uint256 i;
        uint256 length = childInfo.rewardTokens.length;

        while (i < length) {
            childInfo.reservedForCompound[i] += _amounts[i];
            unchecked {
                ++i;
            }
        }

        pendleChildCompoundInfo[_pendleMarket] = childInfo;

        emit IncreaseReservedForCompound(
            _pendleMarket,
            _amounts
        );
    }

    function overWriteIndex(
        address _pendleMarket,
        uint256 _tokenIndex
    )
        public
        onlyChildContract(_pendleMarket)
    {
        CompoundStruct storage childInfo = pendleChildCompoundInfo[
            _pendleMarket
        ];

        childInfo.lastIndex[_tokenIndex] = _getUserRewardIndex(
            _pendleMarket,
            childInfo.rewardTokens[_tokenIndex],
            address(this)
        );
    }

    function overWriteIndexAll(
        address _pendleMarket
    )
        external
        onlyChildContract(_pendleMarket)
    {
        uint256 i;
        uint256 length = pendleChildCompoundInfo[
            _pendleMarket
        ].rewardTokens.length;

        while (i < length) {
            overWriteIndex(
                _pendleMarket,
                i
            );
            unchecked {
                ++i;
            }
        }
    }

    function overWriteAmounts(
        address _pendleMarket
    )
        external
        onlyChildContract(_pendleMarket)
    {
        CompoundStruct storage childInfo = pendleChildCompoundInfo[
            _pendleMarket
        ];

        childInfo.reservedForCompound = new uint256[](
            childInfo.rewardTokens.length
        );
    }

    function claimVoteRewards(
        uint256 _amount,
        bytes32[] calldata _merkleProof
    )
        external
    {
        PENDLE_VOTE_REWARDS.claimRetail(
            address(this),
            _amount,
            _merkleProof
        );

        emit ClaimVoteRewards(
            _amount,
            _merkleProof,
            block.timestamp
        );
    }

    function forwardETH(
        address _to,
        uint256 _amount
    )
        public
        onlyMaster
    {
        if (sendingProgress == true) {
            revert CheckSendingOnGoing();
        }

        _sendValue(
            _to,
            _amount
        );

        sendingProgress = false;
    }

    function vote(
        address[] calldata _pools,
        uint64[] calldata _weights
    )
        external
        onlyMaster
    {
        if (_weights.length != _pools.length) {
            revert InvalidLength();
        }

        uint256 i;
        uint256 len = _weights.length;

        uint256 weightSum;

        while (i < len) {
            unchecked {
                weightSum += _weights[i];
                ++i;
            }
        }

        if (weightSum > PRECISION_FACTOR_E18) {
            revert InvalidWeightSum();
        }

        PENDLE_VOTER.vote(
            _pools,
            _weights
        );
    }
}
PendlePowerFarmTokenFactory.sol 110 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "./PendlePowerFarmToken.sol";

error DeployForbidden();

contract PendlePowerFarmTokenFactory {

    address internal constant ZERO_ADDRESS = address(0x0);

    address public immutable IMPLEMENTATION_TARGET;
    address public immutable PENDLE_POWER_FARM_CONTROLLER;

    constructor(
        address _pendlePowerFarmController
    )
    {
        PENDLE_POWER_FARM_CONTROLLER = _pendlePowerFarmController;

        PendlePowerFarmToken implementation = new PendlePowerFarmToken{
            salt: keccak256(
                abi.encodePacked(
                    _pendlePowerFarmController
                )
            )
        }();

        IMPLEMENTATION_TARGET = address(
            implementation
        );
    }

    function deploy(
        address _underlyingPendleMarket,
        string memory _tokenName,
        string memory _symbolName,
        uint16 _maxCardinality
    )
        external
        returns (address)
    {
        if (msg.sender != PENDLE_POWER_FARM_CONTROLLER) {
            revert DeployForbidden();
        }

        return _clone(
            _underlyingPendleMarket,
            _tokenName,
            _symbolName,
            _maxCardinality
        );
    }

    function _clone(
        address _underlyingPendleMarket,
        string memory _tokenName,
        string memory _symbolName,
        uint16 _maxCardinality
    )
        private
        returns (address pendlePowerFarmTokenAddress)
    {
        bytes32 salt = keccak256(
            abi.encodePacked(
                _underlyingPendleMarket
            )
        );

        bytes20 targetBytes = bytes20(
            IMPLEMENTATION_TARGET
        );

        assembly {

            let clone := mload(0x40)

            mstore(
                clone,
                0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
            )

            mstore(
                add(clone, 0x14),
                targetBytes
            )

            mstore(
                add(clone, 0x28),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
            )

            pendlePowerFarmTokenAddress := create2(
                0,
                clone,
                0x37,
                salt
            )
        }

        PendlePowerFarmToken(pendlePowerFarmTokenAddress).initialize(
            _underlyingPendleMarket,
            PENDLE_POWER_FARM_CONTROLLER,
            _tokenName,
            _symbolName,
            _maxCardinality
        );
    }
}
PendlePowerFarmControllerBase.sol 346 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "../../OwnableMaster.sol";

import "../../TransferHub/TransferHelper.sol";
import "../../TransferHub/ApprovalHelper.sol";
import "../../TransferHub/SendValueHelper.sol";

import "../../InterfaceHub/IPendle.sol";
import "../../InterfaceHub/IArbRewardsClaimer.sol";
import "../../InterfaceHub/IWiseOracleHub.sol";
import "../../InterfaceHub/IPendlePowerFarmToken.sol";
import "../../InterfaceHub/IPendlePowerFarmTokenFactory.sol";

error NotAllowed();
error AlreadySet();
error NotExpired();
error LockTimeTooShort();
error ZeroShares();
error ValueTooSmall();
error InvalidLength();
error InvalidWeightSum();
error ZeroAddress();
error SelfCallNotAllowed();
error NothingToSkim();
error NotFound();
error NotEnoughCompound();
error NotArbitrum();
error CheckSendingOnGoing();
error MaxPendleMarketsReached();
error AirdropFailed();
error HashChainManipulated();
error ForbiddenSelector();
error WrongAddress();
error CallDataTooShort(uint256);

contract PendlePowerFarmControllerBase is
    OwnableMaster,
    TransferHelper,
    ApprovalHelper,
    SendValueHelper
{
    struct CompoundStruct {
        uint256[] reservedForCompound;
        uint128[] lastIndex;
        address[] rewardTokens;
    }

    address internal immutable PENDLE_TOKEN_ADDRESS;

    address internal immutable VOTER_CONTRACT_ADDRESS;
    address internal immutable VOTER_REWARDS_CLAIMER_ADDRESS;

    address internal immutable WISE_ORACLE_HUB_ADDRESS;
    address internal immutable VE_PENDLE_CONTRACT_ADDRESS;

    uint256 internal constant PRECISION_FACTOR_E6 = 1E6;
    uint256 internal constant PRECISION_FACTOR_E10 = 1E10;
    uint256 internal constant PRECISION_FACTOR_E18 = 1E18;

    uint256 internal constant MAINNET_CHAIN_ID = 1;
    uint256 internal constant ARBITRUM_CHAIN_ID = 42161;

    uint256 public reservedPendleForLocking;

    mapping(address => address) public pendleChildAddress;
    mapping(address => CompoundStruct) pendleChildCompoundInfo;
    mapping(address => bool) public syncNotNecessary;

    address[] public activePendleMarkets;

    bool immutable IS_ETH_MAIN;

    uint128 internal constant WEEK = 7 days;
    uint256 public exchangeIncentive;

    uint256 internal constant MAX_PENDLE_MARKETS = 42;

    IPendleLock immutable public PENDLE_LOCK;
    IPendleVoter immutable public PENDLE_VOTER;
    IPendleVoteRewards immutable public PENDLE_VOTE_REWARDS;

    IArbRewardsClaimer public ARB_REWARDS;

    address internal constant ARB_REWARDS_ADDRESS = 0x23a102e78D1FF1645a3666691495174764a5FCAF;
    address internal constant ARB_TOKEN_ADDRESS = 0x912CE59144191C1204E64559FE8253a0e49E6548;

    IWiseOracleHub immutable internal ORACLE_HUB;

    bytes4 internal constant APPROVE_SELECTOR = 0x095ea7b3;
    bytes4 internal constant PERMIT_SELECTOR = 0xd505accf;

    bytes32 internal constant INITIAL_HASH = keccak256(
        abi.encodePacked(ZERO_ADDRESS, uint256(0))
    );

    IERC20 immutable PENDLE_TOKEN_INSTANCE;

    constructor(
        address _vePendle,
        address _pendleToken,
        address _voterContract,
        address _voterRewardsClaimerAddress,
        address _wiseOracleHub
    )
        OwnableMaster(
            msg.sender
        )
    {
        IS_ETH_MAIN = block.chainid == MAINNET_CHAIN_ID
            ? true
            : false;

        PENDLE_TOKEN_ADDRESS = _pendleToken;

        PENDLE_TOKEN_INSTANCE = IERC20(
            _pendleToken
        );

        VOTER_CONTRACT_ADDRESS = _voterContract;
        VOTER_REWARDS_CLAIMER_ADDRESS = _voterRewardsClaimerAddress;

        WISE_ORACLE_HUB_ADDRESS = _wiseOracleHub;
        VE_PENDLE_CONTRACT_ADDRESS = _vePendle;

        PENDLE_LOCK = IPendleLock(
            _vePendle
        );

        PENDLE_VOTER = IPendleVoter(
            _voterContract
        );

        PENDLE_VOTE_REWARDS = IPendleVoteRewards(
            _voterRewardsClaimerAddress
        );

        ORACLE_HUB = IWiseOracleHub(
            _wiseOracleHub
        );

        ARB_REWARDS = IArbRewardsClaimer(
            ARB_REWARDS_ADDRESS
        );

        exchangeIncentive = 50000;
    }

    receive()
        external
        payable
    {
        _checkReentrancy();

        emit ETHReceived(
            msg.value,
            msg.sender
        );
    }

    event ETHReceived(
        uint256 _amount,
        address _sender
    );

    event ChangeExchangeIncentive(
        uint256 _newExchangeIncentive
    );

    event WithdrawLp(
        address indexed _pendleMarket,
        address indexed _to,
        uint256 _amount
    );

    event ExchangeRewardsForCompounding(
        address indexed _pendleMarket,
        address indexed _rewardToken,
        uint256 _rewardAmount,
        uint256 _sendingAmount
    );

    event ExchangeLpFeesForPendle(
        address indexed _pendleMarket,
        uint256 _pendleChildShares,
        uint256 _tokenAmountSend,
        uint256 _withdrawnAmount
    );

    event AddPendleMarket(
        address indexed _pendleMarket,
        address indexed _pendleChildAddress
    );

    event UpdateRewardTokens(
        address indexed _pendleMarket,
        address[] _rewardTokens
    );

    event ChangeMintFee(
        address indexed _pendleMarket,
        uint256 _newFee
    );

    event LockPendle(
        uint256 _amount,
        uint128 _expiry,
        uint256 _newVeBalance,
        bool _fromInside,
        bool _sameExpiry,
        uint256 _timestamp
    );

    event ClaimArb(
        uint256 _accrued,
        bytes32[] _proof,
        uint256 _timestamp
    );

    event IncreaseReservedForCompound(
        address indexed _pendleMarket,
        uint256[] _amounts
    );

    event ClaimVoteRewards(
        uint256 _amount,
        bytes32[] _merkleProof,
        uint256 _timestamp
    );

    event WithdrawLock(
        uint256 _amount,
        uint256 _timestamp
    );

    modifier syncSupply(
        address _pendleMarket
    )
    {
        _syncSupply(
            _pendleMarket
        );
        _;
    }

    modifier onlyChildContract(
        address _pendleMarket
    )
    {
        _onlyChildContract(
            _pendleMarket
        );
        _;
    }

    modifier onlyArbitrum()
    {
        _onlyArbitrum();
        _;
    }

    function _onlyArbitrum()
        private
        view
    {
        if (block.chainid != ARBITRUM_CHAIN_ID) {
            revert NotArbitrum();
        }
    }

    function _onlyChildContract(
        address _pendleMarket
    )
        private
        view
    {
        if (msg.sender != pendleChildAddress[_pendleMarket]) {
            revert NotAllowed();
        }
    }

    function _syncSupply(
        address _pendleMarket
    )
        internal
    {
        address child = pendleChildAddress[
            _pendleMarket
        ];

        if (child == ZERO_ADDRESS) {
            revert WrongAddress();
        }

        IPendlePowerFarmToken(child).manualSync();
    }

    function syncAllSupply()
        public
    {
        uint256 i;
        uint256 length = activePendleMarkets.length;

        while (i < length) {

            address pendleMarket = activePendleMarkets[i];

            unchecked {
                ++i;
            }

            if (_checkSyncNotNecessary(pendleMarket) == true) {
                continue;
            }

            _syncSupply(
                pendleMarket
            );
        }
    }

    function _checkSyncNotNecessary(
        address _pendleMarket
    )
        private
        view
        returns (bool)
    {
        address child = pendleChildAddress[
            _pendleMarket
        ];

        return syncNotNecessary[child] == true;
    }

    function _checkReentrancy()
        internal
        view
    {
        if (sendingProgress == true) {
            revert CheckSendingOnGoing();
        }
    }
}
PendlePowerFarmControllerHelper.sol 377 lines
// SPDX-License-Identifier: -- WISE --

pragma solidity =0.8.25;

import "./PendlePowerFarmControllerBase.sol";

abstract contract PendlePowerFarmControllerHelper is PendlePowerFarmControllerBase {

    function _findIndex(
        address[] memory _array,
        address _value
    )
        internal
        pure
        returns (uint256)
    {
        uint256 i;
        uint256 len = _array.length;

        while (i < len) {
            if (_array[i] == _value) {
                return i;
            }
            unchecked {
                ++i;
            }
        }

        revert NotFound();
    }

    function _calcExpiry(
        uint128 _weeks
    )
        internal
        view
        returns (uint128)
    {
        uint128 startTime = uint128(
            (block.timestamp / WEEK) * WEEK
        );

        return startTime + (_weeks * WEEK);
    }

    function _getExpiry()
        internal
        view
        returns (uint256)
    {
        return _getPositionData(address(this)).expiry;
    }

    function _getLockAmount()
        internal
        view
        returns (uint256)
    {
        return _getPositionData(address(this)).amount;
    }

    function _getPositionData(
        address _user
    )
        private
        view
        returns (LockedPosition memory)
    {
        return PENDLE_LOCK.positionData(
            _user
        );
    }

    function _getAmountToSend(
        address _tokenAddress,
        uint256 _rewardValue
    )
        internal
        view
        returns (uint256)
    {
        uint256 sendingValue = _rewardValue
            * (PRECISION_FACTOR_E6 - exchangeIncentive)
            / PRECISION_FACTOR_E6;

        if (sendingValue < PRECISION_FACTOR_E10) {
            revert ValueTooSmall();
        }

        return _getTokensFromETH(
            _tokenAddress,
            sendingValue
        );
    }

    function pendleChildCompoundInfoReservedForCompound(
        address _pendleMarket
    )
        external
        view
        returns (uint256[] memory)
    {
        return pendleChildCompoundInfo[_pendleMarket].reservedForCompound;
    }

    function pendleChildCompoundInfoLastIndex(
        address _pendleMarket
    )
        external
        view
        returns (uint128[] memory)
    {
        return pendleChildCompoundInfo[_pendleMarket].lastIndex;
    }

    function pendleChildCompoundInfoRewardTokens(
        address _pendleMarket
    )
        external
        view
        returns (address[] memory)
    {
        return pendleChildCompoundInfo[_pendleMarket].rewardTokens;
    }

    function activePendleMarketsLength()
        public
        view
        returns (uint256)
    {
        return activePendleMarkets.length;
    }

    function _checkFeed(
        address token
    )
        internal
        view
    {
        if (ORACLE_HUB.priceFeed(token) == ZERO_ADDRESS) {
            revert WrongAddress();
        }
    }

    function _getRewardTokens(
        address _pendleMarket
    )
        internal
        view
        returns (address[] memory)
    {
        return IPendleMarket(
            _pendleMarket
        ).getRewardTokens();
    }

    function _getUserReward(
        address _pendleMarket,
        address _rewardToken,
        address _user
    )
        internal
        view
        returns (UserReward memory)
    {
        return IPendleMarket(
            _pendleMarket
        ).userReward(
            _rewardToken,
            _user
        );
    }

    function _getUserRewardIndex(
        address _pendleMarket,
        address _rewardToken,
        address _user
    )
        internal
        view
        returns (uint128)
    {
        return _getUserReward(
            _pendleMarket,
            _rewardToken,
            _user
        ).index;
    }

    function _getTokensInETH(
        address _tokenAddress,
        uint256 _tokenAmount
    )
        internal
        view
        returns (uint256)
    {
        return ORACLE_HUB.getTokensInETH(
            _tokenAddress,
            _tokenAmount
        );
    }

    function _getTokensFromETH(
        address _tokenAddress,
        uint256 _ethValue
    )
        internal
        view
        returns (uint256)
    {
        return ORACLE_HUB.getTokensFromETH(
            _tokenAddress,
            _ethValue
        );
    }

    function _compareHashes(
        address _pendleMarket,
        address[] memory rewardTokensToCompare
    )
        internal
        view
        returns (bool)
    {
        return keccak256(
            abi.encode(
                rewardTokensToCompare
            )
        ) == keccak256(
            abi.encode(
                pendleChildCompoundInfo[_pendleMarket].rewardTokens
            )
        );
    }

    function _forbiddenSelector(
        bytes memory _callData
    )
        internal
        pure
        returns (bool forbidden)
    {
        bytes4 selector;

        assembly {
            selector := mload(add(_callData, 32))
        }

        if (selector == APPROVE_SELECTOR) {
            return true;
        }

        if (selector == PERMIT_SELECTOR) {
            return true;
        }
    }

    function _getHashChainResult()
        internal
        view
        returns (bytes32)
    {
        uint256 pendleTokenBalance = PENDLE_TOKEN_INSTANCE.balanceOf(
            address(this)
        );

        bytes32 floatingHash = keccak256(
            abi.encodePacked(
                INITIAL_HASH,
                pendleTokenBalance
            )
        );

        uint256 i;
        address currentMarket;
        uint256 marketLength = activePendleMarkets.length;

        while (i < marketLength) {

            currentMarket = activePendleMarkets[i];

            floatingHash = _getRewardTokenHashes(
                currentMarket,
                floatingHash
            );

            floatingHash = _encodeFloatingHash(
                floatingHash,
                currentMarket
            );

            unchecked{
                ++i;
            }
        }

        return floatingHash;
    }

    function _encodeFloatingHash(
        bytes32 _floatingHash,
        address _currentMarket
    )
        internal
        view
        returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                _floatingHash,
                IERC20(_currentMarket).balanceOf(
                    address(this)
                )
            )
        );
    }

    function _getRewardTokenHashes(
        address _pendleMarket,
        bytes32 _floatingHash
    )
        internal
        view
        returns (bytes32)
    {
        address[] memory rewardTokens = pendleChildCompoundInfo[_pendleMarket].rewardTokens;
        uint256 l = rewardTokens.length;
        uint256 i = 0;

        while (i < l) {

            if (rewardTokens[i] == PENDLE_TOKEN_ADDRESS) {
                unchecked{
                    ++i;
                }
                continue;
            }

            _floatingHash = _encodeFloatingHash(
                _floatingHash,
                rewardTokens[i]
            );

            unchecked{
                ++i;
            }
        }

        return _floatingHash;
    }

    function _setRewardTokens(
        address _pendleMarket,
        address[] memory _rewardTokens
    )
        internal
    {
        pendleChildCompoundInfo[_pendleMarket].rewardTokens = _rewardTokens;
    }

    function getExpiry()
        external
        view
        returns (uint256)
    {
        return _getExpiry();
    }

    function getLockAmount()
        external
        view
        returns (uint256)
    {
        return _getLockAmount();
    }
}

Read Contract

ARB_REWARDS 0x765d8b2e → address
PENDLE_LOCK 0xfcbc1d60 → address
PENDLE_POWER_FARM_TOKEN_FACTORY 0x98ae1f52 → address
PENDLE_VOTER 0x170c95b7 → address
PENDLE_VOTE_REWARDS 0x80ae2e5c → address
activePendleMarkets 0xd850e319 → address
activePendleMarketsLength 0xd682e30a → uint256
exchangeIncentive 0x8d8f3730 → uint256
getExpiry 0xf61c266b → uint256
getLockAmount 0xd64c34fc → uint256
master 0xee97f7f3 → address
pendleChildAddress 0x241d8afe → address
pendleChildCompoundInfoLastIndex 0x66b2d8f9 → uint128[]
pendleChildCompoundInfoReservedForCompound 0xf2bf69f6 → uint256[]
pendleChildCompoundInfoRewardTokens 0x10d2b492 → address[]
proposedMaster 0xd3573a33 → address
reservedPendleForLocking 0xd5ca7970 → uint256
sendingProgress 0x019dbb63 → bool
syncNotNecessary 0x9fc49734 → bool

Write Contract 27 functions

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

addPendleMarket 0x7afcdc3c
address _pendleMarket
string _tokenName
string _symbolName
uint16 _maxCardinality
changeCompoundRoleState 0xcaf44bd6
address _pendleMarket
address _roleReceiver
bool _state
changeExchangeIncentive 0x438e55a0
uint256 _newExchangeIncentive
changeGrowthCheckState 0x3684a72b
address _pendleMarket
bool _state
changeMinDepositAmount 0x17f8abb0
address _pendleMarket
uint256 _newAmount
changeMintFee 0xc8a7caac
address _pendleMarket
uint256 _newFee
changeSyncCheck 0x9c823f37
address _pendleMarket
bool _state
claimAirdropSafe 0xe3b9bac8
bytes[] _calldataArray
address[] _contractAddresses
claimArb 0x00445e4b
uint256 _accrued
bytes32[] _proof
claimOwnership 0x4e71e0c8
No parameters
claimVoteRewards 0x6109cdbf
uint256 _amount
bytes32[] _merkleProof
exchangeLpFeesForPendleWithIncentive 0x6797d24c
address _pendleMarket
uint256 _pendleChildShares
returns: uint256, uint256
exchangeRewardsForCompoundingWithIncentive 0x78b7d455
address _pendleMarket
address _rewardToken
uint256 _rewardAmount
returns: uint256
forwardETH 0xdf61427e
address _to
uint256 _amount
increaseReservedForCompound 0x7aeaa75d
address _pendleMarket
uint256[] _amounts
lockPendle 0x3f6f34de
uint256 _amount
uint128 _weeks
bool _fromInside
bool _sameExpiry
returns: uint256
overWriteAmounts 0x5d99ba83
address _pendleMarket
overWriteIndex 0x04b473bd
address _pendleMarket
uint256 _tokenIndex
overWriteIndexAll 0x3f828600
address _pendleMarket
proposeOwner 0xb5ed298a
address _proposedOwner
renounceOwnership 0x715018a6
No parameters
skim 0xbc25cf77
address _pendleMarket
returns: uint256
syncAllSupply 0xe5e933d3
No parameters
updateRewardTokens 0x9f08e497
address _pendleMarket
returns: bool
vote 0x698766ee
address[] _pools
uint64[] _weights
withdrawLock 0x5c388ca6
No parameters
returns: uint256
withdrawLp 0xa6c3ef8b
address _pendleMarket
address _to
uint256 _amount

Recent Transactions

No transactions found for this address