added tokenbridge code

This commit is contained in:
spacemandev 2022-06-28 23:27:31 -05:00
parent 6af7b63a24
commit 5541f5f2a9
19 changed files with 8483 additions and 0 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "projects/messenger/chains/evm/lib/forge-std"]
path = projects/messenger/chains/evm/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "projects/evm-tokenbridge/chains/evm/lib/openzeppelin-contracts"]
path = projects/evm-tokenbridge/chains/evm/lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts

3
projects/evm-tokenbridge/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules/
wormhole/
deployment.json

View File

@ -0,0 +1,25 @@
# EVM Messenger
Simple messenger project that sends a "Hello World" message between two EVM chains using Wormhole.
## Dependencies
This project uses Foundry to compile and deploy EVM contracts. You can find install instructions at [`https://getfoundry.sh`](http://getfoundry.sh)
The javascript dependencies can be installed via `npm install` in this folder.
You will also need Docker; you can get either [Docker Desktop](https://docs.docker.com/get-docker/) if you're developing on your computer or if you're in a headless vm, install [Docker Engine](https://docs.docker.com/engine/)
## Run Guardiand
After you have the dependencies installed, we'll need to spin up the EVM chains, deploy the Wormhole contracts to them, then startup a Wormhole Guardian to observe and sign VAAs. We have provided a script to automate this all for you.
Simply run `npm run guardiand` and wait while the Wormhole Guardian builds a docker image. The first time you run this command, it might take a while (up to 550 seconds on a modern laptop!). After the image is built however, it'll be relatively fast to bring it up and down.
## Test Scripts
After you have Guardiand running, you can run the basic test with `npm run test`. This will:
- Deploy a simple Messenger contract (found in chains/evm/src/Messenger.sol) to each EVM chain
- Register each contract with the other chain
- Send a message from each contract
- Fetch the VAA from the Guardian
- Submit the VAA to each contract
- Print out the Message
If everything goes correctly, you should get a printout with the Hello World messages on each chain.

View File

View File

@ -0,0 +1,3 @@
cache/
out/
!src/Wormhole/

View File

@ -0,0 +1,7 @@
[default]
src = 'src'
out = 'out'
libs = ['lib']
solc_version = '0.8.10'
# See more config options https://github.com/foundry-rs/foundry/tree/master/config

@ -0,0 +1 @@
Subproject commit e734b42fc2245b520372bca0099870f40f1e6f38

View File

@ -0,0 +1 @@
@openzeppelin/=lib/openzeppelin-contracts

View File

@ -0,0 +1,53 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
//If the below line shows an error, ignore it, it's cause you're root folder is not chains/evm.
import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol";
import "./Wormhole/ITokenBridge.sol";
import "./Wormhole/PortalWrappedToken.sol";
contract Treasury {
address private token_bridge_address = address(0x0290FB167208Af455bB137780163b7B7a9a10C16);
ITokenBridge token_bridge = ITokenBridge(token_bridge_address);
address private TKN_address = address(0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A);
ERC20PresetMinterPauser TKN = ERC20PresetMinterPauser(TKN_address);
uint32 nonce = 0;
mapping(uint16 => bytes32) _applicationContracts;
mapping(bytes32 => bool) _completedMessages;
address owner;
constructor(){
owner = msg.sender;
}
/**
Registers it's sibling applications on other chains as the only ones that can send this instance messages
*/
function registerApplicationContracts(uint16 chainId, bytes32 applicationAddr) public {
require(msg.sender == owner, "Only owner can register new chains!");
_applicationContracts[chainId] = applicationAddr;
}
//Returns the Balance of this Contract
function getTKNCount() public view returns (uint256) {
return TKN.balanceOf(address(this));
}
//Returns the Balance of Wrapped Count
function getWrappedCount(PortalWrappedToken wrappedToken) public view returns (uint256) {
return wrappedToken.balanceOf(address(this));
}
function bridgeToken(uint256 amt, uint16 receipientChainId, bytes32 recipient) public returns (uint64 sequence) {
nonce += 1;
return token_bridge.transferTokens(TKN_address, amt, receipientChainId, recipient, 0, nonce);
}
function approveTokenBridge(uint256 amt) public returns (bool) {
return TKN.approve(token_bridge_address, amt);
}
}

View File

@ -0,0 +1,18 @@
// contracts/Getters.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
interface BridgeGetters {
function governanceActionIsConsumed(bytes32 hash) external view returns (bool) ;
function isInitialized(address impl) external view returns (bool) ;
function isTransferCompleted(bytes32 hash) external view returns (bool) ;
function chainId() external view returns (uint16);
function governanceChainId() external view returns (uint16);
function governanceContract() external view returns (bytes32);
function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress) external view returns (address);
function bridgeContracts(uint16 chainId_) external view returns (bytes32);
function tokenImplementation() external view returns (address);
function outstandingBridged(address token) external view returns (uint256);
function isWrappedAsset(address token) external view returns (bool);
}

View File

@ -0,0 +1,121 @@
// contracts/Bridge.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./BridgeGetters.sol";
interface ITokenBridge is BridgeGetters {
/*
* @dev Produce a AssetMeta message for a given token
*/
function attestToken(address tokenAddress, uint32 nonce) external payable returns (uint64 sequence);
/*
* @notice Send eth through portal by first wrapping it to WETH.
*/
function wrapAndTransferETH(
uint16 recipientChain,
bytes32 recipient,
uint256 arbiterFee,
uint32 nonce
) external payable returns (uint64 sequence);
/*
* @notice Send eth through portal by first wrapping it.
*
* @dev This type of transfer is called a "contract-controlled transfer".
* There are three differences from a regular token transfer:
* 1) Additional arbitrary payload can be attached to the message
* 2) Only the recipient (typically a contract) can redeem the transaction
* 3) The sender's address (msg.sender) is also included in the transaction payload
*
* With these three additional components, xDapps can implement cross-chain
* composable interactions.
*/
function wrapAndTransferETHWithPayload(
uint16 recipientChain,
bytes32 recipient,
uint32 nonce,
bytes memory payload
) external payable returns (uint64 sequence);
/*
* @notice Send ERC20 token through portal.
*/
function transferTokens(
address token,
uint256 amount,
uint16 recipientChain,
bytes32 recipient,
uint256 arbiterFee,
uint32 nonce
) external payable returns (uint64 sequence);
/*
* @notice Send ERC20 token through portal.
*
* @dev This type of transfer is called a "contract-controlled transfer".
* There are three differences from a regular token transfer:
* 1) Additional arbitrary payload can be attached to the message
* 2) Only the recipient (typically a contract) can redeem the transaction
* 3) The sender's address (msg.sender) is also included in the transaction payload
*
* With these three additional components, xDapps can implement cross-chain
* composable interactions.
*/
function transferTokensWithPayload(
address token,
uint256 amount,
uint16 recipientChain,
bytes32 recipient,
uint32 nonce,
bytes memory payload
) external payable returns (uint64 sequence);
function updateWrapped(bytes memory encodedVm) external returns (address token);
function createWrapped(bytes memory encodedVm) external returns (address token);
/*
* @notice Complete a contract-controlled transfer of an ERC20 token.
*
* @dev The transaction can only be redeemed by the recipient, typically a
* contract.
*
* @param encodedVm A byte array containing a VAA signed by the guardians.
*
* @return The byte array representing a BridgeStructs.TransferWithPayload.
*/
function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory);
/*
* @notice Complete a contract-controlled transfer of WETH, and unwrap to ETH.
*
* @dev The transaction can only be redeemed by the recipient, typically a
* contract.
*
* @param encodedVm A byte array containing a VAA signed by the guardians.
*
* @return The byte array representing a BridgeStructs.TransferWithPayload.
*/
function completeTransferAndUnwrapETHWithPayload(bytes memory encodedVm) external returns (bytes memory);
/*
* @notice Complete a transfer of an ERC20 token.
*
* @dev The msg.sender gets paid the associated fee.
*
* @param encodedVm A byte array containing a VAA signed by the guardians.
*/
function completeTransfer(bytes memory encodedVm) external ;
/*
* @notice Complete a transfer of WETH and unwrap to eth.
*
* @dev The msg.sender gets paid the associated fee.
*
* @param encodedVm A byte array containing a VAA signed by the guardians.
*/
function completeTransferAndUnwrapETH(bytes memory encodedVm) external ;
}

