Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update zetachain multichainvalue #150

Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ interface MultiChainValueErrors {
}

/**
* @dev MultiChainValue goal is to send Zeta token across all supported chains
* Extends the logic defined in ZetaInteractor to handle multichain standards
* @dev MultiChainValue goal is to send Zeta token from ZEVM to other chains.
* This contract cannot handle 'onRevert' events, so it should only be used in ZEVM and not on other chains.
*/
contract MultiChainValue is ZetaInteractor, MultiChainValueErrors {
address public zetaToken;
Expand Down Expand Up @@ -56,7 +56,11 @@ contract MultiChainValue is ZetaInteractor, MultiChainValueErrors {
/**
* @dev If the destination chain is a valid chain, send the Zeta tokens to that chain
*/
function sendZeta(uint256 destinationChainId, bytes calldata destinationAddress) public payable {
function sendZeta(
uint256 destinationChainId,
bytes calldata destinationAddress,
uint256 destinationGasLimit
) public payable {
uint256 zetaValueAndGas = msg.value;

if (!availableChainIds[destinationChainId]) revert InvalidDestinationChainId();
Expand All @@ -70,8 +74,8 @@ contract MultiChainValue is ZetaInteractor, MultiChainValueErrors {
ZetaInterfaces.SendInput({
destinationChainId: destinationChainId,
destinationAddress: destinationAddress,
destinationGasLimit: 300000,
message: abi.encode(msg.sender),
destinationGasLimit: destinationGasLimit,
message: abi.encode(),
zetaValueAndGas: zetaValueAndGas,
zetaParams: abi.encode("")
})
Expand All @@ -81,7 +85,12 @@ contract MultiChainValue is ZetaInteractor, MultiChainValueErrors {
/**
* @dev If the destination chain is a valid chain, send the Zeta tokens to that chain
*/
function send(uint256 destinationChainId, bytes calldata destinationAddress, uint256 zetaValueAndGas) external {
function send(
uint256 destinationChainId,
bytes calldata destinationAddress,
uint256 zetaValueAndGas,
uint256 destinationGasLimit
) external {
if (!availableChainIds[destinationChainId]) revert InvalidDestinationChainId();
if (zetaValueAndGas == 0) revert InvalidZetaValueAndGas();

Expand All @@ -93,19 +102,15 @@ contract MultiChainValue is ZetaInteractor, MultiChainValueErrors {
ZetaInterfaces.SendInput({
destinationChainId: destinationChainId,
destinationAddress: destinationAddress,
destinationGasLimit: 300000,
message: abi.encode(msg.sender),
destinationGasLimit: destinationGasLimit,
message: abi.encode(),
zetaValueAndGas: zetaValueAndGas,
zetaParams: abi.encode("")
})
);
}

function onZetaRevert(ZetaInterfaces.ZetaRevert calldata zetaRevert) external isValidRevertCall(zetaRevert) {
address messageFrom = abi.decode(zetaRevert.message, (address));

bool success1 = ZetaEth(zetaToken).approve(address(this), zetaRevert.remainingZetaValue);
bool success2 = ZetaEth(zetaToken).transferFrom(address(this), messageFrom, zetaRevert.remainingZetaValue);
if (!(success1 && success2)) revert ErrorTransferringZeta();
//@dev this version do not handle revert
}
}
21 changes: 14 additions & 7 deletions packages/zeta-app-contracts/data/addresses.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
},
"bsc_mainnet": {
"multiChainSwap": "",
"multiChainValue": "0x33e5fCFfe910B99DB46c259804fCA1317EA0Aa89",
"multiChainValue": "",
"zetaTokenConsumerUniV2": "",
"zetaTokenConsumerUniV3": ""
},
"bsc_testnet": {
"multiChainSwap": "0x8BD7144Ddb59c9Fa3Dcf809998521E9cAD946fa1",
"multiChainValue": "0x064516547ECd3b2D1709e1b2798Aae92b1C8a84C",
"multiChainValue": "",
"zetaTokenConsumerUniV2": "",
"zetaTokenConsumerUniV3": ""
},
Expand All @@ -26,30 +26,37 @@
},
"eth_mainnet": {
"multiChainSwap": "",
"multiChainValue": "0x910966E1C0Bc9FD74f499723c19Ff9799fE258a5",
"multiChainValue": "",
"zetaTokenConsumerUniV2": "",
"zetaTokenConsumerUniV3": ""
},
"goerli_testnet": {
"multiChainSwap": "0x323745f16C93e56a98012970c28788498d8B3a14",
"multiChainValue": "0x14BeC0E4A8e7bF7A02Af54Ad81a57a9fcA4D37Fd",
"multiChainValue": "",
"zetaTokenConsumerUniV2": "",
"zetaTokenConsumerUniV3": ""
},
"mumbai_testnet": {
"multiChainSwap": "0xb1b812b664c28E1bA1d35De925Ae88b7Bc7cdCF5",
"multiChainValue": "0x14BeC0E4A8e7bF7A02Af54Ad81a57a9fcA4D37Fd",
"multiChainValue": "",
"zetaTokenConsumerUniV2": "",
"zetaTokenConsumerUniV3": ""
},
"zeta_testnet": {
"multiChainSwap": "",
"multiChainValue": "0x36Cfb6dCd6926dFb749dc8E4b28efc73f3e6FAe3",
"multiChainValue": "0x73B37B8BAbAC0e846bB2C4c581e60bFF2BFBE76e",
"zetaTokenConsumerUniV2": "",
"zetaTokenConsumerUniV3": ""
},
"zeta_mainnet": {
"multiChainSwap": "",
"multiChainValue": "0xF0a3F93Ed1B126142E61423F9546bf1323Ff82DF",
"zetaTokenConsumerUniV2": "",
"zetaTokenConsumerUniV3": ""
}
},
"zevm": {
"zeta_testnet": {}
"zeta_testnet": {},
"zeta_mainnet": {}
}
}
4 changes: 2 additions & 2 deletions packages/zeta-app-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
},
"dependencies": {
"@openzeppelin/contracts": "^4.9.3",
"@zetachain/networks": "^2.4.3",
"@zetachain/protocol-contracts": "^3.0.1",
"@zetachain/networks": "^4.0.0",
"@zetachain/protocol-contracts": "^4.0.1",
"ethers": "5.6.8"
}
}
30 changes: 14 additions & 16 deletions packages/zeta-app-contracts/scripts/multi-chain-value/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getAddress, isProtocolNetworkName } from "@zetachain/protocol-contracts/dist/lib";
import { getAddress, isProtocolNetworkName, isTestnetNetwork } from "@zetachain/protocol-contracts/dist/lib";
import { ethers, network } from "hardhat";

