ethereum: rm truffle

This commit is contained in:
Evan Gray 2024-08-09 10:18:52 -04:00 committed by Evan Gray
parent 2f4811c190
commit 750645b350
48 changed files with 285 additions and 97090 deletions

View File

@ -57,15 +57,7 @@ flattened: $(patsubst contracts/%, flattened/%, $(FLATTEN_FILES))
.env: .env.test
cp $< $@
test: test-forge test-identifiers test-ganache
.PHONY: test-ganache
test-ganache: build .env dependencies
@if pgrep ganache-cli; then echo "Error: ganache-cli already running. Stop it before running tests"; exit 1; fi
. ./.env && npx ganache-cli --chain.vmErrorsOnRPCResponse --chain.chainId $$INIT_EVM_CHAIN_ID --wallet.defaultBalance 10000 --wallet.deterministic --chain.time="1970-01-01T00:00:00+00:00" --chain.asyncRequestProcessing=false > ganache.log &
sleep 5
npm test || (pkill ganache-cli && exit 1)
pkill ganache-cli || true
test: test-forge test-identifiers
.PHONY: test-upgrade
test-upgrade: build .env node_modules
@ -87,4 +79,4 @@ test-push0: dependencies
@if grep -qr --include \*.json PUSH0 ./build-forge; then echo "Contract uses PUSH0 instruction" 1>&2; exit 1; fi
clean:
rm -rf ganache.log .env node_modules build flattened build-forge ethers-contracts lib/forge-std lib/openzeppelin-contracts
rm -rf .env node_modules build flattened build-forge ethers-contracts lib/forge-std lib/openzeppelin-contracts

View File

@ -74,31 +74,9 @@ ethereum$ MNEMONIC= ./sh/upgrade.sh testnet TokenBridge blast
ethereum$ MNEMONIC= ./sh/registerAllChainsOnTokenBridge.sh <network> <chainName> <tokenBridgeAddress>
```
### Deploying using Truffle (deprecated)
To deploy the bridge on Ethereum you first need to compile all smart contracts:
`npx truffle compile`
To deploy you can either use the bytecode from the `build/contracts` folder or the oz cli `oz deploy <Contract>`
([Documentation](https://docs.openzeppelin.com/learn/deploying-and-interacting)).
You first need to deploy one `Wrapped Asset` and initialize it using dummy data.
Then deploy the `Wormhole` using the initial guardian key (`key_x,y_parity,0`) and the address of the previously deployed
`WrappedAsset`. The wrapped asset contract will be used as proxy library to all the creation of cheap proxy wrapped
assets.
### Testing
For each test run:
Run `npx ganache-cli --chain.vmErrorsOnRPCResponse --chain.chainId 1 --wallet.defaultBalance 10000 --wallet.deterministic --chain.time="1970-01-01T00:00:00+00:00" --chain.asyncRequestProcessing=false` to start a chain.
Run the all ethereum tests using `DEV=True make test`
Run a specific test file using `npx truffle test test/wormhole.js`
Run a specific test file while skipping compile `npx truffle test test/wormhole.js --compile-none`
Run all ethereum tests using `make test`
### User methods

View File

@ -9,7 +9,7 @@ transaction payloads according to the contract ABI.
This document outlines the process of verification. In general, you will need an
API key for the relevant explorer (this can be obtained by creating an account)
and to know at which address the contract code lives. The API key is expected to
be set in the `ETHERSCAN_KEY` environment variable for all APIs (not just
be set in the `ETHERSCAN_API_KEY` environment variable for all APIs (not just
etherscan, bit of a misnomer).
Our contracts are structured as a separate proxy and an implementation. Both of
@ -19,39 +19,21 @@ verified each time it's upgraded.
## Verifying the proxy contract (first time)
The proxy contract is called `TokenBridge`. To verify it on e.g. avalanche, at contract address `0x0e082F06FF657D94310cB8cE8B0D9a04541d8052`, run
The proxy contract is called `TokenBridge`. To verify it on e.g. Ethereum, at contract address `0x3ee18B2214AFF97000D974cf647E7C347E8fa585`, run
```bash
forge verify-contract --etherscan-api-key $ETHERSCAN_API_KEY --verifier-url "https://api.etherscan.io/api" 0x3ee18B2214AFF97000D974cf647E7C347E8fa585 contracts/bridge/TokenBridge.sol:TokenBridge --watch
```
ETHERSCAN_KEY=... npm run verify --module=TokenBridge --contract_address=0x0e082F06FF657D94310cB8cE8B0D9a04541d8052 --network=avalanche
```
(Note: the network name comes from the `truffle-config.json`).
(Note: In this case, the `ETHERSCAN_KEY` is your snowtrace API key).
## Verifying the implementation contract (on each upgrade)
To verify the actual implementation, at address `0xa321448d90d4e5b0a732867c18ea198e75cac48e`, run
To verify the actual implementation, at address `0x381752f5458282d317d12c30d2bd4d6e1fd8841e`, run
```sh
ETHERSCAN_KEY=... npm run verify --module=BridgeImplementation --contract_address=0xa321448d90d4e5b0a732867c18ea198e75cac48e --network=avalanche
```bash
forge verify-contract --etherscan-api-key $ETHERSCAN_API_KEY --verifier-url "https://api.etherscan.io/api" 0x381752f5458282d317d12c30d2bd4d6e1fd8841e contracts/bridge/BridgeImplementation.sol:BridgeImplementation --watch
```
As a final step, when first registering the proxy contract, we need to verify
that it's a proxy that points to the implementation we just verified. This can
be done on avalanche at
https://snowtrace.io/proxyContractChecker?a=0x0e082F06FF657D94310cB8cE8B0D9a04541d8052
be done on ethereum at https://etherscan.io/proxyContractChecker
(other evm scanner sites have an identical page).
# Note
The `npm run verify` script uses the `truffle-plugin-verify` plugin under the
hood. The version of `truffle-plugin-verify` pinned in the repo (`^0.5.11` at
the time of writing) doesn't support the avalanche RPC. In later versions of the
plugin, support was added, but other stuff has changed as well in the transitive
dependencies, so it fails to parse the `HDWallet` arguments in our
`truffle-config.json`. As a quick workaround, we backport the patch to `0.5.11`
by applying the `truffle-verify-constants.patch` file, which the `npm run
verify` script does transparently. Once the toolchain has been upgraded and the
errors fixed, this patch can be removed.

View File

@ -1 +0,0 @@
myth like bonus scare over problem client lizard pioneer submit female collect

View File

@ -47,11 +47,11 @@ https://moonscan.io/verifyContract and paste in contract address, in our case
`0xab3f0245b83feb11d15aaffefd7ad465a59817ed`. Fill in the rest of the form with
the following values, then continue.
| Field | Value |
| ---------------- | ------------------------- |
| Compiler type | Solidity (Single file) |
| Compiler version | v0.8.4+commit.c7e474f2 |
| License type | Apache-2 |
| Field | Value |
| ---------------- | ---------------------- |
| Compiler type | Solidity (Single file) |
| Compiler version | v0.8.4+commit.c7e474f2 |
| License type | Apache-2 |
On the next page, select "optimizations: yes", and paste the contents of
`token/Token.sol` from before into the source file textarea.
@ -61,7 +61,7 @@ default.
## ABI-encoded constructor arguments
The last missing piece is the ABI-encoded constructor arguments field. These
The last missing piece is the ABI-encoded constructor arguments field. These
are the arguments that the contract was instantiated with, and it will be
different for each wrapped contract.
There are two ways to proceed. The first method is easier, but does not
@ -77,8 +77,8 @@ At this point, some explorers will just return a generic error message saying
the bytecodes didn't match, without any additional information. If this is the
case, go to method #2.
If the page shows what the *expected* bytecode was, and lists out the *actual*
bytecodes it found in the source file, then we may proceed here. The *expected*
If the page shows what the _expected_ bytecode was, and lists out the _actual_
bytecodes it found in the source file, then we may proceed here. The _expected_
bytecode will be the same as the `BridgeToken` bytecode with the constructor
arguments appended to the end. This means that the `BridgeToken` bytecode is a
proper prefix of the expected bytecode. Just copy the rest of the bytes of the
@ -130,7 +130,7 @@ section. Click "Decode input data" which will show the hex value of the
We copy this field and go back to our terminal. Run the following
```
wormhole/ethereum $ forge script scripts/TokenABI.s.sol -s "token_constructor_args(bytes, address)" <VAA-BYTES> <CONTRACT-ADDRESS>
wormhole/ethereum $ forge script forge-scripts/TokenABI.s.sol --tc BridgeScript -s "token_constructor_args(bytes, address)" <VAA-BYTES> <CONTRACT-ADDRESS>
```
where in place of `<VAA-BYTES>`, substitute the hex sequence we just copied from
@ -143,5 +143,5 @@ Running that command prints the following:
0x000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d9200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000164c71f461500000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000014c53000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d920000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000d57726170706564204574686572000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004574554480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
```
Copy the hex *excluding* the 0x at the front, and paste that into the
Copy the hex _excluding_ the 0x at the front, and paste that into the
constructor arguments field, then hit verify. The contract should now be verified.

View File