View File

@ -0,0 +1,42 @@
// contracts/TokenImplementation.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
// Based on the OpenZepplin ERC20 implementation, licensed under MIT
interface PortalWrappedToken {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function owner() external view returns (address);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function chainId() external view returns (uint16);
function nativeContract() external view returns (bytes32) ;
function balanceOf(address account_) external view returns (uint256) ;
function transfer(address recipient_, uint256 amount_) external returns (bool) ;
function allowance(address owner_, address spender_) external view returns (uint256) ;
function approve(address spender_, uint256 amount_) external returns (bool) ;
function transferFrom(address sender_, address recipient_, uint256 amount_) external returns (bool) ;
function increaseAllowance(address spender_, uint256 addedValue_) external returns (bool) ;
function decreaseAllowance(address spender_, uint256 subtractedValue_) external returns (bool) ;
function mint(address account_, uint256 amount_) external ;
}

View File

@ -0,0 +1,40 @@
// contracts/Structs.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
interface Structs {
struct Provider {
uint16 chainId;
uint16 governanceChainId;
bytes32 governanceContract;
}
struct GuardianSet {
address[] keys;
uint32 expirationTime;
}
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
uint8 guardianIndex;
}
struct VM {
uint8 version;
uint32 timestamp;
uint32 nonce;
uint16 emitterChainId;
bytes32 emitterAddress;
uint64 sequence;
uint8 consistencyLevel;
bytes payload;
uint32 guardianSetIndex;
Signature[] signatures;
bytes32 hash;
}
}

