From 45cfdf4f9cc19aa1ec32359576fbe760dc4a40ab Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 16 Dec 2024 11:26:14 +0300 Subject: [PATCH] Merge Swap and SwapToAnyToken into a single example (#223) --- examples/swap/contracts/Swap.sol | 187 ++++++++++---- examples/swap/contracts/SwapCompanion.sol | 55 +++++ examples/swap/contracts/SwapToAnyToken.sol | 231 ------------------ examples/swap/hardhat.config.ts | 18 +- examples/swap/package.json | 1 + examples/swap/scripts/localnet.sh | 36 +-- examples/swap/tasks/companionSwap.ts | 61 +++++ examples/swap/tasks/deploy.ts | 34 +-- examples/swap/tasks/deployCompanion.ts | 43 ++++ .../swap/tasks/{swapFromEVM.ts => evmSwap.ts} | 2 +- ...{swapFromZetaChain.ts => zetachainSwap.ts} | 4 +- examples/swap/yarn.lock | 228 ++++++++++++++++- 12 files changed, 558 insertions(+), 342 deletions(-) create mode 100644 examples/swap/contracts/SwapCompanion.sol delete mode 100644 examples/swap/contracts/SwapToAnyToken.sol create mode 100644 examples/swap/tasks/companionSwap.ts create mode 100644 examples/swap/tasks/deployCompanion.ts rename examples/swap/tasks/{swapFromEVM.ts => evmSwap.ts} (97%) rename examples/swap/tasks/{swapFromZetaChain.ts => zetachainSwap.ts} (90%) diff --git a/examples/swap/contracts/Swap.sol b/examples/swap/contracts/Swap.sol index 1c112c63..0b094fcb 100644 --- a/examples/swap/contracts/Swap.sol +++ b/examples/swap/contracts/Swap.sol @@ -9,30 +9,59 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {RevertContext, RevertOptions} from "@zetachain/protocol-contracts/contracts/Revert.sol"; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol"; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol"; +import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IWZETA.sol"; import {GatewayZEVM} from "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol"; -contract Swap is UniversalContract { - address public immutable uniswapRouter; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract Swap is + UniversalContract, + Initializable, + UUPSUpgradeable, + OwnableUpgradeable +{ + address public uniswapRouter; GatewayZEVM public gateway; - uint256 constant BITCOIN = 18332; - uint256 public immutable gasLimit; + uint256 constant BITCOIN = 8332; + uint256 constant BITCOIN_TESTNET = 18332; + uint256 public gasLimit; error InvalidAddress(); error Unauthorized(); error ApprovalFailed(); + error TransferFailed(); + + event TokenSwap( + address sender, + bytes indexed recipient, + address indexed inputToken, + address indexed targetToken, + uint256 inputAmount, + uint256 outputAmount + ); modifier onlyGateway() { if (msg.sender != address(gateway)) revert Unauthorized(); _; } - constructor( + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( address payable gatewayAddress, address uniswapRouterAddress, - uint256 gasLimitAmount - ) { + uint256 gasLimitAmount, + address owner + ) public initializer { if (gatewayAddress == address(0) || uniswapRouterAddress == address(0)) revert InvalidAddress(); + __UUPSUpgradeable_init(); + __Ownable_init(owner); uniswapRouter = uniswapRouterAddress; gateway = GatewayZEVM(gatewayAddress); gasLimit = gasLimitAmount; @@ -41,6 +70,7 @@ contract Swap is UniversalContract { struct Params { address target; bytes to; + bool withdraw; } function onCall( @@ -49,19 +79,29 @@ contract Swap is UniversalContract { uint256 amount, bytes calldata message ) external onlyGateway { - Params memory params = Params({target: address(0), to: bytes("")}); - if (context.chainID == BITCOIN) { + Params memory params = Params({ + target: address(0), + to: bytes(""), + withdraw: true + }); + + if (context.chainID == BITCOIN_TESTNET || context.chainID == BITCOIN) { params.target = BytesHelperLib.bytesToAddress(message, 0); params.to = abi.encodePacked( BytesHelperLib.bytesToAddress(message, 20) ); + if (message.length >= 41) { + params.withdraw = BytesHelperLib.bytesToBool(message, 40); + } } else { - (address targetToken, bytes memory recipient) = abi.decode( - message, - (address, bytes) - ); + ( + address targetToken, + bytes memory recipient, + bool withdrawFlag + ) = abi.decode(message, (address, bytes, bool)); params.target = targetToken; params.to = recipient; + params.withdraw = withdrawFlag; } (uint256 out, address gasZRC20, uint256 gasFee) = handleGasAndSwap( @@ -69,9 +109,60 @@ contract Swap is UniversalContract { amount, params.target ); + emit TokenSwap( + context.sender, + params.to, + zrc20, + params.target, + amount, + out + ); withdraw(params, context.sender, gasFee, gasZRC20, out, zrc20); } + function swap( + address inputToken, + uint256 amount, + address targetToken, + bytes memory recipient, + bool withdrawFlag + ) public { + bool success = IZRC20(inputToken).transferFrom( + msg.sender, + address(this), + amount + ); + if (!success) { + revert TransferFailed(); + } + + (uint256 out, address gasZRC20, uint256 gasFee) = handleGasAndSwap( + inputToken, + amount, + targetToken + ); + emit TokenSwap( + msg.sender, + recipient, + inputToken, + targetToken, + amount, + out + ); + withdraw( + Params({ + target: targetToken, + to: recipient, + withdraw: withdrawFlag + }), + msg.sender, + gasFee, + gasZRC20, + out, + inputToken + ); + } + function handleGasAndSwap( address inputToken, uint256 amount, @@ -97,14 +188,14 @@ contract Swap is UniversalContract { swapAmount = amount - inputForGas; } - uint256 outputAmount = SwapHelperLib.swapExactTokensForTokens( + uint256 out = SwapHelperLib.swapExactTokensForTokens( uniswapRouter, inputToken, swapAmount, targetToken, 0 ); - return (outputAmount, gasZRC20, gasFee); + return (out, gasZRC20, gasFee); } function withdraw( @@ -112,40 +203,43 @@ contract Swap is UniversalContract { address sender, uint256 gasFee, address gasZRC20, - uint256 outputAmount, + uint256 out, address inputToken ) public { - if (gasZRC20 == params.target) { - if ( - !IZRC20(gasZRC20).approve( - address(gateway), - outputAmount + gasFee - ) - ) { - revert ApprovalFailed(); + if (params.withdraw) { + if (gasZRC20 == params.target) { + if (!IZRC20(gasZRC20).approve(address(gateway), out + gasFee)) { + revert ApprovalFailed(); + } + } else { + if (!IZRC20(gasZRC20).approve(address(gateway), gasFee)) { + revert ApprovalFailed(); + } + if (!IZRC20(params.target).approve(address(gateway), out)) { + revert ApprovalFailed(); + } } + gateway.withdraw( + abi.encodePacked(params.to), + out, + params.target, + RevertOptions({ + revertAddress: address(this), + callOnRevert: true, + abortAddress: address(0), + revertMessage: abi.encode(sender, inputToken), + onRevertGasLimit: gasLimit + }) + ); } else { - if (!IZRC20(gasZRC20).approve(address(gateway), gasFee)) { - revert ApprovalFailed(); - } - if ( - !IZRC20(params.target).approve(address(gateway), outputAmount) - ) { - revert ApprovalFailed(); + bool success = IWETH9(params.target).transfer( + address(uint160(bytes20(params.to))), + out + ); + if (!success) { + revert TransferFailed(); } } - gateway.withdraw( - params.to, - outputAmount, - params.target, - RevertOptions({ - revertAddress: address(this), - callOnRevert: true, - abortAddress: address(0), - revertMessage: abi.encode(sender, inputToken), - onRevertGasLimit: gasLimit - }) - ); } function onRevert(RevertContext calldata context) external onlyGateway { @@ -158,6 +252,7 @@ contract Swap is UniversalContract { context.amount, zrc20 ); + gateway.withdraw( abi.encodePacked(sender), out, @@ -172,7 +267,7 @@ contract Swap is UniversalContract { ); } - fallback() external payable {} - - receive() external payable {} + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} } diff --git a/examples/swap/contracts/SwapCompanion.sol b/examples/swap/contracts/SwapCompanion.sol new file mode 100644 index 00000000..b5b84ac6 --- /dev/null +++ b/examples/swap/contracts/SwapCompanion.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +contract SwapCompanion { + using SafeERC20 for IERC20; + + error ApprovalFailed(); + + GatewayEVM public immutable gateway; + + constructor(address payable gatewayAddress) { + gateway = GatewayEVM(gatewayAddress); + } + + function swapNativeGas( + address universalSwapContract, + address targetToken, + bytes memory recipient, + bool withdraw + ) public payable { + gateway.depositAndCall{value: msg.value}( + universalSwapContract, + abi.encode(targetToken, recipient, withdraw), + RevertOptions(msg.sender, false, address(0), "", 0) + ); + } + + function swapERC20( + address universalSwapContract, + address targetToken, + bytes memory recipient, + uint256 amount, + address asset, + bool withdraw + ) public { + IERC20(asset).safeTransferFrom(msg.sender, address(this), amount); + if (!IERC20(asset).approve(address(gateway), amount)) { + revert ApprovalFailed(); + } + gateway.depositAndCall( + universalSwapContract, + amount, + asset, + abi.encode(targetToken, recipient, withdraw), + RevertOptions(msg.sender, false, address(0), "", 0) + ); + } + + receive() external payable {} + + fallback() external payable {} +} diff --git a/examples/swap/contracts/SwapToAnyToken.sol b/examples/swap/contracts/SwapToAnyToken.sol deleted file mode 100644 index 4c25b08d..00000000 --- a/examples/swap/contracts/SwapToAnyToken.sol +++ /dev/null @@ -1,231 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import {SystemContract, IZRC20} from "@zetachain/toolkit/contracts/SystemContract.sol"; -import {SwapHelperLib} from "@zetachain/toolkit/contracts/SwapHelperLib.sol"; -import {BytesHelperLib} from "@zetachain/toolkit/contracts/BytesHelperLib.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import {RevertContext, RevertOptions} from "@zetachain/protocol-contracts/contracts/Revert.sol"; -import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol"; -import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol"; -import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IWZETA.sol"; -import {GatewayZEVM} from "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol"; - -contract SwapToAnyToken is UniversalContract { - address public immutable uniswapRouter; - GatewayZEVM public gateway; - uint256 constant BITCOIN = 18332; - uint256 public immutable gasLimit; - - error InvalidAddress(); - error Unauthorized(); - error ApprovalFailed(); - error TransferFailed(); - - modifier onlyGateway() { - if (msg.sender != address(gateway)) revert Unauthorized(); - _; - } - - constructor( - address payable gatewayAddress, - address uniswapRouterAddress, - uint256 gasLimitAmount - ) { - if (gatewayAddress == address(0) || uniswapRouterAddress == address(0)) - revert InvalidAddress(); - uniswapRouter = uniswapRouterAddress; - gateway = GatewayZEVM(gatewayAddress); - gasLimit = gasLimitAmount; - } - - struct Params { - address target; - bytes to; - bool withdraw; - } - - function onCall( - MessageContext calldata context, - address zrc20, - uint256 amount, - bytes calldata message - ) external onlyGateway { - Params memory params = Params({ - target: address(0), - to: bytes(""), - withdraw: true - }); - - if (context.chainID == BITCOIN) { - params.target = BytesHelperLib.bytesToAddress(message, 0); - params.to = abi.encodePacked( - BytesHelperLib.bytesToAddress(message, 20) - ); - if (message.length >= 41) { - params.withdraw = BytesHelperLib.bytesToBool(message, 40); - } - } else { - ( - address targetToken, - bytes memory recipient, - bool withdrawFlag - ) = abi.decode(message, (address, bytes, bool)); - params.target = targetToken; - params.to = recipient; - params.withdraw = withdrawFlag; - } - - (uint256 out, address gasZRC20, uint256 gasFee) = handleGasAndSwap( - zrc20, - amount, - params.target - ); - withdraw(params, context.sender, gasFee, gasZRC20, out, zrc20); - } - - function swap( - address inputToken, - uint256 amount, - address targetToken, - bytes memory recipient, - bool withdrawFlag - ) public { - bool success = IZRC20(inputToken).transferFrom( - msg.sender, - address(this), - amount - ); - if (!success) { - revert TransferFailed(); - } - - (uint256 out, address gasZRC20, uint256 gasFee) = handleGasAndSwap( - inputToken, - amount, - targetToken - ); - - withdraw( - Params({ - target: targetToken, - to: recipient, - withdraw: withdrawFlag - }), - msg.sender, - gasFee, - gasZRC20, - out, - inputToken - ); - } - - function handleGasAndSwap( - address inputToken, - uint256 amount, - address targetToken - ) internal returns (uint256, address, uint256) { - uint256 inputForGas; - address gasZRC20; - uint256 gasFee; - uint256 swapAmount; - - (gasZRC20, gasFee) = IZRC20(targetToken).withdrawGasFee(); - - if (gasZRC20 == inputToken) { - swapAmount = amount - gasFee; - } else { - inputForGas = SwapHelperLib.swapTokensForExactTokens( - uniswapRouter, - inputToken, - gasFee, - gasZRC20, - amount - ); - swapAmount = amount - inputForGas; - } - - uint256 out = SwapHelperLib.swapExactTokensForTokens( - uniswapRouter, - inputToken, - swapAmount, - targetToken, - 0 - ); - return (out, gasZRC20, gasFee); - } - - function withdraw( - Params memory params, - address sender, - uint256 gasFee, - address gasZRC20, - uint256 out, - address inputToken - ) public { - if (params.withdraw) { - if (gasZRC20 == params.target) { - if (!IZRC20(gasZRC20).approve(address(gateway), out + gasFee)) { - revert ApprovalFailed(); - } - } else { - if (!IZRC20(gasZRC20).approve(address(gateway), gasFee)) { - revert ApprovalFailed(); - } - if (!IZRC20(params.target).approve(address(gateway), out)) { - revert ApprovalFailed(); - } - } - gateway.withdraw( - abi.encodePacked(params.to), - out, - params.target, - RevertOptions({ - revertAddress: address(this), - callOnRevert: true, - abortAddress: address(0), - revertMessage: abi.encode(sender, inputToken), - onRevertGasLimit: gasLimit - }) - ); - } else { - bool success = IWETH9(params.target).transfer( - address(uint160(bytes20(params.to))), - out - ); - if (!success) { - revert TransferFailed(); - } - } - } - - function onRevert(RevertContext calldata context) external onlyGateway { - (address sender, address zrc20) = abi.decode( - context.revertMessage, - (address, address) - ); - (uint256 out, , ) = handleGasAndSwap( - context.asset, - context.amount, - zrc20 - ); - - gateway.withdraw( - abi.encodePacked(sender), - out, - zrc20, - RevertOptions({ - revertAddress: sender, - callOnRevert: false, - abortAddress: address(0), - revertMessage: "", - onRevertGasLimit: gasLimit - }) - ); - } - - fallback() external payable {} - - receive() external payable {} -} diff --git a/examples/swap/hardhat.config.ts b/examples/swap/hardhat.config.ts index 6acf02c2..8a31c48c 100644 --- a/examples/swap/hardhat.config.ts +++ b/examples/swap/hardhat.config.ts @@ -1,6 +1,8 @@ import "./tasks/deploy"; -import "./tasks/swapFromZetaChain"; -import "./tasks/swapFromEVM"; +import "./tasks/companionSwap"; +import "./tasks/deployCompanion"; +import "./tasks/zetachainSwap"; +import "./tasks/evmSwap"; import "@zetachain/localnet/tasks"; import "@nomicfoundation/hardhat-toolbox"; import "@zetachain/toolkit/tasks"; @@ -8,19 +10,15 @@ import "@zetachain/toolkit/tasks"; import { getHardhatConfigNetworks } from "@zetachain/networks"; import { HardhatUserConfig } from "hardhat/config"; +import "@openzeppelin/hardhat-upgrades"; +import "@nomiclabs/hardhat-ethers"; + const config: HardhatUserConfig = { networks: { ...getHardhatConfigNetworks(), }, solidity: { - compilers: [ - { version: "0.5.10" /** For create2 factory */ }, - { version: "0.6.6" /** For uniswap v2 router*/ }, - { version: "0.5.16" /** For uniswap v2 core*/ }, - { version: "0.4.19" /** For weth*/ }, - { version: "0.8.7" }, - { version: "0.8.26" }, - ], + compilers: [{ version: "0.8.20" }, { version: "0.8.26" }], }, }; diff --git a/examples/swap/package.json b/examples/swap/package.json index 0a2bae52..dd0a8900 100644 --- a/examples/swap/package.json +++ b/examples/swap/package.json @@ -22,6 +22,7 @@ "@nomicfoundation/hardhat-toolbox": "^2.0.0", "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.0.0", + "@openzeppelin/hardhat-upgrades": "1.28.0", "@typechain/ethers-v5": "^10.1.0", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.2.0", diff --git a/examples/swap/scripts/localnet.sh b/examples/swap/scripts/localnet.sh index 0ea56366..c46b0d4e 100755 --- a/examples/swap/scripts/localnet.sh +++ b/examples/swap/scripts/localnet.sh @@ -1,6 +1,8 @@ #!/bin/bash set -e +set -x +set -o pipefail if [ "$1" = "start" ]; then npx hardhat localnet --exit-on-error & sleep 10; fi @@ -8,6 +10,7 @@ echo -e "\nšŸš€ Compiling contracts..." npx hardhat compile --force --quiet ZRC20_ETHEREUM=$(jq -r '.addresses[] | select(.type=="ZRC-20 ETH on 5") | .address' localnet.json) +USDC_ETHEREUM=$(jq -r '.addresses[] | select(.type=="ERC-20" and .chain=="ethereum") | .address' localnet.json) ZRC20_USDC=$(jq -r '.addresses[] | select(.type=="ZRC-20 USDC on 97") | .address' localnet.json) ZRC20_BNB=$(jq -r '.addresses[] | select(.type=="ZRC-20 BNB on 97") | .address' localnet.json) GATEWAY_ETHEREUM=$(jq -r '.addresses[] | select(.type=="gatewayEVM" and .chain=="ethereum") | .address' localnet.json) @@ -15,43 +18,42 @@ GATEWAY_ZETACHAIN=$(jq -r '.addresses[] | select(.type=="gatewayZEVM" and .chain UNISWAP_ROUTER=$(jq -r '.addresses[] | select(.type=="uniswapRouterInstance" and .chain=="zetachain") | .address' localnet.json) SENDER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -CONTRACT_SWAP=$(npx hardhat deploy --name Swap --network localhost --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') -echo -e "\nšŸš€ Deployed Swap contract on ZetaChain: $CONTRACT_SWAP" +CONTRACT_SWAP=$(npx hardhat deploy --name Swap --network localhost --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" | jq -r '.contractAddress') +COMPANION=$(npx hardhat deploy-companion --gateway "$GATEWAY_ETHEREUM" --network localhost --json | jq -r '.contractAddress') -CONTRACT_SWAPTOANY=$(npx hardhat deploy --name SwapToAnyToken --network localhost --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') -echo -e "\nšŸš€ Deployed SwapToAny contract on ZetaChain: $CONTRACT_SWAPTOANY" - -npx hardhat swap-from-evm \ +npx hardhat companion-swap \ --network localhost \ - --receiver "$CONTRACT_SWAP" \ + --contract "$COMPANION" \ + --universal-contract "$CONTRACT_SWAP" \ --amount 1 \ --target "$ZRC20_BNB" \ --recipient "$SENDER" npx hardhat localnet-check -npx hardhat swap-from-evm \ +npx hardhat companion-swap \ --network localhost \ - --receiver "$CONTRACT_SWAP" \ + --contract "$COMPANION" \ + --universal-contract "$CONTRACT_SWAP" \ --amount 1 \ + --erc20 "$USDC_ETHEREUM" \ --target "$ZRC20_BNB" \ - --recipient "$SENDER" \ - --withdraw false + --recipient "$SENDER" npx hardhat localnet-check -npx hardhat swap-from-evm \ +npx hardhat evm-swap \ --network localhost \ - --receiver "$CONTRACT_SWAPTOANY" \ + --receiver "$CONTRACT_SWAP" \ --amount 1 \ --target "$ZRC20_BNB" \ --recipient "$SENDER" npx hardhat localnet-check -npx hardhat swap-from-evm \ +npx hardhat evm-swap \ --network localhost \ - --receiver "$CONTRACT_SWAPTOANY" \ + --receiver "$CONTRACT_SWAP" \ --amount 1 \ --target "$ZRC20_BNB" \ --recipient "$SENDER" \ @@ -59,9 +61,9 @@ npx hardhat swap-from-evm \ npx hardhat localnet-check -npx hardhat swap-from-zetachain \ +npx hardhat zetachain-swap \ --network localhost \ - --contract "$CONTRACT_SWAPTOANY" \ + --contract "$CONTRACT_SWAP" \ --amount 1 \ --zrc20 "$ZRC20_BNB" \ --target "$ZRC20_ETHEREUM" \ diff --git a/examples/swap/tasks/companionSwap.ts b/examples/swap/tasks/companionSwap.ts new file mode 100644 index 00000000..011beb47 --- /dev/null +++ b/examples/swap/tasks/companionSwap.ts @@ -0,0 +1,61 @@ +import ERC20_ABI from "@openzeppelin/contracts/build/contracts/ERC20.json"; +import { task, types } from "hardhat/config"; +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { ethers } = hre; + const [signer] = await ethers.getSigners(); + + const factory = (await hre.ethers.getContractFactory("SwapCompanion")) as any; + const contract = factory.attach(args.contract).connect(signer); + + let tx; + if (args.erc20) { + const erc20Contract = new ethers.Contract( + args.erc20, + ERC20_ABI.abi, + signer + ); + const decimals = await erc20Contract.decimals(); + const value = hre.ethers.utils.parseUnits(args.amount, decimals); + const approveTx = await erc20Contract + .connect(signer) + .approve(args.contract, value); + await approveTx.wait(); + + tx = await contract.swapERC20( + args.universalContract, + args.target, + args.recipient, + args.amount, + args.erc20, + args.withdraw + ); + } else { + const value = hre.ethers.utils.parseEther(args.amount); + tx = await contract.swapNativeGas( + args.universalContract, + args.target, + args.recipient, + args.withdraw, + { value } + ); + } + + await tx.wait(); + console.log(`Transaction hash: ${tx.hash}`); +}; + +task("companion-swap", "Swap native gas tokens", main) + .addParam("contract", "Contract address") + .addParam("universalContract", "Universal contract address") + .addOptionalParam( + "withdraw", + "Withdraw to destination or keep token on ZetaChain", + true, + types.boolean + ) + .addOptionalParam("erc20", "ERC-20 token address") + .addParam("target", "ZRC-20 address of the token to swap for") + .addParam("amount", "Amount of tokens to swap") + .addParam("recipient", "Recipient address"); diff --git a/examples/swap/tasks/deploy.ts b/examples/swap/tasks/deploy.ts index 8d78f17c..1a4c680c 100644 --- a/examples/swap/tasks/deploy.ts +++ b/examples/swap/tasks/deploy.ts @@ -12,33 +12,23 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } const factory = await hre.ethers.getContractFactory(args.name); - const contract = await (factory as any).deploy( - args.gateway, - args.uniswapRouter, - args.gasLimit - ); - await contract.deployed(); - if (args.json) { - console.log( - JSON.stringify({ - contractAddress: contract.address, - deployer: signer.address, - network: network, - transactionHash: contract.deployTransaction.hash, - }) - ); - } else { - console.log(`šŸ”‘ Using account: ${signer.address} + const contract = await hre.upgrades.deployProxy( + factory as any, + [args.gateway, args.uniswapRouter, args.gasLimit, signer.address], + { kind: "uups" } + ); -šŸš€ Successfully deployed contract on ${network}. -šŸ“œ Contract address: ${contract.address} -`); - } + console.log( + JSON.stringify({ + contractAddress: contract.address, + deployer: signer.address, + network: network, + }) + ); }; task("deploy", "Deploy the contract", main) - .addFlag("json", "Output in JSON") .addOptionalParam("name", "Contract to deploy", "Swap") .addOptionalParam("uniswapRouter", "Uniswap v2 Router address") .addOptionalParam( diff --git a/examples/swap/tasks/deployCompanion.ts b/examples/swap/tasks/deployCompanion.ts new file mode 100644 index 00000000..10ee849a --- /dev/null +++ b/examples/swap/tasks/deployCompanion.ts @@ -0,0 +1,43 @@ +import { task, types } from "hardhat/config"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; + +const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const network = hre.network.name; + + const [signer] = await hre.ethers.getSigners(); + if (signer === undefined) { + throw new Error( + `Wallet not found. Please, run "npx hardhat account --save" or set PRIVATE_KEY env variable (for example, in a .env file)` + ); + } + + const factory = await hre.ethers.getContractFactory(args.name); + const contract = await (factory as any).deploy(args.gateway); + await contract.deployed(); + + if (args.json) { + console.log( + JSON.stringify({ + contractAddress: contract.address, + deployer: signer.address, + network: network, + transactionHash: contract.deployTransaction.hash, + }) + ); + } else { + console.log(`šŸ”‘ Using account: ${signer.address} + +šŸš€ Successfully deployed "${args.name}" contract on ${network}. +šŸ“œ Contract address: ${contract.address} +`); + } +}; + +task("deploy-companion", "Deploy the companion contract", main) + .addFlag("json", "Output in JSON") + .addOptionalParam("name", "Contract to deploy", "SwapCompanion") + .addOptionalParam( + "gateway", + "Gateway address (default: EVM Gateway on testnet)", + "0x0c487a766110c85d301d96e33579c5b317fa4995" + ); diff --git a/examples/swap/tasks/swapFromEVM.ts b/examples/swap/tasks/evmSwap.ts similarity index 97% rename from examples/swap/tasks/swapFromEVM.ts rename to examples/swap/tasks/evmSwap.ts index 2c5f745f..860d47b9 100644 --- a/examples/swap/tasks/swapFromEVM.ts +++ b/examples/swap/tasks/evmSwap.ts @@ -37,7 +37,7 @@ export const evmDepositAndCall = async ( } }; -task("swap-from-evm", "Swap tokens from EVM", evmDepositAndCall) +task("evm-swap", "Swap tokens from EVM", evmDepositAndCall) .addParam("receiver", "Receiver address on ZetaChain") .addOptionalParam( "gatewayEvm", diff --git a/examples/swap/tasks/swapFromZetaChain.ts b/examples/swap/tasks/zetachainSwap.ts similarity index 90% rename from examples/swap/tasks/swapFromZetaChain.ts rename to examples/swap/tasks/zetachainSwap.ts index a98fc0ea..3c6c2dde 100644 --- a/examples/swap/tasks/swapFromZetaChain.ts +++ b/examples/swap/tasks/zetachainSwap.ts @@ -7,7 +7,7 @@ import ZRC20 from "@zetachain/protocol-contracts/abi/ZRC20.sol/ZRC20.json"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const [signer] = await hre.ethers.getSigners(); - const factory = await hre.ethers.getContractFactory("SwapToAnyToken"); + const factory = await hre.ethers.getContractFactory("Swap"); const contract = factory.attach(args.contract); const zrc20 = new ethers.Contract(args.zrc20, ZRC20.abi, signer); @@ -29,7 +29,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { console.log(`Transaction hash: ${tx.hash}`); }; -task("swap-from-zetachain", "Swap tokens from ZetaChain", main) +task("zetachain-swap", "Swap tokens from ZetaChain", main) .addFlag("json", "Output JSON") .addParam("contract", "Contract address") .addParam("amount", "Token amount to send") diff --git a/examples/swap/yarn.lock b/examples/swap/yarn.lock index c23f5fa0..b1624643 100644 --- a/examples/swap/yarn.lock +++ b/examples/swap/yarn.lock @@ -7,6 +7,39 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== +"@aws-crypto/sha256-js@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz#02acd1a1fda92896fc5a28ec7c6e164644ea32fc" + integrity sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g== + dependencies: + "@aws-crypto/util" "^1.2.2" + "@aws-sdk/types" "^3.1.0" + tslib "^1.11.1" + +"@aws-crypto/util@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-1.2.2.tgz#b28f7897730eb6538b21c18bd4de22d0ea09003c" + integrity sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg== + dependencies: + "@aws-sdk/types" "^3.1.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-sdk/types@^3.1.0": + version "3.696.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.696.0.tgz#559c3df74dc389b6f40ba6ec6daffeab155330cd" + integrity sha512-9rTvUJIAj5d3//U5FDPWGJ1nFJLuWb30vugGOrWk7aNZ6y9tuA3PI7Cc9dP8WEXKVyK1vuuk8rSFP2iqXnlgrw== + dependencies: + "@smithy/types" "^3.7.1" + tslib "^2.6.2" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + "@babel/runtime@^7.21.0", "@babel/runtime@^7.25.0": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" @@ -14,6 +47,11 @@ dependencies: regenerator-runtime "^0.14.0" +"@bytecodealliance/preview2-shim@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz#9bc1cadbb9f86c446c6f579d3431c08a06a6672e" + integrity sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ== + "@coral-xyz/anchor-errors@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30" @@ -1700,6 +1738,13 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-2.0.2.tgz#ec95f23b53cb4e71a1a7091380fa223aad18f156" integrity sha512-vnN1AzxbvpSx9pfdRHbUzTRIXpMLPXnUlkW855VaDk6N1pwRaQ2gNzEmFAABk4lWf11E00PKwFd/q27HuwYrYg== +"@nomicfoundation/slang@^0.18.3": + version "0.18.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.18.3.tgz#976b6c3820081cebf050afbea434038aac9313cc" + integrity sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ== + dependencies: + "@bytecodealliance/preview2-shim" "0.17.0" + "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz#3a9c3b20d51360b20affb8f753e756d553d49557" @@ -1779,6 +1824,56 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.1.0.tgz#4e61162f2a2bf414c4e10c45eca98ce5f1aadbd4" integrity sha512-p1ULhl7BXzjjbha5aqst+QMLY+4/LCWADXOCsmLHRM77AqiPjnd9vvUN9sosUfhL9JGKpZ0TjEGxgvnizmWGSA== +"@openzeppelin/defender-base-client@^1.46.0": + version "1.54.6" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-base-client/-/defender-base-client-1.54.6.tgz#b65a90dba49375ac1439d638832382344067a0b9" + integrity sha512-PTef+rMxkM5VQ7sLwLKSjp2DBakYQd661ZJiSRywx+q/nIpm3B/HYGcz5wPZCA5O/QcEP6TatXXDoeMwimbcnw== + dependencies: + amazon-cognito-identity-js "^6.0.1" + async-retry "^1.3.3" + axios "^1.4.0" + lodash "^4.17.19" + node-fetch "^2.6.0" + +"@openzeppelin/hardhat-upgrades@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-1.28.0.tgz#6361f313a8a879d8a08a5e395acf0933bc190950" + integrity sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ== + dependencies: + "@openzeppelin/defender-base-client" "^1.46.0" + "@openzeppelin/platform-deploy-client" "^0.8.0" + "@openzeppelin/upgrades-core" "^1.27.0" + chalk "^4.1.0" + debug "^4.1.1" + proper-lockfile "^4.1.1" + +"@openzeppelin/platform-deploy-client@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/platform-deploy-client/-/platform-deploy-client-0.8.0.tgz#af6596275a19c283d6145f0128cc1247d18223c1" + integrity sha512-POx3AsnKwKSV/ZLOU/gheksj0Lq7Is1q2F3pKmcFjGZiibf+4kjGxr4eSMrT+2qgKYZQH1ZLQZ+SkbguD8fTvA== + dependencies: + "@ethersproject/abi" "^5.6.3" + "@openzeppelin/defender-base-client" "^1.46.0" + axios "^0.21.2" + lodash "^4.17.19" + node-fetch "^2.6.0" + +"@openzeppelin/upgrades-core@^1.27.0": + version "1.41.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.41.0.tgz#3a5e044cf53acd50c392f3297e7c37e4ff8f8355" + integrity sha512-+oryinqZnxkiZvg7bWqWX4Ki/CNwVUZEqC6Elpi5PQoahpL3/6Sq9xjIozD5AiI2O61h8JHQ+A//5NtczyavJw== + dependencies: + "@nomicfoundation/slang" "^0.18.3" + cbor "^9.0.0" + chalk "^4.1.0" + compare-versions "^6.0.0" + debug "^4.1.1" + ethereumjs-util "^7.0.3" + minimatch "^9.0.5" + minimist "^1.2.7" + proper-lockfile "^4.1.1" + solidity-ast "^0.4.51" + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -1908,6 +2003,13 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@smithy/types@^3.7.1": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-3.7.1.tgz#4af54c4e28351e9101996785a33f2fdbf93debe7" + integrity sha512-XKLcLXZY7sUQgvvWyeaL/qwNPp6V3dWcUjqrQKjSb+tzYiCy340R/c64LV5j+Tnb2GhmunEX0eou+L+m2hJNYA== + dependencies: + tslib "^2.6.2" + "@solana-developers/helpers@^2.4.0": version "2.5.6" resolved "https://registry.yarnpkg.com/@solana-developers/helpers/-/helpers-2.5.6.tgz#2af7613ea6848ce087c0dec7cf38e6f172abcbd4" @@ -2605,6 +2707,17 @@ ajv@^8.0.1: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" +amazon-cognito-identity-js@^6.0.1: + version "6.3.12" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.12.tgz#af73df033094ad4c679c19cf6122b90058021619" + integrity sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg== + dependencies: + "@aws-crypto/sha256-js" "1.2.2" + buffer "4.9.2" + fast-base64-decode "^1.0.0" + isomorphic-unfetch "^3.0.0" + js-cookie "^2.2.1" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -2794,6 +2907,13 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -2825,6 +2945,13 @@ axios@1.7.4: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^0.21.2: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + axios@^1.3.6, axios@^1.4.0, axios@^1.5.1, axios@^1.6.1: version "1.7.9" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" @@ -2856,7 +2983,7 @@ base-x@^5.0.0: resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.0.tgz#6d835ceae379130e1a4cb846a70ac4746f28ea9b" integrity sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ== -base64-js@^1.3.0, base64-js@^1.3.1: +base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -3068,6 +3195,15 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.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" @@ -3136,6 +3272,13 @@ cbor@^8.1.0: dependencies: nofilter "^3.1.0" +cbor@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-9.0.2.tgz#536b4f2d544411e70ec2b19a2453f10f83cd9fdb" + integrity sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ== + dependencies: + nofilter "^3.1.0" + chai-as-promised@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.2.tgz#70cd73b74afd519754161386421fb71832c6d041" @@ -3371,6 +3514,11 @@ commander@^8.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +compare-versions@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.1.tgz#7af3cc1099ba37d244b3145a9af5201b629148a9" + integrity sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4160,7 +4308,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.1.4: +ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.4: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -4340,6 +4488,11 @@ eyes@^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" + integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -4463,7 +4616,7 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== -follow-redirects@^1.12.1, follow-redirects@^1.15.6: +follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -4974,7 +5127,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5271,11 +5424,6 @@ isarray@^2.0.5: resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -5289,6 +5437,14 @@ isomorphic-fetch@^3.0.0: node-fetch "^2.6.1" whatwg-fetch "^3.4.1" +isomorphic-unfetch@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" + integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== + dependencies: + 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" @@ -5323,6 +5479,11 @@ joi@^17.11.0: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + js-sha3@0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -5500,7 +5661,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5615,7 +5776,14 @@ minimatch@^5.0.1, minimatch@^5.1.6: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: +minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -5720,7 +5888,7 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0: +node-fetch@^2.6.0, node-fetch@^2.6.1, 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== @@ -6030,6 +6198,15 @@ promise@^8.0.0: dependencies: asap "~2.0.6" +proper-lockfile@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -6234,6 +6411,16 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -6520,6 +6707,11 @@ solc@0.8.26: semver "^5.5.0" tmp "0.0.33" +solidity-ast@^0.4.51: + version "0.4.59" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.59.tgz#290a2815aef70a61092591ab3e991da080ae5931" + integrity sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g== + solidity-coverage@^0.8.0: version "0.8.14" resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.14.tgz#db9bfcc10e3bc369fc074b35b267d665bcc6ae2e" @@ -6918,7 +7110,7 @@ tslib@2.7.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== -tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -6928,6 +7120,11 @@ tslib@^2.0.3, tslib@^2.1.0, tslib@^2.8.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== +tslib@^2.3.1, tslib@^2.6.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" @@ -7112,6 +7309,11 @@ undici@^5.14.0: dependencies: "@fastify/busboy" "^2.0.0" +unfetch@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"