Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev committed Sep 27, 2023
2 parents abd1a4e + bb3884a commit 425da52
Show file tree
Hide file tree
Showing 20 changed files with 1,199 additions and 308 deletions.
12 changes: 12 additions & 0 deletions contracts/BytesHelperLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,16 @@ library BytesHelperLib {
) internal pure returns (bytes32) {
return bytes32(uint256(uint160(someAddress)));
}

function bytesToBech32Bytes(
bytes calldata data,
uint256 offset
) internal pure returns (bytes memory) {
bytes memory bech32Bytes = new bytes(42);
for (uint i = 0; i < 42; i++) {
bech32Bytes[i] = data[i + offset];
}

return bech32Bytes;
}
}
8 changes: 2 additions & 6 deletions contracts/TestSystemContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@ pragma solidity 0.8.7;

import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol";
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IZRC20.sol";
import "@zetachain/protocol-contracts/contracts/zevm/SystemContract.sol";

interface SystemContractErrors {
contract TestSystemContract {
error CallerIsNotFungibleModule();

error InvalidTarget();

error CantBeIdenticalAddresses();

error CantBeZeroAddress();
}

contract TestSystemContract is SystemContractErrors {
mapping(uint256 => uint256) public gasPriceByChainId;
mapping(uint256 => address) public gasCoinZRC20ByChainId;
mapping(uint256 => address) public gasZetaPoolByChainId;
Expand Down
7 changes: 3 additions & 4 deletions helpers/evm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { MaxUint256 } from "@ethersproject/constants";
import { parseUnits } from "@ethersproject/units";
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { ethers } from "ethers";

import {
TestSystemContract,
Expand All @@ -10,8 +11,6 @@ import {
UniswapV2Router02__factory,
} from "../typechain-types";

declare const hre: any;

const addZetaEthLiquidity = async (
signer: SignerWithAddress,
token: TestZRC20,
Expand Down Expand Up @@ -100,10 +99,10 @@ export const prepareData = (contract: string, types: string[], args: any[]) => {
};

export const prepareParams = (types: string[], args: any[]) => {
const abiCoder = hre.ethers.utils.defaultAbiCoder;
const abiCoder = ethers.utils.defaultAbiCoder;
for (let i = 0; i < args.length; i++) {
if (types[i] === "bytes32") {
args[i] = hre.ethers.utils.hexlify(hre.ethers.utils.zeroPad(args[i], 32));
args[i] = ethers.utils.hexlify(ethers.utils.zeroPad(args[i], 32));
}
}
return abiCoder.encode(types, args);
Expand Down
10 changes: 4 additions & 6 deletions helpers/fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import axios from "axios";
import { ethers } from "ethers";
import { formatEther } from "ethers/lib/utils";

const GAS_LIMIT = 350000;

const formatTo18Decimals = (n: any) => parseFloat(formatEther(n)).toFixed(18);

export const fetchZEVMFees = async (network: string) => {
Expand All @@ -33,15 +31,15 @@ export const fetchZEVMFees = async (network: string) => {
};
};

export const fetchCCMFees = async (network: string) => {
export const fetchCCMFees = async (network: string, gas: Number = 500000) => {
const API = getEndpoints("cosmos-http", "zeta_testnet")[0]?.url;
if (!API) {
throw new Error("getEndpoints: API endpoint not found");
}

const chainID = getHardhatConfigNetworks()[network].chainId;

const url = `${API}/zeta-chain/crosschain/convertGasToZeta?chainId=${chainID}&gasLimit=${GAS_LIMIT}`;
const url = `${API}/zeta-chain/crosschain/convertGasToZeta?chainId=${chainID}&gasLimit=${gas}`;
const { data } = await axios.get(url);

const gasFee = ethers.BigNumber.from(data.outboundGasInZeta);
Expand All @@ -55,7 +53,7 @@ export const fetchCCMFees = async (network: string) => {
};
};

export const fetchFees = async () => {
export const fetchFees = async (gas: Number) => {
let fees = {
feesCCM: {} as Record<string, any>,
feesZEVM: {} as Record<string, any>,
Expand All @@ -68,7 +66,7 @@ export const fetchFees = async () => {
try {
const zevmFees = await fetchZEVMFees(n);
if (zevmFees) fees.feesZEVM[n] = zevmFees;
const ccmFees = await fetchCCMFees(n);
const ccmFees = await fetchCCMFees(n, gas);
if (ccmFees) fees.feesCCM[n] = ccmFees;
} catch (err) {}
})
Expand Down
177 changes: 131 additions & 46 deletions helpers/tx.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getEndpoints } from "@zetachain/networks";
import axios from "axios";
import clc from "cli-color";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import Spinnies from "spinnies";
import WebSocket from "ws";

Expand All @@ -12,24 +13,40 @@ const getEndpoint = (key: any): string => {
return endpoint;
};

const fetchCCTX = async (
const findByChainId = (config: any, targetChainId: Number): Object | null => {
for (const key in config) {
if (config.hasOwnProperty(key) && config[key].hasOwnProperty("chainId")) {
if (config[key].chainId === targetChainId) {
return config[key];
}
}
}
return null;
};

const fetchCCTXByInbound = async (
hash: string,
spinnies: any,
API: string,
cctxList: any
cctxList: any,
json: Boolean
) => {
try {
const url = `${API}/zeta-chain/crosschain/inTxHashToCctx/${hash}`;
const apiResponse = await axios.get(url);
const res = apiResponse?.data?.inTxHashToCctx?.cctx_index;
res.forEach((cctxHash: any) => {
if (cctxHash && !cctxList[cctxHash]) {
if (
cctxHash &&
!cctxList[cctxHash] &&
!spinnies.spinners[`spinner-${cctxHash}`]
) {
cctxList[cctxHash] = [];
}
if (!spinnies.spinners[`spinner-${cctxHash}`]) {
spinnies.add(`spinner-${cctxHash}`, {
text: `${cctxHash}`,
});
if (!json) {
spinnies.add(`spinner-${cctxHash}`, {
text: `${cctxHash}`,
});
}
}
});
} catch (error) {}
Expand All @@ -46,23 +63,47 @@ const fetchCCTXData = async (
cctxHash: string,
spinnies: any,
API: string,
cctxList: any
cctxList: any,
pendingNonces: any,
json: Boolean,
hre: HardhatRuntimeEnvironment
) => {
const url = `${API}/zeta-chain/crosschain/cctx/${cctxHash}`;
const apiResponse = await axios.get(url);
const cctx = apiResponse?.data?.CrossChainTx;
const { networks } = hre.config;
const cctx = await getCCTX(cctxHash, API);
const receiver_chainId = cctx?.outbound_tx_params[0]?.receiver_chainId;
const outbound_tx_hash = cctx?.outbound_tx_params[0]?.outbound_tx_hash;
let confirmed_on_destination = false;
if (outbound_tx_hash) {
const rpc = findByChainId(networks, parseInt(receiver_chainId))?.url;
const provider = new hre.ethers.providers.JsonRpcProvider(rpc);
const confirmed = await provider.getTransaction(outbound_tx_hash);
confirmed_on_destination = confirmed !== null;
}
const tx = {
receiver_chainId: cctx.outbound_tx_params[0].receiver_chainId,
sender_chain_id: cctx.inbound_tx_params.sender_chain_id,
status: cctx.cctx_status.status,
status_message: cctx.cctx_status.status_message,
confirmed_on_destination,
outbound_tx_hash,
outbound_tx_tss_nonce: cctx?.outbound_tx_params[0]?.outbound_tx_tss_nonce,
receiver_chainId,
sender_chain_id: cctx?.inbound_tx_params?.sender_chain_id,
status: cctx?.cctx_status?.status,
status_message: cctx?.cctx_status?.status_message,
};
const lastCCTX = cctxList[cctxHash][cctxList[cctxHash].length - 1];
const isEmpty = cctxList[cctxHash].length === 0;
if (isEmpty || lastCCTX?.status !== tx.status) {
const statusDefined =
tx.status !== undefined && tx.status_message !== undefined;
if (isEmpty || (statusDefined && lastCCTX.status !== tx.status)) {
cctxList[cctxHash].push(tx);
const sender = cctxList[cctxHash]?.[0].sender_chain_id;
const receiver = cctxList[cctxHash]?.[0].receiver_chainId;
let queue;
if (pendingNonces) {
const pending = pendingNonces.find(
(n: any) => n.chain_id === tx.receiver_chainId
)?.nonce_low;
const current = tx.outbound_tx_tss_nonce;
queue = current > pending ? ` (${current - pending} in queue)` : "";
}
const path = cctxList[cctxHash]
.map(
(x: any) =>
Expand All @@ -72,53 +113,101 @@ const fetchCCTXData = async (
)
.join(" → ");
const text = {
text: `${cctxHash}: ${sender}${receiver}: ${path}`,
text: `${cctxHash}: ${sender}${receiver}${queue}: ${path}`,
};
const id = `spinner-${cctxHash}`;
switch (tx.status) {
case "OutboundMined":
case "Reverted":
if (!json && spinnies.spinners[id]) {
const s = tx.status;
if (s == "OutboundMined" || s == "Reverted") {
spinnies.succeed(id, text);
break;
case "Aborted":
} else if (s == "Aborted") {
spinnies.fail(id, text);
break;
default:
} else {
spinnies.update(id, text);
break;
}
}
}
};

export const trackCCTX = async (inboundTxHash: string): Promise<void> => {
const getCCTX = async (hash: string, API: string) => {
try {
const url = `${API}/zeta-chain/crosschain/cctx/${hash}`;
const apiResponse = await axios.get(url);
return apiResponse?.data?.CrossChainTx;
} catch (e) {}
};

const fetchNonces = async (API: string, TSS: string) => {
try {
const url = `${API}/zeta-chain/crosschain/pendingNonces`;
const apiResponse = await axios.get(url);
const nonces = apiResponse?.data?.pending_nonces;
return nonces.filter((n: any) => n.tss === TSS);
} catch (e) {}
};

const fetchTSS = async (API: string) => {
try {
const url = `${API}/zeta-chain/crosschain/TSS`;
const apiResponse = await axios.get(url);
return apiResponse?.data?.TSS.tss_pubkey;
} catch (e) {}
};

export const trackCCTX = async (
hash: string,
hre: HardhatRuntimeEnvironment,
json: Boolean
): Promise<void> => {
const spinnies = new Spinnies();

const API = getEndpoint("cosmos-http");
const WSS = getEndpoint("tendermint-ws");
const TSS = await fetchTSS(API);

return new Promise((resolve, reject) => {
let cctxList: any = {};
const socket = new WebSocket(WSS);
socket.on("open", () => socket.send(JSON.stringify(SUBSCRIBE_MESSAGE)));
socket.on("message", async () => {
let pendingNonces: any = [];

const loopInterval = setInterval(async () => {
pendingNonces = await fetchNonces(API, TSS);
if (Object.keys(cctxList).length === 0) {
spinnies.add(`search`, {
text: `Looking for cross-chain transactions (CCTXs) on ZetaChain...\n`,
});
await fetchCCTX(inboundTxHash, spinnies, API, cctxList);
if (!json) {
spinnies.add(`search`, {
text: `Looking for cross-chain transactions (CCTXs) on ZetaChain...\n`,
});
}
await fetchCCTXByInbound(hash, spinnies, API, cctxList, json);
}
if (Object.keys(cctxList).length === 0 && !cctxList[hash]) {
if ((await getCCTX(hash, API)) && !cctxList[hash]) {
cctxList[hash] = [];
if (!spinnies.spinners[`spinner-${hash}`] && !json) {
spinnies.add(`spinner-${hash}`, {
text: `${hash}`,
});
}
}
}
for (const txHash in cctxList) {
await fetchCCTX(txHash, spinnies, API, cctxList);
await fetchCCTXByInbound(txHash, spinnies, API, cctxList, json);
}
if (Object.keys(cctxList).length > 0) {
if (spinnies.spinners["search"]) {
if (spinnies.spinners["search"] && !json) {
spinnies.succeed(`search`, {
text: `CCTXs on ZetaChain found.\n`,
});
}
for (const cctxHash in cctxList) {
try {
fetchCCTXData(cctxHash, spinnies, API, cctxList);
fetchCCTXData(
cctxHash,
spinnies,
API,
cctxList,
pendingNonces,
json,
hre
);
} catch (error) {}
}
}
Expand All @@ -132,14 +221,10 @@ export const trackCCTX = async (inboundTxHash: string): Promise<void> => {
.filter((s) => !["OutboundMined", "Aborted", "Reverted"].includes(s))
.length === 0
) {
socket.close();
if (json) console.log(JSON.stringify(cctxList, null, 2));
clearInterval(loopInterval); // Clear the interval
resolve();
}
});
socket.on("error", (error: any) => {
reject(error);
});
socket.on("close", () => {
resolve();
});
}, 3000); // Execute every 3 seconds
});
};
5 changes: 0 additions & 5 deletions index.ts

This file was deleted.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"exports": {
"./tasks": "./dist/tasks/index.js",
"./helpers": "./dist/helpers/index.js",
"./helpers/fees": "./dist/helpers/fees.js"
"./helpers/fees": "./dist/helpers/fees.js",
"./helpers/evm": "./dist/helpers/evm.js"
},
"scripts": {
"prebuild": "rimraf dist",
Expand Down Expand Up @@ -90,7 +91,6 @@
"moment": "^2.29.4",
"ora": "5.4.1",
"spinnies": "^0.5.1",
"readline": "^1.3.0",
"tiny-secp256k1": "^2.2.3",
"ws": "^8.13.0"
}
Expand Down
Loading

0 comments on commit 425da52

Please sign in to comment.