@ -0,0 +1,24 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
import {NFTBridgeImplementation} from "../contracts/nft/NFTBridgeImplementation.sol";
import "forge-std/Script.sol";
contract DeployNFTBridgeImplementationOnly is Script {
// DryRun - Deploy the system
function dryRun() public {
_deploy();
}
// Deploy the system
function run() public returns (address deployedAddress) {
vm.startBroadcast();
deployedAddress = _deploy();
vm.stopBroadcast();
}
function _deploy() internal returns (address deployedAddress) {
NFTBridgeImplementation impl = new NFTBridgeImplementation();
return address(impl);
}
}

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
pragma solidity ^0.8.4;
import {NFTBridgeShutdown} from "../contracts/nft/NFTBridgeShutdown.sol";
import "forge-std/Script.sol";

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "forge-std/Script.sol";
import "../contracts/Messages.sol";
import "../contracts/Structs.sol";
import "../contracts/bridge/Bridge.sol";
import "../contracts/bridge/BridgeStructs.sol";
contract BridgeTest is Bridge {
function token_constructor_args(bytes calldata encodedVM, address tokenBridge) public returns (bytes memory constructorArgs) {
Messages m = new Messages();
Structs.VM memory vm = m.parseVM(encodedVM);
BridgeStructs.AssetMeta memory meta = parseAssetMeta(vm.payload);
constructorArgs = token_constructor_args(bytes32ToString(meta.name), bytes32ToString(meta.symbol), meta.decimals, vm.sequence, tokenBridge, meta.tokenChain, meta.tokenAddress);
}
function token_constructor_args(string memory name, string memory symbol, uint8 decimals, uint64 sequence, address tokenBridge, uint16 tokenChain, bytes32 tokenAddress) pure public returns (bytes memory constructorArgs) {
bytes memory initialisationArgs = abi.encodeWithSelector(
TokenImplementation.initialize.selector,
name,
symbol,
decimals,
sequence,
tokenBridge,
tokenChain,
tokenAddress
);
constructorArgs = abi.encode(tokenBridge, initialisationArgs);
}
}
contract BridgeScript is Script {
// forge script forge-scripts/TokenABI.s.sol --tc BridgeScript -s "token_constructor_args(bytes, address)" 0x01000000020d00b7ba3819d44da891c74c583e29eb2222dd37dabbe7929bdbf4f2186bbcc721085d85d9906bbd8ca5ae62cdf30c7555dc4c57fd15f84a0161c27e91846203439c0102736caa697f6c17c2e6b0526291b0e6b4dec760a8494df7f69c93be3df1956224637ef962be9a28ef2dbeebe6bdb30311d9f2394966a1bb170634bd69913abfb200038c598c6e7c288c5dbb0f0008c38168d3f00ac8da7b3ad5420f30c8808c94a8a972c090d25da27558f1b8f8d30f894850d3139f4df92c8e8736be7803d397f33e0006649e6aca07694046fd94b5851ff3711783d4f4c8e0319f9de9431232cb153bce2ff2ac0f7bfad6f3db461571cd6ecffc99d7740a7b653d2f6a25908d821d9ca70107b31051fda4062585f80b291978a480cae6c9191d37a67bc2e1e61db8e97907fa71b5064d2ada48b4cd2f8c4def7fd50484004d1ceb3438a8f67ea071a31a6a88000af4842bbcd0fad425bd3b82bc3b1acefd72555fd1fbb49b71700ec2b41ac6309f20222e24c557f4ad6af35d96f1d4c38fb25177e027a22d2d071956d5d45985ba000bc0ebb4202aae662de331bce75d5e49ea97ac9a74df65006250c96ca9d82a16be6e78c577004a6059169aa7640436e1e5deef5d80bfa52784cf82f67bb368e066010d14586fa1f6f37d2c4d0eae78c42ecc3c9fc6bf17b3a57406382165d615cfb4a1651b979419c42e40a3f62fbe05eb3ff4bafac0af30c15a060e39d935776e54cc000e98d02eb76745301cb5fb12e6b0c7e3e9be347460ed51be360828c46be3bc40ef622f9234fb443b431db9e98980a7165b36eda10bd37abf6998156ebbdf96c4b6010fda503c3deb9c937709ab5742c4a44ed29f04664585c4c73568cd3b4863e1e2326b9cab4d1b139d9698585bb8abcbdc4072b3f98fdfe1b50fa35656c1451f862400106644b7697f41052d4d7c1685d342df4828c7ba7231f86c04476805271c58b4e30614ee43988072decec39f0400a48583f7b6d0fb109516385f73a64ce2a2b16501111cc03c23da18a3ed794cb944aa6d131306c243d13f207796c9ea9430a6c7da063b0ffbc75416c924b588ecc24c3d1c6136ea8e181a4f3d8c1d3d1831c7d4ae7301120b48f7b0c43cb43b4541d179f4bdfe6b9c83289b5b7cd494f6ea33eec062b36408606f4ad406365539d6b3a6b59b2eeae70baf0266c341fb476c8092d64ebd620062cb923534d80000000e000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed00000000000000560102000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a000e12635553440000000000000000000000000000000000000000000000000000000043656c6f20446f6c6c6172000000000000000000000000000000000000000000 $(worm info contract mainnet ethereum TokenBridge)
function token_constructor_args(bytes calldata encodedVM, address tokenBridge) public {
BridgeTest bridge = new BridgeTest();
console.logBytes(bridge.token_constructor_args(encodedVM, tokenBridge));
}
// forge script forge-scripts/TokenABI.s.sol --tc BridgeScript -s "token_constructor_args(string,string,uint8,uint64,address,uint16,bytes32)" "Wrapped Ether" "WETH" 18 69201 0x796Dff6D74F3E27060B71255Fe517BFb23C93eed 2 0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
function token_constructor_args(string memory name, string memory symbol, uint8 decimals, uint64 sequence, address tokenBridge, uint16 tokenChain, bytes32 tokenAddress) public {
BridgeTest bridge = new BridgeTest();
console.logBytes(bridge.token_constructor_args(name, symbol, decimals, sequence, tokenBridge, tokenChain, tokenAddress));
}
}

View File

@ -1,15 +0,0 @@
require('dotenv').config({ path: "../.env" });
const Wormhole = artifacts.require("Wormhole");
const MockBatchedVAASender = artifacts.require("MockBatchedVAASender");
module.exports = async function (deployer, network, accounts) {
await deployer.deploy(MockBatchedVAASender)
const contract = new web3.eth.Contract(MockBatchedVAASender.abi, MockBatchedVAASender.address);
await contract.methods.setup(
Wormhole.address
).send({from: accounts[0]})
};

View File

@ -1,6 +0,0 @@
var Migrations = artifacts.require("Migrations");
module.exports = function(deployer) {
// Deploy the Migrations contract as our only task
deployer.deploy(Migrations);
};

View File

@ -1,34 +0,0 @@
require('dotenv').config({ path: "../.env" });
const Setup = artifacts.require("Setup");
const Implementation = artifacts.require("Implementation");
const Wormhole = artifacts.require("Wormhole");
// CONFIG
const initialSigners = JSON.parse(process.env.INIT_SIGNERS);
const chainId = process.env.INIT_CHAIN_ID;
const governanceChainId = process.env.INIT_GOV_CHAIN_ID;
const governanceContract = process.env.INIT_GOV_CONTRACT; // bytes32
const evmChainId = process.env.INIT_EVM_CHAIN_ID;
module.exports = async function (deployer) {
// deploy setup
await deployer.deploy(Setup);
// deploy implementation
await deployer.deploy(Implementation);
// encode initialisation data
const setup = new web3.eth.Contract(Setup.abi, Setup.address);
const initData = setup.methods.setup(
Implementation.address,
initialSigners,
chainId,
governanceChainId,
governanceContract,
evmChainId
).encodeABI();
// deploy proxy
await deployer.deploy(Wormhole, Setup.address, initData);
};

View File

@ -1,42 +0,0 @@
require('dotenv').config({ path: "../.env" });
const TokenBridge = artifacts.require("TokenBridge");
const BridgeImplementation = artifacts.require("BridgeImplementation");
const BridgeSetup = artifacts.require("BridgeSetup");
const TokenImplementation = artifacts.require("TokenImplementation");
const Wormhole = artifacts.require("Wormhole");
const chainId = process.env.BRIDGE_INIT_CHAIN_ID;
const governanceChainId = process.env.BRIDGE_INIT_GOV_CHAIN_ID;
const governanceContract = process.env.BRIDGE_INIT_GOV_CONTRACT; // bytes32
const WETH = process.env.BRIDGE_INIT_WETH;
const finality = process.env.BRIDGE_INIT_FINALITY;
const evmChainId = process.env.INIT_EVM_CHAIN_ID;
module.exports = async function (deployer) {
// deploy token implementation
await deployer.deploy(TokenImplementation);
// deploy setup
await deployer.deploy(BridgeSetup);
// deploy implementation
await deployer.deploy(BridgeImplementation);
// encode initialisation data
const setup = new web3.eth.Contract(BridgeSetup.abi, BridgeSetup.address);
const initData = setup.methods.setup(
BridgeImplementation.address,
chainId,
(await Wormhole.deployed()).address,
governanceChainId,
governanceContract,
TokenImplementation.address,
WETH,
finality,
evmChainId
).encodeABI();
// deploy proxy
await deployer.deploy(TokenBridge, BridgeSetup.address, initData);
};

View File

@ -1,40 +0,0 @@
require('dotenv').config({ path: "../.env" });
const TokenBridge = artifacts.require("NFTBridgeEntrypoint");
const BridgeImplementation = artifacts.require("NFTBridgeImplementation");
const BridgeSetup = artifacts.require("NFTBridgeSetup");
const TokenImplementation = artifacts.require("NFTImplementation");
const Wormhole = artifacts.require("Wormhole");
const chainId = process.env.BRIDGE_INIT_CHAIN_ID;
const governanceChainId = process.env.BRIDGE_INIT_GOV_CHAIN_ID;
const governanceContract = process.env.BRIDGE_INIT_GOV_CONTRACT; // bytes32
const finality = process.env.BRIDGE_INIT_FINALITY;
const evmChainId = process.env.INIT_EVM_CHAIN_ID;
module.exports = async function (deployer) {
// deploy token implementation
await deployer.deploy(TokenImplementation);
// deploy setup
await deployer.deploy(BridgeSetup);
// deploy implementation
await deployer.deploy(BridgeImplementation);
// encode initialisation data
const setup = new web3.eth.Contract(BridgeSetup.abi, BridgeSetup.address);
const initData = setup.methods.setup(
BridgeImplementation.address,
chainId,
(await Wormhole.deployed()).address,
governanceChainId,
governanceContract,
TokenImplementation.address,
finality,
evmChainId
).encodeABI();
// deploy proxy
await deployer.deploy(TokenBridge, BridgeSetup.address, initData);
};

View File

@ -1,13 +0,0 @@
// run with:
// npm run deploy-bridge-implementation-only
// e.g. Ethereum Mainnet
// INFURA_KEY="" MNEMONIC="" npm run deploy-bridge-implementation-only -- --network mainnet
// e.g. BSC
// MNEMONIC="" npm run deploy-bridge-implementation-only -- --network binance
// e.g. Polygon
// MNEMONIC="" npm run deploy-bridge-implementation-only -- --network polygon
const BridgeImplementation = artifacts.require("BridgeImplementation");
module.exports = async function(deployer, network) {
if (network === "test") return;
await deployer.deploy(BridgeImplementation);
};

View File

@ -1,13 +0,0 @@
// run with:
// npm run deploy-token-implementation-only
// e.g. Ethereum Mainnet
// INFURA_KEY="" MNEMONIC="" npm run deploy-token-implementation-only -- --network mainnet
// e.g. BSC
// MNEMONIC="" npm run deploy-token-implementation-only -- --network binance
// e.g. Polygon
// MNEMONIC="" npm run deploy-token-implementation-only -- --network polygon
const TokenImplementation = artifacts.require("TokenImplementation");
module.exports = async function(deployer, network) {
if (network === "test") return;
await deployer.deploy(TokenImplementation);
};

View File

@ -1,5 +0,0 @@
var WETH9 = artifacts.require("MockWETH9");
module.exports = function(deployer) {
deployer.deploy(WETH9);
};

42829
ethereum/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +1,16 @@
{
"name": "@wormhole-foundation/contracts-ethereum",
"version": "0.0.1",
"description": "",
"main": "networks.js",
"devDependencies": {
"@chainsafe/truffle-plugin-abigen": "0.0.1",
"@openzeppelin/cli": "^2.8.2",
"@openzeppelin/contracts": "^4.3.1",
"@truffle/hdwallet-provider": "^1.7.0",
"chai": "^4.3.7",
"mocha": "^8.4.0",
"truffle": "5.8.4",
"truffle-flattener": "^1.6.0",
"truffle-plugin-verify": "^0.5.11",
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
"@openzeppelin/contracts": "^4.3.1"
},
"scripts": {
"build:core": "truffle compile",
"build:forge": "forge build",
"build": "npm run build:core && npm run build:forge && typechain --target=ethers-v5 --out-dir=./ethers-contracts \"build-forge/!(test).sol/*.json\"",
"test": "npm run build:core && mkdir -p build/contracts && cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle test --network test --compile-none",
"migrate": "npm run build:core && mkdir -p build/contracts && cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle migrate --to 4 --compile-none",
"deploy-bridge-implementation-only": "npm run build:core && mkdir -p build/contracts && cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle migrate --f 6 --to 6 --compile-none",
"deploy-token-implementation-only": "npm run build:core && mkdir -p build/contracts && cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle migrate --f 7 --to 7 --compile-none",
"deploy-read-only": "npm run build:core && mkdir -p build/contracts && cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle migrate --f 1 --to 2 --compile-none",
"deploy-bridges-only": "npm run build:core && mkdir -p build/contracts && cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle migrate --f 3 --to 4 --compile-none",
"deploy_weth9": "npm run build:core && mkdir -p build/contracts && cp node_modules/@openzeppelin/contracts/build/contracts/* build/contracts/ && truffle migrate --f 9 --compile-none",
"verify": "patch -u -f node_modules/truffle-plugin-verify/constants.js -i truffle-verify-constants.patch; truffle run verify $npm_config_module@$npm_config_contract_address --network $npm_config_network",
"verify-token": "patch -u -f node_modules/truffle-plugin-verify/constants.js -i truffle-verify-constants.patch; truffle run verify BridgeToken@$npm_config_contract_address --forceConstructorArgs string:$npm_config_constructor_args --network $npm_config_network",
"abigen": "truffle run abigen",
"typecheck": "tsc --noEmit --skipLibCheck"
"build": "npm run build:forge && typechain --target=ethers-v5 --out-dir=./ethers-contracts \"build-forge/!(test).sol/*.json\""
},
"author": "",
"license": "ISC",
"license": "Apache-2.0",
"dependencies": {
"@typechain/ethers-v5": "^10.2.0",
"dotenv": "^10.0.0",
"elliptic": "^6.5.2",
"jsonfile": "^4.0.0",
"truffle-hdwallet-provider-klaytn": "^1.4.2",
"typechain": "^8.1.1"
}
}

