Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x08BaF37CFEAfF1E8e2A8695Ed9b7DC3Cf96bEB9D
Balance 0.000000000 ETH
Nonce 1
Code Size 9516 bytes
Indexed Transactions 0
External Etherscan · Sourcify

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