From 4d70bedc7ba49bbb80c2f16233e02d1bee31fe31 Mon Sep 17 00:00:00 2001 From: Ed Zynda Date: Mon, 13 May 2024 13:13:05 +0300 Subject: [PATCH] feat(mayan): MayanBridgeFacet v1.0.0 (#606) * update templates for deploy/update * Generate boilerplate for Mayan Bridge Facet * Add interface * Basic outline * Add constants * Initial tests * Use SDK to fetch accurate values for tests * Refactor to take fees from bridge token * Update tests * Update natspec * Deploy to staging * Create demo script * fix decimals for USDT on BSC * Update docs and scripts * Use wormhole chainIds * Redeploy * Use correct wormhole chainid * Redeploy to staging * Get wormhold mappings from storage * Remove unneeded param * fixes * Rename facet to work with backend naming conventions * Rename mayanBridgeData to mayanData * Fix base wormhole chain id * fix json * deploy to prod + test EVM -> Solana --- config/mayan.json | 93 ++++++ deployments/_deployments_log_file.json | 100 +++++++ deployments/arbitrum.diamond.json | 4 + deployments/arbitrum.json | 3 +- deployments/avalanche.diamond.json | 4 + deployments/avalanche.json | 3 +- deployments/bsc.diamond.json | 4 + deployments/bsc.diamond.staging.json | 6 +- deployments/bsc.json | 3 +- deployments/bsc.staging.json | 4 +- deployments/mainnet.diamond.json | 4 + deployments/mainnet.json | 3 +- deployments/polygon.diamond.json | 4 + deployments/polygon.json | 3 +- docs/MayanFacet.md | 115 ++++++++ docs/README.md | 1 + package.json | 1 + script/demoScripts/demoMayan.ts | 111 ++++++++ script/demoScripts/demoMayanSolana.ts | 111 ++++++++ script/deploy/facets/DeployMayanFacet.s.sol | 33 +++ script/deploy/facets/UpdateMayanFacet.s.sol | 44 +++ src/Facets/MayanFacet.sol | 276 ++++++++++++++++++ src/Interfaces/IMayan.sol | 47 ++++ test/solidity/Facets/MayanFacet.t.sol | 203 +++++++++++++ yarn.lock | 297 +++++++++++++++++++- 25 files changed, 1454 insertions(+), 23 deletions(-) create mode 100644 config/mayan.json create mode 100644 docs/MayanFacet.md create mode 100644 script/demoScripts/demoMayan.ts create mode 100644 script/demoScripts/demoMayanSolana.ts create mode 100644 script/deploy/facets/DeployMayanFacet.s.sol create mode 100644 script/deploy/facets/UpdateMayanFacet.s.sol create mode 100644 src/Facets/MayanFacet.sol create mode 100644 src/Interfaces/IMayan.sol create mode 100644 test/solidity/Facets/MayanFacet.t.sol diff --git a/config/mayan.json b/config/mayan.json new file mode 100644 index 000000000..00d7fb581 --- /dev/null +++ b/config/mayan.json @@ -0,0 +1,93 @@ +{ + "bridges": { + "mainnet": { + "bridge": "0xF3f04555f8FdA510bfC77820FD6eB8446f59E72d" + }, + "bsc": { + "bridge": "0xF3f04555f8FdA510bfC77820FD6eB8446f59E72d" + }, + "polygon": { + "bridge": "0xF3f04555f8FdA510bfC77820FD6eB8446f59E72d" + }, + "avalanche": { + "bridge": "0xF3f04555f8FdA510bfC77820FD6eB8446f59E72d" + }, + "arbitrum": { + "bridge": "0xF3f04555f8FdA510bfC77820FD6eB8446f59E72d" + } + }, + "chains": [ + { + "chainId": 1151111081099710, + "wormholeChainId": 1 + }, + { + "chainId": 1, + "wormholeChainId": 2 + }, + { + "chainId": 56, + "wormholeChainId": 4 + }, + { + "chainId": 137, + "wormholeChainId": 5 + }, + { + "chainId": 43114, + "wormholeChainId": 6 + }, + { + "chainId": 4262, + "wormholeChainId": 7 + }, + { + "chainId": 1313161554, + "wormholeChainId": 9 + }, + { + "chainId": 250, + "wormholeChainId": 10 + }, + { + "chainId": 686, + "wormholeChainId": 11 + }, + { + "chainId": 787, + "wormholeChainId": 12 + }, + { + "chainId": 8217, + "wormholeChainId": 13 + }, + { + "chainId": 42220, + "wormholeChainId": 14 + }, + { + "chainId": 1284, + "wormholeChainId": 16 + }, + { + "chainId": 42161, + "wormholeChainId": 23 + }, + { + "chainId": 10, + "wormholeChainId": 24 + }, + { + "chainId": 100, + "wormholeChainId": 25 + }, + { + "chainId": 8453, + "wormholeChainId": 30 + }, + { + "chainId": 534352, + "wormholeChainId": 34 + } + ] +} diff --git a/deployments/_deployments_log_file.json b/deployments/_deployments_log_file.json index 232c77d17..23b7b02ed 100644 --- a/deployments/_deployments_log_file.json +++ b/deployments/_deployments_log_file.json @@ -17336,6 +17336,22 @@ } } }, + "MayanBridgeFacet": { + "bsc": { + "staging": { + "1.0.0": [ + { + "ADDRESS": "0x5Ba4FeD1DAd2fD057A9f687B399B8e4cF2368214", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-03-13 16:20:44", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000f3f04555f8fda510bfc77820fd6eb8446f59e72d", + "SALT": "", + "VERIFIED": "true" + } + ] + } + } + }, "TokenWrapper": { "polygon": { "staging": { @@ -17700,5 +17716,89 @@ ] } } + }, + "MayanFacet": { + "bsc": { + "staging": { + "1.0.0": [ + { + "ADDRESS": "0xcED4B608A468ce334c75c6652e18E2Ba7f3F44dA", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-04-04 11:52:23", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000f3f04555f8fda510bfc77820fd6eb8446f59e72d", + "SALT": "", + "VERIFIED": "true" + } + ] + }, + "production": { + "1.0.0": [ + { + "ADDRESS": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-04-30 12:19:20", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000f3f04555f8fda510bfc77820fd6eb8446f59e72d", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "arbitrum": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-04-30 12:26:04", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000f3f04555f8fda510bfc77820fd6eb8446f59e72d", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "avalanche": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-04-30 12:28:19", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000f3f04555f8fda510bfc77820fd6eb8446f59e72d", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "polygon": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-04-30 12:54:29", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000f3f04555f8fda510bfc77820fd6eb8446f59e72d", + "SALT": "", + "VERIFIED": "true" + } + ] + } + }, + "mainnet": { + "production": { + "1.0.0": [ + { + "ADDRESS": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D", + "OPTIMIZER_RUNS": "1000000", + "TIMESTAMP": "2024-05-01 11:49:46", + "CONSTRUCTOR_ARGS": "0x000000000000000000000000f3f04555f8fda510bfc77820fd6eb8446f59e72d", + "SALT": "", + "VERIFIED": "true" + } + ] + } + } } } diff --git a/deployments/arbitrum.diamond.json b/deployments/arbitrum.diamond.json index 5c173c5f2..390e3134e 100644 --- a/deployments/arbitrum.diamond.json +++ b/deployments/arbitrum.diamond.json @@ -112,6 +112,10 @@ "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c": { "Name": "SquidFacet", "Version": "1.0.0" + }, + "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D": { + "Name": "MayanFacet", + "Version": "1.0.0" } }, "Periphery": { diff --git a/deployments/arbitrum.json b/deployments/arbitrum.json index 2b1b2eb2d..55d3f2426 100644 --- a/deployments/arbitrum.json +++ b/deployments/arbitrum.json @@ -42,5 +42,6 @@ "AmarokFacetPacked": "0xF18A285f4e6f720Eb9b4e05df71f88b9552E6ADB", "SymbiosisFacet": "0xe12b2488c71432F9a116E9ac244D3Ef4c2386d3a", "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d", - "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c" + "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c", + "MayanFacet": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D" } \ No newline at end of file diff --git a/deployments/avalanche.diamond.json b/deployments/avalanche.diamond.json index eb0a56300..27662d970 100644 --- a/deployments/avalanche.diamond.json +++ b/deployments/avalanche.diamond.json @@ -84,6 +84,10 @@ "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c": { "Name": "SquidFacet", "Version": "1.0.0" + }, + "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D": { + "Name": "MayanFacet", + "Version": "1.0.0" } }, "Periphery": { diff --git a/deployments/avalanche.json b/deployments/avalanche.json index fe0a27878..26e20c3dc 100644 --- a/deployments/avalanche.json +++ b/deployments/avalanche.json @@ -39,5 +39,6 @@ "ThorSwapFacet": "0xC3cD90545f30F4F9E71e582510Cc64ab5a743E85", "SymbiosisFacet": "0xe12b2488c71432F9a116E9ac244D3Ef4c2386d3a", "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d", - "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c" + "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c", + "MayanFacet": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D" } \ No newline at end of file diff --git a/deployments/bsc.diamond.json b/deployments/bsc.diamond.json index 7677df8a3..2fa3e3581 100644 --- a/deployments/bsc.diamond.json +++ b/deployments/bsc.diamond.json @@ -88,6 +88,10 @@ "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c": { "Name": "SquidFacet", "Version": "1.0.0" + }, + "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D": { + "Name": "MayanFacet", + "Version": "1.0.0" } }, "Periphery": { diff --git a/deployments/bsc.diamond.staging.json b/deployments/bsc.diamond.staging.json index 16ef7f51f..c49e6edfd 100644 --- a/deployments/bsc.diamond.staging.json +++ b/deployments/bsc.diamond.staging.json @@ -46,8 +46,8 @@ "Version": "" }, "0xcED4B608A468ce334c75c6652e18E2Ba7f3F44dA": { - "Name": "", - "Version": "" + "Name": "MayanFacet", + "Version": "1.0.0" }, "0xAfcC5c55d5Ec3082675D51331E7Ed9AdE195db48": { "Name": "StargateFacet", @@ -82,4 +82,4 @@ "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d" } } -} \ No newline at end of file +} diff --git a/deployments/bsc.json b/deployments/bsc.json index e505f7e06..5e8511260 100644 --- a/deployments/bsc.json +++ b/deployments/bsc.json @@ -40,5 +40,6 @@ "AmarokFacetPacked": "0xF18A285f4e6f720Eb9b4e05df71f88b9552E6ADB", "SymbiosisFacet": "0xe12b2488c71432F9a116E9ac244D3Ef4c2386d3a", "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d", - "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c" + "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c", + "MayanFacet": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D" } \ No newline at end of file diff --git a/deployments/bsc.staging.json b/deployments/bsc.staging.json index 9add3c733..2b8112690 100644 --- a/deployments/bsc.staging.json +++ b/deployments/bsc.staging.json @@ -24,5 +24,7 @@ "OFTWrapperFacet": "0x3004db169fa7956609A872736452E4951D4BDA8b", "StargateFacet": "0xAfcC5c55d5Ec3082675D51331E7Ed9AdE195db48", "ThorSwapFacet": "0xa6aAe470E7B8E8916e692882A5db25bB40C398A7", - "AmarokFacetPacked": "0x7ac3EB2D191EBAb9E925CAbFD4F8155be066b3aa" + "AmarokFacetPacked": "0x7ac3EB2D191EBAb9E925CAbFD4F8155be066b3aa", + "MayanBridgeFacet": "0x5Ba4FeD1DAd2fD057A9f687B399B8e4cF2368214", + "MayanFacet": "0xcED4B608A468ce334c75c6652e18E2Ba7f3F44dA" } \ No newline at end of file diff --git a/deployments/mainnet.diamond.json b/deployments/mainnet.diamond.json index 33d30e5ec..1f27e12eb 100644 --- a/deployments/mainnet.diamond.json +++ b/deployments/mainnet.diamond.json @@ -124,6 +124,10 @@ "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c": { "Name": "SquidFacet", "Version": "1.0.0" + }, + "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D": { + "Name": "MayanFacet", + "Version": "1.0.0" } }, "Periphery": { diff --git a/deployments/mainnet.json b/deployments/mainnet.json index 5327aef8b..386469ce9 100644 --- a/deployments/mainnet.json +++ b/deployments/mainnet.json @@ -50,5 +50,6 @@ "AmarokFacetPacked": "0xF18A285f4e6f720Eb9b4e05df71f88b9552E6ADB", "SymbiosisFacet": "0xe12b2488c71432F9a116E9ac244D3Ef4c2386d3a", "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d", - "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c" + "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c", + "MayanFacet": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D" } \ No newline at end of file diff --git a/deployments/polygon.diamond.json b/deployments/polygon.diamond.json index 3cb44227f..641723b7e 100644 --- a/deployments/polygon.diamond.json +++ b/deployments/polygon.diamond.json @@ -104,6 +104,10 @@ "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c": { "Name": "SquidFacet", "Version": "1.0.0" + }, + "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D": { + "Name": "MayanFacet", + "Version": "1.0.0" } }, "Periphery": { diff --git a/deployments/polygon.json b/deployments/polygon.json index 827f115ae..1939a89f2 100644 --- a/deployments/polygon.json +++ b/deployments/polygon.json @@ -45,5 +45,6 @@ "AmarokFacetPacked": "0xF18A285f4e6f720Eb9b4e05df71f88b9552E6ADB", "SymbiosisFacet": "0xe12b2488c71432F9a116E9ac244D3Ef4c2386d3a", "TokenWrapper": "0x5215E9fd223BC909083fbdB2860213873046e45d", - "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c" + "SquidFacet": "0x5C2C3F56e33F45389aa4e1DA4D3a807A532a910c", + "MayanFacet": "0x14B4e2e2e3422DeC6F8bF3DcDc0BF3566F37197D" } \ No newline at end of file diff --git a/docs/MayanFacet.md b/docs/MayanFacet.md new file mode 100644 index 000000000..63699662b --- /dev/null +++ b/docs/MayanFacet.md @@ -0,0 +1,115 @@ +# Mayan Facet + +## How it works + +The Mayan Facet works by forwarding Mayan specific calls to the Mayan Token Bridge [contract](https://docs.mayan.finance/integration/contracts). + +```mermaid +graph LR; + D{LiFiDiamond}-- DELEGATECALL -->MayanFacet; + MayanFacet -- CALL --> C(Mayan) +``` + +## Public Methods + +- `function startBridgeTokensViaMayan(BridgeData calldata _bridgeData, MayanData calldata _mayanData)` + - Simply bridges tokens using mayan +- `swapAndStartBridgeTokensViamayan(BridgeData memory _bridgeData, LibSwap.SwapData[] calldata _swapData, mayanData memory _mayanData)` + - Performs swap(s) before bridging tokens using mayan + +## mayan Specific Parameters + +The methods listed above take a variable labeled `_mayanData`. This data is specific to mayan and is represented as the following struct type: + +```solidity +/// @dev Optional bridge specific struct +/// @param mayanAddr The address of the Mayan +/// @param referrer The referrer address +/// @param tokenOutAddr The address of the token to be received +/// @param receiver The address of the receiver +/// @param swapFee The swap fee +/// @param redeemFee The redeem fee +/// @param refundFee The refund fee +/// @param transferDeadline The transfer deadline +/// @param swapDeadline The swap deadline +/// @param amountOutMin The minimum amount out +/// @param unwrap Whether to unwrap the asset +/// @param gasDrop The gas drop +struct MayanData { + bytes32 mayanAddr; + bytes32 referrer; + bytes32 tokenOutAddr; + bytes32 receiver; + uint64 swapFee; + uint64 redeemFee; + uint64 refundFee; + uint256 transferDeadline; + uint64 swapDeadline; + uint64 amountOutMin; + bool unwrap; + uint64 gasDrop; +} +``` + +## Swap Data + +Some methods accept a `SwapData _swapData` parameter. + +Swapping is performed by a swap specific library that expects an array of calldata to can be run on variaous DEXs (i.e. Uniswap) to make one or multiple swaps before performing another action. + +The swap library can be found [here](../src/Libraries/LibSwap.sol). + +## LiFi Data + +Some methods accept a `BridgeData _bridgeData` parameter. + +This parameter is strictly for analytics purposes. It's used to emit events that we can later track and index in our subgraphs and provide data on how our contracts are being used. `BridgeData` and the events we can emit can be found [here](../src/Interfaces/ILiFi.sol). + +## Getting Sample Calls to interact with the Facet + +In the following some sample calls are shown that allow you to retrieve a populated transaction that can be sent to our contract via your wallet. + +All examples use our [/quote endpoint](https://apidocs.li.fi/reference/get_quote) to retrieve a quote which contains a `transactionRequest`. This request can directly be sent to your wallet to trigger the transaction. + +The quote result looks like the following: + +```javascript +const quoteResult = { + id: '0x...', // quote id + type: 'lifi', // the type of the quote (all lifi contract calls have the type "lifi") + tool: 'mayan', // the bridge tool used for the transaction + action: {}, // information about what is going to happen + estimate: {}, // information about the estimated outcome of the call + includedSteps: [], // steps that are executed by the contract as part of this transaction, e.g. a swap step and a cross step + transactionRequest: { + // the transaction that can be sent using a wallet + data: '0x...', + to: '0x...', + value: '0x00', + from: '{YOUR_WALLET_ADDRESS}', + chainId: 100, + gasLimit: '0x...', + gasPrice: '0x...', + }, +} +``` + +A detailed explanation on how to use the /quote endpoint and how to trigger the transaction can be found [here](https://docs.li.fi/products/more-integration-options/li.fi-api/transferring-tokens-example). + +**Hint**: Don't forget to replace `{YOUR_WALLET_ADDRESS}` with your real wallet address in the examples. + +### Cross Only + +To get a transaction for a transfer from 30 USDC.e on Avalanche to USDC on Binance you can execute the following request: + +```shell +curl 'https://li.quest/v1/quote?fromChain=AVA&fromAmount=30000000&fromToken=USDC&toChain=BSC&toToken=USDC&slippage=0.03&allowBridges=mayan&fromAddress={YOUR_WALLET_ADDRESS}' +``` + +### Swap & Cross + +To get a transaction for a transfer from 30 USDT on Avalanche to USDC on Binance you can execute the following request: + +```shell +curl 'https://li.quest/v1/quote?fromChain=AVA&fromAmount=30000000&fromToken=USDT&toChain=BSC&toToken=USDC&slippage=0.03&allowBridges=mayan&fromAddress={YOUR_WALLET_ADDRESS}' +``` diff --git a/docs/README.md b/docs/README.md index e75118a46..55948f4ab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,6 +20,7 @@ - [Hyphen Facet](./HyphenFacet.md) - [LIFuel Facet](./LIFuelFacet.md) - [MakerTeleport Facet](./MakerTeleportFacet.md) +- [Mayan Facet](./MayanFacet.md) - [Multichain Facet](./MultichainFacet.md) - [OmniBridge Facet](./OmniBridgeFacet.md) - [Optimism Bridge Facet](./OptimismBridgeFacet.md) diff --git a/package.json b/package.json index a5afd8afa..96fddaad2 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "dependencies": { "@arbitrum/sdk": "^3.0.0", "@hop-protocol/sdk": "0.0.1-beta.310", + "@mayanfinance/swap-sdk": "^5.0.1", "@safe-global/api-kit": "^1.1.0", "@safe-global/protocol-kit": "^1.0.1", "@safe-global/safe-core-sdk-types": "^2.0.0", diff --git a/script/demoScripts/demoMayan.ts b/script/demoScripts/demoMayan.ts new file mode 100644 index 000000000..6dcc0ce25 --- /dev/null +++ b/script/demoScripts/demoMayan.ts @@ -0,0 +1,111 @@ +import deployments from '../../deployments/bsc.staging.json' +import { + fetchQuote, + getSwapFromEvmTxPayload, + Quote, +} from '@mayanfinance/swap-sdk' +import { BigNumber, constants } from 'ethers' +import { + MayanBridgeFacet__factory, + ILiFi, + type MayanBridgeFacet, + ERC20__factory, + IMayanBridge__factory, +} from '../../typechain' +import { ethers, utils } from 'ethers' +import dotenv from 'dotenv' +dotenv.config() + +const main = async () => { + const RPC_URL = process.env.ETH_NODE_URI_BSC + const PRIVATE_KEY = process.env.PRIVATE_KEY + const LIFI_ADDRESS = deployments.LiFiDiamond + const BSC_USDT_ADDRESS = '0x55d398326f99059fF775485246999027B3197955' + + const provider = new ethers.providers.JsonRpcProvider(RPC_URL) + const signer = new ethers.Wallet(PRIVATE_KEY as string, provider) + const mayan = MayanBridgeFacet__factory.connect(LIFI_ADDRESS, provider) + const deadline = Math.floor(Date.now() / 1000) + 60 * 10 // 10 minutes from the current Unix time + + const address = await signer.getAddress() + + let tx + + const quote: Quote = await fetchQuote({ + amount: 10, + fromToken: BSC_USDT_ADDRESS, + toToken: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', + fromChain: 'bsc', + toChain: 'polygon', + slippage: 3, + }) + + const payload = await getSwapFromEvmTxPayload( + quote, + address, + deadline, + null, + address, + 56, + provider + ) + + const iface = IMayanBridge__factory.createInterface() + const parsed = iface.parseTransaction({ data: payload.data as string }) + + const token = ERC20__factory.connect(BSC_USDT_ADDRESS, provider) + + const bridgeData: ILiFi.BridgeDataStruct = { + transactionId: utils.randomBytes(32), + bridge: 'Mayan', + integrator: 'ACME Devs', + referrer: '0x0000000000000000000000000000000000000000', + sendingAssetId: BSC_USDT_ADDRESS, + receiver: address, + minAmount: utils.parseEther('10'), + destinationChainId: 137, + hasSourceSwaps: false, + hasDestinationCall: false, + } + + const mayanData: MayanBridgeFacet.MayanBridgeDataStruct = { + mayanAddr: parsed.args.recipient.mayanAddr, + referrer: utils.hexZeroPad('0x', 32), + tokenOutAddr: parsed.args.tokenOutAddr, + receiver: parsed.args.recipient.destAddr, + swapFee: parsed.args.relayerFees.swapFee, + redeemFee: parsed.args.relayerFees.redeemFee, + refundFee: parsed.args.relayerFees.refundFee, + transferDeadline: parsed.args.criteria.transferDeadline, + swapDeadline: parsed.args.criteria.swapDeadline, + amountOutMin: parsed.args.criteria.amountOutMin, + unwrap: parsed.args.criteria.unwrap, + gasDrop: parsed.args.criteria.gasDrop, + } + + console.info('Dev Wallet Address: ', address) + console.info('Approving USDT...') + const gasPrice = await provider.getGasPrice() + tx = await token + .connect(signer) + .approve(LIFI_ADDRESS, constants.MaxUint256, { gasPrice }) + await tx.wait() + console.info('Approved USDT') + console.info('Bridging USDT...') + tx = await mayan + .connect(signer) + .startBridgeTokensViaMayanBridge(bridgeData, mayanData, { gasPrice }) + await tx.wait() + console.info('Bridged USDT') +} + +main() + .then(() => { + console.log('Success') + process.exit(0) + }) + .catch((error) => { + console.error('error') + console.error(error) + process.exit(1) + }) diff --git a/script/demoScripts/demoMayanSolana.ts b/script/demoScripts/demoMayanSolana.ts new file mode 100644 index 000000000..7afd5cd6e --- /dev/null +++ b/script/demoScripts/demoMayanSolana.ts @@ -0,0 +1,111 @@ +import deployments from '../../deployments/bsc.staging.json' +import { + fetchQuote, + getSwapFromEvmTxPayload, + Quote, +} from '@mayanfinance/swap-sdk' +import { BigNumber, constants } from 'ethers' +import { + MayanFacet__factory, + ILiFi, + type MayanFacet, + ERC20__factory, + IMayan__factory, +} from '../../typechain' +import { ethers, utils } from 'ethers' +import dotenv from 'dotenv' +dotenv.config() + +const main = async () => { + const RPC_URL = process.env.ETH_NODE_URI_BSC + const PRIVATE_KEY = process.env.PRIVATE_KEY + const LIFI_ADDRESS = deployments.LiFiDiamond + const BSC_USDT_ADDRESS = '0x55d398326f99059fF775485246999027B3197955' + + const provider = new ethers.providers.JsonRpcProvider(RPC_URL) + const signer = new ethers.Wallet(PRIVATE_KEY as string, provider) + const mayan = MayanFacet__factory.connect(LIFI_ADDRESS, provider) + const deadline = Math.floor(Date.now() / 1000) + 60 * 10 // 10 minutes from the current Unix time + + const address = await signer.getAddress() + + let tx + + const quote: Quote = await fetchQuote({ + amount: 10, + fromToken: BSC_USDT_ADDRESS, + toToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', + fromChain: 'bsc', + toChain: 'solana', + slippage: 3, + }) + + const payload = await getSwapFromEvmTxPayload( + quote, + '6AUWsSCRFSCbrHKH9s84wfzJXtD6mNzAHs11x6pGEcmJ', + deadline, + null, + address, + 56, + provider + ) + + const iface = IMayan__factory.createInterface() + const parsed = iface.parseTransaction({ data: payload.data as string }) + + const token = ERC20__factory.connect(BSC_USDT_ADDRESS, provider) + + const bridgeData: ILiFi.BridgeDataStruct = { + transactionId: utils.randomBytes(32), + bridge: 'Mayan', + integrator: 'ACME Devs', + referrer: '0x0000000000000000000000000000000000000000', + sendingAssetId: BSC_USDT_ADDRESS, + receiver: '0x11f111f111f111F111f111f111F111f111f111F1', + minAmount: utils.parseEther('10'), + destinationChainId: 1151111081099710, + hasSourceSwaps: false, + hasDestinationCall: false, + } + + const mayanData: MayanFacet.MayanDataStruct = { + mayanAddr: parsed.args.recipient.mayanAddr, + referrer: utils.hexZeroPad('0x', 32), + tokenOutAddr: parsed.args.tokenOutAddr, + receiver: parsed.args.recipient.destAddr, + swapFee: parsed.args.relayerFees.swapFee, + redeemFee: parsed.args.relayerFees.redeemFee, + refundFee: parsed.args.relayerFees.refundFee, + transferDeadline: parsed.args.criteria.transferDeadline, + swapDeadline: parsed.args.criteria.swapDeadline, + amountOutMin: parsed.args.criteria.amountOutMin, + unwrap: parsed.args.criteria.unwrap, + gasDrop: parsed.args.criteria.gasDrop, + } + + console.info('Dev Wallet Address: ', address) + console.info('Approving USDT...') + const gasPrice = await provider.getGasPrice() + tx = await token + .connect(signer) + .approve(LIFI_ADDRESS, constants.MaxUint256, { gasPrice }) + await tx.wait() + console.info('Approved USDT') + console.info('Bridging USDT...') + tx = await mayan + .connect(signer) + .startBridgeTokensViaMayan(bridgeData, mayanData, { gasPrice }) + await tx.wait() + console.info('Bridged USDT') +} + +main() + .then(() => { + console.log('Success') + process.exit(0) + }) + .catch((error) => { + console.error('error') + console.error(error) + process.exit(1) + }) diff --git a/script/deploy/facets/DeployMayanFacet.s.sol b/script/deploy/facets/DeployMayanFacet.s.sol new file mode 100644 index 000000000..3455d8045 --- /dev/null +++ b/script/deploy/facets/DeployMayanFacet.s.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.17; + +import { DeployScriptBase } from "./utils/DeployScriptBase.sol"; +import { stdJson } from "forge-std/Script.sol"; +import { MayanFacet } from "lifi/Facets/MayanFacet.sol"; + +contract DeployScript is DeployScriptBase { + using stdJson for string; + + constructor() DeployScriptBase("MayanFacet") {} + + function run() + public + returns (MayanFacet deployed, bytes memory constructorArgs) + { + constructorArgs = getConstructorArgs(); + + deployed = MayanFacet(deploy(type(MayanFacet).creationCode)); + } + + function getConstructorArgs() internal override returns (bytes memory) { + // If you don't have a constructor or it doesn't take any arguments, you can remove this function + string memory path = string.concat(root, "/config/mayan.json"); + string memory json = vm.readFile(path); + + address bridge = json.readAddress( + string.concat(".bridges.", network, ".bridge") + ); + + return abi.encode(bridge); + } +} diff --git a/script/deploy/facets/UpdateMayanFacet.s.sol b/script/deploy/facets/UpdateMayanFacet.s.sol new file mode 100644 index 000000000..81fdac18c --- /dev/null +++ b/script/deploy/facets/UpdateMayanFacet.s.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.17; + +import { UpdateScriptBase } from "./utils/UpdateScriptBase.sol"; +import { stdJson } from "forge-std/StdJson.sol"; +import { DiamondCutFacet, IDiamondCut } from "lifi/Facets/DiamondCutFacet.sol"; +import { MayanFacet } from "lifi/Facets/MayanFacet.sol"; + +contract DeployScript is UpdateScriptBase { + using stdJson for string; + + struct Config { + uint256 chainId; + uint16 wormholeChainId; + } + + function run() + public + returns (address[] memory facets, bytes memory cutData) + { + return update("MayanFacet"); + } + + function getExcludes() internal pure override returns (bytes4[] memory) { + bytes4[] memory excludes = new bytes4[](1); + excludes[0] = MayanFacet.initMayan.selector; + + return excludes; + } + + function getCallData() internal override returns (bytes memory) { + path = string.concat(root, "/config/mayan.json"); + json = vm.readFile(path); + bytes memory rawConfig = json.parseRaw(".chains"); + Config[] memory configs = abi.decode(rawConfig, (Config[])); + + bytes memory callData = abi.encodeWithSelector( + MayanFacet.initMayan.selector, + configs + ); + + return callData; + } +} diff --git a/src/Facets/MayanFacet.sol b/src/Facets/MayanFacet.sol new file mode 100644 index 000000000..87f5e6b24 --- /dev/null +++ b/src/Facets/MayanFacet.sol @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +import { ILiFi } from "../Interfaces/ILiFi.sol"; +import { LibDiamond } from "../Libraries/LibDiamond.sol"; +import { LibAsset, IERC20 } from "../Libraries/LibAsset.sol"; +import { LibSwap } from "../Libraries/LibSwap.sol"; +import { ReentrancyGuard } from "../Helpers/ReentrancyGuard.sol"; +import { SwapperV2 } from "../Helpers/SwapperV2.sol"; +import { Validatable } from "../Helpers/Validatable.sol"; +import { IMayan } from "../Interfaces/IMayan.sol"; +import { UnsupportedChainId } from "../Errors/GenericErrors.sol"; + +/// @title Mayan Facet +/// @author LI.FI (https://li.fi) +/// @notice Provides functionality for bridging through Mayan Bridge +/// @custom:version 1.0.0 +contract MayanFacet is ILiFi, ReentrancyGuard, SwapperV2, Validatable { + /// Storage /// + + bytes32 internal constant NAMESPACE = keccak256("com.lifi.facets.mayan"); + address internal constant NON_EVM_ADDRESS = + 0x11f111f111f111F111f111f111F111f111f111F1; + bytes32 internal constant MAYAN_AUCTION_ADDRESS = + 0x3383cb0c0c60fc12b717160b699a55db62c56baed78a0ff9ebed68e1b003d38c; + uint16 internal constant MAYAN_CHAIN_ID = 1; + + IMayan public immutable mayan; + + /// Types /// + + struct Storage { + mapping(uint256 => uint16) wormholeChainId; + } + + struct Config { + uint256 chainId; + uint16 wormholeChainId; + } + + /// @dev Optional bridge specific struct + /// @param mayanAddr The address of the Mayan Bridge + /// @param referrer The referrer address + /// @param tokenOutAddr The address of the token to be received + /// @param receiver The address of the receiver + /// @param swapFee The swap fee + /// @param redeemFee The redeem fee + /// @param refundFee The refund fee + /// @param transferDeadline The transfer deadline + /// @param swapDeadline The swap deadline + /// @param amountOutMin The minimum amount out + /// @param destChainId The (wormhole) destination chain id + /// @param unwrap Whether to unwrap the asset + /// @param gasDrop The gas drop + struct MayanData { + bytes32 mayanAddr; + bytes32 referrer; + bytes32 tokenOutAddr; + bytes32 receiver; + uint64 swapFee; + uint64 redeemFee; + uint64 refundFee; + uint256 transferDeadline; + uint64 swapDeadline; + uint64 amountOutMin; + bool unwrap; + uint64 gasDrop; + } + + /// Events /// + + event MayanInitialized(Config[] configs); + event MayanChainIdMapped( + uint256 indexed lifiChainId, + uint256 indexed wormholeChainId + ); + event BridgeToNonEVMChain( + bytes32 indexed transactionId, + uint256 indexed destinationChainId, + bytes32 receiver + ); + + /// Constructor /// + + /// @notice Constructor for the contract. + constructor(IMayan _mayan) { + mayan = _mayan; + } + + /// Init /// + + /// @notice Initialize local variables for the Wormhole Facet + /// @param configs Bridge configuration data + function initMayan(Config[] calldata configs) external { + LibDiamond.enforceIsContractOwner(); + + Storage storage sm = getStorage(); + + uint256 numConfigs = configs.length; + for (uint256 i = 0; i < numConfigs; i++) { + sm.wormholeChainId[configs[i].chainId] = configs[i] + .wormholeChainId; + } + + emit MayanInitialized(configs); + } + + /// External Methods /// + + /// @notice Creates a mapping between a lifi chain id and a wormhole chain id + /// @param _lifiChainId lifi chain id + /// @param _wormholeChainId wormhole chain id + function setMayanChainIdMapping( + uint256 _lifiChainId, + uint16 _wormholeChainId + ) external { + LibDiamond.enforceIsContractOwner(); + Storage storage sm = getStorage(); + sm.wormholeChainId[_lifiChainId] = _wormholeChainId; + emit MayanChainIdMapped(_lifiChainId, _wormholeChainId); + } + + /// @notice Bridges tokens via Mayan + /// @param _bridgeData The core information needed for bridging + /// @param _mayanData Data specific to Mayan + function startBridgeTokensViaMayan( + ILiFi.BridgeData memory _bridgeData, + MayanData calldata _mayanData + ) + external + payable + nonReentrant + refundExcessNative(payable(msg.sender)) + validateBridgeData(_bridgeData) + doesNotContainSourceSwaps(_bridgeData) + doesNotContainDestinationCalls(_bridgeData) + { + uint256 totalFees = _mayanData.swapFee + + _mayanData.redeemFee + + _mayanData.refundFee; + + LibAsset.depositAsset( + _bridgeData.sendingAssetId, + _bridgeData.minAmount + ); + _startBridge(_bridgeData, _mayanData, totalFees); + } + + /// @notice Performs a swap before bridging via Mayan + /// @param _bridgeData The core information needed for bridging + /// @param _swapData An array of swap related data for performing swaps before bridging + /// @param _mayanData Data specific to Mayan + function swapAndStartBridgeTokensViaMayan( + ILiFi.BridgeData memory _bridgeData, + LibSwap.SwapData[] calldata _swapData, + MayanData calldata _mayanData + ) + external + payable + nonReentrant + refundExcessNative(payable(msg.sender)) + containsSourceSwaps(_bridgeData) + doesNotContainDestinationCalls(_bridgeData) + validateBridgeData(_bridgeData) + { + uint256 totalFees = _mayanData.swapFee + + _mayanData.redeemFee + + _mayanData.refundFee; + address assetId = _bridgeData.sendingAssetId; + _bridgeData.minAmount = _depositAndSwap( + _bridgeData.transactionId, + _bridgeData.minAmount, + _swapData, + payable(msg.sender), + LibAsset.isNativeAsset(assetId) ? 0 : totalFees + ); + _startBridge(_bridgeData, _mayanData, totalFees); + } + + /// Internal Methods /// + + /// @dev Contains the business logic for the bridge via Mayan + /// @param _bridgeData The core information needed for bridging + /// @param _mayanData Data specific to Mayan + function _startBridge( + ILiFi.BridgeData memory _bridgeData, + MayanData calldata _mayanData, + uint256 _totalFees + ) internal { + uint16 whDestChainId = getWormholeChainId( + _bridgeData.destinationChainId + ); + + IMayan.RelayerFees memory relayerFees = IMayan.RelayerFees({ + swapFee: _mayanData.swapFee, + redeemFee: _mayanData.redeemFee, + refundFee: _mayanData.refundFee + }); + + IMayan.Recepient memory recipient = IMayan.Recepient({ + mayanAddr: _mayanData.mayanAddr, + mayanChainId: MAYAN_CHAIN_ID, + auctionAddr: MAYAN_AUCTION_ADDRESS, + destAddr: _mayanData.receiver, + destChainId: whDestChainId, + referrer: _mayanData.referrer, + refundAddr: _mayanData.receiver + }); + + IMayan.Criteria memory criteria = IMayan.Criteria({ + transferDeadline: _mayanData.transferDeadline, + swapDeadline: _mayanData.swapDeadline, + amountOutMin: _mayanData.amountOutMin, + unwrap: _mayanData.unwrap, + gasDrop: _mayanData.gasDrop, + customPayload: "" + }); + + if (!LibAsset.isNativeAsset(_bridgeData.sendingAssetId)) { + LibAsset.maxApproveERC20( + IERC20(_bridgeData.sendingAssetId), + address(mayan), + _bridgeData.minAmount + ); + + mayan.swap( + relayerFees, + recipient, + _mayanData.tokenOutAddr, + whDestChainId, + criteria, + _bridgeData.sendingAssetId, + _bridgeData.minAmount - _totalFees + ); + } else { + mayan.wrapAndSwapETH{ value: _bridgeData.minAmount }( + relayerFees, + recipient, + _mayanData.tokenOutAddr, + whDestChainId, + criteria + ); + } + + if (_bridgeData.receiver == NON_EVM_ADDRESS) { + emit BridgeToNonEVMChain( + _bridgeData.transactionId, + _bridgeData.destinationChainId, + _mayanData.receiver + ); + } + + emit LiFiTransferStarted(_bridgeData); + } + + /// @notice Gets the wormhole chain id for a given lifi chain id + /// @param _lifiChainId uint256 of the lifi chain ID + /// @return uint16 of the wormhole chain id + function getWormholeChainId( + uint256 _lifiChainId + ) private view returns (uint16) { + Storage storage sm = getStorage(); + uint16 wormholeChainId = sm.wormholeChainId[_lifiChainId]; + if (wormholeChainId == 0) revert UnsupportedChainId(_lifiChainId); + return wormholeChainId; + } + + /// @dev fetch local storage + function getStorage() private pure returns (Storage storage s) { + bytes32 namespace = NAMESPACE; + // solhint-disable-next-line no-inline-assembly + assembly { + s.slot := namespace + } + } +} diff --git a/src/Interfaces/IMayan.sol b/src/Interfaces/IMayan.sol new file mode 100644 index 000000000..6a17fa8e8 --- /dev/null +++ b/src/Interfaces/IMayan.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.17; + +interface IMayan { + struct RelayerFees { + uint64 swapFee; + uint64 redeemFee; + uint64 refundFee; + } + + struct Recepient { + bytes32 mayanAddr; + uint16 mayanChainId; + bytes32 auctionAddr; + bytes32 destAddr; + uint16 destChainId; + bytes32 referrer; + bytes32 refundAddr; + } + + struct Criteria { + uint256 transferDeadline; + uint64 swapDeadline; + uint64 amountOutMin; + bool unwrap; + uint64 gasDrop; + bytes customPayload; + } + + function swap( + RelayerFees memory relayerFees, + Recepient memory recipient, + bytes32 tokenOutAddr, + uint16 tokenOutChainId, + Criteria memory criteria, + address tokenIn, + uint256 amountIn + ) external payable returns (uint64 sequence); + + function wrapAndSwapETH( + RelayerFees memory relayerFees, + Recepient memory recipient, + bytes32 tokenOutAddr, + uint16 tokenOutChainId, + Criteria memory criteria + ) external payable returns (uint64 sequence); +} diff --git a/test/solidity/Facets/MayanFacet.t.sol b/test/solidity/Facets/MayanFacet.t.sol new file mode 100644 index 000000000..0b74cf2ed --- /dev/null +++ b/test/solidity/Facets/MayanFacet.t.sol @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity 0.8.17; + +import { LibAllowList, TestBaseFacet, console, ERC20, LibSwap } from "../utils/TestBaseFacet.sol"; +import { MayanFacet } from "lifi/Facets/MayanFacet.sol"; +import { IMayan } from "lifi/Interfaces/IMayan.sol"; + +// Stub MayanFacet Contract +contract TestMayanFacet is MayanFacet { + constructor(IMayan _bridge) MayanFacet(_bridge) {} + + function addDex(address _dex) external { + LibAllowList.addAllowedContract(_dex); + } + + function setFunctionApprovalBySignature(bytes4 _signature) external { + LibAllowList.addAllowedSelector(_signature); + } +} + +contract MayanFacetTest is TestBaseFacet { + MayanFacet.MayanData internal validMayanData; + TestMayanFacet internal mayanBridgeFacet; + IMayan internal MAYAN_BRIDGE = + IMayan(0xF3f04555f8FdA510bfC77820FD6eB8446f59E72d); + address internal POLYGON_USDT = 0xc2132D05D31c914a87C6611C10748AEb04B58e8F; + uint256 internal totalFees; + + function setUp() public { + customBlockNumberForForking = 19367700; + initTestBase(); + + address[] memory EXAMPLE_ALLOWED_TOKENS = new address[](2); + EXAMPLE_ALLOWED_TOKENS[0] = address(1); + EXAMPLE_ALLOWED_TOKENS[1] = address(2); + + mayanBridgeFacet = new TestMayanFacet(MAYAN_BRIDGE); + bytes4[] memory functionSelectors = new bytes4[](5); + functionSelectors[0] = mayanBridgeFacet + .startBridgeTokensViaMayan + .selector; + functionSelectors[1] = mayanBridgeFacet + .swapAndStartBridgeTokensViaMayan + .selector; + functionSelectors[2] = mayanBridgeFacet.addDex.selector; + functionSelectors[3] = mayanBridgeFacet + .setFunctionApprovalBySignature + .selector; + functionSelectors[4] = mayanBridgeFacet + .setMayanChainIdMapping + .selector; + + addFacet(diamond, address(mayanBridgeFacet), functionSelectors); + mayanBridgeFacet = TestMayanFacet(address(diamond)); + mayanBridgeFacet.addDex(ADDRESS_UNISWAP); + mayanBridgeFacet.setFunctionApprovalBySignature( + uniswap.swapExactTokensForTokens.selector + ); + mayanBridgeFacet.setFunctionApprovalBySignature( + uniswap.swapTokensForExactETH.selector + ); + mayanBridgeFacet.setFunctionApprovalBySignature( + uniswap.swapETHForExactTokens.selector + ); + + mayanBridgeFacet.setMayanChainIdMapping(137, 5); + + setFacetAddressInTestBase(address(mayanBridgeFacet), "MayanFacet"); + + // adjust bridgeData + bridgeData.bridge = "mayanBridge"; + bridgeData.destinationChainId = 137; + + // produce valid MayanData + validMayanData = MayanFacet.MayanData({ + mayanAddr: 0x32f0af4069bde51a996d1250ef3f7c2431245b98e027b34aa5ca5ae435c435c9, + referrer: bytes32(0), + tokenOutAddr: bytes32(uint256(uint160(POLYGON_USDT))), + receiver: bytes32(uint256(uint160(USER_SENDER))), + swapFee: 100000, + redeemFee: 1000000, + refundFee: 1000000, + transferDeadline: block.timestamp + 1000, + swapDeadline: uint64(block.timestamp + 1000), + amountOutMin: uint64((bridgeData.minAmount * 99) / 100), + unwrap: false, + gasDrop: 0 + }); + + totalFees = + validMayanData.redeemFee + + validMayanData.refundFee + + validMayanData.swapFee; + } + + function initiateBridgeTxWithFacet(bool isNative) internal override { + if (isNative) { + mayanBridgeFacet.startBridgeTokensViaMayan{ + value: bridgeData.minAmount + totalFees + }(bridgeData, validMayanData); + } else { + mayanBridgeFacet.startBridgeTokensViaMayan( + bridgeData, + validMayanData + ); + } + } + + function initiateSwapAndBridgeTxWithFacet( + bool isNative + ) internal override { + if (isNative) { + mayanBridgeFacet.swapAndStartBridgeTokensViaMayan{ + value: swapData[0].fromAmount + }(bridgeData, swapData, validMayanData); + } else { + mayanBridgeFacet.swapAndStartBridgeTokensViaMayan( + bridgeData, + swapData, + validMayanData + ); + } + } + + function test_CanSwapAndBridgeTokensFromNative() + public + assertBalanceChange(ADDRESS_DAI, USER_RECEIVER, 0) + assertBalanceChange(ADDRESS_USDC, USER_RECEIVER, 0) + { + vm.startPrank(USER_SENDER); + // store initial balances + uint256 initialETHBalance = USER_SENDER.balance; + + // prepare bridgeData + bridgeData.hasSourceSwaps = true; + bridgeData.sendingAssetId = ADDRESS_USDC; + + // prepare swap data + address[] memory path = new address[](2); + + path[0] = ADDRESS_WETH; + path[1] = ADDRESS_USDC; + + uint256 amountOut = defaultUSDCAmount; + + // Calculate USDC input amount + uint256[] memory amounts = uniswap.getAmountsIn(amountOut, path); + uint256 amountIn = amounts[0]; + + bridgeData.minAmount = amountOut; + + delete swapData; + swapData.push( + LibSwap.SwapData({ + callTo: address(uniswap), + approveTo: address(uniswap), + sendingAssetId: address(0), + receivingAssetId: ADDRESS_USDC, + fromAmount: amountIn, + callData: abi.encodeWithSelector( + uniswap.swapETHForExactTokens.selector, + amountOut, + path, + _facetTestContractAddress, + block.timestamp + 20 minutes + ), + requiresDeposit: true + }) + ); + + //prepare check for events + vm.expectEmit(true, true, true, true, _facetTestContractAddress); + emit AssetSwapped( + bridgeData.transactionId, + ADDRESS_UNISWAP, + address(0), + ADDRESS_USDC, + swapData[0].fromAmount, + bridgeData.minAmount, + block.timestamp + ); + + //@dev the bridged amount will be higher than bridgeData.minAmount since the code will + // deposit all remaining ETH to the bridge. We cannot access that value (minAmount + remaining gas) + // therefore the test is designed to only check if an event was emitted but not match the parameters + vm.expectEmit(false, false, false, false, _facetTestContractAddress); + emit LiFiTransferStarted(bridgeData); + + // execute call in child contract + initiateSwapAndBridgeTxWithFacet(true); + + // check balances after call + assertEq( + USER_SENDER.balance, + initialETHBalance - swapData[0].fromAmount + ); + } + + function testBase_CanBridgeTokens_fuzzed(uint256 amount) public override { + amount = bound(amount, 150, 100_000); + super.testBase_CanBridgeTokens_fuzzed(amount); + } +} diff --git a/yarn.lock b/yarn.lock index 3f87d62c0..57ebb2e8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + "@arbitrum/sdk@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-3.0.0.tgz#a5dc48a00cb8c6e230a2c696c0e880a7f80c637d" @@ -33,6 +38,13 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e" + integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw== + dependencies: + regenerator-runtime "^0.14.0" + "@balena/dockerignore@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" @@ -683,6 +695,17 @@ chalk "4.1.2" dockerode "^3.3.4" +"@mayanfinance/swap-sdk@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@mayanfinance/swap-sdk/-/swap-sdk-5.0.1.tgz#d1edffed91a65b4064a72d3ad540e1f4fa5dec2a" + integrity sha512-RYI5k9f1x78sRBSgOIZ3/F8pnlsY6oOpq+LgM68nmi4KnHiSJhEGXYTWxS6smZEWlwm3XAz/DOJszBOnaIXyfQ== + dependencies: + "@solana/buffer-layout" "^4 || ^3" + "@solana/web3.js" "^1.87.6" + cross-fetch "^3.1.5" + ethers "^6" + js-sha3 "^0.8.0" + "@metamask/eth-sig-util@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" @@ -694,6 +717,13 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/curves@1.3.0", "@noble/curves@~1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" @@ -701,16 +731,33 @@ dependencies: "@noble/hashes" "1.3.3" +"@noble/curves@^1.2.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== + dependencies: + "@noble/hashes" "1.4.0" + "@noble/hashes@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@noble/hashes@1.3.3", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== +"@noble/hashes@1.4.0", "@noble/hashes@^1.3.3": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@noble/hashes@~1.1.1": version "1.1.5" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.5.tgz#1a0377f3b9020efe2fae03290bd2a12140c95c11" @@ -1201,6 +1248,34 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== +"@solana/buffer-layout@^4 || ^3", "@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== + dependencies: + buffer "~6.0.3" + +"@solana/web3.js@^1.87.6": + version "1.90.1" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.90.1.tgz#1cebb50dd770a8bbec9b4d9b55515b51b2bef694" + integrity sha512-BaopDf3TN54N9/T1iILu+Fz2gthIZzi+6X2A7bb0FWvGlwI/78iKRb2WjSnCfrHmMbWVLJR5n/pmXteezMXgVw== + dependencies: + "@babel/runtime" "^7.23.4" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.3" + "@solana/buffer-layout" "^4.0.1" + agentkeepalive "^4.5.0" + bigint-buffer "^1.1.5" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.0" + node-fetch "^2.7.0" + rpc-websockets "^7.5.1" + superstruct "^0.14.2" + "@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.1", "@solidity-parser/parser@^0.14.5": version "0.14.5" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" @@ -1312,6 +1387,13 @@ "@types/node" "*" "@types/responselike" "^1.0.0" +"@types/connect@^3.4.33": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + "@types/fined@*": version "1.1.3" resolved "https://registry.yarnpkg.com/@types/fined/-/fined-1.1.3.tgz#83f03e8f0a8d3673dfcafb18fce3571f6250e1bc" @@ -1402,7 +1484,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.17.tgz#5c009e1d9c38f4a2a9d45c0b0c493fe6cdb4bcb5" integrity sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng== -"@types/node@^12.12.6": +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + +"@types/node@^12.12.54", "@types/node@^12.12.6": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== @@ -1477,6 +1564,13 @@ dependencies: "@types/node" "*" +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + "@typescript-eslint/eslint-plugin@^5.16.0": version "5.47.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz#dadb79df3b0499699b155839fd6792f16897d910" @@ -1617,6 +1711,14 @@ JSONStream@1.3.2: jsonparse "^1.2.0" through ">=2.2.7 <3" +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1709,6 +1811,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1716,6 +1823,13 @@ agent-base@6: dependencies: debug "4" +agentkeepalive@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -2075,6 +2189,13 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + bigint-crypto-utils@^3.0.23: version "3.1.8" resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.1.8.tgz#e2e0f40cf45488f9d7f0e32ff84152aa73819d5d" @@ -2102,6 +2223,13 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bl@^1.0.0: version "1.2.3" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" @@ -2176,6 +2304,15 @@ body-parser@1.20.1, body-parser@^1.16.0: type-is "~1.6.18" unpipe "1.0.0" +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== + dependencies: + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2272,7 +2409,7 @@ browserify-sign@^4.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" -bs58@^4.0.0: +bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== @@ -2340,6 +2477,14 @@ buffer@4.9.2: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + buffer@^5.0.5, buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -2348,14 +2493,6 @@ buffer@^5.0.5, buffer@^5.5.0, buffer@^5.6.0: base64-js "^1.3.1" ieee754 "^1.1.13" -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - bufferutil@^4.0.1: version "4.0.7" resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" @@ -2784,6 +2921,11 @@ commander@^10.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -2950,6 +3092,13 @@ cross-fetch@^3.1.4: dependencies: node-fetch "2.6.7" +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -3157,6 +3306,11 @@ del@^6.0.0: rimraf "^3.0.2" slash "^3.0.0" +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -3483,11 +3637,18 @@ es6-iterator@^2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" -es6-promise@^4.2.8: +es6-promise@^4.0.3, es6-promise@^4.2.8: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + es6-symbol@^3.1.1, es6-symbol@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" @@ -3996,6 +4157,19 @@ ethers@^4.0.32: uuid "2.0.1" xmlhttprequest "1.8.0" +ethers@^6: + version "6.11.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.11.1.tgz#96aae00b627c2e35f9b0a4d65c7ab658259ee6af" + integrity sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -4130,6 +4304,11 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + fast-base64-decode@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" @@ -4176,6 +4355,11 @@ fast-redact@^3.0.0, fast-redact@^3.1.1: resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.2.tgz#d58e69e9084ce9fa4c1a6fa98a3e1ecf5d7839aa" integrity sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw== +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + fast-text-encoding@^1.0.0, fast-text-encoding@^1.0.3: version "1.0.6" resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867" @@ -4216,6 +4400,11 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -5152,6 +5341,13 @@ human-signals@^4.3.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + husky@^8.0.1: version "8.0.2" resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.2.tgz#5816a60db02650f1f22c8b69b928fd6bcd77a236" @@ -5645,11 +5841,34 @@ isomorphic-unfetch@^3.0.0: node-fetch "^2.6.1" unfetch "^4.2.0" +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== +jayson@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9" + integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + JSONStream "^1.3.5" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + uuid "^8.3.2" + ws "^7.4.5" + js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -5742,7 +5961,7 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== @@ -6448,7 +6667,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -6589,6 +6808,13 @@ node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.12, node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^2.6.6: version "2.6.11" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" @@ -7567,6 +7793,11 @@ reduce-flatten@^2.0.0: resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" @@ -7772,6 +8003,19 @@ rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4: dependencies: bn.js "^5.2.0" +rpc-websockets@^7.5.1: + version "7.9.0" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.9.0.tgz#a3938e16d6f134a3999fdfac422a503731bf8973" + integrity sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw== + dependencies: + "@babel/runtime" "^7.17.2" + eventemitter3 "^4.0.7" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -8458,6 +8702,11 @@ stubs@^3.0.0: resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" integrity sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw== +superstruct@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" + integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== + supports-color@8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" @@ -8596,6 +8845,11 @@ tar@^4.0.2: safe-buffer "^5.2.1" yallist "^3.1.1" +text-encoding-utf-8@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" + integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -8758,6 +9012,11 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -9907,6 +10166,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -9916,11 +10180,16 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" -ws@^7.4.6: +ws@^7.4.5, ws@^7.4.6: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +ws@^8.5.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== + xhr-request-promise@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c"