import { MultiChainValue, MultiChainValue__factory } from "../../typechain-types";
Expand All @@ -21,21 +21,19 @@ async function main() {

console.log("MultiChainValue post rutine...");

networkName !== "goerli_testnet" &&
(await (await contract.addAvailableChainId(getChainId("goerli_testnet")))
.wait()
.catch((e: any) => console.error(e)));

networkName !== "mumbai_testnet" &&
(await (await contract.addAvailableChainId(getChainId("mumbai_testnet")))
.wait()
.catch((e: any) => console.error(e)));

networkName !== "bsc_testnet" &&
(await (await contract.addAvailableChainId(getChainId("bsc_testnet"))).wait().catch((e: any) => console.error(e)));

networkName !== "zeta_testnet" &&
(await (await contract.addAvailableChainId(getChainId("zeta_testnet"))).wait().catch((e: any) => console.error(e)));
//@ts-ignore
const isTestnet = isTestnetNetwork(networkName);

if (isTestnet) {
await (await contract.addAvailableChainId(getChainId("goerli_testnet"))).wait().catch((e: any) => console.error(e));
await (await contract.addAvailableChainId(getChainId("bsc_testnet"))).wait().catch((e: any) => console.error(e));
await (await contract.addAvailableChainId(getChainId("zeta_testnet"))).wait().catch((e: any) => console.error(e));
await (await contract.addAvailableChainId(getChainId("mumbai_testnet"))).wait().catch((e: any) => console.error(e));
} else {
await (await contract.addAvailableChainId(getChainId("bsc_mainnet"))).wait().catch((e: any) => console.error(e));
await (await contract.addAvailableChainId(getChainId("zeta_mainnet"))).wait().catch((e: any) => console.error(e));
await (await contract.addAvailableChainId(getChainId("eth_mainnet"))).wait().catch((e: any) => console.error(e));
}

console.log("MultiChainValue post rutine finish");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { ContractReceipt, ContractTransaction, Transaction } from "ethers";
import { ethers, network } from "hardhat";

// Specify the address you're interested in
const ADDRESS = "0x70e967acFcC17c3941E87562161406d41676FD83";
let API_KEY = "";
let API_ENDPOINT = "";
let START_BLOCK = 0;
let END_BLOCK = 0;

if (network.name === "bsc_mainnet") {
API_KEY = process.env.BSCSCAN_API_KEY || "";
API_ENDPOINT = "api.bscscan.com";
START_BLOCK = 35741686;
END_BLOCK = 35844713;
} else if (network.name === "eth_mainnet") {
API_KEY = process.env.ETHERSCAN_API_KEY || "";
API_ENDPOINT = "api.etherscan.io";
START_BLOCK = 19080591;
END_BLOCK = 19157698;
} else {
throw new Error("Unsupported network");
}

// Function to check if a transaction involves the specified address
const isTransactionOfInterest = (tx: any, address: string) => {
return tx.from.toLowerCase() === address.toLowerCase() || tx.to.toLowerCase() === address.toLowerCase();
};

// Main function to iterate over the block range and find transactions
const findTransactionsInRange = async () => {
let totalTx = 0;
let totalErrorTx = 0;
for (let i = START_BLOCK; i < END_BLOCK; i++) {
// console.log(`Fetching block ${i} to ${END_BLOCK}...`);
const API_URL = `https://${API_ENDPOINT}/api?module=account&action=txlist&address=${ADDRESS}&startblock=${i}&endblock=${END_BLOCK}&sort=asc&apikey=${API_KEY}`;

try {
const call = await fetch(API_URL);
const response = await call.json();
const result = response.result;
const firstBlock = result[0].blockNumber;
const lastBlock = result[result.length - 1].blockNumber;
console.log(`Fetched block ${firstBlock} to ${lastBlock}...`);

const filteredTx = result.filter((tx: any) => isTransactionOfInterest(tx, ADDRESS));
const nonSuccesssfulTx = filteredTx.filter((tx: any) => tx.isError === "1" || tx.txreceipt_status !== "1");

totalTx += filteredTx.length;
totalErrorTx += nonSuccesssfulTx.length;
for (const tx of nonSuccesssfulTx) {
console.log(tx.hash);
}
if (result.length > 9000) {
i = parseInt(result[result.length - 1].blockNumber) - 1;
}
if (lastBlock >= END_BLOCK) {
break;
}
} catch (e) {
console.log(`Error fetching block ${i}`, e);
}
}
console.log(`total tx: ${totalTx} / Errors: ${totalErrorTx}`);
};

// Call the main function
const main = async () => {
await findTransactionsInRange();
};

main().catch((error) => {
console.error(error);
process.exit(1);
});
28 changes: 7 additions & 21 deletions packages/zeta-app-contracts/test/MultiChainValue.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,42 +74,28 @@ describe("MultiChainValue tests", () => {
describe("send", () => {
it("Should send msg", async () => {
await zetaEthMockContract.approve(multiChainValueContractA.address, parseEther("1000"));
const tx = multiChainValueContractA.send(chainBId, account1Address, 10);
const tx = multiChainValueContractA.send(chainBId, account1Address, 10, 300000);

await expect(tx)
.to.be.emit(zetaConnectorMockContract, "Send")
.withArgs(
chainBId,
account1Address.toLowerCase(),
300000,
defaultAbiCoder.encode(["address"], [deployer.address]),
10,
defaultAbiCoder.encode(["string"], [""])
);
.withArgs(chainBId, account1Address.toLowerCase(), 300000, "0x", 10, defaultAbiCoder.encode(["string"], [""]));
});

it("Should send native token", async () => {
const tx = multiChainValueContractA.sendZeta(chainBId, account1Address, { value: 10 });
const tx = multiChainValueContractA.sendZeta(chainBId, account1Address, 100000, { value: 10 });
await expect(tx)
.to.be.emit(zetaConnectorMockContract, "Send")
.withArgs(
chainBId,
account1Address.toLowerCase(),
300000,
defaultAbiCoder.encode(["address"], [deployer.address]),
10,
defaultAbiCoder.encode(["string"], [""])
);
.withArgs(chainBId, account1Address.toLowerCase(), 100000, "0x", 10, defaultAbiCoder.encode(["string"], [""]));
});

it("Should prevent sending value to a disabled chainId", async () => {
const tx = multiChainValueContractA.send(1, account1Address, 100_000);
const tx = multiChainValueContractA.send(1, account1Address, 100_000, 300000);
await expect(tx).to.be.revertedWith("InvalidDestinationChainId");
});

it("Should prevent sending 0 value", async () => {
await (await multiChainValueContractA.addAvailableChainId(1)).wait();
const tx = multiChainValueContractA.send(1, account1Address, 0);
const tx = multiChainValueContractA.send(1, account1Address, 0, 300000);
await expect(tx).to.be.revertedWith("InvalidZetaValueAndGas");
});

Expand Down Expand Up @@ -138,7 +124,7 @@ describe("MultiChainValue tests", () => {
ethers.utils.hexZeroPad("0x0", 32)
);

const balance = await zetaEthMockContract.balanceOf(account1.address);
const balance = await zetaEthMockContract.balanceOf(multiChainValueContractA.address);
await expect(balance).to.be.eq(remainingZetaValue);
});

Expand Down
4 changes: 2 additions & 2 deletions packages/zevm-app-contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
"dependencies": {
"@openzeppelin/contracts": "4.9.3",
"@uniswap/v2-periphery": "1.1.0-beta.0",
"@zetachain/networks": "^2.4.3",
"@zetachain/protocol-contracts": "^3.0.1",
"@zetachain/networks": "^4.0.0",
"@zetachain/protocol-contracts": "^4.0.1",
"ethers": "5.6.8"
}
}
24 changes: 12 additions & 12 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2767,19 +2767,19 @@ __metadata:
languageName: node
linkType: hard

"@zetachain/networks@npm:^2.4.3":
version: 2.5.0
resolution: "@zetachain/networks@npm:2.5.0"
"@zetachain/networks@npm:^4.0.0":
version: 4.0.0
resolution: "@zetachain/networks@npm:4.0.0"
dependencies:
dotenv: ^16.1.4
checksum: f208dbaa2b38e71069f8eb6ddd2b0a6d11f6f987579fcf4242b4398befa61eea381162984f14f339cee61f3a34e9463df20bfd53f3e670bb721b76c09d9840ac
checksum: 2013304de6959e9b33a2e4a23f49dd13ce9747bf4084332fda700ca32f719931998985a65e6e7c017c0919ff9167899a0529dbfaec274917aa8c28e6ac4faa0a
languageName: node
linkType: hard

"@zetachain/protocol-contracts@npm:^3.0.1":
version: 3.0.1
resolution: "@zetachain/protocol-contracts@npm:3.0.1"
checksum: 5a833dc9f59b69b83654754f4587aad57f4c9859908bc3fd9b5f3f6329cf803bf68e66aff4f355a99fb7e23726526196610e43987d15ec60208cc5564bc94259
"@zetachain/protocol-contracts@npm:^4.0.1":
version: 4.0.1
resolution: "@zetachain/protocol-contracts@npm:4.0.1"
checksum: 8d21c901001a735a4a43c4dd9eb90bc8121822bec1d51f0267061f771431691b4bcd7fcdaedb0e7b8bbd0d318937c86972076bf846e5c67506dbab389f9407ff
languageName: node
linkType: hard

Expand All @@ -2789,8 +2789,8 @@ __metadata:
dependencies:
"@defi-wonderland/smock": ^2.3.4
"@openzeppelin/contracts": ^4.9.3
"@zetachain/networks": ^2.4.3
"@zetachain/protocol-contracts": ^3.0.1
"@zetachain/networks": ^4.0.0
"@zetachain/protocol-contracts": ^4.0.1
ethers: 5.6.8
hardhat-gas-reporter: ^1.0.8
solidity-coverage: ^0.7.20
Expand All @@ -2804,8 +2804,8 @@ __metadata:
dependencies:
"@openzeppelin/contracts": 4.9.3
"@uniswap/v2-periphery": 1.1.0-beta.0
"@zetachain/networks": ^2.4.3
"@zetachain/protocol-contracts": ^3.0.1
"@zetachain/networks": ^4.0.0
"@zetachain/protocol-contracts": ^4.0.1
ethers: 5.6.8
hardhat-gas-reporter: ^1.0.8
solidity-coverage: ^0.7.20
Expand Down
Loading