diff --git a/package.json b/package.json index 8ea810c..b8a119d 100644 --- a/package.json +++ b/package.json @@ -7,19 +7,21 @@ "build": "tsc", "start": "node dist/index.js", "dev": "ts-node src/index.ts", - "watch": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts" + "watch": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts", + "postinstall": "patch-package" }, "devDependencies": { "@types/inquirer": "^9.0.7", "@types/node": "^22.10.5", "nodemon": "^3.1.9", + "patch-package": "^8.0.0", "ts-node": "^10.9.2", "typescript": "^5.7.3" }, "dependencies": { - "@cowprotocol/cow-sdk": "6.0.0-RC.42", "@cowprotocol/app-data": "3.0.0-rc.1", "@cowprotocol/contracts": "^1.7.0", + "@cowprotocol/cow-sdk": "6.0.0-RC.42", "axios": "^1.7.9", "dotenv": "^16.4.5", "ethers": "^5.7.2", diff --git a/src/contracts/erc20/index.ts b/src/contracts/erc20/index.ts index 34a65d6..a729e77 100644 --- a/src/contracts/erc20/index.ts +++ b/src/contracts/erc20/index.ts @@ -5,6 +5,7 @@ const ERC20_BALANCE_OF_ABI = [ "function approve(address spender, uint256 amount) external returns (bool)", "function decimals() external view returns (uint8)", "function symbol() external view returns (string)", + "function allowance(address owner, address spender) external view returns (uint256)", ] as const; export function getErc20Contract( diff --git a/src/index.ts b/src/index.ts index e58a97d..a8cda04 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,7 @@ import { run as getAcrossBridgingId } from "./scripts/bridging/getAcrossBridging import { run as getEthFlowId } from "./scripts/ethflow/getEthFlowId"; import { run as minimalAppData } from "./scripts/app-data/minimalAppData"; import { run as getIpfsForLegacyDoc } from "./scripts/app-data/getIpfsForLegacyDoc"; +import { run as postTwapForEOA } from "./scripts/composable-cow/postTwapForEOA"; dotenv.config(); @@ -84,7 +85,8 @@ const JOBS: (() => Promise)[] = [ // getAcrossBridgingId, // getEthFlowId, // minimalAppData, - getIpfsForLegacyDoc, + // getIpfsForLegacyDoc, + postTwapForEOA, ]; async function main() { diff --git a/src/scripts/composable-cow/postTwapForEOA.ts b/src/scripts/composable-cow/postTwapForEOA.ts new file mode 100644 index 0000000..527c220 --- /dev/null +++ b/src/scripts/composable-cow/postTwapForEOA.ts @@ -0,0 +1,300 @@ +import { sepolia, APP_CODE, COW_VAULT_RELAYER_CONTRACT } from "../../const"; + +import { + SupportedChainId, + OrderKind, + TradingSdk, + Twap, + CowShedSdk, + COMPOSABLE_COW_CONTRACT_ADDRESS, + OrderBookApi, +} from "@cowprotocol/cow-sdk"; + +import { MetadataApi } from "@cowprotocol/app-data"; +import { BigNumber, ethers } from "ethers"; +import { confirm, debugStringify, getWallet, printQuote } from "../../utils"; +import { getErc20Contract } from "../../contracts/erc20"; +// import { latest } from "@cowprotocol/app-data"; + +const DEFAULT_GAS_LIMIT = 500_000n; + +interface Token { + symbol: string; + address: string; + decimals: number; + contract: ethers.Contract; +} + +const TOKENS = { + // Ideally, we would have sell=buy support, so this should disappear and twapSellToken should be used instead + beforeTwapSellToken: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d", // wxDAI + + twapSellToken: "0xaf204776c7245bF4147c2612BF6e5972Ee483701", // sDAI + twapBuyToken: "0x177127622c4A00F3d409B75571e12cB3c8973d3c", // COW +} as const; + +const PARTS = 2; + +const CHAIN_ID = SupportedChainId.GNOSIS_CHAIN; + +export async function run() { + const wallet = await getWallet(CHAIN_ID); + const eoaTrader = wallet.address as `0x${string}`; + + // 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 { beforeTwapSellToken, twapSellToken, twapBuyToken } = + await getAssetsInfo({ wallet, trader: eoaTrader }); + + const sellAmount = ethers.utils.parseUnits("0.2", twapSellToken.decimals); // 0.1 EURe + const sellAmountFormatted = ethers.utils.formatUnits( + sellAmount, + twapSellToken.decimals + ); + + const cowShedSdk = new CowShedSdk({ + factoryOptions: { + factoryAddress: "0x4f4350bf2c74aacd508d598a1ba94ef84378793d", + implementationAddress: "0x6773d5aA31A1EAD34127D564D6E258E66254EbDb", + proxyCreationCode: + "0x60a03461009557601f61033d38819003918201601f19168301916001600160401b0383118484101761009957808492604094855283398101031261009557610052602061004b836100ad565b92016100ad565b6080527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5560405161027b90816100c28239608051818181608b01526101750152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036100955756fe60806040526004361015610018575b3661019757610197565b5f3560e01c8063025b22bc146100375763f851a4400361000e57610116565b346101125760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101125760043573ffffffffffffffffffffffffffffffffffffffff81169081810361011257337f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff160361010d577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a2005b61023d565b5f80fd5b34610112575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011257602061014e61016c565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b33300361010d577f000000000000000000000000000000000000000000000000000000000000000090565b60ff7f68df44b1011761f481358c0f49a711192727fb02c377d697bcb0ea8ff8393ac0541615806101f0575b1561023d577ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b507fc4d66de8000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000005f351614156101c3565b5f807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54368280378136915af43d5f803e15610277573d5ff35b3d5ffd", + }, + }); + const cowShed = cowShedSdk.getCowShedAccount(CHAIN_ID, eoaTrader); + console.log("CowShed account:", cowShed); + + // Define trade parameters + console.log( + `TWAP sell ${sellAmountFormatted} ${twapSellToken.symbol} for ${twapBuyToken.symbol} in ${PARTS} parts. +To create the TWAP we we will use for this PoC an intermediate order with a post hook: + - Buy ${sellAmountFormatted} ${twapSellToken.symbol} with ${beforeTwapSellToken.symbol}, sent to ${cowShed} + - Post-hook will create the TWAP using cow-shed. Each part sells ${twapSellToken.symbol} for ${twapBuyToken.symbol}` + ); + + // Generate app data for TWAP order + const metadataApi = new MetadataApi(); + const twapAppData = await metadataApi.generateAppDataDoc({ + appCode: APP_CODE, + environment: "prod", + metadata: {}, + }); + const { appDataContent: twapAppDataContent, appDataHex: twapAppDataHex } = + await metadataApi.getAppDataInfo(twapAppData); + + const orderBookApi = new OrderBookApi({ + chainId: CHAIN_ID, + }); + + // TODO: Create TWAP + Derive shed + set shed as the destination for the TWAP + const twap = Twap.fromData({ + // The TWAP orders sends the bought tokens to the trader + receiver: eoaTrader, + sellAmount: sellAmount, + buyAmount: BigNumber.from(PARTS), // TODO: Get another quote and apply a good slippage + numberOfParts: BigNumber.from(PARTS), + timeBetweenParts: BigNumber.from(300), + sellToken: twapSellToken.address, + buyToken: twapBuyToken.address, + appData: twapAppDataHex, + }); + + console.log("TWAP ID:", twap.id); + console.log("TWAP params for cereation of order", { + twapParams: twap.leaf, + twapData: debugStringify(twap.data), + twapAppDataContent: twapAppDataContent, + }); + + console.log("Uploading TWAP app data to API..."); + await orderBookApi.uploadAppData(twapAppDataHex, twapAppDataContent); + + // Get calldata and gas estimation for the approval + const approveSellTokenCalldata = + twapSellToken.contract.interface.encodeFunctionData("approve", [ + COW_VAULT_RELAYER_CONTRACT, + sellAmount, + ]); + console.log("Approve sell token calldata:", approveSellTokenCalldata); + + const approveSellTokenGasLimit = + await twapSellToken.contract.estimateGas.approve( + COW_VAULT_RELAYER_CONTRACT, + sellAmount + ); + console.log( + "Approve sell token gas limit:", + approveSellTokenGasLimit.toString() + ); + + const deadline = BigInt(Math.ceil(Date.now() / 1000)) + 1800n; + console.log( + `Deadline: ${deadline} (${new Date(Number(deadline) * 1000).toISOString()})` + ); + + const { signedMulticall: approveAndTwap, gasLimit: approveAndTwapGasLimit } = + await cowShedSdk.signCalls({ + chainId: CHAIN_ID, + calls: [ + { + callData: approveSellTokenCalldata, + target: twapSellToken.address, + value: 0n, + isDelegateCall: false, + allowFailure: true, + }, + { + callData: twap.createCalldata, + target: COMPOSABLE_COW_CONTRACT_ADDRESS[CHAIN_ID], + value: 0n, + isDelegateCall: false, + allowFailure: true, + }, + ], + deadline, + signer: wallet, + defaultGasLimit: DEFAULT_GAS_LIMIT, + }); + console.log("Signed twap calldata:", approveAndTwap); + + // Dummy order that creates the TWAP + const { quoteResults, postSwapOrderFromQuote } = await sdk.getQuote( + { + // Buy the sell amount we will later use for creating the TWAP. Using Buy order, so we can be assured we know the sell amount of the TWAP + kind: OrderKind.BUY, + buyToken: twapSellToken.address, + buyTokenDecimals: twapSellToken.decimals, + amount: sellAmount.toString(), + sellToken: beforeTwapSellToken.address, + sellTokenDecimals: beforeTwapSellToken.decimals, + + receiver: cowShed, // Receiver is a special shed with support for Composable Cow. See https://github.com/cowdao-grants/cow-shed/pull/53 + owner: eoaTrader, + partiallyFillable: false, + validFor: 1800, + }, + { + appData: { + appCode: APP_CODE, + metadata: { + hooks: { + post: [ + // Approve and create the TWAP + { + callData: approveAndTwap.data, + gasLimit: approveAndTwapGasLimit.toString(), + target: approveAndTwap.to, + dappId: "cow-sdk-scripts://composable-cow/post-twap-for-eoa", + }, + ], + }, + }, + }, + } + ); + + // Print the quote + printQuote(quoteResults); + const sellAmountIntialTrade = + quoteResults.amountsAndCosts.afterSlippage.sellAmount; + const sellAmountIntialTradeFormatted = ethers.utils.formatUnits( + sellAmountIntialTrade, + beforeTwapSellToken.decimals + ); + + // Ask for confirmation before posting the order + const confirmed = await confirm( + `Your CoW Shed will get exactly ${sellAmountFormatted} ${twapSellToken.symbol} for at most ${sellAmountIntialTradeFormatted} ${beforeTwapSellToken.symbol}. Then a TWAP will be created with each part selling ${twapSellToken.symbol} for ${twapBuyToken.symbol}. ok?` + ); + if (confirmed) { + const allowance = await beforeTwapSellToken.contract.allowance( + eoaTrader, + COW_VAULT_RELAYER_CONTRACT + ); + console.log( + `Allowance for Vault Relayer: ${allowance} ${beforeTwapSellToken.symbol}` + ); + if (allowance < sellAmountIntialTrade) { + console.log( + `Approving sell token for: ${sellAmountIntialTradeFormatted} ${beforeTwapSellToken.symbol}` + ); + + const tx = await beforeTwapSellToken.contract.approve( + COW_VAULT_RELAYER_CONTRACT, + ethers.constants.MaxUint256 + // sellAmountIntialTrade + ); + console.log(`Approving ${beforeTwapSellToken.symbol}. tx:`, tx.hash); + await tx.wait(); + console.log(`${beforeTwapSellToken.symbol} Approved`); + } + + // Post the order + const { orderId } = await postSwapOrderFromQuote(); + + console.log( + `Order created, id: https://explorer.cow.fi/gc/orders/${orderId}?tab=overview` + ); + } +} + +async function getAssetsInfo(params: { + wallet: ethers.Wallet; + trader: string; +}): Promise<{ + beforeTwapSellToken: Token; + twapSellToken: Token; + twapBuyToken: Token; +}> { + const { wallet } = params; + + // Get ERC20 balance for oldUnderlying using ethersjs + const beforeTwapSellToken = await getErc20Contract( + TOKENS.beforeTwapSellToken, + wallet + ); + const twapSellToken = await getErc20Contract(TOKENS.twapSellToken, wallet); + const twapBuyToken = await getErc20Contract(TOKENS.twapBuyToken, wallet); + + const [ + beforeTwapSellTokenSymbol, + beforeTwapSellTokenDecimals, + twapSellTokenSymbol, + twapSellTokenDecimals, + twapBuyTokenSymbol, + twapBuyTokenDecimals, + ] = await Promise.all([ + beforeTwapSellToken.symbol(), + beforeTwapSellToken.decimals(), + twapSellToken.symbol(), + twapSellToken.decimals(), + twapBuyToken.symbol(), + twapBuyToken.decimals(), + ]); + + return { + beforeTwapSellToken: { + symbol: beforeTwapSellTokenSymbol, + address: beforeTwapSellToken.address, + decimals: beforeTwapSellTokenDecimals, + contract: beforeTwapSellToken, + }, + twapSellToken: { + symbol: twapSellTokenSymbol, + address: twapSellToken.address, + decimals: twapSellTokenDecimals, + contract: twapSellToken, + }, + twapBuyToken: { + symbol: twapBuyTokenSymbol, + address: twapBuyToken.address, + decimals: twapBuyTokenDecimals, + contract: twapBuyToken, + }, + }; +} diff --git a/src/scripts/flash-loans/collateralSwapAave.ts b/src/scripts/flash-loans/collateralSwapAave.ts new file mode 100644 index 0000000..b64ad8b --- /dev/null +++ b/src/scripts/flash-loans/collateralSwapAave.ts @@ -0,0 +1,435 @@ +import { sepolia, APP_CODE } from "../../const"; + +import { + SupportedChainId, + OrderKind, + TradeParameters, + TradingSdk, + SigningScheme, + WithPartialTraderParams, + SwapAdvancedSettings, +} from "@cowprotocol/cow-sdk"; +import { ethers } from "ethers"; +import { confirm, getWallet, printQuote } from "../../utils"; +import { getErc20Contract } from "../../contracts/erc20"; +import { latest } from "@cowprotocol/app-data"; +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 +// ``` + +const TOKENS = { + oldUnderlying: "0xc558dbdd856501fcd9aaf1e62eae57a9f0629a3c", // WETH + oldCollateral: "0x5b071b590a59395fe4025a0ccc1fcc931aac1830", // aETHWeth + debt: "0xc4bf5cbdabe595361438f8c6a187bdc330539c60", // GHO + newUnderlying: "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", // USDC + newCollateral: "0x40d16fc0236f5686f0a7030063ca493c4dd83358", // 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 DEFAULT_GAS_LIMIT = "1000000"; // FIXME: This should not be necessary, it should estimate correctly! + +const CHAIN_ID = SupportedChainId.SEPOLIA; + +export async function run() { + const wallet = await getWallet(CHAIN_ID); + const trader = wallet.address; + + // 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} COW. ok?` + ); + if (confirmed) { + // User allows to transfer the old collateral to the helper contract + await approveOldCollateral({ + wallet, + trader, + helperContract, + oldUnderlingBalance, + oldUnderlyingDecimals, + oldUnderlyingSymbol, + }); + + // 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: ${oldUnderlyingBalanceFormatted} ${oldUnderlyingSymbol}` + ); + + 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, + ]; + + 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, + // }); + + // 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 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; + + // 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( + 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 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, + }; + console.log("Trade parameters", parameters); + + // Flash loan + const flashLoanHint = { + lender: AAVE_POOL_ADDRESS, + + borrower: COW_AAVE_BORROWER, + token: TOKENS.oldUnderlying, + amount: oldUnderlingBalance, + + + loanReceiver: helperContract, // TODO: not implemented in backend, but should be useful + }; + + // minimal + { + token: TOKENS.oldUnderlying, + amount: oldUnderlingBalance, + } + + // Use this borrower + { + token: TOKENS.oldUnderlying, + amount: oldUnderlingBalance, + borrower: .., + } + + + // // Use just-in-time borrower + // { + // token: TOKENS.oldUnderlying, + // amount: oldUnderlingBalance, + // borrower: helper, + // calldata: deploymnent + // } + + // { + // token: TOKENS.oldUnderlying, + // amount: oldUnderlingBalance, + // borrower: helperFactory, + // factoryParams: deploymnent + // } + + + + + // + + + + const { receiver, ... } = decode(borrowerData) + + console.log("flashLoanHint", flashLoanHint); + + 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], + }, + }, + }, + }; + + return { + parameters, + advancedSettings, + helperContract, + }; +} diff --git a/src/utils.ts b/src/utils.ts index bfb42c3..e21e1c6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -77,6 +77,56 @@ export const jsonReplacer = (key: string, value: any) => { return value; }; +/** + * Recursively converts BigNumber instances to strings for debugging purposes + * @param obj - The object to process + * @returns A new object with BigNumbers converted to strings + */ +export function debugStringify(obj: any): any { + if (obj === null || obj === undefined) { + return obj; + } + + // Handle BigNumber instances + if (obj?._isBigNumber) { + return obj.toString(); + } + + // Handle BigInt + if (typeof obj === "bigint") { + return obj.toString(); + } + + // Handle arrays + if (Array.isArray(obj)) { + return obj.map(debugStringify); + } + + // Handle objects (but not functions, dates, etc.) + if (typeof obj === "object" && obj.constructor === Object) { + const result: any = {}; + for (const [key, value] of Object.entries(obj)) { + result[key] = debugStringify(value); + } + return result; + } + + // Handle other object types (like class instances) + if (typeof obj === "object" && obj.constructor !== Object) { + try { + // Try to convert to plain object first + const plainObj = JSON.parse(JSON.stringify(obj, jsonReplacer)); + return debugStringify(plainObj); + } catch { + // If that fails, return the string representation + return obj.toString(); + } + } + + // Return primitive values as-is + return obj; +} + export function printQuote(quoteResults: QuoteResults) { console.log(`\nšŸ“‰ Suggested slippage: ${quoteResults.suggestedSlippageBps}`); diff --git a/yarn.lock b/yarn.lock index 9aa616c..ca700c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1227,6 +1227,11 @@ dependencies: ethers "^5.3.1" +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + abitype@1.0.8, abitype@^1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.8.tgz#3554f28b2e9d6e9f35eb59878193eabd1b9f46ba" @@ -1271,7 +1276,7 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^4.0.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -1301,6 +1306,11 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + axios@^1.7.9: version "1.7.9" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" @@ -1362,7 +1372,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -1382,6 +1392,32 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz" @@ -1396,6 +1432,14 @@ camelcase@^5.3.1: resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" @@ -1416,6 +1460,11 @@ chokidar@^3.5.2: optionalDependencies: fsevents "~2.3.2" +ci-info@^3.7.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + cids@^1.0.0, cids@^1.1.5, cids@^1.1.6: version "1.1.9" resolved "https://registry.npmjs.org/cids/-/cids-1.1.9.tgz" @@ -1472,6 +1521,15 @@ cross-fetch@^3.1.5, cross-fetch@^3.2.0: dependencies: node-fetch "^2.7.0" +cross-spawn@^7.0.3: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + debug@^4, debug@^4.3.1, debug@^4.3.4: version "4.4.0" resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" @@ -1497,6 +1555,15 @@ deepmerge@^4.3.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" @@ -1512,6 +1579,15 @@ dotenv@^16.4.5: resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz" integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + elliptic@6.5.4: version "6.5.4" resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" @@ -1555,6 +1631,23 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + ethereum-cryptography@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz#58f2810f8e020aecb97de8c8c76147600b0b8ccf" @@ -1697,6 +1790,13 @@ find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" @@ -1720,6 +1820,21 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +fs-extra@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + fsevents@~2.3.2: version "2.3.3" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" @@ -1730,6 +1845,30 @@ function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +get-intrinsic@^1.2.4, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -1737,6 +1876,28 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graphql-request@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/graphql-request/-/graphql-request-4.3.0.tgz" @@ -1769,6 +1930,23 @@ has-flag@^3.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" @@ -1827,7 +2005,15 @@ indent-string@^4.0.0: resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -inherits@^2.0.3, inherits@^2.0.4: +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1922,6 +2108,11 @@ is-core-module@^2.16.0, is-core-module@^2.5.0: dependencies: hasown "^2.0.2" +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" @@ -1954,6 +2145,23 @@ is-plain-obj@^2.1.0: resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-wsl@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + isows@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7" @@ -2001,16 +2209,48 @@ json-schema-traverse@^1.0.0: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-stable-stringify@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz#8903cfac42ea1a0f97f35d63a4ce0518f0cc6a70" + integrity sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + isarray "^2.0.5" + jsonify "^0.0.1" + object-keys "^1.1.1" + json-stringify-deterministic@^1.0.8: version "1.0.12" resolved "https://registry.npmjs.org/json-stringify-deterministic/-/json-stringify-deterministic-1.0.12.tgz" integrity sha512-q3PN0lbUdv0pmurkBNdJH3pfFvOTL/Zp0lquqpvcjfKzt6Y0j49EPHAmVHCAS4Ceq/Y+PejWTzyiVpoY71+D6g== +jsonfile@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" + integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + kind-of@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + limiter@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/limiter/-/limiter-3.0.0.tgz#03556b76d1a81f547caeecc6b83ecc6f24495715" @@ -2055,6 +2295,11 @@ map-obj@^4.0.0: resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + meow@^9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz" @@ -2085,6 +2330,14 @@ micro-ftch@^0.3.1: resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== +micromatch@^4.0.2: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" @@ -2112,7 +2365,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@^3.1.2: +minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -2128,7 +2381,7 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.5: +minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -2237,6 +2490,26 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" @@ -2284,11 +2557,42 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + ci-info "^3.7.0" + cross-spawn "^7.0.3" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + json-stable-stringify "^1.0.2" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^7.5.3" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^2.2.2" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" @@ -2299,7 +2603,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -2412,6 +2716,13 @@ resolve@^1.10.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + run-async@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz" @@ -2454,6 +2765,30 @@ semver@^7.5.4: resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" @@ -2466,6 +2801,11 @@ simple-update-notifier@^2.0.0: dependencies: semver "^7.5.3" +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + sparse-array@^1.3.1: version "1.3.2" resolved "https://registry.npmjs.org/sparse-array/-/sparse-array-1.3.2.tgz" @@ -2539,6 +2879,13 @@ supports-color@^5.5.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" @@ -2646,6 +2993,11 @@ undici-types@~6.20.0: resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz" integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" @@ -2706,6 +3058,13 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" @@ -2715,6 +3074,11 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + ws@7.4.6: version "7.4.6" resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" @@ -2730,6 +3094,11 @@ yallist@^4.0.0: resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^2.2.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== + yargs-parser@^20.2.3: version "20.2.9" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz"