Skip to content

Commit

Permalink
Refactor the Swap example to swap arbitrary ERC-20 and swap from EVM …
Browse files Browse the repository at this point in the history
…to Bitcoin (#85)
  • Loading branch information
fadeev authored Nov 14, 2023
1 parent fa8c2b6 commit 64d877d
Show file tree
Hide file tree
Showing 6 changed files with 1,158 additions and 707 deletions.
43 changes: 19 additions & 24 deletions omnichain/swap/contracts/Swap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,47 +30,42 @@ contract Swap is zContract {
uint256 amount,
bytes calldata message
) external virtual override onlySystem {
uint32 targetChainID;
address recipient;
uint256 minAmountOut;
address targetTokenAddress;
bytes memory recipientAddress;

if (context.chainID == BITCOIN) {
targetChainID = BytesHelperLib.bytesToUint32(message, 0);
recipient = BytesHelperLib.bytesToAddress(message, 4);
targetTokenAddress = BytesHelperLib.bytesToAddress(message, 0);
recipientAddress = abi.encodePacked(
BytesHelperLib.bytesToAddress(message, 20)
);
} else {
(
uint32 targetChainID_,
address recipient_,
uint256 minAmountOut_
) = abi.decode(message, (uint32, address, uint256));
targetChainID = targetChainID_;
recipient = recipient_;
minAmountOut = minAmountOut_;
(address targetToken, bytes memory recipient) = abi.decode(
message,
(address, bytes)
);
targetTokenAddress = targetToken;
recipientAddress = recipient;
}

address targetZRC20 = systemContract.gasCoinZRC20ByChainId(
targetChainID
);

uint256 outputAmount = SwapHelperLib._doSwap(
systemContract.wZetaContractAddress(),
systemContract.uniswapv2FactoryAddress(),
systemContract.uniswapv2Router02Address(),
zrc20,
amount,
targetZRC20,
minAmountOut
targetTokenAddress,
0
);

(address gasZRC20, uint256 gasFee) = IZRC20(targetZRC20)
(address gasZRC20, uint256 gasFee) = IZRC20(targetTokenAddress)
.withdrawGasFee();

if (gasZRC20 != targetZRC20) revert WrongGasContract();
if (gasZRC20 != targetTokenAddress) revert WrongGasContract();
if (gasFee >= outputAmount) revert NotEnoughToPayGasFee();

IZRC20(targetZRC20).approve(targetZRC20, gasFee);
IZRC20(targetZRC20).withdraw(
abi.encodePacked(recipient),
IZRC20(targetTokenAddress).approve(targetTokenAddress, gasFee);
IZRC20(targetTokenAddress).withdraw(
recipientAddress,
outputAmount - gasFee
);
}
Expand Down
4 changes: 2 additions & 2 deletions omnichain/swap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@types/node": ">=12.0.0",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"@zetachain/toolkit": "^3.0.0",
"@zetachain/toolkit": "^4.0.0",
"axios": "^1.3.6",
"chai": "^4.2.0",
"dotenv": "^16.0.3",
Expand All @@ -48,4 +48,4 @@
"typechain": "^8.1.0",
"typescript": ">=4.5.0"
}
}
}
5 changes: 4 additions & 1 deletion omnichain/swap/tasks/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
}
};

task("deploy", "Deploy the contract", main).addFlag("json", "Output in JSON");
task("deploy", "Deploy the contract", main).addFlag(
"json",
"Output in JSON"
);
29 changes: 18 additions & 11 deletions omnichain/swap/tasks/interact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,28 @@ import { HardhatRuntimeEnvironment } from "hardhat/types";
import { parseEther } from "@ethersproject/units";
import { getAddress } from "@zetachain/protocol-contracts";
import { prepareData } from "@zetachain/toolkit/helpers";
import { BigNumber } from "@ethersproject/bignumber";
import bech32 from "bech32";
import { utils } from "ethers";

const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
const [signer] = await hre.ethers.getSigners();

const targetChainID = hre.config.networks[args.destination]?.chainId;
if (targetChainID === undefined) {
throw new Error("Invalid destination network");
let recipient;
try {
if (bech32.decode(args.recipient)) {
recipient = utils.solidityPack(
["bytes"],
[utils.toUtf8Bytes(args.recipient)]
);
}
} catch (e) {
recipient = args.recipient;
}
const minAmountOut = BigNumber.from("0");

const data = prepareData(
args.contract,
["uint32", "address", "uint256"],
[targetChainID, args.recipient, minAmountOut]
["address", "bytes"],
[args.targetToken, recipient]
);
const to = getAddress("tss", hre.network.name);
const value = parseEther(args.amount);
Expand All @@ -30,14 +37,14 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
console.log(`🔑 Using account: ${signer.address}\n`);

console.log(`🚀 Successfully broadcasted a token transfer transaction on ${hre.network.name} network.
📝 Transaction hash: ${tx.hash}
`);
📝 Transaction hash: ${tx.hash}
`);
}
};

task("interact", "Interact with the contract", main)
.addParam("contract", "The address of the withdraw contract on ZetaChain")
.addParam("amount", "Amount of tokens to send")
.addParam("recipient")
.addFlag("json", "Output in JSON")
.addParam("destination");
.addParam("targetToken")
.addParam("recipient");
Loading

0 comments on commit 64d877d

Please sign in to comment.