Address Contract Verified
Address
0x08BaF37CFEAfF1E8e2A8695Ed9b7DC3Cf96bEB9D
Balance
0.000000000 ETH
Nonce
1
Code Size
9516 bytes
Creator
0x0075C169...8c19 at tx 0xac9bc373...d0a706
Indexed Transactions
0
Contract Bytecode
9516 bytes
0x60806040526004361061002c575f3560e01c8063985f61a1146102f3578063ffa1ad741461030857610033565b3661003357005b34801561003e575f80fd5b505f3660606004835b50803560e01c63d37ac04a1981011561006c576100656020836120b2565b9150610047565b600482013560f81c6001811480610086575060ff81166002145b156101a357600583013560601c608484146100e85760405162461bcd60e51b815260206004820152601d60248201527f496e636f7272656374205633416476616e6365642063616c6c6261636b00000060448201526064015b60405180910390fd5b6004356024355f8083136100fc57816100fe565b825b905060011960ff86160161013f5761013f61011a8860196120b2565b305f86136101305761012b866120c5565b610139565b610139856120c5565b8461032e565b60405163a9059cbb60e01b8152336004820152602481018290526001600160a01b0385169063a9059cbb906044015f604051808303815f87803b158015610184575f80fd5b505af1158015610196573d5f803e3d5ffd5b50505050505050506102d3565b60021960ff82160161024357600583013560601c60a484146102075760405162461bcd60e51b815260206004820152601d60248201527f496e636f7272656374205632416476616e6365642063616c6c6261636b00000060448201526064016100df565b6024356044356019868101359061013f906102239089906120b2565b61022e9060206120b2565b305f861161023c5784610139565b858461032e565b60031960ff8216016102985761026561025d8460056120b2565b335f8061032e565b60405160200161027f9060208082525f9082015260400190565b60405160208183030381529060405293505050506102e8565b60405162461bcd60e51b815260206004820152601060248201526f556e6b6e6f776e2063616c6c6261636b60801b60448201526064016100df565b60405180602001604052805f81525093505050505b915050805190602001f35b6103066103013660046120df565b611efd565b005b348015610313575f80fd5b5061031c600181565b60405190815260200160405180910390f35b6040805180820190915260018086016020830152853560f81c60140286010181525b8051361161038d5760405162461bcd60e51b815260206004820152600a60248201526927b831b7b2329037b7b160b11b60448201526064016100df565b80516001810182523560f81c60408110156106d757305f6060601e60018516156103ce5785516001810187526020870151903560f81c601402013560601c98505b5f808a6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561040c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104309190612163565b509092509050600287161561045c5787516001810189526020890151903560f81c601402013560601c95505b6004871615159450600887161561053d57875160018101895260208901515f913560f81c601402013560601c6040516370a0823160e01b81526001600160a01b038e8116600483015291909116906370a0823190602401602060405180830381865afa1580156104ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104f291906121af565b9050856104ff5781610501565b825b6001600160701b03168110610537578561051b578161051d565b825b610530906001600160701b0316826121c6565b9a5061053b565b809a505b505b60108716156105555787516002810189523560f01c92505b60208716156105dd5787516020890151600682018a52600182013560f090811c833560f890811c9190911b9d50601460038086013590921c029092013560601c9263d37ac04b929184918f916105b69160040135901c8e9061ffff16611f16565b6040516020016105ca9594939291906121f0565b6040516020818303038152906040529450505b5f80866105eb5782846105ee565b83835b6001600160701b0391821693501690505f61060b866127106121c6565b61061660018f6121c6565b6106209190612249565b90508061062f84612710612249565b61063991906120b2565b6106438383612249565b61064d9190612274565b9c508d6001600160a01b031663022c0d9f89610669578e61066b565b5f5b8a610676575f610678565b8f5b8c8b6040518563ffffffff1660e01b815260040161069994939291906122b5565b5f604051808303815f87803b1580156106b0575f80fd5b505af11580156106c2573d5f803e3d5ffd5b50505050889d50505050505050505050611ef1565b60608160ff16101561096d57815160208301516002820184523096506014823560f890811c8202830135606090811c9460019081013590921c90920290920135811c915f91908516156107415785516001810187526020870151903560f81c601402013560601c98505b600285161515915060048516156107bb576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610794573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107b891906121af565b97505b60088516156107eb57855160028101875261ffff906107de903560f01c8a612249565b6107e89190612274565b97505b601085161561085f578551600381018752600181013560f01c903560f81c1b975063d37ac04b60028461083661082b8a8051600281019091523560f01c90565b8a9061ffff16611f16565b60405160200161084994939291906122eb565b60405160208183030381529060405290506108a2565b60405163d37ac04b60e01b6020820152600160f81b60248201526001600160601b0319606085901b16602582015260390160405160208183030381529060405290505b5f806001600160a01b03861663128acb088c866108c060018f6121c6565b886108df5773fffd8963efd1fc6a506488495d951d5263988d256108e6565b6401000276a45b886040518663ffffffff1660e01b8152600401610907959493929190612332565b60408051808303815f875af1158015610922573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610946919061236c565b91509150836109555781610957565b805b610960906120c5565b9950505050505050611ef1565b60688160ff161015610c815781516020830151600282018452813560f890811c6014029091013560601c96506001909101359081901c9060fc1c600f82166003841615610aac57845160018101865260208601515f913560f81c601402013560601c90506001851615610a385760405163095ea7b360e01b81526001600160a01b038a811660048301525f19602483015282169063095ea7b3906044015f604051808303815f87803b158015610a21575f80fd5b505af1158015610a33573d5f803e3d5ffd5b505050505b6002851615610aaa576040516370a0823160e01b81523060048201526001600160a01b038216906370a0823190602401602060405180830381865afa158015610a83573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aa791906121af565b97505b505b6004841615610adc57845160028101865261ffff90610acf903560f01c89612249565b610ad99190612274565b96505b876001600160a01b0316631be913a56040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610b36575060408051601f3d908101601f19168201909252610b33918101906121af565b60015b610bd8576001600160a01b03881663916955868383610b5660018c6121c6565b6040516001600160e01b031960e086901b16815260ff938416600482015292909116602483015260448201525f606482015242608482015260a4016020604051808303815f875af1158015610bad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd191906121af565b9650610c76565b506001600160a01b038816633df0212460ff808516908416610bfb60018c6121c6565b6040516001600160e01b031960e086901b168152600f93840b60048201529190920b602482015260448101919091525f60648201526084016020604051808303815f875af1158015610c4f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7391906121af565b96505b309750505050611ef1565b60708160ff161015610dcd57815160018101835260208301515f913560f81c601402013560601c90506001821615610d1c576040516370a0823160e01b81523060048201526001600160a01b038216906370a0823190602401602060405180830381865afa158015610cf5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1991906121af565b94505b6002821615610d3357610d308460056120b2565b94505b6004821615610d6357825160028101845261ffff90610d56903560f01c87612249565b610d609190612274565b94505b610d6e6001866121c6565b604051632e1a7d4d60e01b8152600481018290529095506001600160a01b03821690632e1a7d4d906024015b5f604051808303815f87803b158015610db1575f80fd5b505af1158015610dc3573d5f803e3d5ffd5b5050505050611ef1565b60748160ff161015610f05578151602083015160028201845260018083013560f890811c6014908102840135606090811c9a50943590911c029091013590911c90821615610e94576040516370a0823160e01b81523060048201526001600160a01b038216906370a0823190602401602060405180830381865afa158015610e57573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e7b91906121af565b94506001851115610e9457610e916001866121c6565b94505b6002821615610ec457825160028101845261ffff90610eb7903560f01c87612249565b610ec19190612274565b94505b8415610eff5760405163a9059cbb60e01b81526001600160a01b0387811660048301526024820187905282169063a9059cbb90604401610d9a565b50611ef1565b60788160ff16101561102857815160018101835260208301515f913560f81c601402013560601c47955090506001821615610f6157825160028101845261ffff90610f54903560f01c87612249565b610f5e9190612274565b94505b610f6c6001866121c6565b9450806001600160a01b031663d0e30db0866040518263ffffffff1660e01b81526004015f604051808303818588803b158015610fa7575f80fd5b505af1158015610fb9573d5f803e3d5ffd5b5050505060028316159050610eff57610fd36001866121c6565b835160018101855260208501519196503560f81c601402013560601c60405163a9059cbb60e01b81526001600160a01b038083166004830152602482018890529197509082169063a9059cbb90604401610d9a565b607c8160ff1610156112865781516020808401516002830185526040805160a081018252843560f890811c6014908102850135606090811c80855260019098013590921c029093013590921c92820183905285516003810187525f92918201903560e81c62ffffff1681526020016110aa878051600381019091523560e81c90565b60020b81528651600181018852602088810151920191903560f81c601402013560601c6001600160a01b03169052905060018416151560028516156111125761110b30826110f857846110fa565b855b6001600160a01b038c169190611f78565b975061111d565b865f0361111d578796505b5f896001600160a01b031663f3cd914c84604051806060016040528086151581526020018d61114b906120c5565b81526020018661116f5773fffd8963efd1fc6a506488495d951d5263988d25611176565b6401000276a45b6001600160a01b03908116909152604080516001600160e01b031960e087901b168152845183166004820152602080860151841660248301528583015162ffffff166044830152606086015160020b6064830152608090950151831660848201528351151560a48201529383015160c485015291909101511660e48201526101206101048201525f610124820152610144016020604051808303815f875af1158015611224573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061124891906121af565b90508161125e576112598160801d90565b611268565b61126881600f0b90565b6fffffffffffffffffffffffffffffffff1698505050505050611ef1565b607e8160ff1610156113865781516001810183526020830151903560f81c601402013560601c945047935060018116156112e157815160028101835261ffff906112d4903560f01c86612249565b6112de9190612274565b93505b6112ec6001856121c6565b93505f856001600160a01b0316856040515f6040518083038185875af1925050503d805f8114611337576040519150601f19603f3d011682016040523d82523d5f602084013e61133c565b606091505b5050905080610eff5760405162461bcd60e51b8152602060048201526016602482015275151c985b9cd9995c8813985d1a5d994819985a5b195960521b60448201526064016100df565b60808160ff16101561159657815160018101835260208301515f913560f81c601402013560601c83516003810185529091505f90600181013560f01c903560f81c1b6113d39060016120b2565b84516020860151600482018752813560f890811c6014029091013560601c995091925060018082013560f01c9260039092013590911c90811580159061142057508261ffff164261ffff16115b1561145657620186a061143660ff84168261238e565b6114459062ffffff1686612249565b61144f9190612274565b9350600290505b60018616156114c8576040516370a0823160e01b81523060048201526001600160a01b038616906370a0823190602401602060405180830381865afa1580156114a1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c591906121af565b98505b83891115610dc3575f6114db858b6121c6565b60405163a9059cbb60e01b81526001600160a01b038d81166004830152602482018390529192509087169063a9059cbb906044015f604051808303815f87803b158015611526575f80fd5b505af1158015611538573d5f803e3d5ffd5b50505050849950856001600160a01b03167fe63aabbc33ca22e832f7159484e5f4905719f6322bf443d9650ae7fb100163658284604051611583929190918252602082015260400190565b60405180910390a2505050505050611ef1565b60828160ff1610156116d557815160018101835260208301515f913560f81c601402013560601c83516003810185529091505f90600181013560f01c903560f81c1b90505f8360011660ff165f141590505f80846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611625573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116499190612163565b5091509150838361167c576116776001600160701b038316600160801b600160f01b03608086901b16612274565b61169f565b61169f6001600160701b038416600160801b600160f01b03608085901b16612274565b11610dc35760405162461bcd60e51b815260206004820152600660248201526527a7a9102b1960d11b60448201526064016100df565b60848160ff16101561178c57815160018101835260208301515f913560f81c601402013560601c83516003810185529091505f90600181013560f01c903560f81c1b90506001831615155f6117298461200f565b9050816117415782816001600160a01b03161061174e565b82816001600160a01b0316115b6117835760405162461bcd60e51b81526020600482015260066024820152654f4f5220563360d01b60448201526064016100df565b50505050611ef1565b60868160ff16101561184857815160018101835260208301515f913560f81c601402013560601c90503060018316156117dc5783516001810185526020850151903560f81c601402013560601c90505b604051630b0d9c0960e01b81526001600160a01b038381166004830152828116602483015260448201889052881690630b0d9c09906064015f604051808303815f87803b15801561182b575f80fd5b505af115801561183d573d5f803e3d5ffd5b505050505050611ef1565b60888160ff1610156118d4575f600182168103611865575f611867565b845b9050856001600160a01b03166311da60b4826040518263ffffffff1660e01b815260040160206040518083038185885af11580156118a7573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906118cc91906121af565b945050611ef1565b60f28160ff1610156119195760405162461bcd60e51b815260206004820152600e60248201526d496e76616c6964204f70636f646560901b60448201526064016100df565b60f38160ff16101561195057815160028101835261ffff9061193f903560f01c86612249565b6119499190612274565b9350611ef1565b60f48160ff1610156119f65781516001810183526020830151903560f81c601402013560601c6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156119ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119de91906121af565b935083156119f1576119496001856121c6565b611ef1565b60f58160ff161015611a165747935083156119f1576119496001856121c6565b60f68160ff161015611a6a5781516001810183526020830151604051632961046560e21b8152913560f81c601402013560601c60048201819052906001600160a01b0387169063a584119490602401610d9a565b60f78160ff161015611ab057815160018101835260208301515f913560f81c601402013560601c9050611aa76001600160a01b0387163083611f78565b6118cc906120c5565b60f88160ff161015611aed57815160018101835260208301515f913560f81c601402013560601c90506118cc6001600160a01b0387163083611f78565b60f98160ff161015611b1a5781516001810183526020830151903560f81c601402013560601c9450611ef1565b60fa8160ff161015611b41578151600381018352600181013560f01c903560f81c1b611949565b60fb8160ff161015611c1e5781516020830151600382018452813560f81c6014020135606090811c96509063d37ac04b90600490611b879086906001013560f01c611f16565b604051602001611b99939291906123a9565b60408051601f19818403018152908290526348c8949160e01b825291506001600160a01b038716906348c8949190611bd59084906004016123dc565b5f604051808303815f875af1158015611bf0573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611c179190810190612409565b5050611ef1565b60fc8160ff161015611caa578151600381018352803560f81c9060019081013560f01c9082165f03611c64578061ffff1661ffff47611c5d91906124bc565b1415611c79565b8061ffff1661ffff47611c7791906124bc565b145b611c175760405162461bcd60e51b815260206004820152600260248201526124a160f11b60448201526064016100df565b60fd8160ff161015611d3c578151601581018352803560f81c907377162b8ade1458b7eb153cdba945af4175b7b19260019182013560601c189082165f03611cfe57416001600160a01b0382161415611d0b565b416001600160a01b038216145b611c175760405162461bcd60e51b8152602060048201526002602482015261494360f01b60448201526064016100df565b60fe8160ff161015611e325781516020830151600382018452479550813560f890811c92600180820135831c6014908102850135606090811c9560029094013590941c029091013590911c90831615611db657845160028101865261ffff90611da9903560f01c89612249565b611db39190612274565b96505b6001600160a01b038216636a627842611dd060018a6121c6565b6040516001600160e01b031960e084901b1681526001600160a01b03851660048201526024015f604051808303818588803b158015611e0d575f80fd5b505af1158015611e1f573d5f803e3d5ffd5b50505050505f9650309750505050611ef1565b60ff8160ff161015611eea57815160018101835260208301515f913560f81c601402013560601c6040516370a0823160e01b81523060048201529091505f906001600160a01b038316906370a0823190602401602060405180830381865afa158015611ea0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ec491906121af565b604051633bf3a0d360e01b815260048101889052602481018290529091506044016100df565b5050611ef7565b50610350565b50505050565b60653560601c60443560801c611ef7606483835f61032e565b815181810183526060905f8136611f2d86836120b2565b92611f3a939291906124cf565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250929450505050505b92915050565b5f806001600160a01b0384165f526001600160a01b03831660205260405f209050846001600160a01b031663f135baaa826040518263ffffffff1660e01b8152600401611fc791815260200190565b602060405180830381865afa158015611fe2573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061200691906121af565b95945050505050565b604051633850c7bd60e01b81525f908180600483865afa3d60208110158216156120465760205f843e6001600160a01b0383511693505b83612081576339db007960e21b83525f80600485885afa91503d905060208110158216156120815760205f843e6001600160a01b0383511693505b5050508061209957639d770d775f528160045260245ffd5b919050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115611f7257611f7261209e565b5f600160ff1b82016120d9576120d961209e565b505f0390565b5f80602083850312156120f0575f80fd5b823567ffffffffffffffff811115612106575f80fd5b8301601f81018513612116575f80fd5b803567ffffffffffffffff81111561212c575f80fd5b85602082840101111561213d575f80fd5b6020919091019590945092505050565b80516001600160701b0381168114612099575f80fd5b5f805f60608486031215612175575f80fd5b61217e8461214d565b925061218c6020850161214d565b9150604084015163ffffffff811681146121a4575f80fd5b809150509250925092565b5f602082840312156121bf575f80fd5b5051919050565b81810381811115611f7257611f7261209e565b5f81518060208401855e5f93019283525090919050565b60e086901b6001600160e01b031916815260f885901b6001600160f81b0319166004820152606084901b6001600160601b0319166005820152601981018390525f61223e60398301846121d9565b979650505050505050565b8082028115828204841417611f7257611f7261209e565b634e487b7160e01b5f52601260045260245ffd5b5f8261228257612282612260565b500490565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b84815283602082015260018060a01b0383166040820152608060608201525f6122e16080830184612287565b9695505050505050565b60e085901b6001600160e01b031916815260f884901b6001600160f81b0319166004820152606083901b6001600160601b03191660058201525f6122e160198301846121d9565b6001600160a01b0386811682528515156020830152604082018590528316606082015260a0608082018190525f9061223e90830184612287565b5f806040838503121561237d575f80fd5b505080516020909101519092909150565b62ffffff8281168282160390811115611f7257611f7261209e565b60e084901b6001600160e01b031916815260f883901b6001600160f81b03191660048201525f61200660058301846121d9565b602081525f6123ee6020830184612287565b9392505050565b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215612419575f80fd5b815167ffffffffffffffff81111561242f575f80fd5b8201601f8101841361243f575f80fd5b805167ffffffffffffffff811115612459576124596123f5565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715612488576124886123f5565b60405281815282820160200186101561249f575f80fd5b8160208401602083015e5f91810160200191909152949350505050565b5f826124ca576124ca612260565b500690565b5f80858511156124dd575f80fd5b838611156124e9575f80fd5b505082019391909203915056fea26469706673582212205f93174d08b3ea0909ee0efb45df69cb1130abbf4c909d5000300ee93148534864736f6c634300081a0033
Verified Source Code Full Match
Compiler: v0.8.26+commit.8a97fa7a
EVM: cancun
Optimization: Yes (200 runs)
AggregatorExecutor.sol 479 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.26;
import "./interfaces/IERC20Unsafe.sol";
import "./interfaces/IAggregatorExecutor.sol";
import "./interfaces/IUniswapV2Pool.sol";
import "./interfaces/IUniswapV3Pool.sol";
import "./interfaces/IStCoreEarn.sol";
import "./interfaces/IBalancer.sol";
import "./interfaces/ICurve.sol";
import "./interfaces/IWeth.sol";
import "./interfaces/IUniswapV4PoolManager.sol";
import "./libaries/CalldataDecoder.sol";
import "./libaries/TransientStateLibrary.sol";
import "./libaries/BalanceDelta.sol";
contract AggregatorExecutor is IAggregatorExecutor {
using CalldataDecoder for uint256;
using TransientStateLibrary for IUniswapV4PoolManager;
using BalanceDeltaLibrary for BalanceDelta;
uint256 public constant VERSION = 1;
uint32 constant CALLBACK_IDENTIFIER = 0xd37ac04b; // random value used to signal where our data starts in callbacks
uint8 constant CALLBACK_TYPE_V3_SIMPLE = 0x01;
uint8 constant CALLBACK_TYPE_V3_ADVANCED = 0x02;
uint8 constant CALLBACK_TYPE_V2_ADVANCED = 0x03;
uint8 constant CALLBACK_TYPE_V4_ADVANCED = 0x04;
error TokenAmountRevert(uint256 outBeforeTaxes, uint256 outAfterTaxes);
error SqrtPriceNotFound(address pool);
event RevenueCaptured(
address indexed token,
uint256 amount,
uint256 kind
);
receive() external payable {}
fallback(bytes calldata) external returns (bytes memory) {
uint256 identifierStart = 4;
uint32 slotIdentifier;
while (true) {
assembly {
slotIdentifier := shr(224, calldataload(identifierStart))
}
if (slotIdentifier == CALLBACK_IDENTIFIER) {
break;
}
identifierStart += 32;
}
uint8 callbackType;
assembly {
callbackType := shr(248, calldataload(add(identifierStart, 4)))
}
if (callbackType == CALLBACK_TYPE_V3_SIMPLE || callbackType == CALLBACK_TYPE_V3_ADVANCED) {
// v3 simple + advanced
address repayTokenAddress;
assembly {
repayTokenAddress := shr(96, calldataload(add(identifierStart, 5)))
}
require(identifierStart == 4+4*32, "Incorrect V3Advanced callback");
int256 amount0;
int256 amount1;
assembly {
amount0 := calldataload(4)
amount1 := calldataload(36)
}
uint256 amountToRepay = uint256(amount0 > 0 ? amount0 : amount1);
if (callbackType == CALLBACK_TYPE_V3_ADVANCED) {
executeOpcodes(identifierStart + 25, address(this), uint256(amount0 > 0 ? -amount1 : -amount0), amountToRepay);
}
IERC20Unsafe(repayTokenAddress).transfer(msg.sender, amountToRepay);
} else if (callbackType == CALLBACK_TYPE_V2_ADVANCED) {
// v2 advanced
address repayTokenAddress;
assembly {
repayTokenAddress := shr(96, calldataload(add(identifierStart, 5)))
}
require(identifierStart == 4+5*32, "Incorrect V2Advanced callback");
uint256 amount0;
uint256 amount1;
uint256 amountIn;
assembly {
amount0 := calldataload(36)
amount1 := calldataload(68)
amountIn := calldataload(add(identifierStart, 25))
}
executeOpcodes(identifierStart + 25 + 32, address(this), uint256(amount0 > 0 ? amount0 : amount1), amountIn);
IERC20Unsafe(repayTokenAddress).transfer(msg.sender, amountIn);
} else if (callbackType == CALLBACK_TYPE_V4_ADVANCED) {
// V4 Callback
executeOpcodes(identifierStart + 5, msg.sender, uint256(0), uint256(0));
return abi.encode("");
} else {
revert("Unknown callback");
}
return "";
}
function executeSwap(bytes calldata) external payable {
address lastToAddress;
uint256 lastAmountOut;
assembly {
lastToAddress := shr(96, calldataload(101))
lastAmountOut := shr(128, calldataload(68))
}
executeOpcodes(100, lastToAddress, lastAmountOut, 0);
}
function executeOpcodes(uint256 opcodeStart, address lastToAddress, uint256 lastAmountOut, uint256 amountToRepay) internal {
uint256 decoder = CalldataDecoder.createDecoder(opcodeStart);
// None of the memory allocated inside the loop is required after the loop finishes.
// As solidity never reclaims memory, leading to higher memory expansion gas cost, we could reset the free memory pointer after each iteration
while (true) {
require(decoder.notEmpty(), "Opcode oob");
uint8 command = decoder.readUint8();
if (command < 64) { // [0-63] 6 flags
// V2 Swap
address to = address(this);
bool zeroForOne;
bytes memory data;
uint256 fee_bps = 30;
if (command & 0x01 != 0) lastToAddress = decoder.readAddress(); // !useLastTo
(uint112 reserve0, uint112 reserve1,) = IUniswapV2Pool(lastToAddress).getReserves();
if (command & 0x02 != 0) to = decoder.readAddress(); // !sendToRouter
zeroForOne = command & 0x04 != 0; // zeroForOne
if (command & 0x08 != 0) { // readPoolBalance
uint256 balance = IERC20Unsafe(decoder.readAddress()).balanceOf(lastToAddress);
if (balance >= (zeroForOne ? reserve0 : reserve1)) {
lastAmountOut = balance - (zeroForOne ? reserve0 : reserve1);
} else {
// special case for virtual liquidity pools where the token is not actually held by the swap contract
lastAmountOut = balance;
}
}
if (command & 0x10 != 0) { // customFee
fee_bps = decoder.readUint16();
}
if (command & 0x20 != 0) { // forwardCalldata
lastAmountOut = decoder.readUint256Compact();
address tokenInAddress = decoder.readAddress();
data = abi.encodePacked(
CALLBACK_IDENTIFIER,
CALLBACK_TYPE_V2_ADVANCED,
tokenInAddress,
lastAmountOut,
decoder.readBytes(decoder.readUint16())
);
}
(uint256 reserveIn, uint256 reserveOut) = zeroForOne ? (reserve0, reserve1) : (reserve1, reserve0);
uint256 amountInWithFee = (lastAmountOut - 1) * (10_000 - fee_bps);
lastAmountOut = (amountInWithFee * reserveOut) / (reserveIn * 10_000 + amountInWithFee);
IUniswapV2Pool(lastToAddress).swap(
zeroForOne? 0 : lastAmountOut,
zeroForOne? lastAmountOut : 0,
to,
data
);
lastToAddress = to;
} else if (command < 96) { // [64-95] 5 flags
// V3 Swap
address poolAddress = decoder.readAddress();
address tokenInAddress = decoder.readAddress();
lastToAddress = address(this);
bool zeroForOne;
bytes memory data;
if (command & 0x01 != 0) lastToAddress = decoder.readAddress(); // !sendToRouter
zeroForOne = command & 0x02 != 0; // zeroForOne
if (command & 0x04 != 0) lastAmountOut = IERC20Unsafe(tokenInAddress).balanceOf(address(this)); // readRouterBalance
if (command & 0x08 != 0) lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff; // partial
if (command & 0x10 != 0) { // forwardCalldata
lastAmountOut = decoder.readUint256Compact();
data = abi.encodePacked(
CALLBACK_IDENTIFIER,
CALLBACK_TYPE_V3_ADVANCED,
tokenInAddress,
decoder.readBytes(decoder.readUint16())
);
} else {
data = abi.encodePacked(
CALLBACK_IDENTIFIER,
CALLBACK_TYPE_V3_SIMPLE,
tokenInAddress
);
}
(int256 amount0, int256 amount1) = IUniswapV3Pool(poolAddress).swap(
lastToAddress,
zeroForOne,
int256(lastAmountOut - 1),
zeroForOne ? 4295128740 : 1461446703485210103287273052203988822378723970341, // min/max sqrt ratio
data
);
lastAmountOut = uint256(-(zeroForOne? amount1 : amount0));
} else if (command < 104) { // [96-103] 3 flags
// Balancer Swap
lastToAddress = decoder.readAddress();
uint8 tokenIndexes = decoder.readUint8();
uint8 tokenIndexFrom = tokenIndexes >> 4;
uint8 tokenIndexTo = tokenIndexes & 0x0f;
if (command & (0x01 + 0x02) != 0) {
address tokenInAddress = decoder.readAddress();
if (command & 0x01 != 0) IERC20Unsafe(tokenInAddress).approve(lastToAddress, type(uint256).max); // needApproval
if (command & 0x02 != 0) lastAmountOut = IERC20Unsafe(tokenInAddress).balanceOf(address(this)); // readRouterBalance
}
if (command & 0x04 != 0) lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff; // partial
try ICurve(lastToAddress).ma_exp_time() {
lastAmountOut = ICurve(lastToAddress).exchange(int128(uint128(tokenIndexFrom)), int128(uint128(tokenIndexTo)), lastAmountOut - 1, 0);
} catch {
lastAmountOut = IBalancer(lastToAddress).swap(tokenIndexFrom, tokenIndexTo, lastAmountOut - 1, 0, block.timestamp);
}
lastToAddress = address(this);
} else if (command < 112) { // [104-111] 3 flag
// Unwrap
address wEthAddress = decoder.readAddress();
if (command & 0x01 != 0) lastAmountOut = IERC20Unsafe(wEthAddress).balanceOf(address(this)); // readRouterBalance
if (command & 0x02 != 0) lastAmountOut = amountToRepay + 5; // unwrapRepayAmount
if (command & 0x04 != 0) lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff; // partial
lastAmountOut -= 1;
IWeth(wEthAddress).withdraw(lastAmountOut);
} else if (command < 116) { // [112-115] 2 flags
// Transfer Token
address tokenAddress = decoder.readAddress();
lastToAddress = decoder.readAddress();
if (command & 0x01 != 0) { // readRouterBalance
lastAmountOut = IERC20Unsafe(tokenAddress).balanceOf(address(this));
if (lastAmountOut > 1) lastAmountOut -= 1;
}
if (command & 0x02 != 0) lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff; // partial
if (lastAmountOut > 0) IERC20Unsafe(tokenAddress).transfer(lastToAddress, lastAmountOut);
} else if (command < 120) { // [116-119] 2 flag
// Wrap
address payable wEthAddress = payable(decoder.readAddress());
lastAmountOut = address(this).balance;
if (command & 0x01 != 0) lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff; // partial
lastAmountOut -= 1;
IWeth(wEthAddress).deposit{value: lastAmountOut}();
if (command & 0x02 != 0) { // transfer
lastAmountOut -= 1;
lastToAddress = decoder.readAddress();
IERC20Unsafe(wEthAddress).transfer(lastToAddress, lastAmountOut);
}
} else if (command < 124) { // [120-123] 2 flags
// V4 Swap
address token0 = decoder.readAddress();
address token1 = decoder.readAddress();
PoolKey memory poolKey = PoolKey({
currency0: token0,
currency1: token1,
fee: decoder.readUint24(),
tickSpacing: int24(decoder.readUint24()),
hooks: decoder.readAddress()
});
bool zeroForOne = command & 0x01 != 0; // zeroForOne
if (command & 0x02 != 0) { // readPoolBalance
lastAmountOut = uint256(IUniswapV4PoolManager(lastToAddress).currencyDelta(address(this), IERC20Unsafe(zeroForOne ? token0 : token1)));
} else if (amountToRepay == 0) {
amountToRepay = lastAmountOut;
}
BalanceDelta swapDelta = IUniswapV4PoolManager(lastToAddress).swap(poolKey, SwapParams({
zeroForOne: zeroForOne,
amountSpecified: -int256(lastAmountOut),
sqrtPriceLimitX96: zeroForOne ? 4295128740 : 1461446703485210103287273052203988822378723970341 // min/max sqrt ratio
}), "");
lastAmountOut = uint256(uint128(zeroForOne ? swapDelta.amount1() : swapDelta.amount0()));
} else if (command < 126) { // [124-125] 1 flag
// Transfer Native
lastToAddress = decoder.readAddress();
lastAmountOut = address(this).balance;
if (command & 0x01 != 0) lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff; // partial
lastAmountOut -= 1;
(bool sent,) = lastToAddress.call{value: lastAmountOut}("");
require(sent, "Transfer Native failed");
} else if (command < 128) { // [126-127] 1 flag
// transfer surplus
address tokenAddress = decoder.readAddress();
uint256 amountToKeep = decoder.readUint256Compact() + 1;
lastToAddress = decoder.readAddress();
uint16 decreaseTs = decoder.readUint16();
uint8 decreaseFraction = decoder.readUint8(); // 10 equals 1bip. Max value is 0.256%
uint256 revenueType = 1;
if (decreaseFraction != 0 && (block.timestamp & 0xFFFF) > decreaseTs) { // small chance this check is incorrect when wrapping around, but this is ok
amountToKeep = amountToKeep * (100_000 - decreaseFraction) / 100_000;
revenueType = 2;
}
if (command & 0x01 != 0) lastAmountOut = IERC20Unsafe(tokenAddress).balanceOf(address(this)); // readRouterBalance
if (lastAmountOut > amountToKeep) {
uint256 revenueAmount = lastAmountOut - amountToKeep;
IERC20Unsafe(tokenAddress).transfer(lastToAddress, revenueAmount);
lastAmountOut = amountToKeep;
emit RevenueCaptured(tokenAddress, revenueAmount, revenueType);
}
} else if (command < 130) { // [128-129] 1 flag
// require UniswapV2 ratio
address poolAddress = decoder.readAddress();
uint256 thresholdRatio = decoder.readUint256Compact();
bool zeroForOne = command & 0x01 != 0; // zeroForOne
(uint112 reserve0, uint112 reserve1,) = IUniswapV2Pool(poolAddress).getReserves();
require((zeroForOne? (uint256(reserve1) << 128) / reserve0 : (uint256(reserve0) << 128) / reserve1) > thresholdRatio, "OOR V2");
} else if (command < 132) { // [130-131] 1 flag
// require UniswapV3 ratio
address poolAddress = decoder.readAddress();
uint256 thresholdRatio = decoder.readUint256Compact();
bool zeroForOne = command & 0x01 != 0; // zeroForOne
uint160 sqrtPriceX96 = _sqrtPriceX96(poolAddress);
require((zeroForOne? sqrtPriceX96 > thresholdRatio : sqrtPriceX96 < thresholdRatio), "OOR V3");
} else if (command < 134) { // [132-133] 1 flags
// V4 Take Credit
address currencyAddress = decoder.readAddress();
address to = address(this);
if (command & 0x01 != 0) to = decoder.readAddress(); // !sendToRouter
IUniswapV4PoolManager(lastToAddress).take(currencyAddress, to, lastAmountOut);
} else if (command < 136) { // [134-135] 1 flags
// V4 Swap Settle
uint256 value = (command & 0x01 != 0) ? lastAmountOut : 0; // native
lastAmountOut = IUniswapV4PoolManager(lastToAddress).settle{value: value}();
} else if (command < 242) { // [136-241]
// unused opcodes, only single bit opcodes afterwards
revert("Invalid Opcode");
} else if (command < 243) { // [242] 0 flags
// split amount
lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff;
} else if (command < 244) { // [243] 0 flags
// read ERC20 balance
lastAmountOut = IERC20Unsafe(decoder.readAddress()).balanceOf(address(this));
if (lastAmountOut > 0) lastAmountOut -= 1;
} else if (command < 245) { // [244] 0 flags
// read native balance
lastAmountOut = address(this).balance;
if (lastAmountOut > 0) lastAmountOut -= 1;
} else if (command < 246) { // [245] 0 flags
// V4 Swap Sync
address tokenAddress = decoder.readAddress();
IUniswapV4PoolManager(lastToAddress).sync(tokenAddress);
} else if (command < 247) { // [246] 0 flags
// V4 Read Debt
address tokenAddress = decoder.readAddress();
lastAmountOut = uint256(-IUniswapV4PoolManager(lastToAddress).currencyDelta(address(this), IERC20Unsafe(tokenAddress)));
} else if (command < 248) { // [247] 0 flags
// V4 Read Credit
address tokenAddress = decoder.readAddress();
lastAmountOut = uint256(IUniswapV4PoolManager(lastToAddress).currencyDelta(address(this), IERC20Unsafe(tokenAddress)));
} else if (command < 249) { // [248] 0 flags
// Set lastToAddress
lastToAddress = decoder.readAddress();
} else if (command < 250) { // [249] 0 flags
// set lastAmountOut
lastAmountOut = decoder.readUint256Compact();
} else if (command < 251) { // [250] 0 flags
// V4 unlock
lastToAddress = decoder.readAddress();
bytes memory data;
data = abi.encodePacked(
CALLBACK_IDENTIFIER,
CALLBACK_TYPE_V4_ADVANCED,
decoder.readBytes(decoder.readUint16())
);
IUniswapV4PoolManager(lastToAddress).unlock(data);
} else if (command < 252) { // [251] 0 flags
// require address(this).value
uint8 flags = decoder.readUint8();
uint16 expectedBalance = decoder.readUint16();
require(flags & 0x01 != 0 ? address(this).balance % 65535 == expectedBalance : address(this).balance % 65535 != expectedBalance, "IB");
} else if (command < 253) { // [252] 0 flags
// require block.coinbase
uint8 flags = decoder.readUint8();
// address is xor'ed with a random hardcoded address to make sure it can not easily be detected in calldata
address expectedValidatorAddress = address(uint160(decoder.readAddressRaw()) ^ 0x0077162b8ade1458b7eb153cdba945af4175b7b192);
require(flags & 0x01 != 0 ? block.coinbase == expectedValidatorAddress : block.coinbase != expectedValidatorAddress, "IC");
} else if (command < 254) { // [253] 0 flags
// Stake StCore
uint8 flags = decoder.readUint8();
IStCoreEarn stCoreEarn = IStCoreEarn(decoder.readAddress());
address validator = payable(decoder.readAddress());
lastAmountOut = address(this).balance;
if (flags & 0x01 != 0) lastAmountOut = lastAmountOut * decoder.readUint16() / 0xffff; // partial
stCoreEarn.mint{value: lastAmountOut-1}(validator);
lastAmountOut = 0;
lastToAddress = address(this);
} else if (command < 255) { // [254] 0 flags
// Revert token amount
address tokenAddress = decoder.readAddress();
uint256 balance = IERC20Unsafe(tokenAddress).balanceOf(address(this));
revert TokenAmountRevert(lastAmountOut, balance);
} else { // [255] 0 flags
// Stop
// stops the interpreter and returns, each executeOpcodes bytes array ends with the stop opcode
return;
}
}
}
// Read just the first 32-byte return word of slot0() and take the low 160 bits.
// Works across many V3 forks that changed slot0's full signature/return tuple.
function _sqrtPriceX96(address pool) internal view returns (uint160 s) {
assembly {
// Free memory pointer
let ptr := mload(0x40)
// -------------------
// 1. Try slot0()
// -------------------
mstore(ptr, shl(224, 0x3850c7bd)) // selector slot0()
let ok := staticcall(gas(), pool, ptr, 4, 0, 0)
let rsz := returndatasize()
if and(ok, iszero(lt(rsz, 32))) {
returndatacopy(ptr, 0, 32)
s := and(mload(ptr), 0xffffffffffffffffffffffffffffffffffffffff)
}
// -------------------
// 2. If slot0 failed, try globalState()
// -------------------
if iszero(s) {
mstore(ptr, shl(224, 0xe76c01e4)) // selector globalState()
ok := staticcall(gas(), pool, ptr, 4, 0, 0)
rsz := returndatasize()
if and(ok, iszero(lt(rsz, 32))) {
returndatacopy(ptr, 0, 32)
s := and(mload(ptr), 0xffffffffffffffffffffffffffffffffffffffff)
}
}
// -------------------
// 3. If both failed, revert with custom error
// -------------------
if iszero(s) {
mstore(0x00, 0x9d770d77) // bytes4(keccak256("SqrtPriceNotFound(address)"))
mstore(0x04, pool)
revert(0x00, 0x24)
}
}
}
}
BalanceDelta.sol 24 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @dev Two `int128` values packed into a single `int256` where the upper 128 bits represent the amount0
/// and the lower 128 bits represent the amount1.
type BalanceDelta is int256;
/// @notice Library for getting the amount0 and amount1 deltas from the BalanceDelta type
library BalanceDeltaLibrary {
function amount0(BalanceDelta balanceDelta) internal pure returns (int128 _amount0) {
assembly ("memory-safe") {
_amount0 := sar(128, balanceDelta)
}
}
function amount1(BalanceDelta balanceDelta) internal pure returns (int128 _amount1) {
assembly ("memory-safe") {
_amount1 := signextend(15, balanceDelta)
}
}
}
TransientStateLibrary.sol 24 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IUniswapV4PoolManager} from "../interfaces/IUniswapV4PoolManager.sol";
import "../interfaces/IERC20Unsafe.sol";
/// @notice A helper library to provide state getters that use exttload
library TransientStateLibrary {
/// @notice Get the current delta for a caller in the given currency
/// @param target The credited account address
/// @param currency The currency for which to lookup the delta
function currencyDelta(IUniswapV4PoolManager manager, address target, IERC20Unsafe currency) internal view returns (int256) {
bytes32 key;
assembly ("memory-safe") {
mstore(0, and(target, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(32, and(currency, 0xffffffffffffffffffffffffffffffffffffffff))
key := keccak256(0, 64)
}
return int256(uint256(manager.exttload(key)));
}
}
CalldataDecoder.sol 124 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.26;
library CalldataDecoder {
function createDecoder(uint256 calldataOffset) internal pure returns (uint256 decoder) {
assembly {
// use 2 memory words for pointers towards next opcode (decoder) and towards the array where the addresses are stored
decoder := mload(0x40)
let addressArray := add(decoder, 32)
mstore(0x40, add(decoder, 64))
// first calldata byte defines the number of addresses in the address array
let numAddresses := shr(248, calldataload(calldataOffset))
// stores the two pointers in memory, decoder starts after the address array
mstore(addressArray, add(calldataOffset, 1))
mstore(decoder, add(add(calldataOffset, 1), mul(numAddresses, 20)))
}
}
function notEmpty(uint256 decoder) internal pure returns (bool) {
uint256 pos;
assembly {
pos := mload(decoder)
}
return pos < msg.data.length;
}
function readUint8(uint256 decoder) internal pure returns (uint8 res) {
assembly {
let pos := mload(decoder)
res := shr(248, calldataload(pos))
mstore(decoder, add(pos, 1))
}
}
function readUint16(uint256 decoder) internal pure returns (uint16 res) {
assembly {
let pos := mload(decoder)
res := shr(240, calldataload(pos))
mstore(decoder, add(pos, 2))
}
}
function readUint24(uint256 decoder) internal pure returns (uint24 res) {
assembly {
let pos := mload(decoder)
res := shr(232, calldataload(pos))
mstore(decoder, add(pos, 3))
}
}
function readUint32(uint256 decoder) internal pure returns (uint32 res) {
assembly {
let pos := mload(decoder)
res := shr(224, calldataload(pos))
mstore(decoder, add(pos, 4))
}
}
function readUint128(uint256 decoder) internal pure returns (uint128 res) {
assembly {
let pos := mload(decoder)
res := shr(128, calldataload(pos))
mstore(decoder, add(pos, 16))
}
}
function readUint256(uint256 decoder) internal pure returns (uint256 res) {
assembly {
let pos := mload(decoder)
res := calldataload(pos)
mstore(decoder, add(pos, 32))
}
}
function readUint256Compact(uint256 decoder) internal pure returns (uint256 res) {
// very efficient way to store numbers representing up to uint256 in just 3 bytes with precision of 1/32k
assembly {
let pos := mload(decoder)
let exponent := shr(248, calldataload(pos))
let mantissa := shr(240, calldataload(add(pos, 1)))
res := shl(exponent, mantissa)
mstore(decoder, add(pos, 3))
}
}
function readBytes32(uint256 decoder) internal pure returns (bytes32 res) {
assembly {
let pos := mload(decoder)
res := calldataload(pos)
mstore(decoder, add(pos, 32))
}
}
function readAddressRaw(uint256 decoder) internal pure returns (address res) {
assembly {
let pos := mload(decoder)
res := shr(96, calldataload(pos))
mstore(decoder, add(pos, 20))
}
}
function readAddress(uint256 decoder) internal pure returns (address res) {
// address is stored as uint8 index of the address array rather than in raw format
assembly {
let pos := mload(decoder)
let addressIndex := shr(248, calldataload(pos))
mstore(decoder, add(pos, 1))
let addressArray := mload(add(decoder, 32))
res := shr(96, calldataload(add(addressArray, mul(addressIndex, 20))))
}
}
function readBytes(uint256 decoder, uint256 numBytes) internal pure returns (bytes memory res) {
uint256 pos;
assembly {
pos := mload(decoder)
mstore(decoder, add(pos, numBytes))
}
return msg.data[pos:pos+numBytes];
}
}
IUniswapV4PoolManager.sol 82 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "../libaries/BalanceDelta.sol";
struct PoolKey {
/// @notice The lower currency of the pool, sorted numerically
address currency0;
/// @notice The higher currency of the pool, sorted numerically
address currency1;
/// @notice The pool LP fee, capped at 1_000_000. If the highest bit is 1, the pool has a dynamic fee and must be exactly equal to 0x800000
uint24 fee;
/// @notice Ticks that involve positions must be a multiple of tick spacing
int24 tickSpacing;
/// @notice The hooks of the pool
address hooks;
}
struct SwapParams {
/// Whether to swap token0 for token1 or vice versa
bool zeroForOne;
/// The desired input amount if negative (exactIn), or the desired output amount if positive (exactOut)
int256 amountSpecified;
/// The sqrt price at which, if reached, the swap will stop executing
uint160 sqrtPriceLimitX96;
}
interface IUniswapV4PoolManager {
/// @notice All interactions on the contract that account deltas require unlocking. A caller that calls `unlock` must implement
/// `IUnlockCallback(msg.sender).unlockCallback(data)`, where they interact with the remaining functions on this contract.
/// @dev The only functions callable without an unlocking are `initialize` and `updateDynamicLPFee`
/// @param data Any data to pass to the callback, via `IUnlockCallback(msg.sender).unlockCallback(data)`
/// @return The data returned by the call to `IUnlockCallback(msg.sender).unlockCallback(data)`
function unlock(bytes calldata data) external returns (bytes memory);
/// @notice Swap against the given pool
/// @param key The pool to swap in
/// @param params The parameters for swapping
/// @param hookData The data to pass through to the swap hooks
/// @return swapDelta The balance delta of the address swapping
/// @dev Swapping on low liquidity pools may cause unexpected swap amounts when liquidity available is less than amountSpecified.
/// Additionally note that if interacting with hooks that have the BEFORE_SWAP_RETURNS_DELTA_FLAG or AFTER_SWAP_RETURNS_DELTA_FLAG
/// the hook may alter the swap input/output. Integrators should perform checks on the returned swapDelta.
function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData) external returns (BalanceDelta swapDelta);
/// @notice Called by the user to net out some value owed to the user
/// @dev Will revert if the requested amount is not available, consider using `mint` instead
/// @dev Can also be used as a mechanism for free flash loans
/// @param currency The currency to withdraw from the pool manager
/// @param to The address to withdraw to
/// @param amount The amount of currency to withdraw
function take(address currency, address to, uint256 amount) external;
/// @notice Called by the user to pay what is owed
/// @return paid The amount of currency settled
function settle() external payable returns (uint256 paid);
/// @notice Called by external contracts to access transient storage of the contract
/// @param slot Key of slot to tload
/// @return value The value of the slot as bytes32
function exttload(bytes32 slot) external view returns (bytes32 value);
/// @notice Called by external contracts to access sparse transient pool state
/// @param slots List of slots to tload
/// @return values List of loaded values
function exttload(bytes32[] calldata slots) external view returns (bytes32[] memory values);
/// @notice Writes the current ERC20 balance of the specified currency to transient storage
/// This is used to checkpoint balances for the manager and derive deltas for the caller.
/// @dev This MUST be called before any ERC20 tokens are sent into the contract, but can be skipped
/// for native tokens because the amount to settle is determined by the sent value.
/// However, if an ERC20 token has been synced and not settled, and the caller instead wants to settle
/// native funds, this function can be called with the native currency to then be able to settle the native currency
function sync(address currency) external;
}
IWeth.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IWeth {
function deposit() external payable;
function withdraw(uint256) external;
}
ICurve.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface ICurve {
function ma_exp_time() external view returns (uint256);
function exchange(int128 i, int128 j, uint256 _dx, uint256 _min_dy) external returns (uint256);
}
IBalancer.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IBalancer {
function swap(uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline) external returns (uint256);
}
IStCoreEarn.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IStCoreEarn {
function mint(address _validator) external payable;
}
IUniswapV3Pool.sol 49 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IUniswapV3Pool {
/// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
/// when accessed externally.
/// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
/// tick The current tick of the pool, i.e. according to the last tick transition that was run.
/// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
/// boundary.
/// observationIndex The index of the last oracle observation that was written,
/// observationCardinality The current maximum number of observations stored in the pool,
/// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
/// feeProtocol The protocol fee for both tokens of the pool.
/// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
/// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
/// unlocked Whether the pool is currently locked to reentrancy
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
/// @notice Swap token0 for token1, or token1 for token0
/// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
/// @param recipient The address to receive the output of the swap
/// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
/// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
/// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
/// value after the swap. If one for zero, the price cannot be greater than this value after the swap
/// @param data Any data to be passed through to the callback
/// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
/// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
}
IUniswapV2Pool.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IUniswapV2Pool {
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}
IAggregatorExecutor.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface IAggregatorExecutor {
function executeSwap(bytes calldata swapData) external payable;
}
IERC20Unsafe.sol 18 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20Unsafe {
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
// no return bool for backwards compatibility with older ERC20 tokens
// caller need to make sure token transfers which do not revert on failure are tolerable
function transfer(address recipient, uint256 amount) external;
// same left out return bool as transfer
function transferFrom(address sender, address recipient, uint256 amount) external;
// same left out return bool as transfer
function approve(address spender, uint256 value) external;
}
Read Contract
VERSION 0xffa1ad74 → uint256
Write Contract 1 functions
These functions modify contract state and require a wallet transaction to execute.
executeSwap 0x985f61a1
bytes
Recent Transactions
No transactions found for this address