-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Create script to verify bytecode (#127)
- Loading branch information
1 parent
bee7a6b
commit 4fd776a
Showing
3 changed files
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export const ETHERSCAN_API_ENDPOINT = "https://api.etherscan.io"; | ||
export const BSC_ETHERSCAN_API_ENDPOINT = "https://api.bscscan.com"; | ||
export const ZETA_NODE_ENDPOINT = "http://100.71.167.102:8545"; | ||
|
||
export const etherscanApiKey = process.env.ETHERSCAN_API_KEY; | ||
export const bscEtherscanApiKey = process.env.BSCSCAN_API_KEY; | ||
|
||
export const ethConnectorAddress = "0x000007Cf399229b2f5A4D043F20E90C9C98B7C6a"; | ||
export const ethERC20CustodyAddress = "0x000001b91C19A31809e769110d35FAd2C15BCeA7"; | ||
export const ethTokenAddress = "0xf091867EC603A6628eD83D274E835539D82e9cc8"; | ||
|
||
export const bscConnectorAddress = "0x000063A6e758D9e2f438d430108377564cf4077D"; | ||
export const bscERC20CustodyAddress = "0x0000006Abbf11Ed0FabFD247f1F4d76A383cC395"; | ||
export const bscTokenAddress = "0x0000028a2eB8346cd5c0267856aB7594B7a55308"; | ||
|
||
export const BTC_BTC = "0x13A0c5930C028511Dc02665E7285134B6d11A5f4"; | ||
export const BNB_BSC = "0x48f80608B672DC30DC7e3dbBd0343c5F02C738Eb"; | ||
export const ETH_ETH = "0xd97B1de3619ed2c6BEb3860147E30cA8A7dC9891"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
const fetch = require("node-fetch"); | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const { ethers } = require("ethers"); | ||
import { BigNumber } from "ethers"; | ||
|
||
import { | ||
BSC_ETHERSCAN_API_ENDPOINT, | ||
bscEtherscanApiKey, | ||
ETHERSCAN_API_ENDPOINT, | ||
etherscanApiKey, | ||
ZETA_NODE_ENDPOINT, | ||
} from "./bytecode.constants"; | ||
|
||
export const encodeNumber = (weiValue: BigNumber) => { | ||
return ethers.utils.hexZeroPad(weiValue.toHexString(), 32).replace("0x", ""); | ||
}; | ||
|
||
export const encodeAddress = (address: string) => { | ||
return ethers.utils.hexZeroPad(address, 32).replace("0x", ""); | ||
}; | ||
|
||
export const compareBytecode = (bytecodeA: string, bytecodeB: string) => { | ||
if (bytecodeA === bytecodeB) { | ||
console.log("Bytecode matches!"); | ||
} else { | ||
console.error("Bytecode doesn't match!"); | ||
} | ||
}; | ||
|
||
export const getEtherscanBytecode = async (network: "bsc" | "eth", contractAddress: string) => { | ||
const endpoint = network === "bsc" ? BSC_ETHERSCAN_API_ENDPOINT : ETHERSCAN_API_ENDPOINT; | ||
const apiKey = network === "bsc" ? bscEtherscanApiKey : etherscanApiKey; | ||
const etherscanApiUrl = `${endpoint}/api?module=proxy&action=eth_getCode&address=${contractAddress}&apikey=${apiKey}`; | ||
|
||
try { | ||
const response = await fetch(etherscanApiUrl); | ||
const data = await response.json(); | ||
const bytecode = data.result; | ||
return bytecode; | ||
} catch (error) { | ||
console.error("Error fetching bytecode:", error); | ||
} | ||
}; | ||
|
||
// @dev: helper to find differences between two bytecodes when there's a mismatch | ||
export const findDiff = (codeA: string, codeB: string) => { | ||
console.log("Lengths:", codeA.length, codeB.length); | ||
for (let i = 0; i < codeA.length; i++) { | ||
if (codeA[i] !== codeB[i]) { | ||
console.log(i, codeA.substring(i - 20, i + 40), codeB.substring(i - 20, i + 40)); | ||
} | ||
} | ||
}; | ||
|
||
export const getZetaNodeBytecode = async (contractAddress: string) => { | ||
try { | ||
const provider = new ethers.providers.JsonRpcProvider(ZETA_NODE_ENDPOINT); | ||
const bytecode = await provider.getCode(contractAddress); | ||
return bytecode; | ||
} catch (error) { | ||
console.error("Error fetching bytecode:", error); | ||
console.error("Please make sure you are connected to tailscale."); | ||
} | ||
}; | ||
|
||
export const removeImmutableAddress = (bytecode: string, pattern: string) => { | ||
const replacement = encodeAddress(ethers.constants.AddressZero); | ||
const regex = new RegExp(pattern, "gi"); | ||
|
||
bytecode = bytecode.replace(regex, replacement); | ||
return bytecode; | ||
}; | ||
|
||
export const removeImmutableNumber = (bytecode: string, pattern: string) => { | ||
const replacement = encodeNumber(BigNumber.from("0")); | ||
const regex = new RegExp(pattern, "gi"); | ||
|
||
bytecode = bytecode.replace(regex, replacement); | ||
return bytecode; | ||
}; | ||
|
||
export const getDeployedBytecode = async (contract: string, kind: "evm" | "zevm") => { | ||
try { | ||
const filePath = path.join(__dirname, `../../../artifacts/contracts/${kind}/${contract}.json`); | ||
const fileContent = fs.readFileSync(filePath, "utf8"); | ||
const jsonContent = JSON.parse(fileContent); | ||
const deployedBytecode = jsonContent.deployedBytecode; | ||
|
||
return deployedBytecode; | ||
} catch (error) { | ||
console.error("Error reading the file or parsing JSON:", error); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { BigNumber } from "ethers"; | ||
import { parseEther } from "ethers/lib/utils"; | ||
|
||
import { | ||
BNB_BSC, | ||
bscConnectorAddress, | ||
bscERC20CustodyAddress, | ||
bscTokenAddress, | ||
BTC_BTC, | ||
ETH_ETH, | ||
ethConnectorAddress, | ||
ethERC20CustodyAddress, | ||
ethTokenAddress, | ||
} from "./bytecode.constants"; | ||
import { | ||
compareBytecode, | ||
encodeAddress, | ||
encodeNumber, | ||
getDeployedBytecode, | ||
getEtherscanBytecode, | ||
getZetaNodeBytecode, | ||
removeImmutableAddress, | ||
removeImmutableNumber, | ||
} from "./bytecode.helpers"; | ||
|
||
const checkEthConnectorBytecode = async () => { | ||
const remoteBytecode = await getEtherscanBytecode("eth", ethConnectorAddress); | ||
const cleanRemoteBytecode = removeImmutableAddress(remoteBytecode, encodeAddress(ethTokenAddress)); | ||
const deployedBytecode = await getDeployedBytecode("ZetaConnector.eth.sol/ZetaConnectorEth", "evm"); | ||
compareBytecode(cleanRemoteBytecode, deployedBytecode); | ||
}; | ||
|
||
const checkEthCustodyBytecode = async () => { | ||
const remoteBytecode = await getEtherscanBytecode("eth", ethERC20CustodyAddress); | ||
let cleanRemoteBytecode = removeImmutableAddress(remoteBytecode, encodeAddress(ethTokenAddress)); | ||
cleanRemoteBytecode = removeImmutableNumber(cleanRemoteBytecode, encodeNumber(parseEther("1000"))); // zetaMaxFee | ||
const deployedBytecode = await getDeployedBytecode("ERC20Custody.sol/ERC20Custody", "evm"); | ||
compareBytecode(cleanRemoteBytecode, deployedBytecode); | ||
}; | ||
|
||
const checkBscConnectorBytecode = async () => { | ||
const remoteBytecode = await getEtherscanBytecode("bsc", bscConnectorAddress); | ||
const cleanRemoteBytecode = removeImmutableAddress(remoteBytecode, encodeAddress(bscTokenAddress)); | ||
const deployedBytecode = await getDeployedBytecode("ZetaConnector.non-eth.sol/ZetaConnectorNonEth", "evm"); | ||
compareBytecode(cleanRemoteBytecode, deployedBytecode); | ||
}; | ||
|
||
const checkBscCustodyBytecode = async () => { | ||
const remoteBytecode = await getEtherscanBytecode("bsc", bscERC20CustodyAddress); | ||
let cleanRemoteBytecode = removeImmutableAddress(remoteBytecode, encodeAddress(bscTokenAddress)); | ||
cleanRemoteBytecode = removeImmutableNumber(cleanRemoteBytecode, encodeNumber(parseEther("1000"))); // zetaMaxFee | ||
const deployedBytecode = await getDeployedBytecode("ERC20Custody.sol/ERC20Custody", "evm"); | ||
compareBytecode(cleanRemoteBytecode, deployedBytecode); | ||
}; | ||
|
||
const checkZRC20ETHBytecode = async () => { | ||
const remoteBytecode = await getZetaNodeBytecode(ETH_ETH); | ||
let cleanRemoteBytecode = removeImmutableNumber(remoteBytecode, encodeNumber(BigNumber.from("1"))); // ETH CHAIN ID | ||
cleanRemoteBytecode = removeImmutableNumber(cleanRemoteBytecode, encodeNumber(BigNumber.from("1"))); // Gas COIN TYPE | ||
const deployedBytecode = await getDeployedBytecode("ZRC20.sol/ZRC20", "zevm"); | ||
compareBytecode(cleanRemoteBytecode, deployedBytecode); | ||
}; | ||
|
||
const checkZRC20BTCBytecode = async () => { | ||
const remoteBytecode = await getZetaNodeBytecode(BTC_BTC); | ||
let cleanRemoteBytecode = removeImmutableNumber(remoteBytecode, encodeNumber(BigNumber.from("8332"))); // BTC CHAIN ID | ||
cleanRemoteBytecode = removeImmutableNumber(cleanRemoteBytecode, encodeNumber(BigNumber.from("1"))); // Gas COIN TYPE | ||
const deployedBytecode = await getDeployedBytecode("ZRC20.sol/ZRC20", "zevm"); | ||
compareBytecode(cleanRemoteBytecode, deployedBytecode); | ||
}; | ||
|
||
const checkZRC20BSCBytecode = async () => { | ||
const remoteBytecode = await getZetaNodeBytecode(BNB_BSC); | ||
let cleanRemoteBytecode = removeImmutableNumber(remoteBytecode, encodeNumber(BigNumber.from("56"))); // BSC CHAIN ID | ||
cleanRemoteBytecode = removeImmutableNumber(cleanRemoteBytecode, encodeNumber(BigNumber.from("1"))); // Gas COIN TYPE | ||
const deployedBytecode = await getDeployedBytecode("ZRC20.sol/ZRC20", "zevm"); | ||
compareBytecode(cleanRemoteBytecode, deployedBytecode); | ||
}; | ||
|
||
const checkBytecode = async () => { | ||
// ETH | ||
await checkEthConnectorBytecode(); | ||
await checkEthCustodyBytecode(); | ||
// BSC | ||
await checkBscConnectorBytecode(); | ||
await checkBscCustodyBytecode(); | ||
// ZEVM | ||
await checkZRC20ETHBytecode(); | ||
await checkZRC20BTCBytecode(); | ||
await checkZRC20BSCBytecode(); | ||
}; | ||
|
||
checkBytecode() | ||
.then(() => process.exit(0)) | ||
.catch((error) => { | ||
console.error(error); | ||
process.exit(1); | ||
}); |