View File

@ -1,5 +0,0 @@
@openzeppelin/=node_modules/@openzeppelin/
@solidity-parser/=node_modules/@solidity-parser/
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
truffle/=node_modules/truffle/

View File

@ -1,40 +0,0 @@
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "forge-std/Script.sol";
import "../contracts/Messages.sol";
import "../contracts/Structs.sol";
import "../contracts/bridge/Bridge.sol";
import "../contracts/bridge/BridgeStructs.sol";
contract BridgeTest is Bridge, Script {
// forge script scripts/TokenABI.s.sol -s "token_constructor_args(bytes, address)" 0x01000000020d00b7ba3819d44da891c74c583e29eb2222dd37dabbe7929bdbf4f2186bbcc721085d85d9906bbd8ca5ae62cdf30c7555dc4c57fd15f84a0161c27e91846203439c0102736caa697f6c17c2e6b0526291b0e6b4dec760a8494df7f69c93be3df1956224637ef962be9a28ef2dbeebe6bdb30311d9f2394966a1bb170634bd69913abfb200038c598c6e7c288c5dbb0f0008c38168d3f00ac8da7b3ad5420f30c8808c94a8a972c090d25da27558f1b8f8d30f894850d3139f4df92c8e8736be7803d397f33e0006649e6aca07694046fd94b5851ff3711783d4f4c8e0319f9de9431232cb153bce2ff2ac0f7bfad6f3db461571cd6ecffc99d7740a7b653d2f6a25908d821d9ca70107b31051fda4062585f80b291978a480cae6c9191d37a67bc2e1e61db8e97907fa71b5064d2ada48b4cd2f8c4def7fd50484004d1ceb3438a8f67ea071a31a6a88000af4842bbcd0fad425bd3b82bc3b1acefd72555fd1fbb49b71700ec2b41ac6309f20222e24c557f4ad6af35d96f1d4c38fb25177e027a22d2d071956d5d45985ba000bc0ebb4202aae662de331bce75d5e49ea97ac9a74df65006250c96ca9d82a16be6e78c577004a6059169aa7640436e1e5deef5d80bfa52784cf82f67bb368e066010d14586fa1f6f37d2c4d0eae78c42ecc3c9fc6bf17b3a57406382165d615cfb4a1651b979419c42e40a3f62fbe05eb3ff4bafac0af30c15a060e39d935776e54cc000e98d02eb76745301cb5fb12e6b0c7e3e9be347460ed51be360828c46be3bc40ef622f9234fb443b431db9e98980a7165b36eda10bd37abf6998156ebbdf96c4b6010fda503c3deb9c937709ab5742c4a44ed29f04664585c4c73568cd3b4863e1e2326b9cab4d1b139d9698585bb8abcbdc4072b3f98fdfe1b50fa35656c1451f862400106644b7697f41052d4d7c1685d342df4828c7ba7231f86c04476805271c58b4e30614ee43988072decec39f0400a48583f7b6d0fb109516385f73a64ce2a2b16501111cc03c23da18a3ed794cb944aa6d131306c243d13f207796c9ea9430a6c7da063b0ffbc75416c924b588ecc24c3d1c6136ea8e181a4f3d8c1d3d1831c7d4ae7301120b48f7b0c43cb43b4541d179f4bdfe6b9c83289b5b7cd494f6ea33eec062b36408606f4ad406365539d6b3a6b59b2eeae70baf0266c341fb476c8092d64ebd620062cb923534d80000000e000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed00000000000000560102000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a000e12635553440000000000000000000000000000000000000000000000000000000043656c6f20446f6c6c6172000000000000000000000000000000000000000000 $(worm info contract mainnet ethereum TokenBridge)
function token_constructor_args(bytes calldata encodedVM, address tokenBridge) public {
Messages m = new Messages();
Structs.VM memory vm = m.parseVM(encodedVM);
BridgeStructs.AssetMeta memory meta = parseAssetMeta(vm.payload);
token_constructor_args(bytes32ToString(meta.name), bytes32ToString(meta.symbol), meta.decimals, vm.sequence, tokenBridge, meta.tokenChain, meta.tokenAddress);
}
// forge script scripts/TokenABI.s.sol -s "token_constructor_args(string,string,uint8,uint64,address,uint16,bytes32)" "Wrapped Ether" "WETH" 18 69201 0x796Dff6D74F3E27060B71255Fe517BFb23C93eed 2 0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
function token_constructor_args(string memory name, string memory symbol, uint8 decimals, uint64 sequence, address tokenBridge, uint16 tokenChain, bytes32 tokenAddress) view public {
bytes memory initialisationArgs = abi.encodeWithSelector(
TokenImplementation.initialize.selector,
name,
symbol,
decimals,
sequence,
tokenBridge,
tokenChain,
tokenAddress
);
bytes memory constructorArgs = abi.encode(tokenBridge, initialisationArgs);
console.logBytes(constructorArgs);
}
}

View File

@ -1,22 +0,0 @@
const Wormhole = artifacts.require("Wormhole");
const MockBatchedVAASender = artifacts.require("MockBatchedVAASender");
module.exports = async function(callback) {
try {
const accounts = await web3.eth.getAccounts();
await MockBatchedVAASender.deploy();
// devnet contract address should be deterministic
if (MockBatchedVAASender.address !== "0xf19a2a01b70519f67adb309a994ec8c69a967e8b") {
throw new Error("unexpected batched-VAA contract address");
}
const batchedSender = new web3.eth.Contract(MockBatchedVAASender.abi, MockBatchedVAASender.address);
await batchedSender.methods.setup(Wormhole.address).send({from: accounts[0]});
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,26 +0,0 @@
const QueryDemo = artifacts.require("QueryDemo");
module.exports = async function(callback) {
const accounts = await web3.eth.getAccounts();
try {
// const ccqDemo = await QueryDemo.new(
// accounts[0],
// "0x0CBE91CF822c73C2315FB05100C2F714765d5c20",
// 5
// );
// const ccqDemo = await QueryDemo.new(
// accounts[0],
// "0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e",
// 23
// );
const ccqDemo = await QueryDemo.new(
accounts[0],
"0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35",
24
);
console.log("tx: " + ccqDemo.transactionHash);
console.log("QueryDemo address: " + ccqDemo.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,11 +0,0 @@
const Implementation = artifacts.require("Implementation");
module.exports = async function(callback) {
try {
const bridge = (await Implementation.new());
console.log('tx: ' + bridge.transactionHash);
console.log('Implementation address: ' + bridge.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,11 +0,0 @@
const Shutdown = artifacts.require("Shutdown");
module.exports = async function(callback) {
try {
const contract = (await Shutdown.new());
console.log('tx: ' + contract.transactionHash);
console.log('Shutdown address: ' + contract.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,11 +0,0 @@
const BridgeImplementation = artifacts.require("NFTBridgeImplementation");
module.exports = async function(callback) {
try {
const bridge = (await BridgeImplementation.new());
console.log('tx: ' + bridge.transactionHash);
console.log('NFTBridge address: ' + bridge.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,11 +0,0 @@
const Shutdown = artifacts.require("NFTBridgeShutdown");
module.exports = async function(callback) {
try {
const contract = (await Shutdown.new());
console.log('tx: ' + contract.transactionHash);
console.log('NFTBridgeShutdown address: ' + contract.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,122 +0,0 @@
// run this script with truffle exec
const ERC20 = artifacts.require("ERC20PresetMinterPauser");
const ERC721 = artifacts.require("ERC721PresetMinterPauserAutoId");
const interateToStandardTransactionCount = async () => {
const accounts = await web3.eth.getAccounts();
const transactionCount = await web3.eth.getTransactionCount(
accounts[0],
"latest"
);
console.log(
"transaction count prior to test token deploys: ",
transactionCount
);
const transactionsToBurn = 32 - transactionCount;
for (let i = 0; i < transactionsToBurn; i++) {
await web3.eth.sendTransaction({
to: accounts[0],
from: accounts[0],
value: 530,
});
}
const burnCount = await web3.eth.getTransactionCount(accounts[0], "latest");
console.log("transaction count after burn: ", burnCount);
return Promise.resolve();
};
module.exports = async function(callback) {
try {
const accounts = await web3.eth.getAccounts();
//Contracts deployed via this script deploy to an address which is determined by the number of transactions
//which have been performed on the chain.
//This is, however, variable. For example, if you optionally deploy contracts, more transactions are
//performed than if you didn't.
//In order to make sure the test contracts deploy to a location
//which is deterministic with regard to other environment conditions, we fire bogus transactions up to a safe
//count, currently 32, before deploying the test contracts.
await interateToStandardTransactionCount();
// deploy token contract
const tokenAddress = (await ERC20.new("Ethereum Test Token", "TKN"))
.address;
const token = new web3.eth.Contract(ERC20.abi, tokenAddress);
console.log("Token deployed at: " + tokenAddress);
// mint 1000 units
await token.methods.mint(accounts[0], "1000000000000000000000").send({
from: accounts[0],
gas: 1000000,
});
const nftAddress = (
await ERC721.new(
"Not an APE 🐒",
"APE🐒",
"https://cloudflare-ipfs.com/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/"
)
).address;
const nft = new web3.eth.Contract(ERC721.abi, nftAddress);
await nft.methods.mint(accounts[0]).send({
from: accounts[0],
gas: 1000000,
});
await nft.methods.mint(accounts[0]).send({
from: accounts[0],
gas: 1000000,
});
console.log("NFT deployed at: " + nftAddress);
const MockWETH9 = await artifacts.require("MockWETH9");
//WETH deploy
// deploy token contract
const wethAddress = (await MockWETH9.new()).address;
const wethToken = new web3.eth.Contract(MockWETH9.abi, wethAddress);
console.log("WETH token deployed at: " + wethAddress);
for (let idx = 2; idx < 11; idx++) {
await token.methods.mint(accounts[idx], "1000000000000000000000").send({
from: accounts[0],
gas: 1000000,
});
}
// devnet WETH token address should be deterministic
if (wethAddress !== "0xDDb64fE46a91D46ee29420539FC25FD07c5FEa3E") {
throw new Error("unexpected WETH token address");
}
// deploy token contract
const accountantTokenAddress = (
await ERC20.new("Accountant Test Token", "GA")
).address;
const accountantToken = new web3.eth.Contract(
ERC20.abi,
accountantTokenAddress
);
console.log("Accountant test token deployed at: " + accountantTokenAddress);
// mint 1000 units
await accountantToken.methods
.mint(accounts[9], "1000000000000000000000")
.send({
from: accounts[0],
gas: 1000000,
});
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,11 +0,0 @@
const BridgeImplementation = artifacts.require("BridgeImplementation");
module.exports = async function(callback) {
try {
const bridge = (await BridgeImplementation.new());
console.log('tx: ' + bridge.transactionHash);
console.log('Bridge address: ' + bridge.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,11 +0,0 @@
const Shutdown = artifacts.require("BridgeShutdown");
module.exports = async function(callback) {
try {
const contract = (await Shutdown.new());
console.log('tx: ' + contract.transactionHash);
console.log('Bridge address: ' + contract.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,66 +0,0 @@
// run this script with truffle exec
const jsonfile = require("jsonfile");
const TokenBridge = artifacts.require("TokenBridge");
const NFTBridge = artifacts.require("NFTBridgeEntrypoint");
const BridgeImplementationFullABI = jsonfile.readFileSync(
"../build/contracts/BridgeImplementation.json"
).abi;
// The input parameter is a RegExp
// It returns an array of process.env variables satisfying the input RegExp
function getFilteredEnvs(regexp) {
const filteredEnvs = [];
for (const [key, value] of Object.entries(process.env)) {
if (regexp.test(key) && value) {
console.log("getFilteredEnvs: pushing " + key);
filteredEnvs.push(value);
}
}
return filteredEnvs;
}
module.exports = async function(callback) {
try {
const accounts = await web3.eth.getAccounts();
const tokenBridge = new web3.eth.Contract(
BridgeImplementationFullABI,
TokenBridge.address
);
const nftBridge = new web3.eth.Contract(
BridgeImplementationFullABI,
NFTBridge.address
);
const TokenBridgeRegExp = new RegExp("REGISTER_.*_TOKEN_BRIDGE_VAA");
const NFTBridgeRegExp = new RegExp("REGISTER_.*_NFT_BRIDGE_VAA");
const TokenBridgeVAAs = getFilteredEnvs(TokenBridgeRegExp);
const NFTBridgeVAAs = getFilteredEnvs(NFTBridgeRegExp);
// Register the token bridge endpoints
console.log("Registering " + TokenBridgeVAAs.length + " Token Bridges...");
for (const vaa of TokenBridgeVAAs) {
await tokenBridge.methods.registerChain("0x" + vaa).send({
value: 0,
from: accounts[0],
gasLimit: 2000000,
});
}
// Register the NFT bridge endpoints
console.log("Registering " + NFTBridgeVAAs.length + " NFT Bridges...");
for (const vaa of NFTBridgeVAAs) {
await nftBridge.methods.registerChain("0x" + vaa).send({
value: 0,
from: accounts[0],
gasLimit: 2000000,
});
}
console.log("Finished registering all Bridges...");
callback();
} catch (e) {
callback(e);
}
};

View File

@ -1,27 +0,0 @@
// run this script with truffle exec
const jsonfile = require("jsonfile");
const TokenBridge = artifacts.require("TokenBridge");
const TokenImplementation = artifacts.require("TokenImplementation");
const BridgeImplementationFullABI = jsonfile.readFileSync("../build/contracts/BridgeImplementation.json").abi
const ethTokenBridgeVAA = process.env.REGISTER_ETH_TOKEN_BRIDGE_VAA
module.exports = async function (callback) {
try {
const accounts = await web3.eth.getAccounts();
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, TokenBridge.address);
// Register the ETH endpoint
await initialized.methods.registerChain("0x" + ethTokenBridgeVAA).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
callback();
}
catch (e) {
callback(e);
}
}

View File

@ -1,29 +0,0 @@
const MockBatchedVAASender = artifacts.require("MockBatchedVAASender");
module.exports = async function(callback) {
try {
const accounts = await web3.eth.getAccounts();
const batchedSender = await MockBatchedVAASender.deployed()
const contract = new web3.eth.Contract(MockBatchedVAASender.abi, batchedSender.address);
const nonce = Math.round(Date.now() / 1000);
const nonceHex = nonce.toString(16)
const res = await contract.methods.sendMultipleMessages(
"0x" + nonceHex,
"0x1",
32
).send({
value: 0,
from: accounts[0]
});
console.log('sendMultipleMessages response', res)
callback();
} catch (e) {
callback(e);
}
};

View File

@ -116,25 +116,31 @@ case "$module" in
bridge|core)
MODULE=Core
if [[ $shutdown = true ]]; then
SCRIPT="scripts/deploy_core_bridge_shutdown.js"
SCRIPT="DeployCoreShutdown.s.sol:DeployCoreShutdown"
SOLFILE="DeployCoreShutdown.s.sol"
else
SCRIPT="scripts/deploy_core_bridge.js"
SCRIPT="DeployCoreImplementationOnly.s.sol:DeployCoreImplementationOnly"
SOLFILE="DeployCoreImplementationOnly.s.sol"
fi
;;
token_bridge)
MODULE=TokenBridge
if [[ $shutdown = true ]]; then
SCRIPT="scripts/deploy_token_bridge_shutdown.js"
SCRIPT="DeployTokenBridgeShutdown.s.sol:DeployTokenBridgeShutdown"
SOLFILE="DeployTokenBridgeShutdown.s.sol"
else
SCRIPT="scripts/deploy_token_bridge.js"
SCRIPT="DeployTokenBridgeImplementationOnly.s.sol:DeployTokenBridgeImplementationOnly"
SOLFILE="DeployTokenBridgeImplementationOnly.s.sol"
fi
;;
nft_bridge)
MODULE=NFTBridge
if [[ $shutdown = true ]]; then
SCRIPT="scripts/deploy_nft_bridge_shutdown.js"
SCRIPT="DeployNFTBridgeShutdown.s.sol:DeployNFTBridgeShutdown"
SOLFILE="DeployNFTBridgeShutdown.s.sol"
else
SCRIPT="scripts/deploy_nft_bridge.js"
SCRIPT="DeployNFTBridgeImplementationOnly.s.sol:DeployNFTBridgeImplementationOnly"
SOLFILE="DeployNFTBridgeImplementationOnly.s.sol"
fi
;;
*) echo "unknown module $module" >&2
@ -144,6 +150,8 @@ esac
CONTRACT=$(worm info contract mainnet "$chain_name" "$MODULE")
EVM_CHAIN_ID=$(printf "%d" $(curl http://localhost:8545/ -X POST -H "Content-Type: application/json" --data '{"method":"eth_chainId","params":[],"id":1,"jsonrpc":"2.0"}' -s | jq -r .result))
# Step 1) Figure out the contract address depending on the flags -- either use
# an address passed in as an argument, or use the most recent contract in the repo.
if [[ -n "$address" ]]; then
@ -154,8 +162,14 @@ else
build_output=$(npm run build) || ( echo "$build_output" && exit 1 )
fi
printf "⬆️ Deploying implementation..."
deploy_output=$(npx truffle exec $SCRIPT --network development) || ( echo "$deploy_output" && exit 1 )
new_implementation=$(echo "$deploy_output" | grep "address:" | cut -d' ' -f3)
forge script ./forge-scripts/${SCRIPT} \
--rpc-url "$RPC" \
--private-key "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" \
--broadcast \
--silent
returnInfo=$(cat ./broadcast/${SOLFILE}/$EVM_CHAIN_ID/run-latest.json)
# Extract the address values from 'returnInfo'
new_implementation=$(jq -r '.returns.deployedAddress.value' <<< "$returnInfo")
fi
printf " %s\n" "$new_implementation"

File diff suppressed because it is too large Load Diff

View File

@ -1,917 +0,0 @@
const jsonfile = require('jsonfile');
const elliptic = require('elliptic');
const BigNumber = require('bignumber.js');
const Wormhole = artifacts.require("Wormhole");
const NFTBridge = artifacts.require("NFTBridgeEntrypoint");
const NFTBridgeImplementation = artifacts.require("NFTBridgeImplementation");
const NFTImplementation = artifacts.require("NFTImplementation");
const MockBridgeImplementation = artifacts.require("MockNFTBridgeImplementation");
const testSigner1PK = "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0";
const testSigner2PK = "892330666a850761e7370376430bb8c2aa1494072d3bfeaed0c4fa3d5a9135fe";
const WormholeImplementationFullABI = jsonfile.readFileSync("build/contracts/Implementation.json").abi
const BridgeImplementationFullABI = jsonfile.readFileSync("build/contracts/NFTBridgeImplementation.json").abi
const NFTImplementationFullABI = jsonfile.readFileSync("build/contracts/NFTImplementation.json").abi
const actionContractUpgrade = "02"
const actionRecoverChainId = "03"
const fakeChainId = 1337;
const fakeEvmChainId = 10001;
let lastDeployed;
contract("NFT", function () {
const testSigner1 = web3.eth.accounts.privateKeyToAccount(testSigner1PK);
const testSigner2 = web3.eth.accounts.privateKeyToAccount(testSigner2PK);
const testChainId = "2";
const testEvmChainId = "1337";
const testFinality = "1";
const testGovernanceChainId = "1";
const testGovernanceContract = "0x0000000000000000000000000000000000000000000000000000000000000004";
let WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const testForeignChainId = "1";
const testForeignBridgeContract = "0x000000000000000000000000000000000000000000000000000000000000ffff";
const testBridgedAssetChain = "0003";
const testBridgedAssetAddress = "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e";
it("should be initialized with the correct signers and values", async function () {
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const tokenImplentation = await initialized.methods.tokenImplementation().call();
assert.equal(tokenImplentation, NFTImplementation.address);
// test beacon functionality
const beaconImplementation = await initialized.methods.implementation().call();
assert.equal(beaconImplementation, NFTImplementation.address);
// chain id
const chainId = await initialized.methods.chainId().call();
assert.equal(chainId, testChainId);
// evm chain id
const evmChainId = await initialized.methods.evmChainId().call();
assert.equal(evmChainId, testEvmChainId);
// finality
const finality = await initialized.methods.finality().call();
assert.equal(finality, testFinality);
// governance
const governanceChainId = await initialized.methods.governanceChainId().call();
assert.equal(governanceChainId, testGovernanceChainId);
const governanceContract = await initialized.methods.governanceContract().call();
assert.equal(governanceContract, testGovernanceContract);
})
it("should register a foreign bridge implementation correctly", async function () {
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const accounts = await web3.eth.getAccounts();
let data = [
"0x",
"00000000000000000000000000000000000000000000004e4654427269646765",
"01",
"0000",
web3.eth.abi.encodeParameter("uint16", testForeignChainId).substring(2 + (64 - 4)),
web3.eth.abi.encodeParameter("bytes32", testForeignBridgeContract).substring(2),
].join('')
const vm = await signAndEncodeVM(
1,
1,
testGovernanceChainId,
testGovernanceContract,
0,
data,
[
testSigner1PK
],
0,
0
);
let before = await initialized.methods.bridgeContracts(testForeignChainId).call();
assert.equal(before, "0x0000000000000000000000000000000000000000000000000000000000000000");
await initialized.methods.registerChain("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
let after = await initialized.methods.bridgeContracts(testForeignChainId).call();
assert.equal(after, testForeignBridgeContract);
})
it("should accept a valid upgrade", async function () {
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const accounts = await web3.eth.getAccounts();
const mock = await MockBridgeImplementation.new();
let data = [
"0x",
"00000000000000000000000000000000000000000000004e4654427269646765",
"02",
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)),
web3.eth.abi.encodeParameter("address", mock.address).substring(2),
].join('')
const vm = await signAndEncodeVM(
1,
1,
testGovernanceChainId,
testGovernanceContract,
0,
data,
[
testSigner1PK
],
0,
0
);
let before = await web3.eth.getStorageAt(NFTBridge.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(BigInt(before), BigInt(NFTBridgeImplementation.address));
await initialized.methods.upgrade("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
let after = await web3.eth.getStorageAt(NFTBridge.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(BigInt(after), BigInt(mock.address));
const mockImpl = new web3.eth.Contract(MockBridgeImplementation.abi, NFTBridge.address);
let isUpgraded = await mockImpl.methods.testNewImplementationActive().call();
assert.ok(isUpgraded);
lastDeployed = mock;
})
it("bridged tokens should only be mint- and burn-able by owner", async function () {
const accounts = await web3.eth.getAccounts();
// initialize our template token contract
const token = new web3.eth.Contract(NFTImplementation.abi, NFTImplementation.address);
await token.methods.initialize(
"TestToken",
"TT",
accounts[0],
0,
"0x0"
).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
await token.methods.mint(accounts[0], 10, "").send({
from: accounts[0],
gasLimit: 2000000
});
let failed = false
try {
await token.methods.mint(accounts[0], 11, "").send({
from: accounts[1],
gasLimit: 2000000
});
} catch (e) {
failed = true
}
assert.ok(failed)
failed = false
try {
await token.methods.burn(10).send({
from: accounts[1],
gasLimit: 2000000
});
} catch (e) {
failed = true
}
assert.ok(failed)
await token.methods.burn(10).send({
from: accounts[0],
gasLimit: 2000000
});
})
it("should deposit and log transfers correctly", async function () {
const accounts = await web3.eth.getAccounts();
const tokenId = "1000000000000000000";
// mint and approve tokens
const token = new web3.eth.Contract(NFTImplementation.abi, NFTImplementation.address);
await token.methods.mint(accounts[0], tokenId, "abcd").send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
await token.methods.approve(NFTBridge.address, tokenId).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
// deposit tokens
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const ownerBefore = await token.methods.ownerOf(tokenId).call();
assert.equal(ownerBefore, accounts[0]);
await initialized.methods.transferNFT(
NFTImplementation.address,
tokenId,
"10",
"0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
"234"
).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
const ownerAfter = await token.methods.ownerOf(tokenId).call();
assert.equal(ownerAfter, NFTBridge.address);
// check transfer log
const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
const log = (await wormhole.getPastEvents('LogMessagePublished', {
fromBlock: 'latest'
}))[0].returnValues
assert.equal(log.sender, NFTBridge.address)
assert.equal(log.payload.length - 2, 340);
// payload id
assert.equal(log.payload.substr(2, 2), "01");
// token
assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("address", NFTImplementation.address).substring(2));
// chain id
assert.equal(log.payload.substr(68, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
// symbol (TT)
assert.equal(log.payload.substr(72, 64), "5454000000000000000000000000000000000000000000000000000000000000")
// name (TestToken (Wormhole))
assert.equal(log.payload.substr(136, 64), "54657374546f6b656e0000000000000000000000000000000000000000000000")
// tokenID
assert.equal(log.payload.substr(200, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(tokenId).toString()).substring(2));
// url length
assert.equal(log.payload.substr(264, 2), web3.eth.abi.encodeParameter("uint8", 4).substring(2 + 64 - 2))
// url
assert.equal(log.payload.substr(266, 8), "61626364")
// to
assert.equal(log.payload.substr(274, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
// to chain id
assert.equal(log.payload.substr(338, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
})
it("should transfer out locked assets for a valid transfer vm", async function () {
const accounts = await web3.eth.getAccounts();
const tokenId = "1000000000000000000";
const token = new web3.eth.Contract(NFTImplementation.abi, NFTImplementation.address);
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const ownerBefore = await token.methods.ownerOf(tokenId).call();
assert.equal(ownerBefore, NFTBridge.address);
// PayloadID uint8 = 1
// // Address of the NFT. Left-zero-padded if shorter than 32 bytes
// NFTAddress [32]uint8
// // Chain ID of the NFT
// NFTChain uint16
// // Name of the NFT
// Name [32]uint8
// // Symbol of the NFT
// Symbol [10]uint8
// // ID of the token (big-endian uint256)
// TokenID [32]uint8
// // URL of the NFT
// URLLength u8
// URL [n]uint8
// // Address of the recipient. Left-zero-padded if shorter than 32 bytes
// To [32]uint8
// // Chain ID of the recipient
// ToChain uint16
const data = "0x" +
"01" +
// tokenaddress
web3.eth.abi.encodeParameter("address", NFTImplementation.address).substr(2) +
// tokenchain
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
// symbol
"0000000000000000000000000000000000000000000000000000000000000000" +
// name
"0000000000000000000000000000000000000000000000000000000000000000" +
// tokenID
web3.eth.abi.encodeParameter("uint256", new BigNumber(tokenId).toString()).substring(2) +
// url length
"00" +
// no URL
"" +
// receiver
web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
// receiving chain
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4));
const vm = await signAndEncodeVM(
0,
0,
testForeignChainId,
testForeignBridgeContract,
0,
data,
[
testSigner1PK
],
0,
0
);
await initialized.methods.completeTransfer("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
const ownerAfter = await token.methods.ownerOf(tokenId).call();
assert.equal(ownerAfter, accounts[0]);
})
it("should mint bridged assets wrappers on transfer from another chain and handle fees correctly", async function () {
const accounts = await web3.eth.getAccounts();
let tokenId = "1000000000000000001";
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
// we are using the asset where we created a wrapper in the previous test
let data = "0x" +
"01" +
// tokenaddress
testBridgedAssetAddress +
// tokenchain
testBridgedAssetChain +
// symbol
"464f520000000000000000000000000000000000000000000000000000000000" +
// name
"466f726569676e20436861696e204e4654000000000000000000000000000000" +
// tokenID
web3.eth.abi.encodeParameter("uint256", new BigNumber(tokenId).toString()).substring(2) +
// url length
"00" +
// no URL
"" +
// receiver
web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
// receiving chain
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4));
let vm = await signAndEncodeVM(
0,
0,
testForeignChainId,
testForeignBridgeContract,
0,
data,
[
testSigner1PK
],
0,
0
);
await initialized.methods.completeTransfer("0x" + vm).send({
value: 0,
from: accounts[1],
gasLimit: 2000000
});
const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
assert.ok(await initialized.methods.isWrappedAsset(wrappedAddress).call())
const wrappedAsset = new web3.eth.Contract(NFTImplementation.abi, wrappedAddress);
let ownerAfter = await wrappedAsset.methods.ownerOf(tokenId).call();
assert.equal(ownerAfter, accounts[0]);
const symbol = await wrappedAsset.methods.symbol().call();
assert.equal(symbol, "FOR");
const name = await wrappedAsset.methods.name().call();
assert.equal(name, "Foreign Chain NFT");
const chainId = await wrappedAsset.methods.chainId().call();
assert.equal(chainId, Number(testBridgedAssetChain));
const nativeContract = await wrappedAsset.methods.nativeContract().call();
assert.equal(nativeContract, "0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
// Transfer another tokenID of the same token address
tokenId = "1000000000000000002"
data = "0x" +
"01" +
// tokenaddress
testBridgedAssetAddress +
// tokenchain
testBridgedAssetChain +
// symbol
"464f520000000000000000000000000000000000000000000000000000000000" +
// name
"466f726569676e20436861696e204e4654000000000000000000000000000000" +
// tokenID
web3.eth.abi.encodeParameter("uint256", new BigNumber(tokenId + 1).toString()).substring(2) +
// url length
"00" +
// no URL
"" +
// receiver
web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
// receiving chain
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4));
vm = await signAndEncodeVM(
0,
0,
testForeignChainId,
testForeignBridgeContract,
1,
data,
[
testSigner1PK
],
0,
0
);
await initialized.methods.completeTransfer("0x" + vm).send({
value: 0,
from: accounts[1],
gasLimit: 2000000
});
ownerAfter = await wrappedAsset.methods.ownerOf(tokenId + 1).call();
assert.equal(ownerAfter, accounts[0]);
})
it("should mint bridged assets from solana under unified name, caching the original", async function () {
const accounts = await web3.eth.getAccounts();
let tokenId = "1000000000000000001";
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
// we are using the asset where we created a wrapper in the previous test
let data = "0x" +
"01" +
// tokenaddress
testBridgedAssetAddress +
// tokenchain
"0001" +
// symbol
"464f520000000000000000000000000000000000000000000000000000000000" +
// name
"466f726569676e20436861696e204e4654000000000000000000000000000000" +
// tokenID
web3.eth.abi.encodeParameter("uint256", new BigNumber(tokenId).toString()).substring(2) +
// url length
"00" +
// no URL
"" +
// receiver
web3.eth.abi.encodeParameter("address", accounts[0]).substr(2) +
// receiving chain
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4));
let vm = await signAndEncodeVM(
0,
0,
testForeignChainId,
testForeignBridgeContract,
0,
data,
[
testSigner1PK
],
0,
0
);
await initialized.methods.completeTransfer("0x" + vm).send({
value: 0,
from: accounts[1],
gasLimit: 2000000
});
const cache = await initialized.methods.splCache(tokenId).call()
assert.equal(cache.symbol, "0x464f520000000000000000000000000000000000000000000000000000000000");
assert.equal(cache.name, "0x466f726569676e20436861696e204e4654000000000000000000000000000000");
const wrappedAddress = await initialized.methods.wrappedAsset("0x0001", "0x" + testBridgedAssetAddress).call();
const wrappedAsset = new web3.eth.Contract(NFTImplementation.abi, wrappedAddress);
const symbol = await wrappedAsset.methods.symbol().call();
assert.equal(symbol, "WORMSPLNFT");
const name = await wrappedAsset.methods.name().call();
assert.equal(name, "Wormhole Bridged Solana-NFT");
})
it("cached SPL names are loaded when transferring out, cache is cleared", async function () {
const accounts = await web3.eth.getAccounts();
let tokenId = "1000000000000000001";
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const wrappedAddress = await initialized.methods.wrappedAsset("0x0001", "0x" + testBridgedAssetAddress).call();
const wrappedAsset = new web3.eth.Contract(NFTImplementation.abi, wrappedAddress);
await wrappedAsset.methods.approve(NFTBridge.address, tokenId).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
const transfer = await initialized.methods.transferNFT(
wrappedAddress,
tokenId,
"10",
"0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
"2345"
).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
// symbol
assert.ok(transfer.events[4].raw.data.includes('464f520000000000000000000000000000000000000000000000000000000000'))
// name
assert.ok(transfer.events[4].raw.data.includes('466f726569676e20436861696e204e4654000000000000000000000000000000'))
// check if cache is cleared
const cache = await initialized.methods.splCache(tokenId).call()
assert.equal(cache.symbol, "0x0000000000000000000000000000000000000000000000000000000000000000");
assert.equal(cache.name, "0x0000000000000000000000000000000000000000000000000000000000000000");
})
it("should should fail deposit unapproved NFTs", async function () {
const accounts = await web3.eth.getAccounts();
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const tokenId = "1000000000000000001";
const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
// deposit tokens
let failed = false
try {
await initialized.methods.transferNFT(
wrappedAddress,
tokenId,
"10",
"0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
"234"
).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
} catch (e) {
assert.include(e.message, "revert ERC721: transfer caller is not owner nor approved")
failed = true
}
assert.ok(failed)
})
it("should refuse to burn wrappers not held by msg.sender", async function () {
const accounts = await web3.eth.getAccounts();
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const tokenId = "1000000000000000001";
const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
const wrappedAsset = new web3.eth.Contract(NFTImplementation.abi, wrappedAddress);
// approve from 0
await wrappedAsset.methods.approve(NFTBridge.address, tokenId).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
// deposit tokens from 1
let failed = false
try {
await initialized.methods.transferNFT(
wrappedAddress,
tokenId,
"10",
"0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
"234"
).send({
value: 0,
from: accounts[1],
gasLimit: 2000000
});
} catch (e) {
assert.include(e.message, "revert ERC721: transfer of token that is not own")
failed = true
}
assert.ok(failed)
})
it("should deposit and burn approved bridged assets wrappers on transfer to another chain", async function () {
const accounts = await web3.eth.getAccounts();
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const tokenId = "1000000000000000001";
const wrappedAddress = await initialized.methods.wrappedAsset("0x" + testBridgedAssetChain, "0x" + testBridgedAssetAddress).call();
const wrappedAsset = new web3.eth.Contract(NFTImplementation.abi, wrappedAddress);
await wrappedAsset.methods.approve(NFTBridge.address, tokenId).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
// deposit tokens
const ownerBefore = await wrappedAsset.methods.ownerOf(tokenId).call();
assert.equal(ownerBefore, accounts[0]);
await initialized.methods.transferNFT(
wrappedAddress,
tokenId,
"10",
"0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
"234"
).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
try {
await wrappedAsset.methods.ownerOf(tokenId).call();
assert.fail("burned token still exists")
} catch (e) {
assert.include(e.message, "revert ERC721: owner query for nonexistent token")
}
})
it("should reject smart contract upgrades on forks", async function () {
const mockInitialized = new web3.eth.Contract(MockBridgeImplementation.abi, NFTBridge.address);
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const accounts = await web3.eth.getAccounts();
const mock = await MockBridgeImplementation.new();
const timestamp = 1000;
const nonce = 1001;
const emitterChainId = testGovernanceChainId;
const emitterAddress = testGovernanceContract
// simulate a fork
await mockInitialized.methods.testOverwriteEVMChainId(fakeChainId, fakeEvmChainId).send({
value: 0,
from: accounts[0],
gasLimit: 1000000
});
const chainId = await initialized.methods.chainId().call();
assert.equal(chainId, fakeChainId);
const evmChainId = await initialized.methods.evmChainId().call();
assert.equal(evmChainId, fakeEvmChainId);
data = [
"0x",
"00000000000000000000000000000000000000000000004e4654427269646765",
// Action 1 (Contract Upgrade)
actionContractUpgrade,
// ChainID
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)),
// New Contract Address
web3.eth.abi.encodeParameter("address", mock.address).substring(2),
].join('')
const vm = await signAndEncodeVM(
timestamp,
nonce,
emitterChainId,
emitterAddress,
0,
data,
[
testSigner1PK,
],
0,
0
);
try {
await initialized.methods.upgrade("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 1000000
});
assert.fail("governance packet accepted")
} catch (e) {
assert.include(e.message, "revert invalid fork")
}
})
it("should allow recover chain ID governance packets forks", async function () {
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const accounts = await web3.eth.getAccounts();
const timestamp = 1000;
const nonce = 1001;
const emitterChainId = testGovernanceChainId;
const emitterAddress = testGovernanceContract
const chainId = await initialized.methods.chainId().call();
assert.equal(chainId, fakeChainId);
const evmChainId = await initialized.methods.evmChainId().call();
assert.equal(evmChainId, fakeEvmChainId);
data = [
"0x",
"00000000000000000000000000000000000000000000004e4654427269646765",
// Action 3 (Recover Chain ID)
actionRecoverChainId,
// EvmChainID
web3.eth.abi.encodeParameter("uint256", testEvmChainId).substring(2),
// NewChainID
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)),
].join('')
const vm = await signAndEncodeVM(
timestamp,
nonce,
emitterChainId,
emitterAddress,
0,
data,
[
testSigner1PK,
],
0,
0
);
await initialized.methods.submitRecoverChainId("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 1000000
});
const newChainId = await initialized.methods.chainId().call();
assert.equal(newChainId, testChainId);
const newEvmChainId = await initialized.methods.evmChainId().call();
assert.equal(newEvmChainId, testEvmChainId);
})
it("should accept smart contract upgrades after chain ID has been recovered", async function () {
const initialized = new web3.eth.Contract(BridgeImplementationFullABI, NFTBridge.address);
const accounts = await web3.eth.getAccounts();
const mock = await MockBridgeImplementation.new();
const timestamp = 1000;
const nonce = 1001;
const emitterChainId = testGovernanceChainId;
const emitterAddress = testGovernanceContract
data = [
"0x",
"00000000000000000000000000000000000000000000004e4654427269646765",
// Action 2 (Contract Upgrade)
actionContractUpgrade,
// ChainID
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)),
// New Contract Address
web3.eth.abi.encodeParameter("address", mock.address).substring(2),
].join('')
const vm = await signAndEncodeVM(
timestamp,
nonce,
emitterChainId,
emitterAddress,
0,
data,
[
testSigner1PK,
],
0,
0
);
let before = await web3.eth.getStorageAt(NFTBridge.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(BigInt(before), BigInt(lastDeployed.address));
let set = await initialized.methods.upgrade("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 1000000
});
let after = await web3.eth.getStorageAt(NFTBridge.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(BigInt(after), BigInt(mock.address));
const mockImpl = new web3.eth.Contract(MockBridgeImplementation.abi, NFTBridge.address);
let isUpgraded = await mockImpl.methods.testNewImplementationActive().call();
assert.ok(isUpgraded);
})
});
const signAndEncodeVM = async function (
timestamp,
nonce,
emitterChainId,
emitterAddress,
sequence,
data,
signers,
guardianSetIndex,
consistencyLevel
) {
const body = [
web3.eth.abi.encodeParameter("uint32", timestamp).substring(2 + (64 - 8)),
web3.eth.abi.encodeParameter("uint32", nonce).substring(2 + (64 - 8)),
web3.eth.abi.encodeParameter("uint16", emitterChainId).substring(2 + (64 - 4)),
web3.eth.abi.encodeParameter("bytes32", emitterAddress).substring(2),
web3.eth.abi.encodeParameter("uint64", sequence).substring(2 + (64 - 16)),
web3.eth.abi.encodeParameter("uint8", consistencyLevel).substring(2 + (64 - 2)),
data.substr(2)
]
const hash = web3.utils.soliditySha3(web3.utils.soliditySha3("0x" + body.join("")))
let signatures = "";
for (let i in signers) {
const ec = new elliptic.ec("secp256k1");
const key = ec.keyFromPrivate(signers[i]);
const signature = key.sign(hash.substr(2), { canonical: true });
const packSig = [
web3.eth.abi.encodeParameter("uint8", i).substring(2 + (64 - 2)),
zeroPadBytes(signature.r.toString(16), 32),
zeroPadBytes(signature.s.toString(16), 32),
web3.eth.abi.encodeParameter("uint8", signature.recoveryParam).substr(2 + (64 - 2)),
]
signatures += packSig.join("")
}
const vm = [
web3.eth.abi.encodeParameter("uint8", 1).substring(2 + (64 - 2)),
web3.eth.abi.encodeParameter("uint32", guardianSetIndex).substring(2 + (64 - 8)),
web3.eth.abi.encodeParameter("uint8", signers.length).substring(2 + (64 - 2)),
signatures,
body.join("")
].join("");
return vm
}
function zeroPadBytes(value, length) {
while (value.length < 2 * length) {
value = "0" + value;
}
return value;
}

View File

@ -1,87 +0,0 @@
const jsonfile = require('jsonfile');
const BigNumber = require('bignumber.js');
const Migrator = artifacts.require("Migrator");
const TokenImplementation = artifacts.require("TokenImplementation");
contract("Migrator", function (accounts) {
var migrator,
fromToken,
toToken,
fromDecimals = 8,
toDecimals = 18;
it("should deploy with the correct values", async function () {
fromToken = await TokenImplementation.new();
await fromToken.initialize(
"TestFrom",
"FROM",
fromDecimals,
0,
accounts[0],
0,
"0x00"
)
toToken = await TokenImplementation.new();
await toToken.initialize(
"TestTo",
"TO",
toDecimals,
0,
accounts[0],
0,
"0x00"
)
migrator = await Migrator.new(
fromToken.address,
toToken.address,
);
assert.equal(await migrator.fromAsset(), fromToken.address)
assert.equal(await migrator.toAsset(), toToken.address)
assert.equal((await migrator.fromDecimals()).toNumber(), fromDecimals)
assert.equal((await migrator.toDecimals()).toNumber(), toDecimals)
})
it("should give out LP tokens 1:1 for a toToken deposit", async function () {
await toToken.mint(accounts[0], "1000000000000000000")
await toToken.approve(migrator.address, "1000000000000000000")
await migrator.add("1000000000000000000")
assert.equal((await toToken.balanceOf(migrator.address)).toString(), "1000000000000000000")
assert.equal((await migrator.balanceOf(accounts[0])).toString(), "1000000000000000000")
})
it("should refund toToken for LP tokens", async function () {
await migrator.remove("500000000000000000")
assert.equal((await toToken.balanceOf(migrator.address)).toString(), "500000000000000000")
assert.equal((await toToken.balanceOf(accounts[0])).toString(), "500000000000000000")
assert.equal((await migrator.balanceOf(accounts[0])).toString(), "500000000000000000")
})
it("should redeem fromToken to toToken adjusting for decimals", async function () {
await fromToken.mint(accounts[1], "50000000")
await fromToken.approve(migrator.address, "50000000", {
from : accounts[1]
})
await migrator.migrate("50000000", {
from : accounts[1]
})
assert.equal((await toToken.balanceOf(accounts[1])).toString(), "500000000000000000")
assert.equal((await fromToken.balanceOf(accounts[1])).toString(), "0")
assert.equal((await fromToken.balanceOf(migrator.address)).toString(), "50000000")
assert.equal((await toToken.balanceOf(migrator.address)).toString(), "0")
})
it("fromToken should be claimable for LP tokens, adjusting for decimals", async function () {
await migrator.claim("500000000000000000")
assert.equal((await fromToken.balanceOf(migrator.address)).toString(), "0")
assert.equal((await fromToken.balanceOf(accounts[0])).toString(), "50000000")
assert.equal((await migrator.balanceOf(accounts[0])).toString(), "0")
})
})

View File

@ -1,418 +0,0 @@
const jsonfile = require('jsonfile');
const elliptic = require('elliptic');
const BigNumber = require('bignumber.js');
const Wormhole = artifacts.require("Wormhole");
const TokenBridge = artifacts.require("TokenBridge");
const BridgeSetup = artifacts.require("BridgeSetup");
const BridgeImplementation = artifacts.require("BridgeImplementation");
const MockBridgeImplementation = artifacts.require("MockBridgeImplementation");
const TokenImplementation = artifacts.require("TokenImplementation");
const FeeToken = artifacts.require("FeeToken");
const testSigner1PK = "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0";
const WormholeImplementationFullABI = jsonfile.readFileSync("build/contracts/Implementation.json").abi
const BridgeImplementationFullABI = jsonfile.readFileSync("build/contracts/BridgeImplementation.json").abi
// needs to run on a mainnet fork
contract("Update Bridge", function (accounts) {
if (config.network === "test") return;
const testChainId = "2";
const testEvmChainId = "1";
const testGovernanceChainId = "1";
const testGovernanceContract = "0x0000000000000000000000000000000000000000000000000000000000000004";
let WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const testForeignChainId = "1";
const testForeignBridgeContract = "0x000000000000000000000000000000000000000000000000000000000000ffff";
const testFinality = 15;
const currentImplementation = "0x6c4c12987303b2c94b2C76c612Fc5F4D2F0360F7";
let bridgeProxy;
it("create bridge instance with current implementation", async function () {
// encode initialisation data
const setup = new web3.eth.Contract(BridgeSetup.abi, BridgeSetup.address);
const initData = setup.methods.setup(
currentImplementation,
testChainId,
(await Wormhole.deployed()).address,
testGovernanceChainId,
testGovernanceContract,
TokenImplementation.address,
WETH,
testFinality,
testEvmChainId
).encodeABI();
const deploy = await TokenBridge.new(BridgeSetup.address, initData);
bridgeProxy = new web3.eth.Contract(BridgeImplementationFullABI, deploy.address);
})
it("register a foreign bridge implementation", async function () {
let data = [
"0x",
"000000000000000000000000000000000000000000546f6b656e427269646765",
"01",
"0000",
web3.eth.abi.encodeParameter("uint16", testForeignChainId).substring(2 + (64 - 4)),
web3.eth.abi.encodeParameter("bytes32", testForeignBridgeContract).substring(2),
].join('')
const vm = await signAndEncodeVM(
1,
1,
testGovernanceChainId,
testGovernanceContract,
0,
data,
[
testSigner1PK
],
0,
0
);
let before = await bridgeProxy.methods.bridgeContracts(testForeignChainId).call();
assert.equal(before, "0x0000000000000000000000000000000000000000000000000000000000000000");
await bridgeProxy.methods.registerChain("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
let after = await bridgeProxy.methods.bridgeContracts(testForeignChainId).call();
assert.equal(after, testForeignBridgeContract);
})
it("mimic previous deposits (deposit some ETH)", async function () {
const amount = "100000000000000000";
const fee = "10000000000000000";
await bridgeProxy.methods.wrapAndTransferETH(
"10",
"0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
fee,
"234"
).send({
value: amount,
from: accounts[0],
gasLimit: 2000000
});
// check transfer log
const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
const log = (await wormhole.getPastEvents('LogMessagePublished', {
fromBlock: 'latest'
}))[0].returnValues
assert.equal(log.payload.length - 2, 266);
// payload id
assert.equal(log.payload.substr(2, 2), "01");
// amount
assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2));
// token
assert.equal(log.payload.substr(68, 64), web3.eth.abi.encodeParameter("address", WETH).substring(2));
// chain id
assert.equal(log.payload.substr(132, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
// to
assert.equal(log.payload.substr(136, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
// to chain id
assert.equal(log.payload.substr(200, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
// fee
assert.equal(log.payload.substr(204, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).div(1e10).toString()).substring(2))
})
let upgradeDeployedAt;
it("apply upgrade", async function () {
const deploy = await BridgeImplementation.new();
upgradeDeployedAt = deploy.address;
let data = [
"0x",
"000000000000000000000000000000000000000000546f6b656e427269646765",
"02",
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)),
web3.eth.abi.encodeParameter("address", deploy.address).substring(2),
].join('')
const vm = await signAndEncodeVM(
1,
1,
testGovernanceChainId,
testGovernanceContract,
0,
data,
[
testSigner1PK
],
0,
0
);
let before = await web3.eth.getStorageAt(bridgeProxy.options.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(before.toLowerCase(), currentImplementation.toLowerCase());
await bridgeProxy.methods.upgrade("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
let after = await web3.eth.getStorageAt(bridgeProxy.options.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(after.toLowerCase(), deploy.address.toLowerCase());
})
it("test withdrawing existing assets (deposited ETH)", async function () {
const amount = "100000000000000000";
const accountBalanceBefore = await web3.eth.getBalance(accounts[1]);
// we are using the asset where we created a wrapper in the previous test
const data = "0x" +
"01" +
// amount
web3.eth.abi.encodeParameter("uint256", new BigNumber(amount).div(1e10).toString()).substring(2) +
// tokenaddress
web3.eth.abi.encodeParameter("address", WETH).substr(2) +
// tokenchain
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
// receiver
web3.eth.abi.encodeParameter("address", accounts[1]).substr(2) +
// receiving chain
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)) +
// fee
web3.eth.abi.encodeParameter("uint256", 0).substring(2);
const vm = await signAndEncodeVM(
0,
0,
testForeignChainId,
testForeignBridgeContract,
0,
data,
[
testSigner1PK
],
0,
0
);
const transferTX = await bridgeProxy.methods.completeTransferAndUnwrapETH("0x" + vm).send({
from: accounts[0],
gasLimit: 2000000
});
const accountBalanceAfter = await web3.eth.getBalance(accounts[1]);
assert.equal((new BigNumber(accountBalanceAfter)).minus(accountBalanceBefore).toString(10), (new BigNumber(amount)).toString(10))
})
it("test new functionality (fee token transfers)", async function () {
const accounts = await web3.eth.getAccounts();
const mintAmount = "10000000000000000000";
const amount = "1000000000000000000";
const fee = "100000000000000000";
// mint and approve tokens
const deployFeeToken = await FeeToken.new();
const token = new web3.eth.Contract(FeeToken.abi, deployFeeToken.address);
await token.methods.initialize(
"Test",
"TST",
"18",
"123",
accounts[0],
"0",
"0x0000000000000000000000000000000000000000000000000000000000000000"
).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
await token.methods.mint(accounts[0], mintAmount).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
await token.methods.approve(bridgeProxy.options.address, mintAmount).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
const bridgeBalanceBefore = await token.methods.balanceOf(bridgeProxy.options.address).call();
assert.equal(bridgeBalanceBefore.toString(10), "0");
await bridgeProxy.methods.transferTokens(
deployFeeToken.address,
amount,
"10",
"0x000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e",
fee,
"234"
).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
const bridgeBalanceAfter = await token.methods.balanceOf(bridgeProxy.options.address).call();
let feeAmount = new BigNumber(amount).times(9).div(10)
assert.equal(bridgeBalanceAfter.toString(10), feeAmount);
// check transfer log
const wormhole = new web3.eth.Contract(WormholeImplementationFullABI, Wormhole.address);
const log = (await wormhole.getPastEvents('LogMessagePublished', {
fromBlock: 'latest'
}))[0].returnValues
assert.equal(log.sender, bridgeProxy.options.address)
assert.equal(log.payload.length - 2, 266);
// payload id
assert.equal(log.payload.substr(2, 2), "01");
// amount
assert.equal(log.payload.substr(4, 64), web3.eth.abi.encodeParameter("uint256", feeAmount.div(1e10).toString()).substring(2));
// token
assert.equal(log.payload.substr(68, 64), web3.eth.abi.encodeParameter("address", deployFeeToken.address).substring(2));
// chain id
assert.equal(log.payload.substr(132, 4), web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + 64 - 4))
// to
assert.equal(log.payload.substr(136, 64), "000000000000000000000000b7a2211e8165943192ad04f5dd21bedc29ff003e");
// to chain id
assert.equal(log.payload.substr(200, 4), web3.eth.abi.encodeParameter("uint16", 10).substring(2 + 64 - 4))
// fee
assert.equal(log.payload.substr(204, 64), web3.eth.abi.encodeParameter("uint256", new BigNumber(fee).div(1e10).toString()).substring(2))
})
it("should accept a further upgrade", async function () {
const mock = await MockBridgeImplementation.new();
let data = [
"0x",
"000000000000000000000000000000000000000000546f6b656e427269646765",
"02",
web3.eth.abi.encodeParameter("uint16", testChainId).substring(2 + (64 - 4)),
web3.eth.abi.encodeParameter("address", mock.address).substring(2),
].join('')
const vm = await signAndEncodeVM(
1,
1,
testGovernanceChainId,
testGovernanceContract,
0,
data,
[
testSigner1PK
],
0,
0
);
let before = await web3.eth.getStorageAt(bridgeProxy.options.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(before.toLowerCase(), upgradeDeployedAt.toLowerCase());
await bridgeProxy.methods.upgrade("0x" + vm).send({
value: 0,
from: accounts[0],
gasLimit: 2000000
});
let after = await web3.eth.getStorageAt(bridgeProxy.options.address, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
assert.equal(after.toLowerCase(), mock.address.toLowerCase());
const mockImpl = new web3.eth.Contract(MockBridgeImplementation.abi, bridgeProxy.options.address);
let isUpgraded = await mockImpl.methods.testNewImplementationActive().call();
assert.ok(isUpgraded);
})
});
const signAndEncodeVM = async function (
timestamp,
nonce,
emitterChainId,
emitterAddress,
sequence,
data,
signers,
guardianSetIndex,
consistencyLevel
) {
const body = [
web3.eth.abi.encodeParameter("uint32", timestamp).substring(2 + (64 - 8)),
web3.eth.abi.encodeParameter("uint32", nonce).substring(2 + (64 - 8)),
web3.eth.abi.encodeParameter("uint16", emitterChainId).substring(2 + (64 - 4)),
web3.eth.abi.encodeParameter("bytes32", emitterAddress).substring(2),
web3.eth.abi.encodeParameter("uint64", sequence).substring(2 + (64 - 16)),
web3.eth.abi.encodeParameter("uint8", consistencyLevel).substring(2 + (64 - 2)),
data.substr(2)
]
const hash = web3.utils.soliditySha3(web3.utils.soliditySha3("0x" + body.join("")))
let signatures = "";
for (let i in signers) {
const ec = new elliptic.ec("secp256k1");
const key = ec.keyFromPrivate(signers[i]);
const signature = key.sign(hash.substr(2), {canonical: true});
const packSig = [
web3.eth.abi.encodeParameter("uint8", i).substring(2 + (64 - 2)),
zeroPadBytes(signature.r.toString(16), 32),
zeroPadBytes(signature.s.toString(16), 32),
web3.eth.abi.encodeParameter("uint8", signature.recoveryParam).substr(2 + (64 - 2)),
]
signatures += packSig.join("")
}
const vm = [
web3.eth.abi.encodeParameter("uint8", 1).substring(2 + (64 - 2)),
web3.eth.abi.encodeParameter("uint32", guardianSetIndex).substring(2 + (64 - 8)),
web3.eth.abi.encodeParameter("uint8", signers.length).substring(2 + (64 - 2)),
signatures,
body.join("")
].join("");
return vm
}
function zeroPadBytes(value, length) {
while (value.length < 2 * length) {
value = "0" + value;
}
return value;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,493 +0,0 @@
require("dotenv").config({ path: ".env" });
const HDWalletProvider = require("@truffle/hdwallet-provider");
const KLAYHDWalletProvider = require("truffle-hdwallet-provider-klaytn");
module.exports = {
contracts_directory:
"contracts/{*.sol,bridge/{*.sol,interfaces/*.sol,token/*.sol,mock/*.sol,utils/*.sol},interfaces/IWormhole.sol,mock/*.sol,nft/{*.sol,interfaces/*.sol,token/*.sol,mock/*.sol}}",
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*",
},
// test network is the same as development but allows us to omit certain migrations
test: {
host: "127.0.0.1",
port: 8545,
network_id: "*",
},
ethereum: {
provider: () =>
new HDWalletProvider(process.env.MNEMONIC, "https://rpc.ankr.com/eth"),
network_id: 1,
confirmations: 1,
timeoutBlocks: 200,
skipDryRun: false,
},
rinkeby: {
provider: () =>
new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ankr.com/eth_rinkeby"
),
network_id: 4,
gas: 5500000,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true,
},
ethereum_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ankr.com/eth_goerli"
);
},
network_id: "5",
},
bsc: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://bsc-dataseed.binance.org/"
);
},
network_id: "56",
gas: 70000000,
gasPrice: 8000000000,
},
bsc_testnet: {
provider: () =>
new HDWalletProvider(
process.env.MNEMONIC,
"https://data-seed-prebsc-1-s1.binance.org:8545/"
),
network_id: "97",
},
polygon: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://polygon-rpc.com"
);
},
network_id: "137",
gas: 10000000,
gasPrice: 700000000000,
},
polygon_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ankr.com/polygon_mumbai"
);
},
network_id: "80001",
},
polygon_sepolia_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc-amoy.polygon.technology/"
);
},
network_id: "80002",
},
avalanche: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://api.avax.network/ext/bc/C/rpc"
);
},
network_id: "43114",
gas: 8000000,
gasPrice: 26000000000,
},
avalanche_testnet: {
provider: () =>
new HDWalletProvider(
process.env.MNEMONIC,
"https://api.avax-test.network/ext/bc/C/rpc"
),
network_id: "43113",
},
oasis: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://emerald.oasis.dev/"
);
},
network_id: 42262,
},
oasis_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://testnet.emerald.oasis.dev"
);
},
network_id: 42261,
},
aurora: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://mainnet.aurora.dev"
);
},
network_id: 0x4e454152,
from: "0xE2e2d9E31d7e1CC1178Fe0d1c5950f6C809816a3",
},
aurora_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://testnet.aurora.dev"
);
},
network_id: 0x4e454153,
gas: 10000000,
from: "0x8F26A0025dcCc6Cfc07A7d38756280a10E295ad7", // public key
},
fantom: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ftm.tools/"
);
},
network_id: 250,
gas: 8000000,
gasPrice: 3000000000000,
timeoutBlocks: 15000,
},
fantom_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.testnet.fantom.network/"
);
},
network_id: 0xfa2,
},
karura: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
// NOTE: To use this local host, needed to run this: ENDPOINT_URL=wss://karura-rpc-1.aca-api.network npx @acala-network/eth-rpc-adapter@latest
// "http://localhost:8545"
"https://eth-rpc-karura.aca-api.network/"
);
},
network_id: 686,
// NOTE: run ./karura-gas-prices and update the following two values, otherwise the transactions will likely fail
gasPrice: "0x2fad8f03ea",
gasLimit: "0x329b140",
gas: "0x329b140",
},
karura_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://eth-rpc-karura-testnet.aca-staging.network"
);
},
network_id: 596,
gasPrice: "0x3006b003ea",
gasLimit: "0x329b140",
gas: "0x329b0dc",
},
acala: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
// To use this local host, needed to run this: ENDPOINT_URL=wss://acala-rpc-0.aca-api.network npx @acala-network/eth-rpc-adapter@latest
//"http://localhost:8545"
"https://eth-rpc-acala.aca-api.network/"
);
},
network_id: 787,
gasPrice: "0x33a70303ea",
gasLimit: "0x6fc3540",
gas: "0x6fc3400",
},
acala_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://eth-rpc-acala-testnet.aca-staging.network"
);
},
network_id: 597,
gasPrice: "0x33a70303ea", // Query for gas parameters.
gas: "0x6fc3540", // This is the value reported as "gasLimit" in the query.
},
klaytn: {
// Note that Klaytn works with version 5.3.14 of truffle, but not some of the newer versions.
provider: () => {
return new KLAYHDWalletProvider(
process.env.MNEMONIC,
"https://public-node-api.klaytnapi.com/v1/cypress"
);
},
network_id: "8217", //Klaytn mainnet's network id
gas: "8500000",
gasPrice: null,
},
klaytn_testnet: {
// Note that Klaytn works with version 5.3.14 of truffle, but not some of the newer versions.
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://api.baobab.klaytn.net:8651/"
);
},
network_id: "1001",
gas: "8500000",
gasPrice: null,
},
celo: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://forno.celo.org"
);
},
network_id: 42220,
gas: 8000000,
gasPrice: null,
},
celo_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://alfajores-forno.celo-testnet.org"
);
},
network_id: 44787,
},
moonbeam: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.api.moonbeam.network"
//"https://moonbeam.api.onfinality.io/public" // When the core was deployed on 7/21/2022, the one above kept timing out but this one worked.
);
},
network_id: 1284,
},
moonbeam_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.api.moonbase.moonbeam.network"
);
},
network_id: 1287,
gasPrice: 3000000000, // 3.0 gwei
timeoutBlocks: 15000,
},
neon_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://proxy.devnet.neonlabs.org/solana"
);
},
network_id: "*",
gas: 3000000000,
gasPrice: 443065000000,
},
arbitrum: {
// Note that arbitrum did not work with our standard version of truffle (5.3.14), but it did work with the latest (5.5.22)
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://arb1.arbitrum.io/rpc"
);
},
network_id: 42161,
},
arbitrum_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://goerli-rollup.arbitrum.io/rpc"
);
},
network_id: 421613,
},
arbitrum_sepolia_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://arbitrum-sepolia.publicnode.com"
//"https://sepolia-rollup.arbitrum.io/rpc" // This didn't work.
);
},
network_id: 421614,
},
optimism: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://mainnet.optimism.io"
);
},
network_id: 10,
},
optimism_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ankr.com/optimism_testnet"
// "https://goerli.optimism.io" <== This didn't work for testnet
);
},
network_id: 420,
},
optimism_sepolia_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ankr.com/optimism_sepolia"
// "https://sepolia.optimism.io/" <== This didn't work for testnet
);
},
network_id: 11155420,
},
gnosis: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.gnosischain.com/"
);
},
network_id: 100,
},
gnosis_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://sokol.poa.network/"
);
},
network_id: 77,
},
base: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://developer-access-mainnet.base.org"
);
},
network_id: 8453,
},
base_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://goerli.base.org"
);
},
network_id: 84531,
},
base_sepolia_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://sepolia.base.org"
);
},
network_id: 84532,
},
scroll_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://sepolia-rpc.scroll.io"
);
},
network_id: 534351,
},
mantle_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.sepolia.mantle.xyz"
);
},
network_id: 5003,
gasPrice: 2520000000,
},
blast_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://blast-sepolia.drpc.org"
// "https://sepolia.blast.io" // This didn't work.
);
},
network_id: 168587773,
gasPrice: 2500000000,
},
rootstock: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://public-node.rsk.co"
);
},
network_id: 30,
},
rootstock_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://public-node.testnet.rsk.co"
);
},
network_id: 31,
},
sepolia_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ankr.com/eth_sepolia"
);
},
network_id: "11155111",
},
holesky_testnet: {
provider: () => {
return new HDWalletProvider(
process.env.MNEMONIC,
"https://rpc.ankr.com/eth_holesky"
);
},
network_id: "17000",
},
},
compilers: {
solc: {
version: "0.8.4",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
viaIR: false,
},
},
},
plugins: ["@chainsafe/truffle-plugin-abigen", "truffle-plugin-verify"],
api_keys: {
etherscan: process.env.ETHERSCAN_KEY,
},
};