7659
projects/evm-tokenbridge/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
{
"name": "xdapp-starter",
"version": "1.0.0",
"description": "A simple template for getting started with xDapps.",
"main": "starter.js",
"scripts": {
"guardiand": "sh wormhole.sh",
"cleanup": "docker kill guardiand && docker rm guardiand && npx pm2 kill",
"test": "sh tests/treasury_bridge.sh"
},
"keywords": [],
"author": "",
"license": "MIT",
"workspaces": [],
"type": "module",
"dependencies": {
"@certusone/wormhole-sdk": "^0.3.3",
"byteify": "^2.0.10",
"ethers": "^5.6.9",
"ganache": "^7.3.1",
"node-fetch": "^3.2.6",
"pm2": "^5.2.0"
}
}

View File

@ -0,0 +1,11 @@
node treasury.js evm0 deploy
node treasury.js evm1 deploy
node treasury.js evm0 register_chain evm1
node treasury.js evm1 register_chain evm0
node treasury.js evm0 get_tokens 100
node treasury.js evm0 attest_token evm1
node treasury.js evm1 get_token_counts
node treasury.js evm0 bridge_token evm1 50
node treasury.js evm0 get_token_counts
node treasury.js evm1 get_token_counts

View File

@ -0,0 +1,334 @@
import { exec } from "child_process";
import fs from "fs";
import { ethers } from "ethers";
import {
getEmitterAddressEth,
parseSequenceFromLogEth,
attestFromEth,
tryNativeToHexString,
} from "@certusone/wormhole-sdk";
import fetch from "node-fetch";
async function main() {
let config = JSON.parse(fs.readFileSync("./xdapp.config.json").toString());
let network = config.networks[process.argv[2]];
let deployment;
try {
deployment = JSON.parse(fs.readFileSync("./deployment.json").toString());
} catch (e) {
deployment = {};
deployment[[process.argv[2]]] = {
deployedAddress: "",
emittedVAAs: []
};
}
if (!network) {
throw new Error("Network not defined in config file.");
}
if (process.argv[3] == "deploy") {
console.log(
`Deploying EVM network: ${process.argv[2]} to ${network.rpc}`
);
exec(
`cd chains/evm && forge build && forge create --legacy --rpc-url ${network.rpc} --private-key ${network.privateKey} src/Treasury.sol:Treasury && exit`,
(err, out, errStr) => {
if (err) {
throw new Error(err);
}
if (out) {
console.log(out);
deployment[[process.argv[2]]] = {
deployedAddress: "",
emittedVAAs: []
};
deployment[process.argv[2]].deployedAddress = out
.split("Deployed to: ")[1]
.split("\n")[0]
.trim();
deployment[process.argv[2]].emittedVAAs = [];
fs.writeFileSync(
"./deployment.json",
JSON.stringify(deployment, null, 4)
);
}
}
);
} else if (process.argv[3] == "register_chain") {
if (!deployment[process.argv[2]].deployedAddress) {
throw new Error("Deploy to this network first!");
}
const targetNetwork = config.networks[process.argv[4]];
const targetDeployment = deployment[process.argv[4]]
if (!targetDeployment.deployedAddress) {
throw new Error("Target Network not deployed yet!");
}
let emitterAddr = Buffer.from(
getEmitterAddressEth(targetDeployment.deployedAddress),
"hex"
);
const signer = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(network.rpc)
);
const treasury = new ethers.Contract(
deployment[process.argv[2]].deployedAddress,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/Treasury.sol/Treasury.json"
)
.toString()
).abi,
signer
);
await treasury.registerApplicationContracts(
targetNetwork.wormholeChainId,
emitterAddr
);
console.log(
`Network(${process.argv[2]}) Registered Emitter: ${targetDeployment.deployedAddress} from Chain: ${process.argv[4]}`
);
} else if (process.argv[3] == "get_tokens") {
if (!deployment[process.argv[2]].deployedAddress) {
throw new Error("Deploy to this network first!");
}
const signer = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(network.rpc)
);
const treasury = new ethers.Contract(
deployment[process.argv[2]].deployedAddress,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/Treasury.sol/Treasury.json"
)
.toString()
).abi,
signer
);
const TKN = new ethers.Contract(
network.testToken,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/ERC20PresetMinterPauser.sol/ERC20PresetMinterPauser.json"
)
.toString()
).abi,
signer
);
console.log(`${process.argv[2]} Treasury has ${await treasury.getTKNCount()} tokens.`);
console.log(`Minting 100 tokens.`);
await TKN.mint(deployment[process.argv[2]].deployedAddress, 100);
await new Promise((r) => setTimeout(r, 3000));
console.log(`${process.argv[2]} Treasury has ${await treasury.getTKNCount()} tokens.`);
} else if (process.argv[3] == "attest_token") {
if (!deployment[process.argv[2]].deployedAddress) {
throw new Error("Deploy to this network first!");
}
const signer = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(network.rpc)
);
const networkTokenAttestation = await attestFromEth(
network.tokenBridgeAddress,
signer,
network.testToken
);
const emitterAddr = getEmitterAddressEth(network.tokenBridgeAddress);
const seq = parseSequenceFromLogEth(networkTokenAttestation, network.bridgeAddress);
const vaaURL = `${config.wormhole.restAddress}/v1/signed_vaa/${network.wormholeChainId}/${emitterAddr}/${seq}`;
console.log("Searching for: ", vaaURL);
let vaaBytes = await (await fetch(vaaURL)).json();
while(!vaaBytes.vaaBytes){
console.log("VAA not found, retrying in 5s!");
await new Promise((r) => setTimeout(r, 5000)); //Timeout to let Guardiand pick up log and have VAA ready
vaaBytes = await (await fetch(vaaURL)).json();
}
if (!deployment[process.argv[2]].emittedVAAs) {
deployment[process.argv[2]].emittedVAAs = [vaaBytes.vaaBytes];
} else {
deployment[process.argv[2]].emittedVAAs.push(vaaBytes.vaaBytes);
}
fs.writeFileSync(
"./deployment.json",
JSON.stringify(deployment, null, 2)
);
console.log(
`Network(${process.argv[2]}) Emitted VAA: `,
vaaBytes.vaaBytes
);
// Now create the Wrapped Version of the Token on the target chain
const targetNetwork = config.networks[process.argv[4]];
const targetDeployment = deployment[process.argv[4]];
const targetSigner = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(targetNetwork.rpc)
);
const targetTokenBridge = new ethers.Contract(
targetNetwork.tokenBridgeAddress,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/ITokenBridge.sol/ITokenBridge.json"
)
.toString()
).abi,
targetSigner
);
await targetTokenBridge.createWrapped(Buffer.from(vaaBytes.vaaBytes, "base64"), {
gasLimit: 2000000
})
await new Promise((r) => setTimeout(r, 5000)); //Time out to let block propogate
const wrappedTokenAddress = await targetTokenBridge.wrappedAsset(network.wormholeChainId, Buffer.from(tryNativeToHexString(network.testToken, "ethereum"), "hex"));
console.log("Wrapped token created at: ", wrappedTokenAddress);
targetDeployment["wrappedTestTokenAddress"] = wrappedTokenAddress;
deployment[process.argv[4]] = targetDeployment;
fs.writeFileSync('./deployment.json', JSON.stringify(deployment, null, 4));
} else if (process.argv[3] == "get_token_counts") {
if (!deployment[process.argv[2]].deployedAddress) {
throw new Error("Deploy to this network first!");
}
const signer = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(network.rpc)
);
const treasury = new ethers.Contract(
deployment[process.argv[2]].deployedAddress,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/Treasury.sol/Treasury.json"
)
.toString()
).abi,
signer
);
console.log(`${process.argv[2]} Treasury has ${await treasury.getTKNCount()} native TKN.`)
if(deployment[process.argv[2]]['wrappedTestTokenAddress']){
console.log(`${process.argv[2]} Treasury has ${await treasury.getWrappedCount(deployment[process.argv[2]]['wrappedTestTokenAddress'])} wrapped TKN.`)
}
} else if (process.argv[3] == "bridge_token") {
if (!deployment[process.argv[2]].deployedAddress) {
throw new Error("Deploy to this network first!");
}
const signer = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(network.rpc)
);
const treasury = new ethers.Contract(
deployment[process.argv[2]].deployedAddress,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/Treasury.sol/Treasury.json"
)
.toString()
).abi,
signer
);
// Remember to allow Token Bridge to move tokens from Treasury account to it's own account
console.log(`Approving ${process.argv[5]} Tokens to be bridged by Token Bridge`);
await treasury.approveTokenBridge(parseInt(process.argv[5], {
gasLimit: 2000000,
}));
await new Promise((r) => setTimeout(r, 5000)); //Time out to let block propogate
const targetNetwork = config.networks[process.argv[4]];
const targetDeployment = deployment[process.argv[4]]
if (!targetDeployment.deployedAddress) {
throw new Error("Target Network not deployed yet!");
}
console.log("Bridging Tokens!")
const targetRecepient = Buffer.from(tryNativeToHexString(targetDeployment.deployedAddress, "ethereum"), 'hex');
const tx = await (await treasury.bridgeToken(parseInt(process.argv[5]), targetNetwork.wormholeChainId, targetRecepient)).wait();
const emitterAddr = getEmitterAddressEth(network.tokenBridgeAddress);
const seq = parseSequenceFromLogEth(tx, network.bridgeAddress);
const vaaURL = `${config.wormhole.restAddress}/v1/signed_vaa/${network.wormholeChainId}/${emitterAddr}/${seq}`;
let vaaBytes = await (await fetch(vaaURL)).json();
while(!vaaBytes.vaaBytes){
console.log("VAA not found, retrying in 5s!");
await new Promise((r) => setTimeout(r, 5000)); //Timeout to let Guardiand pick up log and have VAA ready
vaaBytes = await (await fetch(vaaURL)).json();
}
if (!deployment[process.argv[2]].emittedVAAs) {
deployment[process.argv[2]].emittedVAAs = [vaaBytes.vaaBytes];
} else {
deployment[process.argv[2]].emittedVAAs.push(vaaBytes.vaaBytes);
}
fs.writeFileSync(
"./deployment.json",
JSON.stringify(deployment, null, 2)
);
console.log(
`Network(${process.argv[2]}) Emitted VAA: `,
vaaBytes.vaaBytes
);
// Now create the Wrapped Version of the Token on the target chain
const targetSigner = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(targetNetwork.rpc)
);
const targetTokenBridge = new ethers.Contract(
targetNetwork.tokenBridgeAddress,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/ITokenBridge.sol/ITokenBridge.json"
)
.toString()
).abi,
targetSigner
);
const completeTransferTx = await targetTokenBridge.completeTransfer(Buffer.from(vaaBytes.vaaBytes, "base64"));
console.log("Complete Transfer TX: ", await completeTransferTx.wait());
} else if (process.argv[3] == "debug") {
const signer = new ethers.Wallet(network.privateKey).connect(
new ethers.providers.JsonRpcProvider(network.rpc)
);
const TKN = new ethers.Contract(
network.testToken,
JSON.parse(
fs
.readFileSync(
"./chains/evm/out/ERC20PresetMinterPauser.sol/ERC20PresetMinterPauser.json"
)
.toString()
).abi,
signer
);
console.log((await TKN.allowance(deployment[process.argv[2]].deployedAddress, network.tokenBridgeAddress)).toNumber());
console.log((await TKN.balanceOf(network.tokenBridgeAddress)).toNumber());
} else {
throw new Error("Unkown command!");
}
}
main();

