From 86fd6627843873c1e9d4764b5715af52a9083b56 Mon Sep 17 00:00:00 2001 From: carlos Date: Tue, 8 Jul 2025 19:19:08 -0400 Subject: [PATCH 1/6] fix: minor issues --- src/scripts/flash-loans/collateralSwapAave.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/scripts/flash-loans/collateralSwapAave.ts b/src/scripts/flash-loans/collateralSwapAave.ts index 75cc957..b581911 100644 --- a/src/scripts/flash-loans/collateralSwapAave.ts +++ b/src/scripts/flash-loans/collateralSwapAave.ts @@ -9,8 +9,8 @@ import { WithPartialTraderParams, SwapAdvancedSettings, } from "@cowprotocol/cow-sdk"; -import { ethers } from "ethers"; -import { confirm, getWallet, printQuote } from "../../utils"; +import { ethers, providers } from "ethers"; +import { confirm, getRpcProvider, getWallet, printQuote } from "../../utils"; import { getErc20Contract } from "../../contracts/erc20"; import { latest } from "@cowprotocol/app-data"; import { orderHelperFactoryAbi } from "./abi/OrderHelperFactoryAbi"; @@ -33,12 +33,12 @@ const TOKENS = { oldCollateral: "0x5b071b590a59395fe4025a0ccc1fcc931aac1830", // aETHWeth debt: "0xc4bf5cbdabe595361438f8c6a187bdc330539c60", // GHO newUnderlying: "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", // USDC - newCollateral: "0x40d16fc0236f5686f0a7030063ca493c4dd83358", // aUSDC + newCollateral: "0x16dA4541aD1807f4443d92D26044C1147406EB80", // aUSDC } as const; const AAVE_POOL_ADDRESS = "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951"; // See https://search.onaave.com/?q=sepolia const COW_AAVE_BORROWER = "0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A"; // See https://github.com/cowprotocol/flash-loan-router/blob/main/networks.json -const COW_AAVE_HELPER_FACTORY = "0xc55098a66d2225c37bf33c1f7b8b9b0abc8fd32f"; // https://sepolia.etherscan.io/address/0xc55098a66d2225c37bf33c1f7b8b9b0abc8fd32f#code +const COW_AAVE_HELPER_FACTORY = "0xe7De9F737135AEE2d154D1b6b23414C1bf115109"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code const DEFAULT_GAS_LIMIT = "1000000"; // FIXME: This should not be necessary, it should estimate correctly! const CHAIN_ID = SupportedChainId.SEPOLIA; @@ -47,6 +47,8 @@ export async function run() { const wallet = await getWallet(CHAIN_ID); const trader = wallet.address; + console.log(`Trader ${trader}`); + // Initialize the SDK with the wallet const sdk = new TradingSdk({ chainId: CHAIN_ID, @@ -178,7 +180,7 @@ async function getAssetsInfo(params: { ); console.log( - `Old underlying balance: ${oldUnderlyingBalanceFormatted} ${oldUnderlyingSymbol}` + `Old underlying balance as collateral: ${oldUnderlyingBalanceFormatted} ${oldUnderlyingSymbol}` ); const newUnderlying = await getErc20Contract(TOKENS.newUnderlying, wallet); @@ -318,9 +320,14 @@ async function getOrderDetails(props: { wallet, } = props; + // validFor is based on block.timestamp + const rpc = await getRpcProvider(CHAIN_ID); + const block = await rpc.getBlock("latest"); + const validFor = block.timestamp + 60 * 5; // 5 minutes from now + // Get the minimum receive const minReceivedAmount = "1"; // 1 Wei. Technically I would need to ask for a quote. Its a bit tricky, because we would need to ask for a quote with the helper contract as owner. Could be possible with a dirty trick (find an user with balance for the oldUnderlying and ask for a quote to dump it for the newUnderlying). For simplicity, I start hardcoding to 1 web. - const validFor = 60 * 30; // 30 minutes from now + // Ger factory contract instance const orderHelperFactory = new ethers.Contract( @@ -342,6 +349,7 @@ async function getOrderDetails(props: { // Get the hook to swap the collateral const collateralSwapHook = getCollateralSwapPostHook({ helperContract }); + const orderValidFor = validFor - block.timestamp; const parameters: TradeParameters = { kind: OrderKind.SELL, @@ -354,7 +362,7 @@ async function getOrderDetails(props: { partiallyFillable: false, owner: helperContract as `0x${string}`, receiver: helperContract, - validFor, + validFor: orderValidFor, }; console.log("Trade parameters", parameters); From 4e2c26bd3c74bde63b980cbd64e356d9bd29d3c6 Mon Sep 17 00:00:00 2001 From: carlos Date: Tue, 8 Jul 2025 19:52:36 -0400 Subject: [PATCH 2/6] feat: gnosis version --- src/scripts/flash-loans/collateralSwapAave.ts | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/scripts/flash-loans/collateralSwapAave.ts b/src/scripts/flash-loans/collateralSwapAave.ts index b581911..64e574d 100644 --- a/src/scripts/flash-loans/collateralSwapAave.ts +++ b/src/scripts/flash-loans/collateralSwapAave.ts @@ -29,19 +29,19 @@ import { orderHelperAbi } from "./abi/OrderHelperAbi"; // ``` const TOKENS = { - oldUnderlying: "0xc558dbdd856501fcd9aaf1e62eae57a9f0629a3c", // WETH - oldCollateral: "0x5b071b590a59395fe4025a0ccc1fcc931aac1830", // aETHWeth - debt: "0xc4bf5cbdabe595361438f8c6a187bdc330539c60", // GHO - newUnderlying: "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", // USDC - newCollateral: "0x16dA4541aD1807f4443d92D26044C1147406EB80", // aUSDC + oldUnderlying: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", // WXDAI + oldCollateral: "0xd0Dd6cEF72143E22cCED4867eb0d5F2328715533", // aWXDAI + debt: "0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb", // GNO + newUnderlying: "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", // USDC + newCollateral: "0xc6B7AcA6DE8a6044E0e32d0c841a89244A10D284", // aUSDC } as const; -const AAVE_POOL_ADDRESS = "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951"; // See https://search.onaave.com/?q=sepolia +const AAVE_POOL_ADDRESS = "0xb50201558B00496A145fE76f7424749556E326D8"; // See https://search.onaave.com/?q=sepolia const COW_AAVE_BORROWER = "0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A"; // See https://github.com/cowprotocol/flash-loan-router/blob/main/networks.json -const COW_AAVE_HELPER_FACTORY = "0xe7De9F737135AEE2d154D1b6b23414C1bf115109"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code +const COW_AAVE_HELPER_FACTORY = "0xC55098a66D2225c37Bf33c1F7B8b9B0ABc8fd32f"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code const DEFAULT_GAS_LIMIT = "1000000"; // FIXME: This should not be necessary, it should estimate correctly! -const CHAIN_ID = SupportedChainId.SEPOLIA; +const CHAIN_ID = SupportedChainId.GNOSIS_CHAIN; export async function run() { const wallet = await getWallet(CHAIN_ID); @@ -95,18 +95,16 @@ export async function run() { // Ask for confirmation before posting the order const confirmed = await confirm( - `You will get at least ${buyAmount} COW. ok?` + `You will get at least ${buyAmount} BUY_TOKEN. ok?` ); if (confirmed) { - // User allows to transfer the old collateral to the helper contract - await approveOldCollateral({ - wallet, - trader, - helperContract, - oldUnderlingBalance, - oldUnderlyingDecimals, - oldUnderlyingSymbol, - }); + // Sign the helper contract + const orderHelperFactory = new ethers.Contract( + COW_AAVE_HELPER_FACTORY, + orderHelperFactoryAbi, + wallet + ); + await orderHelperFactory.setPreApprovedContracts(helperContract); // Post the order const { orderId } = await postSwapOrderFromQuote(); From 738224893812ad79e3d716f245253189f77fb03b Mon Sep 17 00:00:00 2001 From: carlos Date: Wed, 9 Jul 2025 15:44:50 -0400 Subject: [PATCH 3/6] feat: min version in gnosis --- .../flash-loans/abi/OrderHelperFactoryAbi.ts | 9 + src/scripts/flash-loans/collateralSwapAave.ts | 451 ++++-------------- 2 files changed, 109 insertions(+), 351 deletions(-) diff --git a/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts b/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts index fabab55..ab36c8b 100644 --- a/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts +++ b/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts @@ -47,6 +47,15 @@ export const orderHelperFactoryAbi = [ ], stateMutability: "nonpayable", }, + { + type: "function", + name: "setPreApprovedContracts", + inputs: [ + { name: "_helper", type: "address", internalType: "address" }, + ], + outputs: [], + stateMutability: "nonpayable", + }, { type: "function", name: "getOrderHelperAddress", diff --git a/src/scripts/flash-loans/collateralSwapAave.ts b/src/scripts/flash-loans/collateralSwapAave.ts index 64e574d..e4566b5 100644 --- a/src/scripts/flash-loans/collateralSwapAave.ts +++ b/src/scripts/flash-loans/collateralSwapAave.ts @@ -1,32 +1,11 @@ -import { sepolia, APP_CODE } from "../../const"; - import { SupportedChainId, - OrderKind, - TradeParameters, - TradingSdk, - SigningScheme, - WithPartialTraderParams, - SwapAdvancedSettings, } from "@cowprotocol/cow-sdk"; -import { ethers, providers } from "ethers"; -import { confirm, getRpcProvider, getWallet, printQuote } from "../../utils"; -import { getErc20Contract } from "../../contracts/erc20"; -import { latest } from "@cowprotocol/app-data"; +import { ethers } from "ethers"; +import { getWallet } from "../../utils"; import { orderHelperFactoryAbi } from "./abi/OrderHelperFactoryAbi"; import { orderHelperAbi } from "./abi/OrderHelperAbi"; - -// To setup an account to test this script: -// 1. Create a test account (PK to use in the script) -// 2. Go to https://app.aave.com, enable sepolia (in the gear icon on the top right), and supply sepolia ETH -// Example: https://sepolia.etherscan.io/tx/0x7cf4f7853963292ff7819d4a5cd5e31c55e7f679e49237c93315b47029486698 -// 3. Borrow some GHO -// Example: https://sepolia.etherscan.io/tx/0xb470bbf7e98d1b4cad7fa79e97b64e295bb2e077f0e91f9220d39c48f339641c -// 4. Add the private key and the RPC URL to the `.env` file: -// ```ini -// RPC_URL_11155111=your-rpc -// PRIVATE_KEY=your-pk -// ``` +import { MetadataApi } from '@cowprotocol/app-data'; const TOKENS = { oldUnderlying: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", // WXDAI @@ -38,361 +17,131 @@ const TOKENS = { const AAVE_POOL_ADDRESS = "0xb50201558B00496A145fE76f7424749556E326D8"; // See https://search.onaave.com/?q=sepolia const COW_AAVE_BORROWER = "0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A"; // See https://github.com/cowprotocol/flash-loan-router/blob/main/networks.json -const COW_AAVE_HELPER_FACTORY = "0xC55098a66D2225c37Bf33c1F7B8b9B0ABc8fd32f"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code -const DEFAULT_GAS_LIMIT = "1000000"; // FIXME: This should not be necessary, it should estimate correctly! - +const COW_AAVE_HELPER_FACTORY = "0xb1e836ae7fe26db465351998d0e8e6fc5a512c46"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code +const DEFAULT_GAS_LIMIT = "100000"; // FIXME: This should not be necessary, it should estimate correctly! +const VALID_FOR = 1752100000; const CHAIN_ID = SupportedChainId.GNOSIS_CHAIN; export async function run() { const wallet = await getWallet(CHAIN_ID); const trader = wallet.address; + console.log(`Trader ${trader} needs to approve the collateral to ${COW_AAVE_HELPER_FACTORY}`); - console.log(`Trader ${trader}`); - - // Initialize the SDK with the wallet - const sdk = new TradingSdk({ - chainId: CHAIN_ID, - signer: wallet, // Use a signer - appCode: APP_CODE, - }); - - // Get some info about the assets - const { - oldUnderlingBalance, - oldUnderlyingSymbol, - oldUnderlyingDecimals, - oldUnderlyingBalanceFormatted, - newUnderlyingSymbol, - newUnderlyingDecimals, - } = await getAssetsInfo({ wallet, trader }); - - // Define trade parameters - console.log( - `Get quote for selling ${oldUnderlyingBalanceFormatted} ${oldUnderlyingSymbol} for ${newUnderlyingSymbol}` - ); - - // Get the order details - const { parameters, advancedSettings, helperContract } = - await getOrderDetails({ - trader, - oldUnderlingBalance, - oldUnderlyingDecimals, - newUnderlyingDecimals, - wallet, - }); - - // Post the 1271 order (including the flash-loan hint and the pre-hook) - // TODO: I believe the SDK doesn't handle very well 1271 orders, we might need to use another specific method to pass also the signature either in the quote, or at the time of posting the order. - // TODO: The signature should contain the order, so it can be decoded: `GPv2Order.Data memory _order = abi.decode(_signature, (GPv2Order.Data));`. . Keep in mind the signature will be simpler in a future implementation, because we don't need all the order data (most of them are already constants in the contract) - const { quoteResults, postSwapOrderFromQuote } = await sdk.getQuote( - parameters, - advancedSettings - ); - - // Print the quote - printQuote(quoteResults); - const buyAmount = quoteResults.amountsAndCosts.afterSlippage.buyAmount; - - // Ask for confirmation before posting the order - const confirmed = await confirm( - `You will get at least ${buyAmount} BUY_TOKEN. ok?` - ); - if (confirmed) { - // Sign the helper contract - const orderHelperFactory = new ethers.Contract( - COW_AAVE_HELPER_FACTORY, - orderHelperFactoryAbi, - wallet - ); - await orderHelperFactory.setPreApprovedContracts(helperContract); - - // Post the order - const { orderId } = await postSwapOrderFromQuote(); - - console.log( - `Order created, id: https://explorer.cow.fi/sepolia/orders/${orderId}?tab=overview` - ); - } -} - -async function approveOldCollateral(params: { - wallet: ethers.Wallet; - trader: string; - helperContract: string; - oldUnderlingBalance: ethers.BigNumberish; - oldUnderlyingDecimals: number; - oldUnderlyingSymbol: string; -}) { - const { - wallet, - trader, - helperContract, - oldUnderlingBalance, - oldUnderlyingDecimals, - oldUnderlyingSymbol, - } = params; - - // Approve the helper contract to spend the old collateral - const oldCollateral = await getErc20Contract(TOKENS.oldCollateral, wallet); - - // Get the allowance for the helper contract - const allowance = await oldCollateral.allowance(trader, helperContract); - const allowanceFormatted = ethers.utils.formatUnits( - allowance, - oldUnderlyingDecimals - ); - console.log( - `Allowance for the helper contract: ${allowanceFormatted} ${oldUnderlyingSymbol}` - ); - - if (allowance < oldUnderlingBalance) { - console.log( - "Alright! First make sure the helper contract has an approval (we could use permit pre-hook instead too)" - ); - - const tx = await oldCollateral.approve(helperContract, oldUnderlingBalance); - await tx.wait(); - } else { - console.log("The helper contract has enough allowance to post the order"); - } -} - -async function getAssetsInfo(params: { - wallet: ethers.Wallet; - trader: string; -}) { - const { wallet, trader } = params; - - // Get ERC20 balance for oldUnderlying using ethersjs - const oldUnderlying = await getErc20Contract(TOKENS.oldUnderlying, wallet); - const oldCollateral = await getErc20Contract(TOKENS.oldCollateral, wallet); - const [oldUnderlyingSymbol, oldUnderlyingDecimals, oldUnderlingBalance] = - await Promise.all([ - oldUnderlying.symbol(), - oldUnderlying.decimals(), - oldCollateral.balanceOf(trader), - ]); - const oldUnderlyingBalanceFormatted = ethers.utils.formatUnits( - oldUnderlingBalance, - oldUnderlyingDecimals - ); - - console.log( - `Old underlying balance as collateral: ${oldUnderlyingBalanceFormatted} ${oldUnderlyingSymbol}` + const orderHelperFactory = new ethers.Contract( + COW_AAVE_HELPER_FACTORY, + orderHelperFactoryAbi, + wallet ); - const newUnderlying = await getErc20Contract(TOKENS.newUnderlying, wallet); - const [newUnderlyingSymbol, newUnderlyingDecimals] = await Promise.all([ - newUnderlying.symbol(), - newUnderlying.decimals(), - ]); - - return { - // Old underlying info - oldUnderlingBalance, - oldUnderlyingSymbol, - oldUnderlyingDecimals, - oldUnderlyingBalanceFormatted, - - // New underlying info - newUnderlyingSymbol, - newUnderlyingDecimals, - }; -} - -async function getHelperDeploymentPreHook(params: { - trader: string; - oldUnderlingBalance: ethers.BigNumberish; - minReceivedAmount: string; - validFor: number; - orderHelperFactory: ethers.Contract; - wallet: ethers.Wallet; -}): Promise<{ - helperContract: string; - helperContractDeploymentHook: latest.CoWHook; -}> { - const { - trader, - oldUnderlingBalance, - minReceivedAmount, - validFor, - orderHelperFactory, - wallet, - } = params; - const orderHelperParams = [ trader, // owner - AAVE_POOL_ADDRESS, // borrower - TOKENS.oldCollateral, - oldUnderlingBalance, - TOKENS.newCollateral, - minReceivedAmount, - validFor, + COW_AAVE_BORROWER, // cow borrower + TOKENS.oldUnderlying, + "20000000000000000000", + TOKENS.newUnderlying, + "19500000", + VALID_FOR, ]; - console.log("Get helper contract", orderHelperParams); const helperContract: string = await orderHelperFactory.getOrderHelperAddress( ...orderHelperParams ); - // TODO: We might want to use this function to save one RPC call - // const helperContract = predictDeterministicAddress({ - // implementation, - // salt: getSalt(orderHelperParams), - // factoryAddress: COW_AAVE_COLLATERAL_SWAP_HELPER_FACTORY, - // }); + + console.log("will use helperContract", helperContract); + + const appCode = 'aave-v3-flashloan' + const flashLoanHint = { + lender: AAVE_POOL_ADDRESS, + borrower: helperContract, + token: TOKENS.oldUnderlying, + amount: "20000000000000000000", + }; + console.log("flashLoanHint", flashLoanHint); // Prepare deployment of the helper contract const deployOrderHelperData = orderHelperFactory.interface.encodeFunctionData( "deployOrderHelper", orderHelperParams ); - console.log("deployOrderHelperData", deployOrderHelperData); - - const gasEstimate = await wallet - .estimateGas({ - to: COW_AAVE_HELPER_FACTORY, - data: deployOrderHelperData, - value: ethers.constants.Zero, - }) - .catch((error) => { - console.error("error estimating gas", error); - console.log("Check the call", { - to: COW_AAVE_HELPER_FACTORY, - data: deployOrderHelperData, - }); - return DEFAULT_GAS_LIMIT; - }); - console.log("gasEstimate", gasEstimate); - - const helperContractDeploymentHook: latest.CoWHook = { - target: COW_AAVE_HELPER_FACTORY, - callData: deployOrderHelperData, - gasLimit: gasEstimate.toString(), - dappId: "cow-sdk-scripts://flash-loans/collateralSwapAave", - }; - - return { - helperContract, - helperContractDeploymentHook, - }; -} - -function getCollateralSwapPostHook(params: { - helperContract: string; -}): latest.CoWHook { - const { helperContract } = params; - // Get the helper contract const helperContractInstance = new ethers.Contract( helperContract, orderHelperAbi ); + const stringify = require('json-stringify-deterministic'); + const appDataDoc = { + appCode: appCode, + metadata: { + flashloan: flashLoanHint, + hooks: { + // pre: [ + // { + // target: COW_AAVE_HELPER_FACTORY, + // callData: deployOrderHelperData, + // gasLimit: DEFAULT_GAS_LIMIT, + // }, + // ], + post: [ + { + target: helperContract, + callData: helperContractInstance.interface.encodeFunctionData("swapCollateral"), + gasLimit: DEFAULT_GAS_LIMIT, + } + ], + } + + } + } + const metadataApi = new MetadataApi(); + const fullAppData = stringify(appDataDoc); + console.log("fullAppData", fullAppData); + + const module = await import('ethers/lib/utils') + const { keccak256, toUtf8Bytes } = module.default || module + + const preAppDataHex = keccak256(toUtf8Bytes(fullAppData)) + console.log("preAppDataHex", preAppDataHex); + const appDataHex = await metadataApi.appDataHexToCid(preAppDataHex); + console.log("appDataHex", appDataHex) + + + const data = { + "sellToken": TOKENS.oldUnderlying, + "buyToken": TOKENS.newUnderlying, + "receiver": helperContract, + "feeAmount": "0", + "sellAmount": "20000000000000000000", + "buyAmount": "19500000", + "validTo": VALID_FOR, + "kind": "sell", + "partiallyFillable": false, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20", + "signingScheme": "eip1271", + "signature": "0x000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a83000000000000000000000000b4f89a000f964b50eb6d37e758d51884452d5396000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000000000000001298be000000000000000000000000000000000000000000000000000000000686eeca0f6b7417024d42d8da3472b65bd63447f8d854c40a5eaabc9f79de9e55139a7bc0000000000000000000000000000000000000000000000000000000000000000f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677500000000000000000000000000000000000000000000000000000000000000005a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc95a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9", + "from": helperContract.toString(), + "quoteId": 0, + "appData": fullAppData, + //"appDataHash": preAppDataHex + } - const collateralSwapHook: latest.CoWHook = { - target: helperContract, - callData: - helperContractInstance.interface.encodeFunctionData("swapCollateral"), - gasLimit: DEFAULT_GAS_LIMIT, // TODO: Estimate gas - dappId: "cow-sdk-scripts://flash-loans/collateralSwapAave", - }; - - return collateralSwapHook; -} - -async function getOrderDetails(props: { - trader: string; - oldUnderlingBalance: ethers.BigNumberish; - oldUnderlyingDecimals: number; - newUnderlyingDecimals: number; - wallet: ethers.Wallet; -}): Promise<{ - parameters: WithPartialTraderParams; - advancedSettings?: SwapAdvancedSettings; - helperContract: string; -}> { - const { - trader, - oldUnderlingBalance, - oldUnderlyingDecimals, - newUnderlyingDecimals, - wallet, - } = props; - - // validFor is based on block.timestamp - const rpc = await getRpcProvider(CHAIN_ID); - const block = await rpc.getBlock("latest"); - const validFor = block.timestamp + 60 * 5; // 5 minutes from now - - // Get the minimum receive - const minReceivedAmount = "1"; // 1 Wei. Technically I would need to ask for a quote. Its a bit tricky, because we would need to ask for a quote with the helper contract as owner. Could be possible with a dirty trick (find an user with balance for the oldUnderlying and ask for a quote to dump it for the newUnderlying). For simplicity, I start hardcoding to 1 web. - - - // Ger factory contract instance - const orderHelperFactory = new ethers.Contract( - COW_AAVE_HELPER_FACTORY, - orderHelperFactoryAbi, - wallet - ); - - // Get the hook to deploy the helper contract - const { helperContractDeploymentHook, helperContract } = - await getHelperDeploymentPreHook({ - trader, - oldUnderlingBalance, - minReceivedAmount, - validFor, - orderHelperFactory, - wallet, - }); - - // Get the hook to swap the collateral - const collateralSwapHook = getCollateralSwapPostHook({ helperContract }); - const orderValidFor = validFor - block.timestamp; - - const parameters: TradeParameters = { - kind: OrderKind.SELL, - amount: oldUnderlingBalance.toString(), // All underlying balance - sellToken: TOKENS.oldUnderlying, - sellTokenDecimals: oldUnderlyingDecimals, - buyToken: TOKENS.newUnderlying, - buyTokenDecimals: newUnderlyingDecimals, - - partiallyFillable: false, - owner: helperContract as `0x${string}`, - receiver: helperContract, - validFor: orderValidFor, - }; - console.log("Trade parameters", parameters); - - // Flash loan - const flashLoanHint = { - lender: AAVE_POOL_ADDRESS, - borrower: COW_AAVE_BORROWER, - token: TOKENS.oldUnderlying, - amount: oldUnderlingBalance, - }; - console.log("flashLoanHint", flashLoanHint); + console.log("data", data); + console.log("json", JSON.stringify(data)); - const advancedSettings: SwapAdvancedSettings = { - additionalParams: { - signingScheme: SigningScheme.EIP1271, - }, - appData: { - appCode: APP_CODE, - metadata: { - // @ts-ignore The flash-loan hint is still not added officially to https://github.com/cowprotocol/app-data - flashLoan: flashLoanHint, - hooks: { - pre: [helperContractDeploymentHook], - post: [collateralSwapHook], - }, - }, + // Post the order + const response = await fetch("https://api.cow.fi/xdai/api/v1/orders", { + method: "POST", + headers: { + "Content-Type": "application/json" }, - }; + body: JSON.stringify(data) + }); - return { - parameters, - advancedSettings, - helperContract, - }; + if (!response.ok) { + // Handle error response + const errorText = await response.text(); + throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`); + } + + console.log("response", response); } From 439b389991d06c224705b004953e0d5fcd6adaef Mon Sep 17 00:00:00 2001 From: carlos Date: Fri, 11 Jul 2025 15:57:05 -0400 Subject: [PATCH 4/6] fix: push for miguel --- .../flash-loans/abi/OrderHelperFactoryAbi.ts | 10 ++++++ src/scripts/flash-loans/collateralSwapAave.ts | 34 ++++++++++--------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts b/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts index ab36c8b..2d76bf8 100644 --- a/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts +++ b/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts @@ -37,6 +37,11 @@ export const orderHelperFactoryAbi = [ internalType: "uint256", }, { name: "_validTo", type: "uint32", internalType: "uint32" }, + { + name: "_flashloanFee", + type: "uint256", + internalType: "uint256", + }, ], outputs: [ { @@ -83,6 +88,11 @@ export const orderHelperFactoryAbi = [ internalType: "uint256", }, { name: "_validTo", type: "uint32", internalType: "uint32" }, + { + name: "_flashloanFee", + type: "uint256", + internalType: "uint256", + }, ], outputs: [ { diff --git a/src/scripts/flash-loans/collateralSwapAave.ts b/src/scripts/flash-loans/collateralSwapAave.ts index e4566b5..bda40ad 100644 --- a/src/scripts/flash-loans/collateralSwapAave.ts +++ b/src/scripts/flash-loans/collateralSwapAave.ts @@ -17,10 +17,11 @@ const TOKENS = { const AAVE_POOL_ADDRESS = "0xb50201558B00496A145fE76f7424749556E326D8"; // See https://search.onaave.com/?q=sepolia const COW_AAVE_BORROWER = "0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A"; // See https://github.com/cowprotocol/flash-loan-router/blob/main/networks.json -const COW_AAVE_HELPER_FACTORY = "0xb1e836ae7fe26db465351998d0e8e6fc5a512c46"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code -const DEFAULT_GAS_LIMIT = "100000"; // FIXME: This should not be necessary, it should estimate correctly! -const VALID_FOR = 1752100000; +const COW_AAVE_HELPER_FACTORY = "0x937255bc7b62171e3f6c2373a851048b9e412a23"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code +const DEFAULT_GAS_LIMIT = "1000000"; // FIXME: This should not be necessary, it should estimate correctly! +const VALID_FOR = 1752266000; const CHAIN_ID = SupportedChainId.GNOSIS_CHAIN; +const FLASHLOAN_FEE = "10000000000000000"; export async function run() { const wallet = await getWallet(CHAIN_ID); @@ -39,8 +40,9 @@ export async function run() { TOKENS.oldUnderlying, "20000000000000000000", TOKENS.newUnderlying, - "19500000", + "18000000", VALID_FOR, + FLASHLOAN_FEE ]; console.log("Get helper contract", orderHelperParams); const helperContract: string = await orderHelperFactory.getOrderHelperAddress( @@ -74,13 +76,13 @@ export async function run() { metadata: { flashloan: flashLoanHint, hooks: { - // pre: [ - // { - // target: COW_AAVE_HELPER_FACTORY, - // callData: deployOrderHelperData, - // gasLimit: DEFAULT_GAS_LIMIT, - // }, - // ], + pre: [ + { + target: COW_AAVE_HELPER_FACTORY, + callData: deployOrderHelperData, + gasLimit: DEFAULT_GAS_LIMIT, + }, + ], post: [ { target: helperContract, @@ -110,15 +112,15 @@ export async function run() { "buyToken": TOKENS.newUnderlying, "receiver": helperContract, "feeAmount": "0", - "sellAmount": "20000000000000000000", - "buyAmount": "19500000", + "sellAmount": "19990000000000000000", // 20000000000000000000 - 10000000000000000 + "buyAmount": "18000000", "validTo": VALID_FOR, "kind": "sell", - "partiallyFillable": false, + "partiallyFillable": true, "sellTokenBalance": "erc20", "buyTokenBalance": "erc20", "signingScheme": "eip1271", - "signature": "0x000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a83000000000000000000000000b4f89a000f964b50eb6d37e758d51884452d5396000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000000000000001298be000000000000000000000000000000000000000000000000000000000686eeca0f6b7417024d42d8da3472b65bd63447f8d854c40a5eaabc9f79de9e55139a7bc0000000000000000000000000000000000000000000000000000000000000000f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677500000000000000000000000000000000000000000000000000000000000000005a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc95a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9", + "signature": "0x000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a83000000000000000000000000e6950540c88fb6238389a622b3be3c67079a84ee000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000000000000001298be000000000000000000000000000000000000000000000000000000000686fee708890759ffe2a084a75f881305cb151d56d6a7c8229c8b8febcc7d939e46b68530000000000000000000000000000000000000000000000000000000000000000f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677500000000000000000000000000000000000000000000000000000000000000005a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc95a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9", "from": helperContract.toString(), "quoteId": 0, "appData": fullAppData, @@ -129,7 +131,7 @@ export async function run() { console.log("json", JSON.stringify(data)); // Post the order - const response = await fetch("https://api.cow.fi/xdai/api/v1/orders", { + const response = await fetch("https://barn.api.cow.fi/xdai/api/v1/orders", { method: "POST", headers: { "Content-Type": "application/json" From 9dd680d0f6d736b1bdd41285320723d43cd257ce Mon Sep 17 00:00:00 2001 From: carlos Date: Thu, 31 Jul 2025 18:54:09 -0400 Subject: [PATCH 5/6] feat: script working --- src/scripts/flash-loans/abi/OrderHelperAbi.ts | 9 +- .../flash-loans/abi/OrderHelperFactoryAbi.ts | 6 +- src/scripts/flash-loans/collateralSwapAave.ts | 162 ++++++++++++++---- 3 files changed, 143 insertions(+), 34 deletions(-) diff --git a/src/scripts/flash-loans/abi/OrderHelperAbi.ts b/src/scripts/flash-loans/abi/OrderHelperAbi.ts index a60d0ea..dbb3e5e 100644 --- a/src/scripts/flash-loans/abi/OrderHelperAbi.ts +++ b/src/scripts/flash-loans/abi/OrderHelperAbi.ts @@ -106,7 +106,14 @@ export const orderHelperAbi = [ }, { type: "function", - name: "swapCollateral", + name: "preHook", + inputs: [], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "postHook", inputs: [], outputs: [], stateMutability: "nonpayable", diff --git a/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts b/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts index 2d76bf8..70dca08 100644 --- a/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts +++ b/src/scripts/flash-loans/abi/OrderHelperFactoryAbi.ts @@ -15,7 +15,7 @@ export const orderHelperFactoryAbi = [ name: "deployOrderHelper", inputs: [ { name: "_owner", type: "address", internalType: "address" }, - { name: "_borrower", type: "address", internalType: "address" }, + { name: "_tracker", type: "address", internalType: "address" }, { name: "_oldCollateral", type: "address", @@ -42,6 +42,7 @@ export const orderHelperFactoryAbi = [ type: "uint256", internalType: "uint256", }, + { name: "_flashloanPayee", type: "address", internalType: "address" } ], outputs: [ { @@ -66,7 +67,7 @@ export const orderHelperFactoryAbi = [ name: "getOrderHelperAddress", inputs: [ { name: "_owner", type: "address", internalType: "address" }, - { name: "_borrower", type: "address", internalType: "address" }, + { name: "_tracker", type: "address", internalType: "address" }, { name: "_oldCollateral", type: "address", @@ -93,6 +94,7 @@ export const orderHelperFactoryAbi = [ type: "uint256", internalType: "uint256", }, + { name: "_flashloanPayee", type: "address", internalType: "address" } ], outputs: [ { diff --git a/src/scripts/flash-loans/collateralSwapAave.ts b/src/scripts/flash-loans/collateralSwapAave.ts index bda40ad..63541ec 100644 --- a/src/scripts/flash-loans/collateralSwapAave.ts +++ b/src/scripts/flash-loans/collateralSwapAave.ts @@ -1,32 +1,45 @@ import { SupportedChainId, + OrderSigningUtils, + UnsignedOrder } from "@cowprotocol/cow-sdk"; import { ethers } from "ethers"; -import { getWallet } from "../../utils"; +import { confirm, getWallet } from "../../utils"; +import { getErc20Contract } from "../../contracts/erc20"; import { orderHelperFactoryAbi } from "./abi/OrderHelperFactoryAbi"; import { orderHelperAbi } from "./abi/OrderHelperAbi"; import { MetadataApi } from '@cowprotocol/app-data'; +import { utils } from 'ethers' +import { + OrderBalance, + OrderKind, + hashOrder, + type Order} from '@cowprotocol/contracts' +import { GPv2Settlement__factory } from "@cowprotocol/cow-sdk/dist/common/generated"; + const TOKENS = { - oldUnderlying: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", // WXDAI - oldCollateral: "0xd0Dd6cEF72143E22cCED4867eb0d5F2328715533", // aWXDAI + oldUnderlying: "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", // USDC + oldCollateral: "0xc6B7AcA6DE8a6044E0e32d0c841a89244A10D284", // aUSDC debt: "0x9C58BAcC331c9aa871AFD802DB6379a98e80CEdb", // GNO - newUnderlying: "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", // USDC - newCollateral: "0xc6B7AcA6DE8a6044E0e32d0c841a89244A10D284", // aUSDC + newUnderlying: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", // WXDAI + newCollateral: "0xd0Dd6cEF72143E22cCED4867eb0d5F2328715533", // aWXDAI } as const; const AAVE_POOL_ADDRESS = "0xb50201558B00496A145fE76f7424749556E326D8"; // See https://search.onaave.com/?q=sepolia -const COW_AAVE_BORROWER = "0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A"; // See https://github.com/cowprotocol/flash-loan-router/blob/main/networks.json -const COW_AAVE_HELPER_FACTORY = "0x937255bc7b62171e3f6c2373a851048b9e412a23"; // https://sepolia.etherscan.io/address/0xe7De9F737135AEE2d154D1b6b23414C1bf115109#code +const COW_FLASHLOAN_TRACKER = "0xCB77A75B5fbb2FFE143BD05c3660b4e1fb44929D"; +const COW_AAVE_BORROWER = "0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A"; +const COW_AAVE_HELPER_FACTORY = "0x9364CA1a885CA56b357A62A8DddaFa73D85EC826"; const DEFAULT_GAS_LIMIT = "1000000"; // FIXME: This should not be necessary, it should estimate correctly! -const VALID_FOR = 1752266000; +const VALID_FOR = 1754010000; const CHAIN_ID = SupportedChainId.GNOSIS_CHAIN; -const FLASHLOAN_FEE = "10000000000000000"; +const FLASHLOAN_FEE = "10000"; // 0.05% of the flashloan amount +const OLD_COLLATERAL_AMOUNT = "20000000"; +const NEW_COLLATERAL_AMOUNT = "18000000000000000000"; export async function run() { const wallet = await getWallet(CHAIN_ID); const trader = wallet.address; - console.log(`Trader ${trader} needs to approve the collateral to ${COW_AAVE_HELPER_FACTORY}`); const orderHelperFactory = new ethers.Contract( COW_AAVE_HELPER_FACTORY, @@ -36,27 +49,39 @@ export async function run() { const orderHelperParams = [ trader, // owner - COW_AAVE_BORROWER, // cow borrower + COW_FLASHLOAN_TRACKER, TOKENS.oldUnderlying, - "20000000000000000000", + OLD_COLLATERAL_AMOUNT, TOKENS.newUnderlying, - "18000000", + NEW_COLLATERAL_AMOUNT, VALID_FOR, - FLASHLOAN_FEE + FLASHLOAN_FEE, + COW_AAVE_BORROWER ]; console.log("Get helper contract", orderHelperParams); + const helperContract: string = await orderHelperFactory.getOrderHelperAddress( ...orderHelperParams ); console.log("will use helperContract", helperContract); + const confirmed = await confirm( + `Do you want to approve token ${TOKENS.oldCollateral} to spender ${helperContract}?` + ); + if (confirmed) { + const oldCollateral = getErc20Contract(TOKENS.oldCollateral, wallet); + const tx = await oldCollateral.approve(helperContract, OLD_COLLATERAL_AMOUNT); + await tx.wait(); + console.log("approved: ", tx.hash); + } + const appCode = 'aave-v3-flashloan' const flashLoanHint = { lender: AAVE_POOL_ADDRESS, borrower: helperContract, token: TOKENS.oldUnderlying, - amount: "20000000000000000000", + amount: OLD_COLLATERAL_AMOUNT, // this is actually in UNDERLYING but aave tokens are 1:1 }; console.log("flashLoanHint", flashLoanHint); @@ -82,11 +107,16 @@ export async function run() { callData: deployOrderHelperData, gasLimit: DEFAULT_GAS_LIMIT, }, + { + target: helperContract, + callData: helperContractInstance.interface.encodeFunctionData("preHook"), + gasLimit: DEFAULT_GAS_LIMIT, + }, ], post: [ { target: helperContract, - callData: helperContractInstance.interface.encodeFunctionData("swapCollateral"), + callData: helperContractInstance.interface.encodeFunctionData("postHook"), gasLimit: DEFAULT_GAS_LIMIT, } ], @@ -94,37 +124,108 @@ export async function run() { } } - const metadataApi = new MetadataApi(); + + // TODO: Update the metadataApi dependency to avoid this hack + //const metadataApi = new MetadataApi(); const fullAppData = stringify(appDataDoc); console.log("fullAppData", fullAppData); const module = await import('ethers/lib/utils') const { keccak256, toUtf8Bytes } = module.default || module - - const preAppDataHex = keccak256(toUtf8Bytes(fullAppData)) - console.log("preAppDataHex", preAppDataHex); - const appDataHex = await metadataApi.appDataHexToCid(preAppDataHex); - console.log("appDataHex", appDataHex) + const appDataHash = keccak256(toUtf8Bytes(fullAppData)) + console.log("appDataHash", appDataHash); + const order: Order = { + sellToken: TOKENS.oldCollateral, + buyToken: TOKENS.newCollateral, + receiver: trader, + feeAmount: "0", + sellAmount: "19990000", // 20000000 - 10000 + buyAmount: "18000000000000000000", + validTo: VALID_FOR, + appData: appDataHash, + kind: OrderKind.SELL, + partiallyFillable: false, + sellTokenBalance: OrderBalance.ERC20, + buyTokenBalance: OrderBalance.ERC20, + } + const orderHash = hashOrder(await OrderSigningUtils.getDomain(CHAIN_ID), order); + console.log("orderHash", orderHash); + + // TODO: There should be an easier way to encode an order + const types = [ + "address", // sellToken + "address", // buyToken + "address", // receiver + "uint256", // sellAmount + "uint256", // buyAmount + "uint32", // validTo + "bytes32", // appData + "uint256", // feeAmount + "bytes32", // kind + "bool", // partiallyFillable + "bytes32", // sellTokenBalance + "bytes32", // buyTokenBalance + ]; + const encodedOrder = utils.defaultAbiCoder.encode(types, [ + order.sellToken, + order.buyToken, + order.receiver, + order.sellAmount, + order.buyAmount, + order.validTo, + order.appData, + order.feeAmount, + "0xf3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775", // order.kind + order.partiallyFillable, + "0x5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9", // order.sellTokenBalance + "0x5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9", // order.buyTokenBalance + ]); + console.log("encodedOrder", encodedOrder); + + + const signedOrder = await OrderSigningUtils.signOrder(order as UnsignedOrder, CHAIN_ID, wallet); + console.log("signedOrder", signedOrder.signature); + + // TODO: ugly. Find a better way to encode the order+signature + const fullSingature = utils.defaultAbiCoder.encode( + ["tuple(address sellToken, address buyToken, address receiver, uint256 sellAmount, uint256 buyAmount, uint32 validTo, bytes32 appData, uint256 feeAmount, bytes32 kind, bool partiallyFillable, bytes32 sellTokenBalance, bytes32 buyTokenBalance)", "bytes"], + [ + [ + order.sellToken, + order.buyToken, + order.receiver, + order.sellAmount, + order.buyAmount, + order.validTo, + order.appData, + order.feeAmount, + "0xf3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775", // order.kind + order.partiallyFillable, + "0x5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9", // order.sellTokenBalance + "0x5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9" + ], + signedOrder.signature + ]); + console.log("fullSignature", fullSingature); const data = { - "sellToken": TOKENS.oldUnderlying, - "buyToken": TOKENS.newUnderlying, - "receiver": helperContract, + "sellToken": TOKENS.oldCollateral, + "buyToken": TOKENS.newCollateral, + "receiver": trader, "feeAmount": "0", - "sellAmount": "19990000000000000000", // 20000000000000000000 - 10000000000000000 - "buyAmount": "18000000", + "sellAmount": "19990000", // 20000000 - 10000 + "buyAmount": "18000000000000000000", "validTo": VALID_FOR, "kind": "sell", - "partiallyFillable": true, + "partiallyFillable": false, "sellTokenBalance": "erc20", "buyTokenBalance": "erc20", "signingScheme": "eip1271", - "signature": "0x000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a83000000000000000000000000e6950540c88fb6238389a622b3be3c67079a84ee000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000000000000001298be000000000000000000000000000000000000000000000000000000000686fee708890759ffe2a084a75f881305cb151d56d6a7c8229c8b8febcc7d939e46b68530000000000000000000000000000000000000000000000000000000000000000f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677500000000000000000000000000000000000000000000000000000000000000005a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc95a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9", + "signature": fullSingature, "from": helperContract.toString(), "quoteId": 0, "appData": fullAppData, - //"appDataHash": preAppDataHex } console.log("data", data); @@ -140,7 +241,6 @@ export async function run() { }); if (!response.ok) { - // Handle error response const errorText = await response.text(); throw new Error(`HTTP error! status: ${response.status}, body: ${errorText}`); } From 993247dba0ee2ac0ef634c673a64e6cc2f0390ac Mon Sep 17 00:00:00 2001 From: carlos Date: Wed, 13 Aug 2025 17:44:41 -0400 Subject: [PATCH 6/6] fix: latest version --- src/scripts/flash-loans/collateralSwapAave.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/flash-loans/collateralSwapAave.ts b/src/scripts/flash-loans/collateralSwapAave.ts index 63541ec..e599d02 100644 --- a/src/scripts/flash-loans/collateralSwapAave.ts +++ b/src/scripts/flash-loans/collateralSwapAave.ts @@ -29,9 +29,9 @@ const TOKENS = { const AAVE_POOL_ADDRESS = "0xb50201558B00496A145fE76f7424749556E326D8"; // See https://search.onaave.com/?q=sepolia const COW_FLASHLOAN_TRACKER = "0xCB77A75B5fbb2FFE143BD05c3660b4e1fb44929D"; const COW_AAVE_BORROWER = "0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A"; -const COW_AAVE_HELPER_FACTORY = "0x9364CA1a885CA56b357A62A8DddaFa73D85EC826"; +const COW_AAVE_HELPER_FACTORY = "0xDc3aF1e540849826Abb43E6ee9B407C8451C5eE8"; const DEFAULT_GAS_LIMIT = "1000000"; // FIXME: This should not be necessary, it should estimate correctly! -const VALID_FOR = 1754010000; +const VALID_FOR = 1755130000; const CHAIN_ID = SupportedChainId.GNOSIS_CHAIN; const FLASHLOAN_FEE = "10000"; // 0.05% of the flashloan amount const OLD_COLLATERAL_AMOUNT = "20000000";