View File

@ -1,57 +0,0 @@
--- node_modules/truffle-plugin-verify/contants-old.js 2022-01-28 12:44:53.140709519 +0000
+++ node_modules/truffle-plugin-verify/constants.js 2022-01-28 12:45:16.800710171 +0000
@@ -3,13 +3,25 @@
3: 'https://api-ropsten.etherscan.io/api',
4: 'https://api-rinkeby.etherscan.io/api',
5: 'https://api-goerli.etherscan.io/api',
+ 10: 'https://api-optimistic.etherscan.io/api',
42: 'https://api-kovan.etherscan.io/api',
56: 'https://api.bscscan.com/api',
+ 69: 'https://api-kovan-optimistic.etherscan.io/api',
97: 'https://api-testnet.bscscan.com/api',
128: 'https://api.hecoinfo.com/api',
137: 'https://api.polygonscan.com/api',
250: 'https://api.ftmscan.com/api',
256: 'https://api-testnet.hecoinfo.com/api',
+ 1284: 'https://api-moonbeam.moonscan.io/api',
+ 1285: 'https://api-moonriver.moonscan.io/api',
+ 1287: 'https://api-moonbase.moonscan.io/api',
+ 4002: 'https://api-testnet.ftmscan.com/api',
+ 42161: 'https://api.arbiscan.io/api',
+ 43113: 'https://api-testnet.snowtrace.io/api',
+ 43114: 'https://api.snowtrace.io/api',
+ 421611: 'https://api-testnet.arbiscan.io/api',
+ 1313161554: 'https://api.aurorascan.dev/api',
+ 1313161555: 'https://api-testnet.aurorascan.dev/api',
80001: 'https://api-testnet.polygonscan.com/api'
}
@@ -18,16 +28,27 @@
3: 'https://ropsten.etherscan.io/address',
4: 'https://rinkeby.etherscan.io/address',
5: 'https://goerli.etherscan.io/address',
+ 10: 'https://optimistic.etherscan.io/address',
42: 'https://kovan.etherscan.io/address',
56: 'https://bscscan.com/address',
+ 69: 'https://kovan-optimistic.etherscan.io/address',
97: 'https://testnet.bscscan.com/address',
128: 'https://hecoinfo.com/address',
137: 'https://polygonscan.com/address',
250: 'https://ftmscan.com/address',
256: 'https://testnet.hecoinfo.com/address',
+ 1284: 'https://moonbeam.moonscan.io/address',
+ 1285: 'https://moonriver.moonscan.io/address',
+ 1287: 'https://moonbase.moonscan.io/address',
+ 4002: 'https://testnet.ftmscan.com/address',
+ 42161: 'https://arbiscan.io/address',
+ 43113: 'https://testnet.snowtrace.io/address',
+ 43114: 'https://snowtrace.io/address',
+ 421611: 'https://testnet.arbiscan.io/address',
+ 1313161554: 'https://aurorascan.dev/address',
+ 1313161555: 'https://testnet.aurorascan.dev/address',
80001: 'https://mumbai.polygonscan.com/address'
}
-
const RequestStatus = {
OK: '1',
NOTOK: '0'

View File

@ -1,14 +0,0 @@
{
"compilerOptions": {
"types": ["mocha", "chai", "node"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2020"],
"skipLibCheck": true,
"module": "CommonJS",
"target": "es2020",
"esModuleInterop": true,
"strict": true,
"resolveJsonModule": true,
"moduleResolution": "node"
}
}

View File

@ -1,82 +0,0 @@
#!/bin/bash
set -euo pipefail
network=$1
module=$2
chain=$3
secret=$MNEMONIC
guardian_secret=""
if [ "$network" = testnet ]; then
guardian_secret=$GUARDIAN_MNEMONIC
fi
SCRIPT=""
verify_module=""
case "$module" in
Core)
SCRIPT="scripts/deploy_core_bridge.js"
FILE="build/contracts/Implementation.json"
verify_module="core"
;;
TokenBridge)
SCRIPT="scripts/deploy_token_bridge.js"
FILE="build/contracts/BridgeImplementation.json"
verify_module="token_bridge"
;;
NFTBridge)
SCRIPT="scripts/deploy_nft_bridge.js"
FILE="build/contracts/NFTBridgeImplementation.json"
verify_module="nft_bridge"
;;
*) echo "unknown module $module" >&2
;;
esac
# TODO: add option to not compile (but compile by default)
truffle_network=""
case "$network" in
mainnet)
truffle_network="$chain"
;;
testnet)
truffle_network="$chain"_testnet
esac
ret=0
implementation=$(worm evm info -c "$chain" -m "$module" -n "$network" -i 2>/dev/null) || ret=$?
if [ $ret != 0 ]; then
printf "☐ %s %s: skipping (no deployment available)\n" "$chain" "$module"
exit 1
fi
ret=0
(./verify -n "$network" -c "$chain" $FILE "$implementation" > /dev/null) || ret=$?
if [ $ret = 0 ]; then
printf "✔ %s %s: skipping (implementation matches same bytecode)\n" "$chain" "$module"
exit
fi
deploy_output=$(npx truffle exec $SCRIPT --network "$truffle_network") || ( echo "✘ $chain $module: $deploy_output" && exit 1 )
new_implementation=$(echo "$deploy_output" | grep "address:" | cut -d' ' -f3)
ret=0
(./verify -n "$network" -c "$chain" $FILE "$new_implementation" > /dev/null) || ret=$?
if [ $ret = 0 ]; then
printf "✔ %s %s: deployed (%s)\n" "$chain" "$module" "$new_implementation"
else
printf "✘ %s %s: deployed (%s) but failed to match bytecode\n" "$chain" "$module" "$new_implementation"
exit 1
fi
if [ "$network" = testnet ]; then
worm submit $(worm generate upgrade -c "$chain" -a "$new_implementation" -m "$module" -g "$guardian_secret") -n "$network"
else
echo "./scripts/contract-upgrade-governance.sh -c $chain -m $verify_module -a $new_implementation"
fi