View File

@ -0,0 +1,113 @@
#!/usr/bin/env bash
npm run cleanup
if [! docker info > /dev/null ] ; then
echo "This script uses docker, and it isn't running - please start docker and try again!"
exit 1
fi
# Check if wormhole/ repo exists.
# If it doens't then clone and build guardiand
if [ ! -d "./wormhole" ]
then
git clone https://github.com/certusone/wormhole
cd wormhole/
DOCKER_BUILDKIT=1 docker build --target go-export -f Dockerfile.proto -o type=local,dest=node .
DOCKER_BUILDKIT=1 docker build --target node-export -f Dockerfile.proto -o type=local,dest=. .
cd node/
echo "Have patience, this step takes upwards of 500 seconds!"
if [ $(uname -m) = "arm64" ]; then
echo "Building Guardian for linux/amd64"
DOCKER_BUILDKIT=1 docker build --platform linux/amd64 -f Dockerfile -t guardian .
else
echo "Building Guardian natively"
DOCKER_BUILDKIT=1 docker build -f Dockerfile -t guardian .
fi
cd ../../
fi
# Start EVM Chain 0
npx pm2 start 'ganache -p 8545 -m "myth like bonus scare over problem client lizard pioneer submit female collect" --block-time 1' --name evm0
# Start EVM Chain 1
npx pm2 start 'ganache -p 8546 -m "myth like bonus scare over problem client lizard pioneer submit female collect" --block-time 1' --name evm1
#Install Wormhole Eth Dependencies
cd wormhole/ethereum
npm i
cp .env.test .env
npm run build
# Deploy Wormhole Contracts to EVM Chain 0
npm run migrate && npx truffle exec scripts/deploy_test_token.js && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_bsc_chain.js && npx truffle exec scripts/register_algo_chain.js
# Deploy Wormhole Contracts to EVM Chain 1
perl -pi -e 's/CHAIN_ID=0x2/CHAIN_ID=0x4/g' .env && perl -pi -e 's/8545/8546/g' truffle-config.js
npm run migrate && npx truffle exec scripts/deploy_test_token.js && npx truffle exec scripts/register_solana_chain.js && npx truffle exec scripts/register_terra_chain.js && npx truffle exec scripts/register_eth_chain.js && npx truffle exec scripts/register_algo_chain.js && nc -lkp 2000 0.0.0.0
perl -pi -e 's/CHAIN_ID=0x4/CHAIN_ID=0x2/g' .env && perl -pi -e 's/8546/8545/g' truffle-config.js
cd ../../
# Run Guardiand
if [ $(uname -m) = "arm64" ]; then
docker run -d --name guardiand -p 7070:7070 -p 7071:7071 -p 7073:7073 --platform linux/amd64 --hostname guardian-0 --cap-add=IPC_LOCK --entrypoint /guardiand guardian node \
--unsafeDevMode --guardianKey /tmp/bridge.key --publicRPC "[::]:7070" --publicWeb "[::]:7071" --adminSocket /tmp/admin.sock --dataDir /tmp/data \
--ethRPC ws://host.docker.internal:8545 \
--ethContract "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" \
--bscRPC ws://host.docker.internal:8546 \
--bscContract "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" \
--polygonRPC ws://host.docker.internal:8545 \
--avalancheRPC ws://host.docker.internal:8545 \
--auroraRPC ws://host.docker.internal:8545 \
--fantomRPC ws://host.docker.internal:8545 \
--oasisRPC ws://host.docker.internal:8545 \
--karuraRPC ws://host.docker.internal:8545 \
--acalaRPC ws://host.docker.internal:8545 \
--klaytnRPC ws://host.docker.internal:8545 \
--celoRPC ws://host.docker.internal:8545 \
--moonbeamRPC ws://host.docker.internal:8545 \
--neonRPC ws://host.docker.internal:8545 \
--terraWS ws://host.docker.internal:8545 \
--terra2WS ws://host.docker.internal:8545 \
--terraLCD https://host.docker.internal:1317 \
--terra2LCD http://host.docker.internal:1317 \
--terraContract terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 \
--terra2Contract terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 \
--solanaContract Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o \
--solanaWS ws://host.docker.internal:8900 \
--solanaRPC http://host.docker.internal:8899 \
--algorandIndexerRPC ws://host.docker.internal:8545 \
--algorandIndexerToken "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
--algorandAlgodToken "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
--algorandAlgodRPC https://host.docker.internal:4001 \
--algorandAppID "4"
else
docker run -d --name guardiand --network host --hostname guardian-0 --cap-add=IPC_LOCK --entrypoint /guardiand guardian node \
--unsafeDevMode --guardianKey /tmp/bridge.key --publicRPC "[::]:7070" --publicWeb "[::]:7071" --adminSocket /tmp/admin.sock --dataDir /tmp/data \
--ethRPC ws://localhost:8545 \
--ethContract "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" \
--bscRPC ws://localhost:8546 \
--bscContract "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" \
--polygonRPC ws://localhost:8545 \
--avalancheRPC ws://localhost:8545 \
--auroraRPC ws://localhost:8545 \
--fantomRPC ws://localhost:8545 \
--oasisRPC ws://localhost:8545 \
--karuraRPC ws://localhost:8545 \
--acalaRPC ws://localhost:8545 \
--klaytnRPC ws://localhost:8545 \
--celoRPC ws://localhost:8545 \
--moonbeamRPC ws://localhost:8545 \
--neonRPC ws://localhost:8545 \
--terraWS ws://localhost:8545 \
--terra2WS ws://localhost:8545 \
--terraLCD https://terra-terrad:1317 \
--terra2LCD http://localhost:1317 \
--terraContract terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 \
--terra2Contract terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 \
--solanaContract Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o \
--solanaWS ws://localhost:8900 \
--solanaRPC http://localhost:8899 \
--algorandIndexerRPC ws://localhost:8545 \
--algorandIndexerToken "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
--algorandAlgodToken "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
--algorandAlgodRPC https://localhost:4001 \
--algorandAppID "4"
fi
echo "Guardiand Running! To look at logs: \"docker logs guardiand -f\""

View File

@ -0,0 +1,25 @@
{
"networks": {
"evm0": {
"type": "evm",
"wormholeChainId": 2,
"rpc": "http://localhost:8545",
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550",
"tokenBridgeAddress": "0x0290FB167208Af455bB137780163b7B7a9a10C16",
"testToken": "0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A"
},
"evm1": {
"type": "evm",
"wormholeChainId": 4,
"rpc": "http://localhost:8546",
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
"tokenBridgeAddress": "0x0290FB167208Af455bB137780163b7B7a9a10C16",
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550",
"testToken": "0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A"
}
},
"wormhole": {
"restAddress": "http://localhost:7071"
}
}