From 12c6d3ae22b7378280d6fed6c675281761bc092d Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 9 Oct 2023 20:55:52 +0300 Subject: [PATCH] feat: make swap example compatible with Bitcoin (#63) --- omnichain/swap/contracts/Swap.sol | 39 ++++++++++++++++++++++++++++--- omnichain/swap/package.json | 2 +- omnichain/swap/tasks/interact.ts | 9 ++++--- omnichain/swap/yarn.lock | 8 +++---- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/omnichain/swap/contracts/Swap.sol b/omnichain/swap/contracts/Swap.sol index 56a2749a..68393a44 100644 --- a/omnichain/swap/contracts/Swap.sol +++ b/omnichain/swap/contracts/Swap.sol @@ -5,11 +5,15 @@ import "@zetachain/protocol-contracts/contracts/zevm/SystemContract.sol"; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol"; import "@zetachain/toolkit/contracts/SwapHelperLib.sol"; +import "@zetachain/toolkit/contracts/BytesHelperLib.sol"; contract Swap is zContract { error SenderNotSystemContract(); + error WrongGasContract(); + error NotEnoughToPayGasFee(); SystemContract public immutable systemContract; + uint256 constant BITCOIN = 18332; constructor(address systemContractAddress) { systemContract = SystemContract(systemContractAddress); @@ -24,8 +28,29 @@ contract Swap is zContract { if (msg.sender != address(systemContract)) { revert SenderNotSystemContract(); } - (address targetZRC20, bytes32 recipient, uint256 minAmountOut) = abi - .decode(message, (address, bytes32, uint256)); + + uint32 targetChainID; + bytes memory recipient; + uint256 minAmountOut; + + if (context.chainID == BITCOIN) { + targetChainID = BytesHelperLib.bytesToUint32(message, 0); + recipient = BytesHelperLib.bytesToBech32Bytes(message, 4); + } else { + ( + uint32 targetChainID_, + bytes32 recipient_, + uint256 minAmountOut_ + ) = abi.decode(message, (uint32, bytes32, uint256)); + targetChainID = targetChainID_; + recipient = abi.encodePacked(recipient_); + minAmountOut = minAmountOut_; + } + + address targetZRC20 = systemContract.gasCoinZRC20ByChainId( + targetChainID + ); + uint256 outputAmount = SwapHelperLib._doSwap( systemContract.wZetaContractAddress(), systemContract.uniswapv2FactoryAddress(), @@ -35,6 +60,14 @@ contract Swap is zContract { targetZRC20, minAmountOut ); - SwapHelperLib._doWithdrawal(targetZRC20, outputAmount, recipient); + + (address gasZRC20, uint256 gasFee) = IZRC20(targetZRC20) + .withdrawGasFee(); + + if (gasZRC20 != targetZRC20) revert WrongGasContract(); + if (gasFee >= outputAmount) revert NotEnoughToPayGasFee(); + + IZRC20(targetZRC20).approve(targetZRC20, gasFee); + IZRC20(targetZRC20).withdraw(recipient, outputAmount - gasFee); } } diff --git a/omnichain/swap/package.json b/omnichain/swap/package.json index bbf17fb5..cc4e7460 100644 --- a/omnichain/swap/package.json +++ b/omnichain/swap/package.json @@ -27,7 +27,7 @@ "@types/node": ">=12.0.0", "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", - "@zetachain/toolkit": "^2.1.2", + "@zetachain/toolkit": "^2.2.4", "axios": "^1.3.6", "chai": "^4.2.0", "dotenv": "^16.0.3", diff --git a/omnichain/swap/tasks/interact.ts b/omnichain/swap/tasks/interact.ts index 22705099..64655a91 100644 --- a/omnichain/swap/tasks/interact.ts +++ b/omnichain/swap/tasks/interact.ts @@ -9,13 +9,16 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const [signer] = await hre.ethers.getSigners(); console.log(`🔑 Using account: ${signer.address}\n`); - const targetZRC20 = getAddress("zrc20", args.destination); + const targetChainID = hre.config.networks[args.destination]?.chainId; + if (targetChainID === undefined) { + throw new Error("Invalid destination network"); + } const minAmountOut = BigNumber.from("0"); const data = prepareData( args.contract, - ["address", "bytes32", "uint256"], - [targetZRC20, args.recipient, minAmountOut] + ["uint32", "bytes32", "uint256"], + [targetChainID, args.recipient, minAmountOut] ); const to = getAddress("tss", hre.network.name as any); const value = parseEther(args.amount); diff --git a/omnichain/swap/yarn.lock b/omnichain/swap/yarn.lock index 4f204992..46dd45e2 100644 --- a/omnichain/swap/yarn.lock +++ b/omnichain/swap/yarn.lock @@ -1690,10 +1690,10 @@ resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-2.1.0.tgz#775b4eee7c85d115232dece121cbfc798fde6b63" integrity sha512-xmG6p8DizIk0h7Tr8Lt6UMG0ejrfRrPx0qH9ze3enwblo7W+eGP12oQ7djanYu50B0pNhh9z7xy/IYxKa9wD0Q== -"@zetachain/toolkit@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@zetachain/toolkit/-/toolkit-2.1.2.tgz#f83b57d323eab2f54961565b8bd15279eab964e7" - integrity sha512-eKZDUKWCf/h5RRvQsP0rG2qB0kKaw9GvpSylZwetx8+NckhKwQi52sUisX7sjHVqjDziTSdsagkrl4HmiPJ0pQ== +"@zetachain/toolkit@^2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@zetachain/toolkit/-/toolkit-2.2.4.tgz#4c80d160fdac1ebe9058c4f626934056476982f7" + integrity sha512-njh+owCjXAMe3PVvgm/5zIjErUqx87M/SciJXolAHYnbnKm85/gVwyguQu3mpHFQ5sIYBU2YN/W7HoMn6kVG1g== dependencies: "@inquirer/prompts" "^2.1.1" "@inquirer/select" "1.1.3"