View File

@ -8,6 +8,6 @@ chains=$(worm evm chains)
for module in ${modules[@]}; do
for chain in ${chains[@]}; do
./upgrade "$network" "$module" "$chain"
./sh/upgrade.sh "$network" "$module" "$chain"
done
done

View File

@ -16,6 +16,7 @@ remappings = [
'@solidity-parser/=node_modules/@solidity-parser/',
'ds-test/=lib/forge-std/lib/ds-test/src/',
'forge-std/=lib/forge-std/src/',
'truffle/=node_modules/truffle/',
]
[fmt]

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,8 @@
{
"name": "@wormhole-foundation/contracts-ethereum-relayer",
"version": "0.0.1",
"description": "",
"main": "networks.js",
"devDependencies": {
"@chainsafe/truffle-plugin-abigen": "0.0.1",
"@openzeppelin/cli": "^2.8.2",
"@openzeppelin/contracts": "^4.3.1",
"@truffle/hdwallet-provider": "^1.7.0",
"chai": "^4.3.7",
"mocha": "^8.4.0",
"truffle": "5.8.4",
"truffle-flattener": "^1.6.0",
"truffle-plugin-verify": "^0.5.11",
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
},
@ -24,15 +14,13 @@
"deploy-relayers-evm2": "ENV=kubernetes CONTAINER=evm2 bash ./ts-scripts/relayer/shell/deployInContainer.sh",
"typecheck": "tsc --noEmit --skipLibCheck"
},
"author": "",
"license": "ISC",
"license": "Apache-2.0",
"dependencies": {
"@certusone/wormhole-sdk": "^0.9.11",
"@typechain/ethers-v5": "^10.2.0",
"dotenv": "^10.0.0",
"elliptic": "^6.5.2",
"jsonfile": "^4.0.0",
"truffle-hdwallet-provider-klaytn": "^1.4.2",
"js-sha3": "^0.8.0",
"typechain": "^8.1.1"
}
}

8458
sdk/js/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -60,7 +60,6 @@
"ethers": "^5.6.8",
"jest": "^27.3.1",
"prettier": "^2.3.2",
"truffle": "^5.7.2",
"ts-jest": "^27.0.7",
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0",
@ -87,6 +86,7 @@
"bs58": "^4.0.1",
"elliptic": "^6.5.4",
"js-base64": "^3.6.1",
"js-sha3": "0.8.0",
"near-api-js": "^1.0.0"
},
"optionalDependencies": {