Skip to content

Commit

Permalink
feat: add script to check if B3TR contract is same as the one deployed
Browse files Browse the repository at this point in the history
  • Loading branch information
Agilulfo1820 committed Feb 4, 2025
1 parent 7d55bd8 commit 0f0541d
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 1 deletion.
21 changes: 21 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,27 @@ yarn generate-docs

The same documentation is available at github pages: [GithubPages](https://vechain.github.io/vebetterdao-contracts/)

### Verify contract

To verify that the B3TR contract deployed at a specific address is the same as the one compiled in the repo, you can use the following command:

```bash
yarn verify B3TR <contract_address>
```

This command will check that the bytecode of the contract deployed at the given address is the same as the source code in the repo.

To achieve this, it will:

1. Deploy the contract on the hardhat network
2. Fetch the bytecode of the deployed contract
3. Compare the bytecode with the bytecode of the compiled contract

Deploying the contract on the hardhat network is necessary because there is something wrong with the compiled bytecode,
some bytes are different between the actual deployed contract, maybe due to the way VeChainThor is deploying contracts.

This solution though is not perfect, it's just a quick way to verify that the contract deployed is the same as the one compiled in the repo.

# Disclaimer

This repository is for educational and demonstration purposes. The maintainers are not liable for any misuse or faults within the code.
1 change: 1 addition & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "@vechain/hardhat-vechain"
import "@vechain/hardhat-ethers"
import "hardhat-contract-sizer"
import "hardhat-ignore-warnings"
import "@nomicfoundation/hardhat-verify"
import { getConfig } from "./config"
import "solidity-coverage"
import "solidity-docgen"
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
"clean": "rm -rf dist artifacts typechain-types cache node_modules",
"lint": "eslint . --ext .ts",
"format": "eslint . --ext .ts --fix",
"generate-docs": "npx hardhat docgen"
"generate-docs": "npx hardhat docgen",
"verify": "./scripts/verify/verify-contract.sh",
"verify-contract": "CONTRACT_NAME=$CONTRACT_NAME CONTRACT_ADDRESS=$CONTRACT_ADDRESS npx hardhat run scripts/verify/verifyContract.ts --network hardhat"
},
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.2",
Expand Down
13 changes: 13 additions & 0 deletions scripts/verify/verify-contract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

# Check if both arguments are provided
if [ $# -ne 2 ]; then
echo "Usage: $0 <contract_name> <contract_address>"
exit 1
fi

CONTRACT_NAME=$1
CONTRACT_ADDRESS=$2

# Execute the yarn command with the environment variables
dotenv -v NEXT_PUBLIC_APP_ENV=local -v CONTRACT_NAME="$CONTRACT_NAME" -v CONTRACT_ADDRESS="$CONTRACT_ADDRESS" -- yarn verify-contract
69 changes: 69 additions & 0 deletions scripts/verify/verifyContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { ethers } from "hardhat"
import fetch from "node-fetch"

// This script is used to verify the bytecode of a contract on the mainnet.
//
// Currently it only supports B3TR.
// In order to verify the bytecode we are using the VeChain API to fetch the bytecode from the mainnet
// and then we are deploying the same contract on the hardhat network (local) and fetching the bytecode from there
// and then we are comparing the two bytecodes to ensure they are the same.
//
// We are doing this instead of just compiling the contract because there is something wrong with the compiled bytecode,
// some bytes are different between the actual deployed contract.
// It could be related to also how VeChainThor is deploying contracts.
async function verifyContract() {
const contractName = process.env.CONTRACT_NAME
const deployedAddress = process.env.CONTRACT_ADDRESS

if (!contractName || !deployedAddress) {
throw new Error("CONTRACT_NAME and CONTRACT_ADDRESS environment variables are required")
}

if (contractName !== "B3TR") {
throw new Error("This script only supports B3TR")
}

// First, get the bytecode from mainnet using VeChain's API
const mainnetResponse = await fetch(`https://mainnet.vechain.org/accounts/${deployedAddress}/code`)
if (!mainnetResponse.ok) {
throw new Error(`Failed to fetch code from mainnet: ${mainnetResponse.statusText}`)
}
const mainnetData = await mainnetResponse.json()
const mainnetCode = mainnetData.code
const mainnetCodeNoMeta = mainnetCode.slice(0, -86) // Remove metadata

// Then deploy on Hardhat network
const B3trContract = await ethers.getContractFactory("B3TR")
const [deployer] = await ethers.getSigners()
const hardhatContract = await B3trContract.deploy(
deployer.address, // admin
deployer.address, // minter
deployer.address, // pauser
)
await hardhatContract.waitForDeployment()

// Get deployed contract bytecode from Hardhat network
const hardhatDeployedCode = await ethers.provider.getCode(await hardhatContract.getAddress())
const hardhatDeployedCodeNoMeta = hardhatDeployedCode.slice(0, -86) // Remove metadata

console.log(`\nVerifying ${contractName} at ${deployedAddress} on Mainnet`)

// Compare bytecodes
console.log("\nBytecode comparison:")
console.log("Thor deployed:", mainnetCodeNoMeta)
console.log("Hardhat deployed:", hardhatDeployedCodeNoMeta)

if (mainnetCodeNoMeta === hardhatDeployedCodeNoMeta) {
console.log("\n✅ Bytecode matches!")
} else {
console.log("\n❌ Bytecode does not match!")
process.exit(1)
}
}

verifyContract()
.then(() => process.exit(0))
.catch(error => {
console.error(error)
process.exit(1)
})

0 comments on commit 0f0541d

Please sign in to comment.