Address Contract Verified
Address
0xE5B2FAbF3b2000eB6b03Bb4EbeA80fABC6159cF0
Balance
0 ETH
Nonce
1
Code Size
12624 bytes
Creator
0xCa36bfF1...B0f4 at tx 0x5854c70c...6787f4
Indexed Transactions
0
Contract Bytecode
12624 bytes
0x608060405234801561000f575f80fd5b5060043610610156575f3560e01c80638d072c40116100c1578063cf891ad81161007a578063cf891ad8146103b5578063e521136f146103d1578063e7986466146103ed578063f2fde38b14610409578063f887ea4014610425578063fbfa77cf1461044357610156565b80638d072c40146102f35780638da5cb5b1461030f578063aced16611461032d578063c7ed089e1461034b578063ca362ab414610369578063cea9d26f1461039957610156565b80635fcbd285116101135780635fcbd285146102455780636817031b1461026357806368c4ac261461027f578063715018a6146102af578063748747e6146102b957806380f55605146102d557610156565b8063023a8c8b1461015a57806317f333401461018a5780631dbef4a9146101a857806351261050146101c6578063515ce517146101f657806359356c5c14610227575b5f80fd5b610174600480360381019061016f91906125b0565b610461565b60405161018191906125f3565b60405180910390f35b610192610546565b60405161019f919061261b565b60405180910390f35b6101b061056b565b6040516101bd919061268f565b60405180910390f35b6101e060048036038101906101db9190612733565b610590565b6040516101ed91906125f3565b60405180910390f35b610210600480360381019061020b91906125b0565b610c09565b60405161021e929190612912565b60405180910390f35b61022f610fcd565b60405161023c91906125f3565b60405180910390f35b61024d61106c565b60405161025a9190612967565b60405180910390f35b61027d600480360381019061027891906125b0565b611091565b005b610299600480360381019061029491906125b0565b6111c1565b6040516102a6919061299a565b60405180910390f35b6102b76111de565b005b6102d360048036038101906102ce91906125b0565b6111f1565b005b6102dd61123c565b6040516102ea919061261b565b60405180910390f35b61030d600480360381019061030891906129b3565b611261565b005b6103176113e5565b604051610324919061261b565b60405180910390f35b61033561140c565b604051610342919061261b565b60405180910390f35b610353611431565b60405161036091906129f1565b60405180910390f35b610383600480360381019061037e9190612733565b6114c9565b60405161039091906125f3565b60405180910390f35b6103b360048036038101906103ae9190612a11565b611add565b005b6103cf60048036038101906103ca9190612a61565b611b7a565b005b6103eb60048036038101906103e691906125b0565b611d95565b005b61040760048036038101906104029190612ac9565b611ec5565b005b610423600480360381019061041e91906125b0565b611fd8565b005b61042d61205c565b60405161043a9190612b27565b60405180910390f35b61044b612080565b604051610458919061261b565b60405180910390f35b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036104c7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610500919061261b565b602060405180830381865afa15801561051b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061053f9190612b54565b9050919050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f6105996120a5565b60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461061f576040517f62df054500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8403610658576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036106bd576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1661073d576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610798919061261b565b602060405180830381865afa1580156107b3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d79190612b54565b1015610818576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161080f90612bd9565b60405180910390fd5b5f8590506108887f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f9468660025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166120eb9092919063ffffffff16565b5f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016108c2919061261b565b602060405180830381865afa1580156108dd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109019190612b54565b90505f807f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f94673ffffffffffffffffffffffffffffffffffffffff16878760405161094c929190612c33565b5f604051808303815f865af19150503d805f8114610985576040519150601f19603f3d011682016040523d82523d5f602084013e61098a565b606091505b509150915081610a4b57610a007f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f9465f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166120eb9092919063ffffffff16565b5f815103610a43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a3a90612cbb565b60405180910390fd5b805160208201fd5b610ab77f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f9465f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166120eb9092919063ffffffff16565b5f8473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610af1919061261b565b602060405180830381865afa158015610b0c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b309190612b54565b90508381610b3e9190612d06565b95505f8603610b79576040517f97d9569c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ba433878773ffffffffffffffffffffffffffffffffffffffff166121f89092919063ffffffff16565b8973ffffffffffffffffffffffffffffffffffffffff167f02ffa641367f5b897c0f8be81bce51f2ef055b4113d7a1e4fd082feea749bf528a88604051610bec929190612d39565b60405180910390a25050505050610c01612277565b949350505050565b606080610c146120a5565b60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610cbe575060085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15610cf5576040517fea8e4eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610d2f5783610d52565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff165b905060045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c4f59f9b6040518163ffffffff1660e01b81526004015f60405180830381865afa158015610dbd573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610de59190612ebc565b925060045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639262187b306040518263ffffffff1660e01b8152600401610e41919061261b565b5f604051808303815f875af1158015610e5c573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610e849190612fc3565b91505f5b8351811015610f57575f848281518110610ea557610ea461300a565b5b602002602001015190505f82855111610ebe575f610eda565b848381518110610ed157610ed061300a565b5b60200260200101515b90505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610f1757505f81115b15610f4857610f4784828473ffffffffffffffffffffffffffffffffffffffff166121f89092919063ffffffff16565b5b50508080600101915050610e88565b508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f10a210883f97ab1cc72d6887723a3cfc7c0270e43a65c960ff9fc9a14239b12c8585604051610fb7929190612912565b60405180910390a350610fc8612277565b915091565b5f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611028919061261b565b602060405180830381865afa158015611043573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110679190612b54565b905090565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611099612280565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036110fe576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f483bdedaaf23706a9800ac1af0d852b34927780d79f9d6ba60a80c7cad75ea3960405160405180910390a35050565b6006602052805f5260405f205f915054906101000a900460ff1681565b6111e6612280565b6111ef5f612307565b565b6111f9612280565b8060085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6112696120a5565b60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146112ef576040517f62df054500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611354576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f810361138d576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113d9828260025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166121f89092919063ffffffff16565b6113e1612277565b5050565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c4f59f9b6040518163ffffffff1660e01b81526004015f60405180830381865afa15801561149c573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906114c49190612ebc565b905090565b5f6114d26120a5565b60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611558576040517f62df054500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8403611591576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036115f6576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16611676576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8590505f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016116b4919061261b565b602060405180830381865afa1580156116cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116f39190612b54565b90508581101561173b575f818761170a9190612d06565b90506117393330838673ffffffffffffffffffffffffffffffffffffffff166123c8909392919063ffffffff16565b505b6117867f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f946878473ffffffffffffffffffffffffffffffffffffffff166120eb9092919063ffffffff16565b5f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016117e1919061261b565b602060405180830381865afa1580156117fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118209190612b54565b90505f807f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f94673ffffffffffffffffffffffffffffffffffffffff16888860405161186b929190612c33565b5f604051808303815f865af19150503d805f81146118a4576040519150601f19603f3d011682016040523d82523d5f602084013e6118a9565b606091505b509150915081611949576118fe7f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f9465f8773ffffffffffffffffffffffffffffffffffffffff166120eb9092919063ffffffff16565b5f815103611941576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161193890612cbb565b60405180910390fd5b805160208201fd5b6119947f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f9465f8773ffffffffffffffffffffffffffffffffffffffff166120eb9092919063ffffffff16565b5f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016119ef919061261b565b602060405180830381865afa158015611a0a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a2e9190612b54565b90508381611a3c9190612d06565b96505f8703611a77576040517f97d9569c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8a73ffffffffffffffffffffffffffffffffffffffff167ffaddc2a572d923daf0944fe20bf804595e90ca57c85045b1081d338d1510bf148b89604051611abf929190612d39565b60405180910390a2505050505050611ad5612277565b949350505050565b611ae5612280565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611b4a576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b7582828573ffffffffffffffffffffffffffffffffffffffff166121f89092919063ffffffff16565b505050565b611b82612280565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480611be757505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b15611c1e576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508360035f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f7ec9b4ca0d9d91122c2ce339e653f9c87d70a5e9e681f085961edea2ce86503d8386604051611d87929190613037565b60405180910390a350505050565b611d9d612280565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611e02576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167fc8c11bb97ac2ffa10ce2e2a98f4c1fd8df84cfa2e1a15e013ed2383ab1f527ad60405160405180910390a35050565b611ecd612280565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611f32576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060065f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff167fd86c88b4a367d9b81a6e00c9d3f7d01657bffef358fa8968c91c045ae99f0d5282604051611fcc919061299a565b60405180910390a25050565b611fe0612280565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612050575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401612047919061261b565b60405180910390fd5b61205981612307565b50565b7f000000000000000000000000888888888889758f76e7103c6cbf23abbf58f94681565b60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6002600154036120e1576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600181905550565b5f8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b3848460405160240161211b92919061305e565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050612169848261244a565b6121f2576121e7848573ffffffffffffffffffffffffffffffffffffffff1663095ea7b3865f6040516024016121a09291906130be565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506124a3565b6121f184826124a3565b5b50505050565b612272838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb858560405160240161222b92919061305e565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506124a3565b505050565b60018081905550565b61228861253e565b73ffffffffffffffffffffffffffffffffffffffff166122a66113e5565b73ffffffffffffffffffffffffffffffffffffffff1614612305576122c961253e565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016122fc919061261b565b60405180910390fd5b565b5f805f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b612444848573ffffffffffffffffffffffffffffffffffffffff166323b872dd8686866040516024016123fd939291906130e5565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506124a3565b50505050565b5f805f8060205f8651602088015f8a5af192503d91505f51905082801561249857505f821461247c5760018114612497565b5f8673ffffffffffffffffffffffffffffffffffffffff163b115b5b935050505092915050565b5f8060205f8451602086015f885af1806124c2576040513d5f823e3d81fd5b3d92505f519150505f82146124db5760018114156124f6565b5f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561253857836040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161252f919061261b565b60405180910390fd5b50505050565b5f33905090565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61257f82612556565b9050919050565b61258f81612575565b8114612599575f80fd5b50565b5f813590506125aa81612586565b92915050565b5f602082840312156125c5576125c461254e565b5b5f6125d28482850161259c565b91505092915050565b5f819050919050565b6125ed816125db565b82525050565b5f6020820190506126065f8301846125e4565b92915050565b61261581612575565b82525050565b5f60208201905061262e5f83018461260c565b92915050565b5f819050919050565b5f61265761265261264d84612556565b612634565b612556565b9050919050565b5f6126688261263d565b9050919050565b5f6126798261265e565b9050919050565b6126898161266f565b82525050565b5f6020820190506126a25f830184612680565b92915050565b6126b1816125db565b81146126bb575f80fd5b50565b5f813590506126cc816126a8565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f8401126126f3576126f26126d2565b5b8235905067ffffffffffffffff8111156127105761270f6126d6565b5b60208301915083600182028301111561272c5761272b6126da565b5b9250929050565b5f805f806060858703121561274b5761274a61254e565b5b5f6127588782880161259c565b9450506020612769878288016126be565b935050604085013567ffffffffffffffff81111561278a57612789612552565b5b612796878288016126de565b925092505092959194509250565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6127d681612575565b82525050565b5f6127e783836127cd565b60208301905092915050565b5f602082019050919050565b5f612809826127a4565b61281381856127ae565b935061281e836127be565b805f5b8381101561284e57815161283588826127dc565b9750612840836127f3565b925050600181019050612821565b5085935050505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61288d816125db565b82525050565b5f61289e8383612884565b60208301905092915050565b5f602082019050919050565b5f6128c08261285b565b6128ca8185612865565b93506128d583612875565b805f5b838110156129055781516128ec8882612893565b97506128f7836128aa565b9250506001810190506128d8565b5085935050505092915050565b5f6040820190508181035f83015261292a81856127ff565b9050818103602083015261293e81846128b6565b90509392505050565b5f6129518261265e565b9050919050565b61296181612947565b82525050565b5f60208201905061297a5f830184612958565b92915050565b5f8115159050919050565b61299481612980565b82525050565b5f6020820190506129ad5f83018461298b565b92915050565b5f80604083850312156129c9576129c861254e565b5b5f6129d68582860161259c565b92505060206129e7858286016126be565b9150509250929050565b5f6020820190508181035f830152612a0981846127ff565b905092915050565b5f805f60608486031215612a2857612a2761254e565b5b5f612a358682870161259c565b9350506020612a468682870161259c565b9250506040612a57868287016126be565b9150509250925092565b5f8060408385031215612a7757612a7661254e565b5b5f612a848582860161259c565b9250506020612a958582860161259c565b9150509250929050565b612aa881612980565b8114612ab2575f80fd5b50565b5f81359050612ac381612a9f565b92915050565b5f8060408385031215612adf57612ade61254e565b5b5f612aec8582860161259c565b9250506020612afd85828601612ab5565b9150509250929050565b5f612b118261265e565b9050919050565b612b2181612b07565b82525050565b5f602082019050612b3a5f830184612b18565b92915050565b5f81519050612b4e816126a8565b92915050565b5f60208284031215612b6957612b6861254e565b5b5f612b7684828501612b40565b91505092915050565b5f82825260208201905092915050565b7f696e73756666696369656e74204c5000000000000000000000000000000000005f82015250565b5f612bc3600f83612b7f565b9150612bce82612b8f565b602082019050919050565b5f6020820190508181035f830152612bf081612bb7565b9050919050565b5f81905092915050565b828183375f83830152505050565b5f612c1a8385612bf7565b9350612c27838584612c01565b82840190509392505050565b5f612c3f828486612c0f565b91508190509392505050565b7f526f757465722063616c6c206661696c656420776974686f757420726561736f5f8201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b5f612ca5602183612b7f565b9150612cb082612c4b565b604082019050919050565b5f6020820190508181035f830152612cd281612c99565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612d10826125db565b9150612d1b836125db565b9250828203905081811115612d3357612d32612cd9565b5b92915050565b5f604082019050612d4c5f8301856125e4565b612d5960208301846125e4565b9392505050565b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612da682612d60565b810181811067ffffffffffffffff82111715612dc557612dc4612d70565b5b80604052505050565b5f612dd7612545565b9050612de38282612d9d565b919050565b5f67ffffffffffffffff821115612e0257612e01612d70565b5b602082029050602081019050919050565b5f81519050612e2181612586565b92915050565b5f612e39612e3484612de8565b612dce565b90508083825260208201905060208402830185811115612e5c57612e5b6126da565b5b835b81811015612e855780612e718882612e13565b845260208401935050602081019050612e5e565b5050509392505050565b5f82601f830112612ea357612ea26126d2565b5b8151612eb3848260208601612e27565b91505092915050565b5f60208284031215612ed157612ed061254e565b5b5f82015167ffffffffffffffff811115612eee57612eed612552565b5b612efa84828501612e8f565b91505092915050565b5f67ffffffffffffffff821115612f1d57612f1c612d70565b5b602082029050602081019050919050565b5f612f40612f3b84612f03565b612dce565b90508083825260208201905060208402830185811115612f6357612f626126da565b5b835b81811015612f8c5780612f788882612b40565b845260208401935050602081019050612f65565b5050509392505050565b5f82601f830112612faa57612fa96126d2565b5b8151612fba848260208601612f2e565b91505092915050565b5f60208284031215612fd857612fd761254e565b5b5f82015167ffffffffffffffff811115612ff557612ff4612552565b5b61300184828501612f96565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60408201905061304a5f83018561260c565b613057602083018461260c565b9392505050565b5f6040820190506130715f83018561260c565b61307e60208301846125e4565b9392505050565b5f819050919050565b5f6130a86130a361309e84613085565b612634565b6125db565b9050919050565b6130b88161308e565b82525050565b5f6040820190506130d15f83018561260c565b6130de60208301846130af565b9392505050565b5f6060820190506130f85f83018661260c565b613105602083018561260c565b61311260408301846125e4565b94935050505056fea2646970667358221220292113e2a536e49409d73c10d8d91c780f8f1a49664363eb0adf08961545819964736f6c63430008160033
Verified Source Code Full Match
Compiler: v0.8.22+commit.4fc1097e
EVM: shanghai
Optimization: No
PendleAdapter_v3.sol 475 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/**
* @title PendleAdapter
* @notice Production-grade adapter for Pendle LP strategy
* @dev This adapter is an EXECUTOR ONLY - all pricing, slippage, and routing
* is handled OFF-CHAIN via Pendle SDK or Hosted API.
*
* Architecture:
* - Backend/Keeper generates swap parameters (SwapData, GuessPtReceivedFromSy, minOut)
* - Adapter executes the zap with provided parameters
* - NO on-chain price calculations
* - NO on-chain swap calldata building
* - Follows Yearn-style adapter architecture
*/
//VAULT 0x1B6Bb412a7E077958C9FdA5e6f0235dbB22F7a8B
//usdc 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
//usdt 0xdAC17F958D2ee523a2206206994597C13D831ec7
//lptoken 0x6D520a943a4Da0784917a2e71defe95248A1DaA1
//market address 0x6D520a943a4Da0784917a2e71defe95248A1DaA1
//ZapRouter 0x888888888889758F76e7103c6CbF23ABbF58F946
// NEW DEPLOY 0xCbFDBAe49883E378752fF3F64bf8d89562912Da6
// ========= Pendle Router Structs (must match ABI exactly) =========
interface IPMarket {
function getRewardTokens() external view returns (address[] memory);
function redeemRewards(address user) external returns (uint256[] memory);
}
/// =======================
/// IPAllActionV3 (minimal)
/// =======================
interface IPAllActionV3 {
struct ApproxParams {
uint256 guessMin;
uint256 guessMax;
uint256 guessOffchain;
uint256 maxIteration;
uint256 eps;
}
// EXACTLY: (uint256,address,bytes,bool)
struct SwapData {
uint8 swapType;
address extRouter;
bytes extCalldata;
bool needScale;
}
// EXACTLY: (address,uint256,address,address,SwapData)
struct TokenInput {
address tokenIn;
uint256 netTokenIn;
address tokenMintSy;
address pendleSwap;
SwapData swapData;
}
// EXACTLY (for removeLiquidity): (address,uint256,address,address,SwapData) but as output params
struct TokenOutput {
address tokenOut;
uint256 minTokenOut;
address tokenRedeemSy;
address pendleSwap;
SwapData swapData;
}
/**
* @dev Minimal placeholder for tuple element type.
* If in future you actually pass fills (non-empty), you MUST match Pendle's real struct.
* With empty arrays, ABI encoding is still correct.
*/
struct FillOrderParams {
bytes order;
bytes signature;
uint256 makingAmount;
uint256 takingAmount;
}
// EXACTLY: (address,uint256,tuple[],tuple[],bytes)
struct LimitOrderData {
address limitRouter;
uint256 epsSkipMarket;
FillOrderParams[] normalFills;
FillOrderParams[] flashFills;
bytes optData;
}
function addLiquiditySingleToken(
address receiver,
address market,
uint256 minLpOut,
ApproxParams calldata approx,
TokenInput calldata input,
LimitOrderData calldata limit
) external payable returns (uint256 netLpOut, uint256 netSyFee, uint256 netSyInterm);
function removeLiquiditySingleToken(
address receiver,
address market,
uint256 netLpToRemove,
TokenOutput calldata output,
LimitOrderData calldata limit
) external returns (uint256 netTokenOut, uint256 netSyFee, uint256 netSyInterm);
}
// ========= Main Contract =========
contract PendleAdapter is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
// ========= Immutable State =========
IERC20 public lpToken; // Pendle LP token
address public market; // Pendle market address (gauge embedded)
IPAllActionV3 public immutable router;
// NEW: market interface for rewards
IPMarket public marketRewards;
// ========= Mutable State =========
address public vault; // Authorized vault address
mapping(address => bool) public supportedTokens; // Supported tokens (USDC, USDT, etc.)
// NEW: where harvested rewards are sent (default: vault)
address public rewardRecipient;
// ========= Events =========
event Deposited(uint256 tokenAmount, uint256 lpReceived, address indexed token);
event Withdrawn(uint256 lpAmount, uint256 tokenReceived, address indexed token);
event VaultUpdated(address indexed oldVault, address indexed newVault);
event TokenSupported(address indexed token, bool supported);
// NEW events
event RewardRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);
event RewardsHarvested(address indexed caller, address indexed recipient, address[] rewardTokens, uint256[] amounts);
// ========= Errors =========
error ZeroAddress();
error ZeroAmount();
error NotVault();
error InvalidInput();
error ZapFailed();
error NotAuthorized();
error BadCalldataSelector();
error BadCalldataReceiver();
error BadCalldataMarket();
// ========= Modifiers =========
modifier onlyVault() {
if (msg.sender != vault) revert NotVault();
_;
}
// optional: allow a keeper to harvest (owner sets it)
address public keeper;
modifier onlyVaultOrKeeper() {
if (msg.sender != vault && msg.sender != keeper) revert NotAuthorized();
_;
}
constructor(
address _vault,
address _lpToken,
address _market,
address _router
) Ownable(msg.sender) {
if (_vault == address(0) || _lpToken == address(0) ||
_market == address(0) || _router == address(0)) revert ZeroAddress();
vault = _vault;
lpToken = IERC20(_lpToken);
market = _market;
router = IPAllActionV3(_router);
// NEW
marketRewards = IPMarket(_market);
rewardRecipient = _vault;
}
function setKeeper(address _keeper) external onlyOwner {
keeper = _keeper; // can be zero to disable
}
function setRewardRecipient(address _recipient) external onlyOwner {
if (_recipient == address(0)) revert ZeroAddress();
address old = rewardRecipient;
rewardRecipient = _recipient;
emit RewardRecipientUpdated(old, _recipient);
}
// ========= Token Management =========
/**
* @notice Add or remove a supported token
* @param token Token address to set
* @param supported Whether the token is supported
*/
function setSupportedToken(address token, bool supported) external onlyOwner {
if (token == address(0)) revert ZeroAddress();
supportedTokens[token] = supported;
emit TokenSupported(token, supported);
}
// -------------------- NEW: rewards view helpers --------------------
/// @notice Reward tokens for this market (can include PENDLE + others)
function getMarketRewardTokens() external view returns (address[] memory) {
return marketRewards.getRewardTokens();
}
// -------------------- NEW: harvest rewards --------------------
/**
* @notice Claims (redeems) market rewards accrued by this Adapter (LP holder).
* @dev Pendle V2 rewards for LP holders are claimed via Market.redeemRewards(adapter).
* This does NOT unstake anything; gauge is embedded in the market. :contentReference[oaicite:2]{index=2}
*
* @param recipient Where to send harvested rewards (if zero, uses rewardRecipient)
* @return rewardTokens tokens claimed
* @return amounts amounts claimed (same order as rewardTokens)
*/
function harvestRewards(address recipient)
external
nonReentrant
onlyVaultOrKeeper
returns (address[] memory rewardTokens, uint256[] memory amounts)
{
address to = recipient == address(0) ? rewardRecipient : recipient;
rewardTokens = marketRewards.getRewardTokens();
// Claim rewards for THIS adapter address
amounts = marketRewards.redeemRewards(address(this));
// Send claimed tokens to recipient
// Note: redeemRewards returns amounts in order of getRewardTokens() :contentReference[oaicite:3]{index=3}
for (uint256 i = 0; i < rewardTokens.length; i++) {
address rt = rewardTokens[i];
uint256 amt = amounts.length > i ? amounts[i] : 0;
if (rt != address(0) && amt > 0) {
IERC20(rt).safeTransfer(to, amt);
}
}
emit RewardsHarvested(msg.sender, to, rewardTokens, amounts);
}
/* =========================
HARDENED ZAP CALL HELPERS
========================= */
function _selector(bytes calldata data) internal pure returns (bytes4 sel) {
if (data.length < 4) return 0x00000000;
assembly {
sel := calldataload(data.offset)
}
}
/**
* @dev Validates that calldata is calling the expected Pendle router function
* and that first 2 args match (receiver, market).
*
* ABI: function(receiver, market, ...) => first two args are address,address.
*/
function _validateRouterCalldata(bytes calldata data) internal view {
bytes4 sel = _selector(data);
bytes4 addSel = IPAllActionV3.addLiquiditySingleToken.selector;
bytes4 remSel = IPAllActionV3.removeLiquiditySingleToken.selector;
if (sel != addSel && sel != remSel) revert BadCalldataSelector();
// decode first two args after selector:
// data layout: 4 bytes selector + ABI encoded args
// args start at offset 4
(address receiver, address mkt) = abi.decode(data[4:], (address, address));
if (receiver != address(this)) revert BadCalldataReceiver();
if (mkt != market) revert BadCalldataMarket();
}
function _approveExactThenZero(IERC20 token, address spender, uint256 amount) internal {
// forceApprove handles USDT-style approvals
token.forceApprove(spender, amount);
// Important: reset after use to minimize allowance misuse window
token.forceApprove(spender, 0);
}
// ========= Zap In (Deposit) =========
/**
* @notice Deposit token using pre-built calldata from Pendle API (GENERIC)
* @dev This is the RECOMMENDED method - uses Pendle API's pre-built calldata
* which ensures correct struct encoding and selector matching.
* Supports any ERC20 token (USDC, USDT, etc.)
*
* @param token Token address to deposit (must be supported)
* @param tokenAmount Amount of token to deposit
* @param routerCalldata Pre-built calldata from Pendle API (routerTx.data)
* @return lpReceived Amount of LP tokens received
*/
function depositWithCalldataGeneric(
address token,
uint256 tokenAmount,
bytes calldata routerCalldata
) external nonReentrant onlyVault returns (uint256 lpReceived) {
if (tokenAmount == 0) revert ZeroAmount();
if (token == address(0)) revert ZeroAddress();
if (!supportedTokens[token]) revert InvalidInput();
// _validateRouterCalldata(routerCalldata);
IERC20 tokenContract = IERC20(token);
// 1. Transfer token from caller to adapter (if not already present)
uint256 currentBalance = tokenContract.balanceOf(address(this));
if (currentBalance < tokenAmount) {
uint256 needed = tokenAmount - currentBalance;
tokenContract.safeTransferFrom(msg.sender, address(this), needed);
}
// 2. Approve token to ZapRouter
// ⭐ CRITICAL: Use forceApprove for USDT compatibility
// USDT requires allowance to be 0 before setting a new value,
// and doesn't return true on approve() calls.
// forceApprove() handles both cases automatically.
tokenContract.forceApprove(address(router), tokenAmount);
// 3. Record LP balance before
uint256 lpBefore = lpToken.balanceOf(address(this));
// 4. Execute router call with pre-built calldata
// The calldata is built by Pendle API with correct struct encoding
(bool success, bytes memory result) = address(router).call(routerCalldata);
if (!success) {
// reset allowance before bubbling revert (best effort)
tokenContract.forceApprove(address(router), 0);
if (result.length == 0) {
revert("Router call failed without reason");
}
assembly {
revert(add(result, 32), mload(result))
}
}
// Reset allowance after success
tokenContract.forceApprove(address(router), 0);
// 5. Calculate LP received
uint256 lpAfter = lpToken.balanceOf(address(this));
lpReceived = lpAfter - lpBefore;
if (lpReceived == 0) revert ZapFailed();
emit Deposited(tokenAmount, lpReceived, token);
}
function withdrawWithCalldataGeneric(
address tokenOut,
uint256 lpAmount,
bytes calldata routerCalldata
) external nonReentrant onlyVault returns (uint256 tokenReceived) {
if (lpAmount == 0) revert ZeroAmount();
if (tokenOut == address(0)) revert ZeroAddress();
if (!supportedTokens[tokenOut]) revert InvalidInput();
// _validateRouterCalldata(routerCalldata);
require(lpToken.balanceOf(address(this)) >= lpAmount, "insufficient LP");
IERC20 tokenContract = IERC20(tokenOut);
// 1. Approve LP tokens to ZapRouter
// Using forceApprove for consistency (LP token is standard ERC20 but this is safer)
lpToken.forceApprove(address(router), lpAmount);
// 2. Record token balance before
uint256 tokenBefore = tokenContract.balanceOf(address(this));
// 3. Execute router call with pre-built calldata
(bool success, bytes memory result) = address(router).call(routerCalldata);
if (!success) {
lpToken.forceApprove(address(router), 0);
if (result.length == 0) {
revert("Router call failed without reason");
}
assembly {
revert(add(result, 32), mload(result))
}
}
lpToken.forceApprove(address(router), 0);
// 4. Calculate token received
uint256 tokenAfter = tokenContract.balanceOf(address(this));
tokenReceived = tokenAfter - tokenBefore;
if (tokenReceived == 0) revert ZapFailed();
// 5. Transfer token to caller
tokenContract.safeTransfer(msg.sender, tokenReceived);
emit Withdrawn(lpAmount, tokenReceived, tokenOut);
}
function underlyingBalance() external view returns (uint256) {
return lpToken.balanceOf(address(this));
}
/**
* @notice Get idle balance of a specific token
* @param token Token address to check
* @return balance Idle balance of the token
*/
function idleTokenBalance(address token) external view returns (uint256) {
if (token == address(0)) revert ZeroAddress();
return IERC20(token).balanceOf(address(this));
}
function setVault(address _newVault) external onlyOwner {
if (_newVault == address(0)) revert ZeroAddress();
address oldVault = vault;
vault = _newVault;
emit VaultUpdated(oldVault, _newVault);
}
event MarketUpdated(
address indexed oldMarket,
address indexed newMarket,
address oldLpToken,
address newLpToken
);
function setMarketAndLpToken(
address _newMarket,
address _newLpToken
) external onlyOwner {
if (_newMarket == address(0) || _newLpToken == address(0)) revert ZeroAddress();
address oldMarket = market;
address oldLp = address(lpToken);
market = _newMarket;
lpToken = IERC20(_newLpToken);
marketRewards = IPMarket(_newMarket);
emit MarketUpdated(oldMarket, _newMarket, oldLp, _newLpToken);
}
function rescueTokens(address token, address to, uint256 amount) external onlyOwner {
if (to == address(0)) revert ZeroAddress();
IERC20(token).safeTransfer(to, amount);
}
/* =========================
LP-BASED WITHDRAW HELPERS
========================= */
/// @notice Transfer LP to `to` (for withdrawAlternativeLP in the router)
function transferLp(address to, uint256 lpAmount) external nonReentrant onlyVault {
if (to == address(0)) revert ZeroAddress();
if (lpAmount == 0) revert ZeroAmount();
lpToken.safeTransfer(to, lpAmount);
}
}
ReentrancyGuard.sol 87 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
Read Contract
getMarketRewardTokens 0xc7ed089e → address[]
idleTokenBalance 0x023a8c8b → uint256
keeper 0xaced1661 → address
lpToken 0x5fcbd285 → address
market 0x80f55605 → address
marketRewards 0x1dbef4a9 → address
owner 0x8da5cb5b → address
rewardRecipient 0x17f33340 → address
router 0xf887ea40 → address
supportedTokens 0x68c4ac26 → bool
underlyingBalance 0x59356c5c → uint256
vault 0xfbfa77cf → address
Write Contract 12 functions
These functions modify contract state and require a wallet transaction to execute.
depositWithCalldataGeneric 0xca362ab4
address token
uint256 tokenAmount
bytes routerCalldata
returns: uint256
harvestRewards 0x515ce517
address recipient
returns: address[], uint256[]
renounceOwnership 0x715018a6
No parameters
rescueTokens 0xcea9d26f
address token
address to
uint256 amount
setKeeper 0x748747e6
address _keeper
setMarketAndLpToken 0xcf891ad8
address _newMarket
address _newLpToken
setRewardRecipient 0xe521136f
address _recipient
setSupportedToken 0xe7986466
address token
bool supported
setVault 0x6817031b
address _newVault
transferLp 0x8d072c40
address to
uint256 lpAmount
transferOwnership 0xf2fde38b
address newOwner
withdrawWithCalldataGeneric 0x51261050
address tokenOut
uint256 lpAmount
bytes routerCalldata
returns: uint256
Recent Transactions
No transactions found for this address