diff --git a/broadcast/FlashloanDeployer.s.sol/8453/run-1751501652.json b/broadcast/FlashloanDeployer.s.sol/8453/run-1751501652.json new file mode 100644 index 0000000..6fab688 --- /dev/null +++ b/broadcast/FlashloanDeployer.s.sol/8453/run-1751501652.json @@ -0,0 +1,58 @@ +{ + "transactions": [ + { + "hash": "0x49e68e7b17833be9126886aca9fae946b3f7583eed414df1765e987d47b9466a", + "transactionType": "CREATE2", + "contractName": "EnsoFlashloanShortcuts", + "contractAddress": "0x0649f744bffff139ee46765ab85af0fbb077f541", + "function": null, + "arguments": null, + "transaction": { + "from": "0x826e0bb2276271efdf2a500597f37b94f6c153ba", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x298681", + "value": "0x0", + "input": "0x456e736f466c6173686c6f616e53686f727463757473000000000000000000006080806040523460155761228e908161001a8239f35b5f80fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301ffc9a7146100b9578063150b7a02146100b45780631b11d0ff146100af57806331f57072146100aa578063bc197c81146100a5578063c4850ea8146100a0578063de792d5f1461009b578063ee08d45214610096578063f04f2707146100915763f23a6e610361000e5761089c565b6107ff565b61076e565b6106ff565b61055b565b6104c2565b61034c565b610245565b6101bf565b3461010f57602036600319011261010f5760043563ffffffff60e01b811680910361010f57602090630271189760e51b81149081156100fe575b506040519015158152f35b6301ffc9a760e01b1490505f6100f3565b5f80fd5b6001600160a01b0381160361010f57565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761015957604052565b610124565b6001600160401b03811161015957601f01601f191660200190565b81601f8201121561010f578035906101908261015e565b9261019e6040519485610138565b8284526020838301011161010f57815f926020809301838601378301015290565b3461010f57608036600319011261010f576101db600435610113565b6101e6602435610113565b6064356001600160401b03811161010f57610205903690600401610179565b50604051630a85bd0160e11b8152602090f35b9181601f8401121561010f578235916001600160401b03831161010f576020838186019501011161010f57565b3461010f5760a036600319011261010f5760043561026281610113565b602435906044359060643561027681610113565b608435906001600160401b03821161010f576102b161029c6102b9933690600401610218565b90929091906001600160a01b031630146108f5565b810190610968565b919390303b1561010f5760405163de792d5f60e01b8152925f91849182916102e5919060048401610a45565b038183305af1908115610347576103219561031a936103099361032d575b50610ac6565b926001600160a01b03168383610d3f565b3390610dcc565b60405160018152602090f35b8061033b5f61034193610138565b806109bf565b5f610303565b610a94565b3461010f57604036600319011261010f576004356024356001600160401b03811161010f5761037f903690600401610218565b8101919060808184031261010f5780359061039982610113565b6020810135906103a882610113565b60408101356001600160401b03811161010f57856103c791830161090b565b9460608201356001600160401b03811161010f576103e59201610681565b93303b1561010f5760405163de792d5f60e01b8152945f918691829161040f919060048401610a45565b038183305af1908115610347576100189461031a9261043a575b506001600160a01b03168383610d3f565b8061033b5f61044893610138565b5f610429565b6001600160401b0381116101595760051b60200190565b9080601f8301121561010f57813561047c8161044e565b9261048a6040519485610138565b81845260208085019260051b82010192831161010f57602001905b8282106104b25750505090565b81358152602091820191016104a5565b3461010f5760a036600319011261010f576104de600435610113565b6104e9602435610113565b6044356001600160401b03811161010f57610508903690600401610465565b506064356001600160401b03811161010f57610528903690600401610465565b506084356001600160401b03811161010f57610548903690600401610179565b5060405163bc197c8160e01b8152602090f35b3461010f57602036600319011261010f576004356001600160401b03811161010f5761058b903690600401610218565b81019060a08183031261010f578035906020810135906105aa82610113565b6040810135906105b982610113565b60608101356001600160401b03811161010f57856105d891830161090b565b9460808201356001600160401b03811161010f576105f69201610681565b93303b1561010f5760405163de792d5f60e01b8152945f9186918291610620919060048401610a45565b038183305af1908115610347576100189461064a9261043a57506001600160a01b03168383610d3f565b3390610ea6565b9181601f8401121561010f578235916001600160401b03831161010f576020808501948460051b01011161010f57565b9080601f8301121561010f5781356106988161044e565b926106a66040519485610138565b81845260208085019260051b8201019183831161010f5760208201905b8382106106d257505050505090565b81356001600160401b03811161010f576020916106f487848094880101610179565b8152019101906106c3565b3461010f57604036600319011261010f576004356001600160401b03811161010f5761072f903690600401610651565b6024356001600160401b03811161010f5761074e903690600401610681565b9030330361075f5761001892610ff3565b6314e1dbf760e11b5f5260045ffd5b60a036600319011261010f57600435600481101561010f5760243561079281610113565b6044356001600160401b03811161010f576107b1903690600401610218565b6064939193356001600160401b03811161010f576107d3903690600401610651565b91608435956001600160401b03871161010f576107f7610018973690600401610651565b969095610af1565b3461010f57608036600319011261010f576004356001600160401b03811161010f5761082f903690600401610651565b6024356001600160401b03811161010f5761084e903690600401610651565b6044939193356001600160401b03811161010f57610870903690600401610651565b91606435956001600160401b03871161010f57610894610018973690600401610218565b969095610c58565b3461010f5760a036600319011261010f576108b8600435610113565b6108c3602435610113565b6084356001600160401b03811161010f576108e2903690600401610179565b5060405163f23a6e6160e01b8152602090f35b156108fc57565b63ea8e4eb560e01b5f5260045ffd5b9080601f8301121561010f5781356109228161044e565b926109306040519485610138565b81845260208085019260051b82010192831161010f57602001905b8282106109585750505090565b813581526020918201910161094b565b9160608383031261010f57823561097e81610113565b9260208101356001600160401b03811161010f578361099e91830161090b565b9260408201356001600160401b03811161010f576109bc9201610681565b90565b5f91031261010f57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9080602083519182815201916020808360051b8301019401925f915b838310610a1857505050505090565b9091929394602080610a36600193601f1986820301875289516109c9565b97019301930191939290610a09565b9291604084019360408152825180955260206060820193015f955b808710610a7c5750506109bc93945060208184039101526109ed565b90936020806001928751815201950196019590610a60565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b9060048201809211610ac157565b610a9f565b91908201809211610ac157565b60041115610add57565b634e487b7160e01b5f52602160045260245ffd5b96959493929190610b0188610ad3565b87610b1257610b10975061173a565b565b610b1b88610ad3565b60018803610b2d57610b1097506115d5565b610b3688610ad3565b60028803610b4857610b1097506114ad565b9190959294939680610b5b600392610ad3565b03610c1057856060918101031261010f57610ba2610bb092863594610b7f86610113565b6040602089013598610b908a610113565b013598604051978895602087016113d4565b03601f198101845283610138565b6001600160a01b0316803b1561010f576040516310ac2ddf60e21b8152935f938593849286928492610bf19290916001600160a01b03163060048601611408565b03925af1801561034757610c025750565b8061033b5f610b1093610138565b637079d06b60e01b5f5260045ffd5b60010190565b634e487b7160e01b5f52603260045260245ffd5b9190811015610c495760051b0190565b610c25565b356109bc81610113565b94919695610c6b91949396810190610968565b6001600160a01b03909216969190303b1561010f5760405163de792d5f60e01b8152915f9183918291610ca2919060048401610a45565b038183305af1801561034757610d2b575b505f5b848110610cc7575050505050505050565b80610d2586610d118a8a610d0c610d078f98610cff8d610cf8838f8f60019f610cf1918491610c39565b3593610c39565b3590610ac6565b968794610c39565b610c4e565b610d3f565b33610d20610d07858b8d610c39565b610ea6565b01610cb6565b8061033b5f610d3993610138565b5f610cb3565b6040516370a0823160e01b81523060048201529290916020846024816001600160a01b0387165afa938415610347575f94610d98575b50808411610d84575b50505050565b610d8f930391610ea6565b5f808080610d7e565b9093506020813d602011610dc4575b81610db460209383610138565b8101031261010f5751925f610d75565b3d9150610da7565b60405163095ea7b360e01b60208083019182526001600160a01b0385166024840152604480840196909652948252929390925f90610e0b606486610138565b84519082855af15f51903d81610e7a575b501590505b610e2a57505050565b60405163095ea7b360e01b60208201526001600160a01b0390931660248401525f6044840152610b1092610e7590610e6f81606481015b03601f198101835282610138565b826117cd565b6117cd565b15159050610e9a5750610e216001600160a01b0382163b15155b5f610e1c565b6001610e219114610e94565b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044820192909252610b1091610e758260648101610ba2565b8051821015610c495760209160051b010190565b15610efa57565b60405162461bcd60e51b815260206004820152601660248201527556616c7565206d75737420626520333220627974657360501b6044820152606490fd5b602081519101519060208110610f4c575090565b5f199060200360031b1b1690565b5f19810191908211610ac157565b601f19810191908211610ac157565b3d15610fa1573d90610f888261015e565b91610f966040519384610138565b82523d5f602084013e565b606090565b60405190610fb5604083610138565b60078252662ab735b737bbb760c91b6020830152565b9081526001600160a01b0390911660208201526060604082018190526109bc929101906109c9565b905f5b8181106110035750505090565b61100e818385610c39565b359061103c6110366110306110238560201b90565b6001600160f81b03191690565b60f81c90565b60ff1690565b91604083161591826112f55760010192611057848688610c39565b356020905b60038316600181036111b057505f91829190602085166111995761108b916001600160e01b031987168c61188b565b805190602001826001600160a01b0387165af1926110a7610f77565b935b8490156110fd575050608016156110da576110d592916110cf611023610c1f9360581b90565b87611d81565b610ff6565b906110d592956110f06110236110f69460581b90565b90611cd6565b9360010190565b859250611108610fa6565b946044815111611158575b505090611145915f1461114957925b60405163ef3dcb2f60e01b81529384936001600160a01b03169060048501610fcb565b0390fd5b61115290610f5a565b92611122565b602061116f600461116884611aaa565b9301610f38565b036111135761118060248301610f38565b1461118c575b80611113565b6044019350611145611186565b50607f6111aa9160f81c168a610edf565b5161108b565b6002810361121357505f91829190602085166111fc576111db916001600160e01b031987168c61188b565b8051906020016001600160a01b0386165afa926111f6610f77565b936110a9565b50607f61120d9160f81c168a610edf565b516111db565b6003036112bd575f9181611244611231607f869560f81c168d610edf565b5161123f6020825114610ef3565b610f38565b9160208616158414611296576112666112606112789360081b90565b91610f5a565b906001600160e01b031988168d61188b565b905b815191602001906001600160a01b0387165af1926111f6610f77565b50607f6112af6110366110306110236112b69560081b90565b168b610edf565b519061127a565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063616c6c7479706560801b6044820152606490fd5b926006602883901b6001600160d01b031761105c565b81835290916001600160fb1b03831161010f5760209260051b809284830137010190565b908060209392818452848401375f828201840152601f01601f1916010190565b90602083828152019060208160051b85010193835f915b8383106113765750505050505090565b909192939495601f198282030186528635601e198436030181121561010f57830190602082359201916001600160401b03811161010f57803603831361010f576113c6602092839260019561132f565b980196019493019190611366565b93916109bc95936113fa9260018060a01b0316865260606020870152606086019161130b565b92604081850391015261134f565b6001600160a01b03918216815291166020820152604081019190915260a0606082018190529092915f91608091611441918601906109c9565b930152565b6001600160a01b039182168152911660208201526080604082018190526109bc9591949193919261147b92918601919061130b565b92606081850391015261134f565b6109bc939260609260018060a01b03168252602082015281604082015201906109c9565b90959186606091969495968101031261010f57610ba2611503928735946114d386610113565b604060208a0135996114e48b610113565b604051910135996001600160a01b031698909788958a60208801611446565b6001600160a01b0316803b1561010f57610bf1935f80946040519687958694859363701195a160e11b855260048501611489565b6001600160a01b03909116815260806020808301829052835191830182905260a0830196959301905f5b8181106115b65750505080850360408201526020808451968781520193015f955b80871061159e5750506109bc93945060608184039101526109c9565b90936020806001928751815201950196019590611582565b82516001600160a01b0316885260209788019790920191600101611561565b90919592939582019160608184031261010f578035936115f485610113565b60208201356001600160401b03811161010f5782019684601f8901121561010f578735976116218961044e565b9861162f6040519a8b610138565b808a526020808b019160051b8301019187831161010f57602001905b8282106116c0575050506040830135926001600160401b03841161010f5761168b95610ba29461167b9201610465565b98604051978895602087016113d4565b6001600160a01b0316803b1561010f57610bf1935f809460405196879586948593632e1c224f60e11b85523060048601611537565b6020809183356116cf81610113565b81520191019061164b565b9081526001600160a01b0391821660208201529116604082015260a0606082018190526109bc9591949193919261171592918601919061130b565b92608081850391015261134f565b6040906109bc9392815281602082015201906109c9565b9592949091826060918101031261010f576117999261178b9183359561175f87610113565b604060208601359561177087610113565b013597604051998a9660018060a01b03168a602089016116da565b03601f198101855284610138565b6001600160a01b031691823b1561010f57610bf1925f9283604051809681958294635296a43160e01b845260048401611723565b905f602091828151910182855af115610a94575f513d61181c57506001600160a01b0381163b155b6117fc5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156117f5565b60405161016091906118378382610138565b600a815291601f1901366020840137565b9060206109bc9281815201906109ed565b906118638261015e565b6118706040519182610138565b8281528092611881601f199161015e565b0190602036910137565b91939290935f5f915f9261189d611825565b906060935f905b8782106119f9575b50506118ba6118bf91610ab3565b611859565b9760208901525f9060248901925f955b8787106118e157505050505050505050565b6020871015610c4957888b83891a60808116156119d75760fe810361193c5750505060208160019287526119298d61191883610ab3565b6119228b51610f68565b918b611f2f565b875101601f1901955b01960195936118cf565b60fd819794959697145f1461197157509261196592868660019b948a9998978560209c52612085565b50979195909594611932565b60fc810361199357509261196592868660019b948a9998978560209c52611f41565b936119d08882936119bf602096607f6001999c9b9a16906119b48282610edf565b515197889552610edf565b51906119ca85610ab3565b91611f1d565b0195611932565b602092506001939791506119ef607f8492168d610edf565b5101518152611932565b909395916020851015610c495786851a60ff8114611a96576080811615611a815760fe8103611a615750855115611a3f575b6020600191875101935b01969401906118a4565b945060016020604051611a5881610e618d858301611848565b96915050611a2b565b90611a759260019692602095968a8d611e4e565b95919390939294611a35565b611a906020916001938c611ddb565b93611a35565b5093965090949290506118ba6118bf6118ac565b9081516043198101818111610ac1579260445b828110611ac957505050565b8151811015610c4957818101602001516001600160f81b03191615611af057600101611abd565b92935050506043198101908111610ac15790565b15611b0b57565b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f75742d6f662d626f756e647360681b6044820152606490fd5b15611b4d57565b60405162461bcd60e51b815260206004820152602860248201527f4f6e6c79206f6e652072657475726e2076616c7565207065726d697474656420604482015267287374617469632960c01b6064820152608490fd5b15611baa57565b60405162461bcd60e51b815260206004820152602a60248201527f4f6e6c79206f6e652072657475726e2076616c7565207065726d697474656420604482015269287661726961626c652960b01b6064820152608490fd5b60208183031261010f578051906001600160401b03821161010f57019080601f8301121561010f57815191611c368361044e565b92611c446040519485610138565b80845260208085019160051b8301019183831161010f5760208101915b838310611c7057505050505090565b82516001600160401b03811161010f57820185603f8201121561010f57602081015191611c9c8361015e565b611ca96040519182610138565b838152604083850101881061010f575f602085819660408397018386015e83010152815201920191611c61565b91908060f81c60ff8114611d7b576080811615611d435760fe8103611d0b5750506109bc915060208082518301019101611c02565b602091611d21610fe092607f8751911610611b04565b82840193611d3184865114611ba3565b51601f1901845260f31c168301015290565b611d77929150607f1690611d5984518310611b04565b611d666020825114611b46565b611d708285610edf565b5282610edf565b5090565b50505090565b9060f81c60ff8114611dd65782519060208201809211610ac157602092607f611dac611dbf94611859565b921691611db98383610edf565b52610edf565b51918051604084018184840160045afa5051910152565b505050565b611dec90607f602093941690610edf565b515103611df95760200190565b60405162461bcd60e51b815260206004820152602760248201527f537461746963207374617465207661726961626c6573206d75737420626520336044820152663220627974657360c81b6064820152608490fd5b90969594939260fd8103611e6e575095611e689596612212565b90919293565b60fc8103611e82575095611e68959661212b565b9196509194939291611e9791607f1690610edf565b515180151580611f12575b15611eae570160200191565b60405162461bcd60e51b815260206004820152603660248201527f44796e616d6963207374617465207661726961626c6573206d7573742062652060448201527561206d756c7469706c65206f6620333220627974657360501b6064820152608490fd5b50601f811615611ea2565b916020809185930101920160045afa50565b910160200190829060400160045afa50565b9193959692905f94611f538884610edf565b51936024600180878b019b019b0198820101915b60208910611f78575b505050505050565b80891a608081161561205c5760fb8103611f925750611f70565b60fd819c92959a9499969b93979c145f14611fe3575090611fba92918b89528a858b89612085565b9260209a93926001928c969480919d939d97929d9e01970101985b019301979291939490611f67565b60fc810361201d575090611ffe92918b89528a858b89611f41565b9260209a93926001928c969480919d939d97929d9e0197010198611fd5565b6020898b8e6001959f9e979896612050607f869716948d6119bf6120418888610edf565b51519788978897889552610edf565b019d0197010198611fd5565b602060019293979694998161207988607f999e9983961690610edf565b5101518b520198611fd5565b939291909495600101946020861015610c495760206120bf97816120ae607f868b1a1685610edf565b510151602482890101520194611f41565b929391929091602090910190565b156120d457565b60405162461bcd60e51b815260206004820152602960248201527f43616e6e6f74207573652073746174652066726f6d20696e736964652064796e604482015268616d6963207479706560b81b6064820152608490fd5b6001808501976020909601960194935f929091905b602087106121995760405162461bcd60e51b8152602060048201526024808201527f44796e616d6963207479706520776173206e6f742070726f7065726c7920636c6044820152631bdcd95960e21b6064820152608490fd5b80871a60808116156121fa5760fb81036121c1575050506121ba9083610edf565b5293929190565b6121e194956121da60fe839c949a969b959c14156120cd565b888b611e4e565b9197909692939192916001906020905b01930195612140565b61220c60209160019399969a85611ddb565b986121f1565b9291909394600101936020851015610c49576020612235607f83881a1686610edf565b515103612249576020611e6896019361212b565b60405162461bcd60e51b815260206004820152601d60248201527f4172726179206c656e677468206d7573742062652033322062797465730000006044820152606490fd", + "nonce": "0x40", + "chainId": "0x2105" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x24fcd56", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x49e68e7b17833be9126886aca9fae946b3f7583eed414df1765e987d47b9466a", + "transactionIndex": "0xbe", + "blockHash": "0xcbec2e74c50bf126c83bb6ae241311125e792dd2cccb3dda9d2f09c7a4af33e5", + "blockNumber": "0x1edb72d", + "gasUsed": "0x1e104c", + "effectiveGasPrice": "0x40d1d7", + "from": "0x826e0bb2276271efdf2a500597f37b94f6c153ba", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0x0649f744bffff139ee46765ab85af0fbb077f541", + "l1BaseFeeScalar": "0x8dd", + "l1BlobBaseFee": "0x1", + "l1BlobBaseFeeScalar": "0x101c12", + "l1Fee": "0x1e37402eb8", + "l1GasPrice": "0x285593ab", + "l1GasUsed": "0x14a29" + } + ], + "libraries": [], + "pending": [], + "returns": { + "flashloanShortcuts": { + "internal_type": "contract EnsoFlashloanShortcuts", + "value": "0x0649f744bfFFF139eE46765aB85AF0FBb077F541" + } + }, + "timestamp": 1751501652, + "chain": 8453, + "commit": "4cabf3f" +} \ No newline at end of file diff --git a/broadcast/FlashloanDeployer.s.sol/8453/run-latest.json b/broadcast/FlashloanDeployer.s.sol/8453/run-latest.json new file mode 100644 index 0000000..6fab688 --- /dev/null +++ b/broadcast/FlashloanDeployer.s.sol/8453/run-latest.json @@ -0,0 +1,58 @@ +{ + "transactions": [ + { + "hash": "0x49e68e7b17833be9126886aca9fae946b3f7583eed414df1765e987d47b9466a", + "transactionType": "CREATE2", + "contractName": "EnsoFlashloanShortcuts", + "contractAddress": "0x0649f744bffff139ee46765ab85af0fbb077f541", + "function": null, + "arguments": null, + "transaction": { + "from": "0x826e0bb2276271efdf2a500597f37b94f6c153ba", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x298681", + "value": "0x0", + "input": "0x456e736f466c6173686c6f616e53686f727463757473000000000000000000006080806040523460155761228e908161001a8239f35b5f80fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806301ffc9a7146100b9578063150b7a02146100b45780631b11d0ff146100af57806331f57072146100aa578063bc197c81146100a5578063c4850ea8146100a0578063de792d5f1461009b578063ee08d45214610096578063f04f2707146100915763f23a6e610361000e5761089c565b6107ff565b61076e565b6106ff565b61055b565b6104c2565b61034c565b610245565b6101bf565b3461010f57602036600319011261010f5760043563ffffffff60e01b811680910361010f57602090630271189760e51b81149081156100fe575b506040519015158152f35b6301ffc9a760e01b1490505f6100f3565b5f80fd5b6001600160a01b0381160361010f57565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761015957604052565b610124565b6001600160401b03811161015957601f01601f191660200190565b81601f8201121561010f578035906101908261015e565b9261019e6040519485610138565b8284526020838301011161010f57815f926020809301838601378301015290565b3461010f57608036600319011261010f576101db600435610113565b6101e6602435610113565b6064356001600160401b03811161010f57610205903690600401610179565b50604051630a85bd0160e11b8152602090f35b9181601f8401121561010f578235916001600160401b03831161010f576020838186019501011161010f57565b3461010f5760a036600319011261010f5760043561026281610113565b602435906044359060643561027681610113565b608435906001600160401b03821161010f576102b161029c6102b9933690600401610218565b90929091906001600160a01b031630146108f5565b810190610968565b919390303b1561010f5760405163de792d5f60e01b8152925f91849182916102e5919060048401610a45565b038183305af1908115610347576103219561031a936103099361032d575b50610ac6565b926001600160a01b03168383610d3f565b3390610dcc565b60405160018152602090f35b8061033b5f61034193610138565b806109bf565b5f610303565b610a94565b3461010f57604036600319011261010f576004356024356001600160401b03811161010f5761037f903690600401610218565b8101919060808184031261010f5780359061039982610113565b6020810135906103a882610113565b60408101356001600160401b03811161010f57856103c791830161090b565b9460608201356001600160401b03811161010f576103e59201610681565b93303b1561010f5760405163de792d5f60e01b8152945f918691829161040f919060048401610a45565b038183305af1908115610347576100189461031a9261043a575b506001600160a01b03168383610d3f565b8061033b5f61044893610138565b5f610429565b6001600160401b0381116101595760051b60200190565b9080601f8301121561010f57813561047c8161044e565b9261048a6040519485610138565b81845260208085019260051b82010192831161010f57602001905b8282106104b25750505090565b81358152602091820191016104a5565b3461010f5760a036600319011261010f576104de600435610113565b6104e9602435610113565b6044356001600160401b03811161010f57610508903690600401610465565b506064356001600160401b03811161010f57610528903690600401610465565b506084356001600160401b03811161010f57610548903690600401610179565b5060405163bc197c8160e01b8152602090f35b3461010f57602036600319011261010f576004356001600160401b03811161010f5761058b903690600401610218565b81019060a08183031261010f578035906020810135906105aa82610113565b6040810135906105b982610113565b60608101356001600160401b03811161010f57856105d891830161090b565b9460808201356001600160401b03811161010f576105f69201610681565b93303b1561010f5760405163de792d5f60e01b8152945f9186918291610620919060048401610a45565b038183305af1908115610347576100189461064a9261043a57506001600160a01b03168383610d3f565b3390610ea6565b9181601f8401121561010f578235916001600160401b03831161010f576020808501948460051b01011161010f57565b9080601f8301121561010f5781356106988161044e565b926106a66040519485610138565b81845260208085019260051b8201019183831161010f5760208201905b8382106106d257505050505090565b81356001600160401b03811161010f576020916106f487848094880101610179565b8152019101906106c3565b3461010f57604036600319011261010f576004356001600160401b03811161010f5761072f903690600401610651565b6024356001600160401b03811161010f5761074e903690600401610681565b9030330361075f5761001892610ff3565b6314e1dbf760e11b5f5260045ffd5b60a036600319011261010f57600435600481101561010f5760243561079281610113565b6044356001600160401b03811161010f576107b1903690600401610218565b6064939193356001600160401b03811161010f576107d3903690600401610651565b91608435956001600160401b03871161010f576107f7610018973690600401610651565b969095610af1565b3461010f57608036600319011261010f576004356001600160401b03811161010f5761082f903690600401610651565b6024356001600160401b03811161010f5761084e903690600401610651565b6044939193356001600160401b03811161010f57610870903690600401610651565b91606435956001600160401b03871161010f57610894610018973690600401610218565b969095610c58565b3461010f5760a036600319011261010f576108b8600435610113565b6108c3602435610113565b6084356001600160401b03811161010f576108e2903690600401610179565b5060405163f23a6e6160e01b8152602090f35b156108fc57565b63ea8e4eb560e01b5f5260045ffd5b9080601f8301121561010f5781356109228161044e565b926109306040519485610138565b81845260208085019260051b82010192831161010f57602001905b8282106109585750505090565b813581526020918201910161094b565b9160608383031261010f57823561097e81610113565b9260208101356001600160401b03811161010f578361099e91830161090b565b9260408201356001600160401b03811161010f576109bc9201610681565b90565b5f91031261010f57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9080602083519182815201916020808360051b8301019401925f915b838310610a1857505050505090565b9091929394602080610a36600193601f1986820301875289516109c9565b97019301930191939290610a09565b9291604084019360408152825180955260206060820193015f955b808710610a7c5750506109bc93945060208184039101526109ed565b90936020806001928751815201950196019590610a60565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b9060048201809211610ac157565b610a9f565b91908201809211610ac157565b60041115610add57565b634e487b7160e01b5f52602160045260245ffd5b96959493929190610b0188610ad3565b87610b1257610b10975061173a565b565b610b1b88610ad3565b60018803610b2d57610b1097506115d5565b610b3688610ad3565b60028803610b4857610b1097506114ad565b9190959294939680610b5b600392610ad3565b03610c1057856060918101031261010f57610ba2610bb092863594610b7f86610113565b6040602089013598610b908a610113565b013598604051978895602087016113d4565b03601f198101845283610138565b6001600160a01b0316803b1561010f576040516310ac2ddf60e21b8152935f938593849286928492610bf19290916001600160a01b03163060048601611408565b03925af1801561034757610c025750565b8061033b5f610b1093610138565b637079d06b60e01b5f5260045ffd5b60010190565b634e487b7160e01b5f52603260045260245ffd5b9190811015610c495760051b0190565b610c25565b356109bc81610113565b94919695610c6b91949396810190610968565b6001600160a01b03909216969190303b1561010f5760405163de792d5f60e01b8152915f9183918291610ca2919060048401610a45565b038183305af1801561034757610d2b575b505f5b848110610cc7575050505050505050565b80610d2586610d118a8a610d0c610d078f98610cff8d610cf8838f8f60019f610cf1918491610c39565b3593610c39565b3590610ac6565b968794610c39565b610c4e565b610d3f565b33610d20610d07858b8d610c39565b610ea6565b01610cb6565b8061033b5f610d3993610138565b5f610cb3565b6040516370a0823160e01b81523060048201529290916020846024816001600160a01b0387165afa938415610347575f94610d98575b50808411610d84575b50505050565b610d8f930391610ea6565b5f808080610d7e565b9093506020813d602011610dc4575b81610db460209383610138565b8101031261010f5751925f610d75565b3d9150610da7565b60405163095ea7b360e01b60208083019182526001600160a01b0385166024840152604480840196909652948252929390925f90610e0b606486610138565b84519082855af15f51903d81610e7a575b501590505b610e2a57505050565b60405163095ea7b360e01b60208201526001600160a01b0390931660248401525f6044840152610b1092610e7590610e6f81606481015b03601f198101835282610138565b826117cd565b6117cd565b15159050610e9a5750610e216001600160a01b0382163b15155b5f610e1c565b6001610e219114610e94565b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044820192909252610b1091610e758260648101610ba2565b8051821015610c495760209160051b010190565b15610efa57565b60405162461bcd60e51b815260206004820152601660248201527556616c7565206d75737420626520333220627974657360501b6044820152606490fd5b602081519101519060208110610f4c575090565b5f199060200360031b1b1690565b5f19810191908211610ac157565b601f19810191908211610ac157565b3d15610fa1573d90610f888261015e565b91610f966040519384610138565b82523d5f602084013e565b606090565b60405190610fb5604083610138565b60078252662ab735b737bbb760c91b6020830152565b9081526001600160a01b0390911660208201526060604082018190526109bc929101906109c9565b905f5b8181106110035750505090565b61100e818385610c39565b359061103c6110366110306110238560201b90565b6001600160f81b03191690565b60f81c90565b60ff1690565b91604083161591826112f55760010192611057848688610c39565b356020905b60038316600181036111b057505f91829190602085166111995761108b916001600160e01b031987168c61188b565b805190602001826001600160a01b0387165af1926110a7610f77565b935b8490156110fd575050608016156110da576110d592916110cf611023610c1f9360581b90565b87611d81565b610ff6565b906110d592956110f06110236110f69460581b90565b90611cd6565b9360010190565b859250611108610fa6565b946044815111611158575b505090611145915f1461114957925b60405163ef3dcb2f60e01b81529384936001600160a01b03169060048501610fcb565b0390fd5b61115290610f5a565b92611122565b602061116f600461116884611aaa565b9301610f38565b036111135761118060248301610f38565b1461118c575b80611113565b6044019350611145611186565b50607f6111aa9160f81c168a610edf565b5161108b565b6002810361121357505f91829190602085166111fc576111db916001600160e01b031987168c61188b565b8051906020016001600160a01b0386165afa926111f6610f77565b936110a9565b50607f61120d9160f81c168a610edf565b516111db565b6003036112bd575f9181611244611231607f869560f81c168d610edf565b5161123f6020825114610ef3565b610f38565b9160208616158414611296576112666112606112789360081b90565b91610f5a565b906001600160e01b031988168d61188b565b905b815191602001906001600160a01b0387165af1926111f6610f77565b50607f6112af6110366110306110236112b69560081b90565b168b610edf565b519061127a565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063616c6c7479706560801b6044820152606490fd5b926006602883901b6001600160d01b031761105c565b81835290916001600160fb1b03831161010f5760209260051b809284830137010190565b908060209392818452848401375f828201840152601f01601f1916010190565b90602083828152019060208160051b85010193835f915b8383106113765750505050505090565b909192939495601f198282030186528635601e198436030181121561010f57830190602082359201916001600160401b03811161010f57803603831361010f576113c6602092839260019561132f565b980196019493019190611366565b93916109bc95936113fa9260018060a01b0316865260606020870152606086019161130b565b92604081850391015261134f565b6001600160a01b03918216815291166020820152604081019190915260a0606082018190529092915f91608091611441918601906109c9565b930152565b6001600160a01b039182168152911660208201526080604082018190526109bc9591949193919261147b92918601919061130b565b92606081850391015261134f565b6109bc939260609260018060a01b03168252602082015281604082015201906109c9565b90959186606091969495968101031261010f57610ba2611503928735946114d386610113565b604060208a0135996114e48b610113565b604051910135996001600160a01b031698909788958a60208801611446565b6001600160a01b0316803b1561010f57610bf1935f80946040519687958694859363701195a160e11b855260048501611489565b6001600160a01b03909116815260806020808301829052835191830182905260a0830196959301905f5b8181106115b65750505080850360408201526020808451968781520193015f955b80871061159e5750506109bc93945060608184039101526109c9565b90936020806001928751815201950196019590611582565b82516001600160a01b0316885260209788019790920191600101611561565b90919592939582019160608184031261010f578035936115f485610113565b60208201356001600160401b03811161010f5782019684601f8901121561010f578735976116218961044e565b9861162f6040519a8b610138565b808a526020808b019160051b8301019187831161010f57602001905b8282106116c0575050506040830135926001600160401b03841161010f5761168b95610ba29461167b9201610465565b98604051978895602087016113d4565b6001600160a01b0316803b1561010f57610bf1935f809460405196879586948593632e1c224f60e11b85523060048601611537565b6020809183356116cf81610113565b81520191019061164b565b9081526001600160a01b0391821660208201529116604082015260a0606082018190526109bc9591949193919261171592918601919061130b565b92608081850391015261134f565b6040906109bc9392815281602082015201906109c9565b9592949091826060918101031261010f576117999261178b9183359561175f87610113565b604060208601359561177087610113565b013597604051998a9660018060a01b03168a602089016116da565b03601f198101855284610138565b6001600160a01b031691823b1561010f57610bf1925f9283604051809681958294635296a43160e01b845260048401611723565b905f602091828151910182855af115610a94575f513d61181c57506001600160a01b0381163b155b6117fc5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156117f5565b60405161016091906118378382610138565b600a815291601f1901366020840137565b9060206109bc9281815201906109ed565b906118638261015e565b6118706040519182610138565b8281528092611881601f199161015e565b0190602036910137565b91939290935f5f915f9261189d611825565b906060935f905b8782106119f9575b50506118ba6118bf91610ab3565b611859565b9760208901525f9060248901925f955b8787106118e157505050505050505050565b6020871015610c4957888b83891a60808116156119d75760fe810361193c5750505060208160019287526119298d61191883610ab3565b6119228b51610f68565b918b611f2f565b875101601f1901955b01960195936118cf565b60fd819794959697145f1461197157509261196592868660019b948a9998978560209c52612085565b50979195909594611932565b60fc810361199357509261196592868660019b948a9998978560209c52611f41565b936119d08882936119bf602096607f6001999c9b9a16906119b48282610edf565b515197889552610edf565b51906119ca85610ab3565b91611f1d565b0195611932565b602092506001939791506119ef607f8492168d610edf565b5101518152611932565b909395916020851015610c495786851a60ff8114611a96576080811615611a815760fe8103611a615750855115611a3f575b6020600191875101935b01969401906118a4565b945060016020604051611a5881610e618d858301611848565b96915050611a2b565b90611a759260019692602095968a8d611e4e565b95919390939294611a35565b611a906020916001938c611ddb565b93611a35565b5093965090949290506118ba6118bf6118ac565b9081516043198101818111610ac1579260445b828110611ac957505050565b8151811015610c4957818101602001516001600160f81b03191615611af057600101611abd565b92935050506043198101908111610ac15790565b15611b0b57565b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f75742d6f662d626f756e647360681b6044820152606490fd5b15611b4d57565b60405162461bcd60e51b815260206004820152602860248201527f4f6e6c79206f6e652072657475726e2076616c7565207065726d697474656420604482015267287374617469632960c01b6064820152608490fd5b15611baa57565b60405162461bcd60e51b815260206004820152602a60248201527f4f6e6c79206f6e652072657475726e2076616c7565207065726d697474656420604482015269287661726961626c652960b01b6064820152608490fd5b60208183031261010f578051906001600160401b03821161010f57019080601f8301121561010f57815191611c368361044e565b92611c446040519485610138565b80845260208085019160051b8301019183831161010f5760208101915b838310611c7057505050505090565b82516001600160401b03811161010f57820185603f8201121561010f57602081015191611c9c8361015e565b611ca96040519182610138565b838152604083850101881061010f575f602085819660408397018386015e83010152815201920191611c61565b91908060f81c60ff8114611d7b576080811615611d435760fe8103611d0b5750506109bc915060208082518301019101611c02565b602091611d21610fe092607f8751911610611b04565b82840193611d3184865114611ba3565b51601f1901845260f31c168301015290565b611d77929150607f1690611d5984518310611b04565b611d666020825114611b46565b611d708285610edf565b5282610edf565b5090565b50505090565b9060f81c60ff8114611dd65782519060208201809211610ac157602092607f611dac611dbf94611859565b921691611db98383610edf565b52610edf565b51918051604084018184840160045afa5051910152565b505050565b611dec90607f602093941690610edf565b515103611df95760200190565b60405162461bcd60e51b815260206004820152602760248201527f537461746963207374617465207661726961626c6573206d75737420626520336044820152663220627974657360c81b6064820152608490fd5b90969594939260fd8103611e6e575095611e689596612212565b90919293565b60fc8103611e82575095611e68959661212b565b9196509194939291611e9791607f1690610edf565b515180151580611f12575b15611eae570160200191565b60405162461bcd60e51b815260206004820152603660248201527f44796e616d6963207374617465207661726961626c6573206d7573742062652060448201527561206d756c7469706c65206f6620333220627974657360501b6064820152608490fd5b50601f811615611ea2565b916020809185930101920160045afa50565b910160200190829060400160045afa50565b9193959692905f94611f538884610edf565b51936024600180878b019b019b0198820101915b60208910611f78575b505050505050565b80891a608081161561205c5760fb8103611f925750611f70565b60fd819c92959a9499969b93979c145f14611fe3575090611fba92918b89528a858b89612085565b9260209a93926001928c969480919d939d97929d9e01970101985b019301979291939490611f67565b60fc810361201d575090611ffe92918b89528a858b89611f41565b9260209a93926001928c969480919d939d97929d9e0197010198611fd5565b6020898b8e6001959f9e979896612050607f869716948d6119bf6120418888610edf565b51519788978897889552610edf565b019d0197010198611fd5565b602060019293979694998161207988607f999e9983961690610edf565b5101518b520198611fd5565b939291909495600101946020861015610c495760206120bf97816120ae607f868b1a1685610edf565b510151602482890101520194611f41565b929391929091602090910190565b156120d457565b60405162461bcd60e51b815260206004820152602960248201527f43616e6e6f74207573652073746174652066726f6d20696e736964652064796e604482015268616d6963207479706560b81b6064820152608490fd5b6001808501976020909601960194935f929091905b602087106121995760405162461bcd60e51b8152602060048201526024808201527f44796e616d6963207479706520776173206e6f742070726f7065726c7920636c6044820152631bdcd95960e21b6064820152608490fd5b80871a60808116156121fa5760fb81036121c1575050506121ba9083610edf565b5293929190565b6121e194956121da60fe839c949a969b959c14156120cd565b888b611e4e565b9197909692939192916001906020905b01930195612140565b61220c60209160019399969a85611ddb565b986121f1565b9291909394600101936020851015610c49576020612235607f83881a1686610edf565b515103612249576020611e6896019361212b565b60405162461bcd60e51b815260206004820152601d60248201527f4172726179206c656e677468206d7573742062652033322062797465730000006044820152606490fd", + "nonce": "0x40", + "chainId": "0x2105" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x24fcd56", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x49e68e7b17833be9126886aca9fae946b3f7583eed414df1765e987d47b9466a", + "transactionIndex": "0xbe", + "blockHash": "0xcbec2e74c50bf126c83bb6ae241311125e792dd2cccb3dda9d2f09c7a4af33e5", + "blockNumber": "0x1edb72d", + "gasUsed": "0x1e104c", + "effectiveGasPrice": "0x40d1d7", + "from": "0x826e0bb2276271efdf2a500597f37b94f6c153ba", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0x0649f744bffff139ee46765ab85af0fbb077f541", + "l1BaseFeeScalar": "0x8dd", + "l1BlobBaseFee": "0x1", + "l1BlobBaseFeeScalar": "0x101c12", + "l1Fee": "0x1e37402eb8", + "l1GasPrice": "0x285593ab", + "l1GasUsed": "0x14a29" + } + ], + "libraries": [], + "pending": [], + "returns": { + "flashloanShortcuts": { + "internal_type": "contract EnsoFlashloanShortcuts", + "value": "0x0649f744bfFFF139eE46765aB85AF0FBb077F541" + } + }, + "timestamp": 1751501652, + "chain": 8453, + "commit": "4cabf3f" +} \ No newline at end of file diff --git a/script/FlashloanDeployer.s.sol b/script/FlashloanDeployer.s.sol new file mode 100644 index 0000000..2bea2b0 --- /dev/null +++ b/script/FlashloanDeployer.s.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.28; + +import "../src/flashloan/EnsoFlashloanShortcuts.sol"; +import "forge-std/Script.sol"; + +contract FlashloanDeployer is Script { + function run() public returns (EnsoFlashloanShortcuts flashloanShortcuts) { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + flashloanShortcuts = new EnsoFlashloanShortcuts{ salt: "EnsoFlashloanShortcuts" }(); + + vm.stopBroadcast(); + } +} diff --git a/src/flashloan/EnsoFlashloanInterfaces.sol b/src/flashloan/EnsoFlashloanInterfaces.sol new file mode 100644 index 0000000..452aef2 --- /dev/null +++ b/src/flashloan/EnsoFlashloanInterfaces.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.28; + +interface IERC3156FlashBorrower { + function onFlashLoan( + address initiator, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) + external + returns (bytes32); +} + +interface IMorpho { + function flashLoan(address token, uint256 assets, bytes calldata data) external; +} + +interface IEVault { + function flashLoan(uint256 amount, bytes calldata data) external; +} + +interface IBalancerV2Vault { + function flashLoan( + address recipient, + address[] memory tokens, + uint256[] memory amounts, + bytes memory userData + ) + external; +} + +interface IAaveV3Pool { + function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128); + + function flashLoanSimple( + address receiverAddress, + address asset, + uint256 amount, + bytes calldata params, + uint16 referralCode + ) + external; +} diff --git a/src/flashloan/EnsoFlashloanShortcuts.sol b/src/flashloan/EnsoFlashloanShortcuts.sol new file mode 100644 index 0000000..ffcf4e5 --- /dev/null +++ b/src/flashloan/EnsoFlashloanShortcuts.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.28; + +import { IAaveV3Pool, IBalancerV2Vault, IERC3156FlashBorrower, IEVault, IMorpho } from "./EnsoFlashloanInterfaces.sol"; + +import { VM } from "enso-weiroll/VM.sol"; + +import { ERC1155Holder } from "openzeppelin-contracts/token/ERC1155/utils/ERC1155Holder.sol"; + +import { IERC20, SafeERC20 } from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; +import { ERC721Holder } from "openzeppelin-contracts/token/ERC721/utils/ERC721Holder.sol"; + +enum FlashloanProtocols { + Euler, + BalancerV2, + Morpho, + AaveV3 +} + +contract EnsoFlashloanShortcuts is VM, ERC721Holder, ERC1155Holder { + using SafeERC20 for IERC20; + + error UnsupportedFlashloanProtocol(); + error NotSelf(); + error NotAuthorized(); + + function flashLoan( + FlashloanProtocols protocol, + address excessReceiver, + bytes calldata data, + bytes32[] calldata commands, + bytes[] calldata state + ) + external + payable + { + if (protocol == FlashloanProtocols.Euler) { + _executeEulerFlashLoan(excessReceiver, data, commands, state); + } else if (protocol == FlashloanProtocols.BalancerV2) { + _executeBalancerV2FlashLoan(excessReceiver, data, commands, state); + } else if (protocol == FlashloanProtocols.Morpho) { + _executeMorphoFlashLoan(excessReceiver, data, commands, state); + } else if (protocol == FlashloanProtocols.AaveV3) { + _executeAaveV3FlashLoan(excessReceiver, data, commands, state); + } else { + revert UnsupportedFlashloanProtocol(); + } + } + + function execute(bytes32[] calldata commands, bytes[] memory state) public { + require(msg.sender == address(this), NotSelf()); + _execute(commands, state); + } + + // --- Flashloan execution --- + + function _executeEulerFlashLoan( + address excessReceiver, + bytes calldata data, + bytes32[] calldata commands, + bytes[] calldata state + ) + private + { + (IEVault EulerVault, address token, uint256 amount) = abi.decode(data, (IEVault, address, uint256)); + + bytes memory eulerCallback = abi.encode(amount, token, excessReceiver, commands, state); + + EulerVault.flashLoan(amount, eulerCallback); + } + + function _executeBalancerV2FlashLoan( + address excessReceiver, + bytes calldata data, + bytes32[] calldata commands, + bytes[] calldata state + ) + private + { + (IBalancerV2Vault Vault, address[] memory tokens, uint256[] memory amounts) = + abi.decode(data, (IBalancerV2Vault, address[], uint256[])); + + bytes memory balancerV2Callback = abi.encode(excessReceiver, commands, state); + + Vault.flashLoan(address(this), tokens, amounts, balancerV2Callback); + } + + function _executeMorphoFlashLoan( + address excessReceiver, + bytes calldata data, + bytes32[] calldata commands, + bytes[] calldata state + ) + private + { + (IMorpho morpho, address token, uint256 amount) = abi.decode(data, (IMorpho, address, uint256)); + bytes memory morphoCallback = abi.encode(token, excessReceiver, commands, state); + + morpho.flashLoan(token, amount, morphoCallback); + } + + function _executeAaveV3FlashLoan( + address excessReceiver, + bytes calldata data, + bytes32[] calldata commands, + bytes[] calldata state + ) + private + { + (IAaveV3Pool Pool, address token, uint256 amount) = abi.decode(data, (IAaveV3Pool, address, uint256)); + + bytes memory aaveCallback = abi.encode(excessReceiver, commands, state); + + Pool.flashLoanSimple(address(this), token, amount, aaveCallback, 0); + } + + // --- Flashloan callbacks --- + + // Euler + function onFlashLoan(bytes calldata data) external { + (uint256 amount, IERC20 token, address excessReceiver, bytes32[] memory commands, bytes[] memory state) = + abi.decode(data, (uint256, IERC20, address, bytes32[], bytes[])); + + this.execute(commands, state); + + _returnExcessAssets(token, amount, excessReceiver); + + token.safeTransfer(msg.sender, amount); + } + + // BalancerV2 + function receiveFlashLoan( + IERC20[] calldata tokens, + uint256[] calldata amounts, + uint256[] calldata feeAmounts, + bytes calldata data + ) + external + { + (address excessReceiver, bytes32[] memory commands, bytes[] memory state) = + abi.decode(data, (address, bytes32[], bytes[])); + + this.execute(commands, state); + + for (uint256 i = 0; i < tokens.length; i++) { + uint256 repayAmount = amounts[i] + feeAmounts[i]; + _returnExcessAssets(tokens[i], repayAmount, excessReceiver); + tokens[i].safeTransfer(msg.sender, repayAmount); + } + } + + // Morpho + function onMorphoFlashLoan(uint256 amount, bytes calldata data) external { + (IERC20 token, address excessReceiver, bytes32[] memory commands, bytes[] memory state) = + abi.decode(data, (IERC20, address, bytes32[], bytes[])); + + this.execute(commands, state); + + _returnExcessAssets(token, amount, excessReceiver); + + token.forceApprove(msg.sender, amount); + } + + // Aave V3 + function executeOperation( + IERC20 asset, + uint256 amount, + uint256 premium, + address initiator, + bytes calldata data + ) + external + returns (bool) + { + require(initiator == address(this), NotAuthorized()); + (address excessReceiver, bytes32[] memory commands, bytes[] memory state) = + abi.decode(data, (address, bytes32[], bytes[])); + + this.execute(commands, state); + + uint256 repayAmount = amount + premium; + _returnExcessAssets(asset, repayAmount, excessReceiver); + asset.forceApprove(msg.sender, repayAmount); + + return true; + } + + function _returnExcessAssets(IERC20 token, uint256 flashloanAmount, address receiver) private { + uint256 flashloanAssetBalance = token.balanceOf(address(this)); + if (flashloanAssetBalance > flashloanAmount) { + uint256 excessAmount; + unchecked { + excessAmount = flashloanAssetBalance - flashloanAmount; + } + token.safeTransfer(receiver, excessAmount); + } + } + + receive() external payable { } +} diff --git a/test/EnsoFlashloanShortcuts.t.sol b/test/EnsoFlashloanShortcuts.t.sol new file mode 100644 index 0000000..8c9ac81 --- /dev/null +++ b/test/EnsoFlashloanShortcuts.t.sol @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import "../lib/forge-std/src/Test.sol"; + +import "../src/flashloan/EnsoFlashloanShortcuts.sol"; +import "../src/router/EnsoRouter.sol"; + +import "./mocks/MockERC1155.sol"; +import "./mocks/MockERC20.sol"; +import "./mocks/MockERC721.sol"; + +import "./mocks/MockMultiVault.sol"; +import "./mocks/MockNFTVault.sol"; +import "./mocks/MockVault.sol"; + +import "./utils/WeirollPlanner.sol"; + +import { ERC1155Holder } from "openzeppelin-contracts/token/ERC1155/utils/ERC1155Holder.sol"; +import { ERC721Holder } from "openzeppelin-contracts/token/ERC721/utils/ERC721Holder.sol"; + +interface IWETH { + function deposit() external payable; + + function withdraw(uint256) external; + + function transfer(address to, uint256 value) external returns (bool); + + function balanceOf(address) external view returns (uint256); +} + +contract EnsoFlashloanShortcutsTest is Test, ERC721Holder, ERC1155Holder { + EnsoFlashloanShortcuts public shortcuts; + + address user_bob = makeAddr("bob"); + address receiver = makeAddr("receiver"); + + address morpho = address(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb); + + string _rpcURL = vm.envString("ETHEREUM_RPC_URL"); + uint256 _ethereumFork; + + function setUp() public { + _ethereumFork = vm.createFork(_rpcURL); + vm.selectFork(_ethereumFork); + shortcuts = new EnsoFlashloanShortcuts(); + } + + // Morpho test: + // - flashlent asset: WETH + // - no other assets involved + // - WETH.withdraw -> WETH.deposit + function testMorphoFlashloan() public { + vm.selectFork(_ethereumFork); + + IWETH token = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + uint256 amount = 10 ** 18; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + + // Unwrap -> Wrap + commands[0] = WeirollPlanner.buildCommand( + token.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + commands[1] = WeirollPlanner.buildCommand( + token.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + + state[0] = abi.encode(amount); + + bytes memory morphoData = abi.encode(morpho, token, amount); + + shortcuts.flashLoan(FlashloanProtocols.Morpho, user_bob, morphoData, commands, state); + } + + // Morpho test: + // - flashlent asset: WETH + // - other assets: additional WETH + // - WETH.withdraw -> WETH.deposit + // - make sure excess is sent back to user + function testMorphoFlashloan_excess() public { + vm.selectFork(_ethereumFork); + + IWETH token = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + uint256 amount = 1 ether; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + commands[0] = WeirollPlanner.buildCommand( + token.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + commands[1] = WeirollPlanner.buildCommand( + token.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + + state[0] = abi.encode(amount); + + bytes memory morphoData = abi.encode(morpho, token, amount); + + vm.startPrank(user_bob); + vm.deal(user_bob, amount); + token.deposit{ value: amount }(); + + // Simulate that router transfers tokens to flashloan contract + token.transfer(address(shortcuts), amount); + + uint256 balanceBefore = token.balanceOf(receiver); + shortcuts.flashLoan(FlashloanProtocols.Morpho, receiver, morphoData, commands, state); + uint256 balanceAfter = token.balanceOf(receiver); + + assertEq(balanceAfter - balanceBefore, amount); + } + + // Euler test: + // - flashlent asset: WETH + // - no other assets involved + // - WETH.withdraw -> WETH.deposit + function testEulerFlashLoan() public { + vm.selectFork(_ethereumFork); + + // eWETH-2 Euler vault + address eulerVault = address(0xD8b27CF359b7D15710a5BE299AF6e7Bf904984C2); + + IWETH token = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + uint256 amount = 1 ether; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + + // Unwrap -> Wrap + commands[0] = WeirollPlanner.buildCommand( + token.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + commands[1] = WeirollPlanner.buildCommand( + token.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + + state[0] = abi.encode(amount); + + bytes memory eulerData = abi.encode(eulerVault, token, amount); + + shortcuts.flashLoan(FlashloanProtocols.Euler, user_bob, eulerData, commands, state); + } + + // Euler test: + // - flashlent asset: WETH + // - other assets: additional WETH + // - WETH.withdraw -> WETH.deposit + // - make sure excess is sent back to user + function testEulerFlashLoan_excess() public { + vm.selectFork(_ethereumFork); + + // eWETH-2 Euler vault + address eulerVault = address(0xD8b27CF359b7D15710a5BE299AF6e7Bf904984C2); + + IWETH token = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + uint256 amount = 1 ether; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + + // Unwrap -> Wrap + commands[0] = WeirollPlanner.buildCommand( + token.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + commands[1] = WeirollPlanner.buildCommand( + token.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + + state[0] = abi.encode(amount); + + bytes memory eulerData = abi.encode(eulerVault, token, amount); + + vm.startPrank(user_bob); + vm.deal(user_bob, amount); + token.deposit{ value: amount }(); + + // Simulate that router transfers tokens to flashloan contract + token.transfer(address(shortcuts), amount); + + uint256 balanceBefore = token.balanceOf(receiver); + shortcuts.flashLoan(FlashloanProtocols.Euler, receiver, eulerData, commands, state); + + uint256 balanceAfter = token.balanceOf(receiver); + + assertEq(balanceAfter - balanceBefore, amount); + } + + // BalancerV2 test: + // - flashlent asset: WETH + // - no other assets involved + // - WETH.withdraw -> WETH.deposit + function testBalancerV2Flashloan() public { + vm.selectFork(_ethereumFork); + + address balancerV2Vault = address(0xBA12222222228d8Ba445958a75a0704d566BF2C8); + + IWETH weth = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + uint256 wethAmount = 1 ether; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + + // Unwrap -> Wrap + commands[0] = WeirollPlanner.buildCommand( + weth.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(weth) + ); + commands[1] = WeirollPlanner.buildCommand( + weth.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(weth) + ); + + state[0] = abi.encode(wethAmount); + + address[] memory tokens = new address[](1); + uint256[] memory amounts = new uint256[](1); + tokens[0] = address(weth); + amounts[0] = wethAmount; + + bytes memory balancerV2Data = abi.encode(balancerV2Vault, tokens, amounts); + + shortcuts.flashLoan(FlashloanProtocols.BalancerV2, user_bob, balancerV2Data, commands, state); + } + + // BalancerV2 test: + // - flashlent assets: WETH and USDC + // - no other assets involved + // - WETH.withdraw -> WETH.deposit + function testBalancerV2Flashloan_multipleAssets() public { + vm.selectFork(_ethereumFork); + + address balancerV2Vault = address(0xBA12222222228d8Ba445958a75a0704d566BF2C8); + + IWETH weth = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + uint256 wethAmount = 1 ether; + + address usdc = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); + uint256 usdcAmount = 100 * 10 ** 6; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + + // Unwrap -> Wrap + commands[0] = WeirollPlanner.buildCommand( + weth.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(weth) + ); + commands[1] = WeirollPlanner.buildCommand( + weth.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(weth) + ); + + state[0] = abi.encode(wethAmount); + + address[] memory tokens = new address[](2); + uint256[] memory amounts = new uint256[](2); + + // NOTE: Tokens must be in sorted order + tokens[0] = address(usdc); + amounts[0] = usdcAmount; + tokens[1] = address(weth); + amounts[1] = wethAmount; + + bytes memory balancerV2Data = abi.encode(balancerV2Vault, tokens, amounts); + + shortcuts.flashLoan(FlashloanProtocols.BalancerV2, user_bob, balancerV2Data, commands, state); + } + + function testBalancerV2Flashloan_excess() public { + vm.selectFork(_ethereumFork); + + address balancerV2Vault = address(0xBA12222222228d8Ba445958a75a0704d566BF2C8); + + IWETH weth = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + uint256 wethAmount = 1 ether; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + + // Unwrap -> Wrap + commands[0] = WeirollPlanner.buildCommand( + weth.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(weth) + ); + commands[1] = WeirollPlanner.buildCommand( + weth.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(weth) + ); + + state[0] = abi.encode(wethAmount); + + address[] memory tokens = new address[](1); + uint256[] memory amounts = new uint256[](1); + + tokens[0] = address(weth); + amounts[0] = wethAmount; + + bytes memory balancerV2Data = abi.encode(balancerV2Vault, tokens, amounts); + + vm.startPrank(user_bob); + vm.deal(user_bob, wethAmount); + weth.deposit{ value: wethAmount }(); + + // Simulate that router transfers tokens to flashloan contract + weth.transfer(address(shortcuts), wethAmount); + + uint256 balanceBefore = weth.balanceOf(receiver); + shortcuts.flashLoan(FlashloanProtocols.BalancerV2, receiver, balancerV2Data, commands, state); + uint256 balanceAfter = weth.balanceOf(receiver); + + assertEq(balanceAfter - balanceBefore, wethAmount); + } + + function testAaveV3FlashLoan() public { + vm.selectFork(_ethereumFork); + + IAaveV3Pool aaveV3Pool = IAaveV3Pool(address(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2)); + IWETH token = IWETH(address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)); + + uint256 amount = 1 ether; + uint256 BPS = 10_000; + uint256 totalFee = aaveV3Pool.FLASHLOAN_PREMIUM_TOTAL(); + uint256 fee = (amount * totalFee) / BPS; + + bytes32[] memory commands = new bytes32[](2); + bytes[] memory state = new bytes[](1); + + // Unwrap -> Wrap + commands[0] = WeirollPlanner.buildCommand( + token.withdraw.selector, + 0x01, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + commands[1] = WeirollPlanner.buildCommand( + token.deposit.selector, + 0x03, // call + 0x00ffffffffff, // 1 inputs + 0xff, // no output + address(token) + ); + + state[0] = abi.encode(amount); + bytes memory aaveData = abi.encode(aaveV3Pool, token, amount); + + // Pretend that user did necessary actions to have enough to repay + // for the flashloan with fee + vm.startPrank(user_bob); + vm.deal(user_bob, amount); + token.deposit{ value: fee }(); + token.transfer(address(shortcuts), fee); + + shortcuts.flashLoan(FlashloanProtocols.AaveV3, user_bob, aaveData, commands, state); + } +}