messenger/evm is working
This commit is contained in:
parent
f5d290ad59
commit
4d0b827b65
|
@ -0,0 +1 @@
|
|||
deployinfo/*.deploy.json
|
|
@ -0,0 +1,3 @@
|
|||
cache/
|
||||
out/
|
||||
!src/Wormhole/
|
|
@ -4,13 +4,14 @@
|
|||
"artifacts": "out",
|
||||
"sources": "src",
|
||||
"tests": "test",
|
||||
"scripts": "script",
|
||||
"libraries": [
|
||||
"lib"
|
||||
]
|
||||
},
|
||||
"files": {
|
||||
"src/Messenger.sol": {
|
||||
"lastModificationDate": 1654006013773,
|
||||
"lastModificationDate": 1659683988145,
|
||||
"contentHash": "b21dd2ab010d42c4abc588eed32658bd",
|
||||
"sourceName": "src/Messenger.sol",
|
||||
"solcConfig": {
|
||||
|
@ -35,7 +36,8 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"evmVersion": "london"
|
||||
"evmVersion": "london",
|
||||
"libraries": {}
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
|
@ -45,12 +47,12 @@
|
|||
"versionRequirement": "^0.8.0",
|
||||
"artifacts": {
|
||||
"Messenger": {
|
||||
"0.8.10+commit.fc410830.Linux.gcc": "Messenger.sol/Messenger.json"
|
||||
"0.8.10+commit.fc410830.Darwin.appleclang": "Messenger.sol/Messenger.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"src/Wormhole/IWormhole.sol": {
|
||||
"lastModificationDate": 1654006013783,
|
||||
"lastModificationDate": 1659683988146,
|
||||
"contentHash": "7c930d4b68538e731af28a8d1979f44e",
|
||||
"sourceName": "src/Wormhole/IWormhole.sol",
|
||||
"solcConfig": {
|
||||
|
@ -75,7 +77,8 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"evmVersion": "london"
|
||||
"evmVersion": "london",
|
||||
"libraries": {}
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
|
@ -84,12 +87,12 @@
|
|||
"versionRequirement": "^0.8.0",
|
||||
"artifacts": {
|
||||
"IWormhole": {
|
||||
"0.8.10+commit.fc410830.Linux.gcc": "IWormhole.sol/IWormhole.json"
|
||||
"0.8.10+commit.fc410830.Darwin.appleclang": "IWormhole.sol/IWormhole.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"src/Wormhole/Structs.sol": {
|
||||
"lastModificationDate": 1654006013783,
|
||||
"lastModificationDate": 1659683988147,
|
||||
"contentHash": "4e824cc204959f4fcab06c4e806448c4",
|
||||
"sourceName": "src/Wormhole/Structs.sol",
|
||||
"solcConfig": {
|
||||
|
@ -114,14 +117,15 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"evmVersion": "london"
|
||||
"evmVersion": "london",
|
||||
"libraries": {}
|
||||
}
|
||||
},
|
||||
"imports": [],
|
||||
"versionRequirement": "^0.8.0",
|
||||
"artifacts": {
|
||||
"Structs": {
|
||||
"0.8.10+commit.fc410830.Linux.gcc": "Structs.sol/Structs.json"
|
||||
"0.8.10+commit.fc410830.Darwin.appleclang": "Structs.sol/Structs.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,53 @@
|
|||
//SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./Wormhole/IWormhole.sol";
|
||||
|
||||
contract Messenger {
|
||||
string private current_msg;
|
||||
address private wormhole_core_bridge_address = address(0xC89Ce4735882C9F0f0FE26686c53074E09B0D550);
|
||||
IWormhole core_bridge = IWormhole(wormhole_core_bridge_address);
|
||||
uint32 nonce = 0;
|
||||
mapping(uint16 => bytes32) _applicationContracts;
|
||||
address owner;
|
||||
mapping(bytes32 => bool) _completedMessages;
|
||||
|
||||
constructor(){
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function sendMsg(bytes memory str) public returns (uint64 sequence) {
|
||||
sequence = core_bridge.publishMessage(nonce, str, 1);
|
||||
nonce = nonce+1;
|
||||
}
|
||||
|
||||
function receiveEncodedMsg(bytes memory encodedMsg) public {
|
||||
(IWormhole.VM memory vm, bool valid, string memory reason) = core_bridge.parseAndVerifyVM(encodedMsg);
|
||||
|
||||
//1. Check Wormhole Guardian Signatures
|
||||
// If the VM is NOT valid, will return the reason it's not valid
|
||||
// If the VM IS valid, reason will be blank
|
||||
require(valid, reason);
|
||||
|
||||
//2. Check if the Emitter Chain contract is registered
|
||||
require(_applicationContracts[vm.emitterChainId] == vm.emitterAddress, "Invalid Emitter Address!");
|
||||
|
||||
//3. Check that the message hasn't already been processed
|
||||
require(!_completedMessages[vm.hash], "Message already processed");
|
||||
_completedMessages[vm.hash] = true;
|
||||
|
||||
//Do the thing
|
||||
current_msg = string(vm.payload);
|
||||
}
|
||||
|
||||
function getCurrentMsg() public view returns (string memory){
|
||||
return current_msg;
|
||||
}
|
||||
/**
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// contracts/Messages.sol
|
||||
// SPDX-License-Identifier: Apache 2
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./Structs.sol";
|
||||
|
||||
interface IWormhole is Structs {
|
||||
event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel);
|
||||
|
||||
function publishMessage(
|
||||
uint32 nonce,
|
||||
bytes memory payload,
|
||||
uint8 consistencyLevel
|
||||
) external payable returns (uint64 sequence);
|
||||
|
||||
function parseAndVerifyVM(bytes calldata encodedVM) external view returns (Structs.VM memory vm, bool valid, string memory reason);
|
||||
|
||||
function verifyVM(Structs.VM memory vm) external view returns (bool valid, string memory reason);
|
||||
|
||||
function verifySignatures(bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet) external pure returns (bool valid, string memory reason) ;
|
||||
|
||||
function parseVM(bytes memory encodedVM) external pure returns (Structs.VM memory vm);
|
||||
|
||||
function getGuardianSet(uint32 index) external view returns (Structs.GuardianSet memory) ;
|
||||
|
||||
function getCurrentGuardianSetIndex() external view returns (uint32) ;
|
||||
|
||||
function getGuardianSetExpiry() external view returns (uint32) ;
|
||||
|
||||
function governanceActionIsConsumed(bytes32 hash) external view returns (bool) ;
|
||||
|
||||
function isInitialized(address impl) external view returns (bool) ;
|
||||
|
||||
function chainId() external view returns (uint16) ;
|
||||
|
||||
function governanceChainId() external view returns (uint16);
|
||||
|
||||
function governanceContract() external view returns (bytes32);
|
||||
|
||||
function messageFee() external view returns (uint256) ;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
.anchor
|
||||
.DS_Store
|
||||
target
|
||||
**/*.rs.bk
|
||||
node_modules
|
||||
test-ledger
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
.anchor
|
||||
.DS_Store
|
||||
target
|
||||
node_modules
|
||||
dist
|
||||
build
|
||||
test-ledger
|
|
@ -0,0 +1,15 @@
|
|||
[features]
|
||||
seeds = false
|
||||
skip-lint = false
|
||||
[programs.localnet]
|
||||
solana = "24FoTeX7BKbhTh3UF3feWusoAVKDPWZneiEqhXLVzZPL"
|
||||
|
||||
[registry]
|
||||
url = "https://api.apr.dev"
|
||||
|
||||
[provider]
|
||||
cluster = "localnet"
|
||||
wallet = "keypairs/id.json"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,13 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"programs/*"
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
overflow-checks = true
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
[profile.release.build-override]
|
||||
opt-level = 3
|
||||
incremental = false
|
||||
codegen-units = 1
|
|
@ -0,0 +1 @@
|
|||
[40,148,125,159,224,157,172,169,55,161,127,226,88,78,71,229,217,201,39,206,158,115,118,202,14,123,164,207,238,75,132,230,182,36,37,126,2,94,41,70,100,148,232,150,11,41,158,177,192,236,3,96,36,8,15,61,46,248,128,167,184,106,42,24]
|
|
@ -0,0 +1 @@
|
|||
[208,42,49,103,247,30,120,52,59,87,100,149,183,99,116,225,88,94,168,108,203,46,196,252,4,147,13,136,178,97,159,130,15,177,42,56,142,141,170,79,183,156,130,147,48,241,148,173,6,109,136,29,40,28,120,159,255,113,29,219,240,142,226,151]
|
|
@ -0,0 +1,12 @@
|
|||
// Migrations are an early feature. Currently, they're nothing more than this
|
||||
// single deploy script that's invoked from the CLI, injecting a provider
|
||||
// configured from the workspace's Anchor.toml.
|
||||
|
||||
const anchor = require("@project-serum/anchor");
|
||||
|
||||
module.exports = async function (provider) {
|
||||
// Configure client to use the provider.
|
||||
anchor.setProvider(provider);
|
||||
|
||||
// Add your deploy script here.
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"scripts": {
|
||||
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
|
||||
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@project-serum/anchor": "^0.25.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.3.4",
|
||||
"mocha": "^9.0.3",
|
||||
"ts-mocha": "^10.0.0",
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/chai": "^4.3.0",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"typescript": "^4.3.5",
|
||||
"prettier": "^2.6.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "solana"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "solana"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
no-log-ix-name = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = "0.25.0"
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,4 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize {}
|
|
@ -0,0 +1,25 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
mod account;
|
||||
mod constant;
|
||||
mod context;
|
||||
mod error;
|
||||
mod event;
|
||||
|
||||
use account::*;
|
||||
use constant::*;
|
||||
use context::*;
|
||||
use error::*;
|
||||
use event::*;
|
||||
|
||||
declare_id!("24FoTeX7BKbhTh3UF3feWusoAVKDPWZneiEqhXLVzZPL");
|
||||
|
||||
#[program]
|
||||
pub mod solana {
|
||||
use super::*;
|
||||
|
||||
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import * as anchor from "@project-serum/anchor";
|
||||
import { Program } from "@project-serum/anchor";
|
||||
import { Solana } from "../target/types/solana";
|
||||
|
||||
describe("solana", () => {
|
||||
// Configure the client to use the local cluster.
|
||||
anchor.setProvider(anchor.AnchorProvider.env());
|
||||
|
||||
const program = anchor.workspace.Solana as Program<Solana>;
|
||||
|
||||
it("Is initialized!", async () => {
|
||||
// Add your test here.
|
||||
const tx = await program.methods.initialize().rpc();
|
||||
console.log("Your transaction signature", tx);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,212 @@
|
|||
import * as fs from 'fs';
|
||||
import { exec } from "child_process";
|
||||
import { getEmitterAddressEth, getEmitterAddressSolana, parseSequenceFromLogEth } from '@certusone/wormhole-sdk';
|
||||
import * as ethers from 'ethers';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString());
|
||||
|
||||
export async function deploy(chain: string){
|
||||
const rpc = config.networks[chain]['rpc'];
|
||||
const privateKey = config.networks[chain]['privateKey'];
|
||||
|
||||
exec(
|
||||
`cd chains/evm && forge build && forge create --legacy --rpc-url ${rpc} --private-key ${privateKey} src/Messenger.sol:Messenger && exit`,
|
||||
(err, out, errStr) => {
|
||||
if (err) {
|
||||
throw new Error(err.message);
|
||||
}
|
||||
|
||||
if (out) {
|
||||
console.log(out);
|
||||
const deploymentAddress = out
|
||||
.split("Deployed to: ")[1]
|
||||
.split("\n")[0]
|
||||
.trim();
|
||||
const emittedVAAs = []; //Resets the emittedVAAs
|
||||
fs.writeFileSync(
|
||||
`./deployinfo/${chain}.deploy.json`,
|
||||
JSON.stringify({
|
||||
address: deploymentAddress,
|
||||
vaas: emittedVAAs
|
||||
}, null, 4)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function registerApp(src:string, target:string){
|
||||
const srcNetwork = config.networks[src];
|
||||
const targetNetwork = config.networks[target];
|
||||
let srcDeploymentInfo;
|
||||
let targetDeploymentInfo;
|
||||
let targetEmitter;
|
||||
|
||||
|
||||
try{
|
||||
srcDeploymentInfo = JSON.parse(fs.readFileSync(`./deployinfo/${src}.deploy.json`).toString());
|
||||
} catch (e){
|
||||
throw new Error(`${src} is not deployed yet`);
|
||||
}
|
||||
|
||||
try{
|
||||
targetDeploymentInfo = JSON.parse(fs.readFileSync(`./deployinfo/${target}.deploy.json`).toString());
|
||||
} catch (e){
|
||||
throw new Error(`${target} is not deployed yet`);
|
||||
}
|
||||
|
||||
switch (targetNetwork['type']){
|
||||
case 'evm':
|
||||
targetEmitter = getEmitterAddressEth(targetDeploymentInfo['address']);
|
||||
break;
|
||||
case 'solana':
|
||||
targetEmitter = await getEmitterAddressSolana(targetDeploymentInfo['address']);
|
||||
break;
|
||||
}
|
||||
|
||||
const emitterBuffer = Buffer.from(targetEmitter, 'hex');
|
||||
const signer = new ethers.Wallet(srcNetwork.privateKey).connect(
|
||||
new ethers.providers.JsonRpcProvider(srcNetwork.rpc)
|
||||
);
|
||||
const messenger = new ethers.Contract(
|
||||
srcDeploymentInfo.address,
|
||||
JSON.parse(
|
||||
fs
|
||||
.readFileSync(
|
||||
"./chains/evm/out/Messenger.sol/Messenger.json"
|
||||
)
|
||||
.toString()
|
||||
).abi,
|
||||
signer
|
||||
);
|
||||
const tx = await messenger.registerApplicationContracts(
|
||||
targetNetwork.wormholeChainId,
|
||||
emitterBuffer
|
||||
);
|
||||
return tx;
|
||||
}
|
||||
|
||||
export async function sendMsg(src:string, msg:string){
|
||||
const srcNetwork = config.networks[src];
|
||||
let srcDeploymentInfo;
|
||||
try{
|
||||
srcDeploymentInfo = JSON.parse(fs.readFileSync(`./deployinfo/${src}.deploy.json`).toString());
|
||||
} catch (e){
|
||||
throw new Error(`${src} is not deployed yet`);
|
||||
}
|
||||
const signer = new ethers.Wallet(srcNetwork.privateKey).connect(
|
||||
new ethers.providers.JsonRpcProvider(srcNetwork.rpc)
|
||||
);
|
||||
const messenger = new ethers.Contract(
|
||||
srcDeploymentInfo.address,
|
||||
JSON.parse(
|
||||
fs
|
||||
.readFileSync(
|
||||
"./chains/evm/out/Messenger.sol/Messenger.json"
|
||||
)
|
||||
.toString()
|
||||
).abi,
|
||||
signer
|
||||
);
|
||||
|
||||
const tx = await (await messenger.sendMsg(Buffer.from(msg))).wait();
|
||||
const seq = parseSequenceFromLogEth(tx, srcNetwork['bridgeAddress']);
|
||||
const emitterAddr = getEmitterAddressEth(srcDeploymentInfo['address']);
|
||||
|
||||
|
||||
await new Promise((r) => setTimeout(r, 5000)); //wait for Guardian to pick up message
|
||||
console.log(
|
||||
"Searching for: ",
|
||||
`${config.wormhole.restAddress}/v1/signed_vaa/${srcNetwork.wormholeChainId}/${emitterAddr}/${seq}`
|
||||
);
|
||||
const vaaBytes = await (
|
||||
await fetch(
|
||||
`${config.wormhole.restAddress}/v1/signed_vaa/${srcNetwork.wormholeChainId}/${emitterAddr}/${seq}`
|
||||
)
|
||||
).json();
|
||||
|
||||
if(!vaaBytes['vaaBytes']){
|
||||
throw new Error("VAA not found!");
|
||||
}
|
||||
|
||||
if(!srcDeploymentInfo['vaas']){
|
||||
srcDeploymentInfo['vaas'] = [vaaBytes['vaaBytes']]
|
||||
} else {
|
||||
srcDeploymentInfo['vaas'].push(vaaBytes['vaaBytes'])
|
||||
}
|
||||
fs.writeFileSync(
|
||||
`./deployinfo/${src}.deploy.json`,
|
||||
JSON.stringify(srcDeploymentInfo, null, 4)
|
||||
);
|
||||
return vaaBytes['vaaBytes'];
|
||||
}
|
||||
|
||||
export async function submitVaa(src:string, target:string, idx:string){
|
||||
const srcNetwork = config.networks[src];
|
||||
const targetNetwork = config.networks[target];
|
||||
let srcDeploymentInfo;
|
||||
let targetDeploymentInfo;
|
||||
|
||||
try{
|
||||
srcDeploymentInfo = JSON.parse(fs.readFileSync(`./deployinfo/${src}.deploy.json`).toString());
|
||||
} catch (e){
|
||||
throw new Error(`${src} is not deployed yet`);
|
||||
}
|
||||
|
||||
try{
|
||||
targetDeploymentInfo = JSON.parse(fs.readFileSync(`./deployinfo/${target}.deploy.json`).toString());
|
||||
} catch (e){
|
||||
throw new Error(`${target} is not deployed yet`);
|
||||
}
|
||||
|
||||
const vaa = isNaN(parseInt(idx))
|
||||
? targetDeploymentInfo.vaas.pop()
|
||||
: targetDeploymentInfo.vaas[parseInt(idx)];
|
||||
|
||||
const signer = new ethers.Wallet(srcNetwork.privateKey).connect(
|
||||
new ethers.providers.JsonRpcProvider(srcNetwork.rpc)
|
||||
);
|
||||
const messenger = new ethers.Contract(
|
||||
srcDeploymentInfo.address,
|
||||
JSON.parse(
|
||||
fs
|
||||
.readFileSync(
|
||||
"./chains/evm/out/Messenger.sol/Messenger.json"
|
||||
)
|
||||
.toString()
|
||||
).abi,
|
||||
signer
|
||||
);
|
||||
const tx = await messenger.receiveEncodedMsg(Buffer.from(vaa, "base64"));
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
export async function getCurrentMsg(src:string){
|
||||
const srcNetwork = config.networks[src];
|
||||
let srcDeploymentInfo;
|
||||
|
||||
try{
|
||||
srcDeploymentInfo = JSON.parse(fs.readFileSync(`./deployinfo/${src}.deploy.json`).toString());
|
||||
} catch (e){
|
||||
throw new Error(`${src} is not deployed yet`);
|
||||
}
|
||||
const signer = new ethers.Wallet(srcNetwork.privateKey).connect(
|
||||
new ethers.providers.JsonRpcProvider(srcNetwork.rpc)
|
||||
);
|
||||
|
||||
const messenger = new ethers.Contract(
|
||||
srcDeploymentInfo.address,
|
||||
JSON.parse(
|
||||
fs
|
||||
.readFileSync(
|
||||
"./chains/evm/out/Messenger.sol/Messenger.json"
|
||||
)
|
||||
.toString()
|
||||
).abi,
|
||||
signer
|
||||
);
|
||||
|
||||
return await messenger.getCurrentMsg();
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
import { Command } from 'commander';
|
||||
import * as fs from 'fs';
|
||||
import * as evm from './handlers/evm';
|
||||
|
||||
const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString())
|
||||
|
||||
const program = new Command();
|
||||
program
|
||||
.name('xMessenger')
|
||||
.description("Cross chain messaging example project.")
|
||||
.version("0.2.0");
|
||||
|
||||
// $ deploy <chain>
|
||||
program
|
||||
.command('deploy')
|
||||
.argument('<network>', 'name of the network in xdapp.config.json to deploy')
|
||||
.action(async (network) => {
|
||||
if(!config.networks[network]){
|
||||
console.error(`ERROR: ${network} not found in xdapp.config.json`);
|
||||
return;
|
||||
}
|
||||
console.log(`Deploying ${network}...`);
|
||||
|
||||
switch(config.networks[network].type){
|
||||
case "evm":
|
||||
await evm.deploy(network);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Deploy finished!`);
|
||||
});
|
||||
|
||||
// $ register-network <source> <target>
|
||||
program
|
||||
.command("register-network")
|
||||
.argument('<source>', 'The network you are registering on.')
|
||||
.argument('<target>', 'The foreign network that you want to register.')
|
||||
.action(async (src, target) => {
|
||||
if(!config.networks[src]){
|
||||
console.error(`ERROR: ${src} not found in xdapp.config.json`);
|
||||
return;
|
||||
}
|
||||
if(!config.networks[target]){
|
||||
console.error(`ERROR: ${target} not found in xdapp.config.json`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
switch(config.networks[src].type){
|
||||
case 'evm':
|
||||
await evm.registerApp(src,target);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Foreign Network ${target} registered on ${src}`);
|
||||
} catch (e){
|
||||
console.error(`ERROR: ${e}`)
|
||||
}
|
||||
});
|
||||
|
||||
// $ send-msg <source> <msg>
|
||||
program
|
||||
.command('emit-msg')
|
||||
.argument('<source>', 'The network you want to emit the message from')
|
||||
.argument('<msg>', 'The message you want to emit')
|
||||
.action(async (src, msg) => {
|
||||
if(!config.networks[src]){
|
||||
console.error(`ERROR: ${src} not found in xdapp.config.json`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
switch(config.networks[src].type){
|
||||
case 'evm':
|
||||
await evm.sendMsg(src,msg);
|
||||
break;
|
||||
}
|
||||
console.log(`Emitted VAA on ${src} network. Submit it using \`submit-vaa\` command on a target network.`)
|
||||
} catch (e){
|
||||
console.error(`ERROR: ${e}`)
|
||||
}
|
||||
});
|
||||
|
||||
// $ submit-vaa <source> <target> <vaa#>
|
||||
program
|
||||
.command('submit-vaa')
|
||||
.argument('<source>', 'The network you want to submit the VAA on')
|
||||
.argument('<target>', 'The network you want to submit the VAA from')
|
||||
.argument('<vaa#>', 'The index of the VAA in the list of emitted VAAs that you want to submit. Use \'latest\' to submit the latest VAA')
|
||||
.action(async (src, target, idx) => {
|
||||
if(!config.networks[src]){
|
||||
console.error(`ERROR: ${src} not found in xdapp.config.json`);
|
||||
return;
|
||||
}
|
||||
if(!config.networks[target]){
|
||||
console.error(`ERROR: ${target} not found in xdapp.config.json`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
switch(config.networks[src].type){
|
||||
case 'evm':
|
||||
await evm.submitVaa(src,target,idx);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Submitted VAA #${idx} from ${target} to chain ${src}`);
|
||||
} catch (e){
|
||||
console.error(`ERROR: ${e}`)
|
||||
}
|
||||
});
|
||||
|
||||
// $ get-msg <source>
|
||||
program
|
||||
.command('get-msg')
|
||||
.argument('<source>', 'The chain to fetch the current message from')
|
||||
.action(async (src) => {
|
||||
if(!config.networks[src]){
|
||||
console.error(`ERROR: ${src} not found in xdapp.config.json`);
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = "ERROR!";
|
||||
try {
|
||||
switch(config.networks[src].type){
|
||||
case 'evm':
|
||||
msg = await evm.getCurrentMsg(src);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Current Message on Network ${src} is ${msg}`);
|
||||
} catch (e){
|
||||
console.error(`ERROR: ${e}`)
|
||||
}
|
||||
})
|
||||
|
||||
program.parse();
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "messenger",
|
||||
"version": "1.0.0",
|
||||
"description": "A simple example of cross chain messaging with wormhole",
|
||||
"main": "orchestrator.ts",
|
||||
"author": "Dev Bharel",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.6.0",
|
||||
"commander": "^9.4.0",
|
||||
"ethers": "^5.6.9",
|
||||
"node-fetch": "2",
|
||||
"ts-node": "^10.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.6.4"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
# Deploy evm0 and evm1
|
||||
ts-node orchestrator.ts deploy evm0
|
||||
ts-node orchestrator.ts deploy evm1
|
||||
|
||||
# Register evm0 on evm1 and vice versa
|
||||
ts-node orchestrator.ts register-network evm0 evm1
|
||||
ts-node orchestrator.ts register-network evm1 evm0
|
||||
|
||||
# Emit VAA from evm0
|
||||
ts-node orchestrator.ts emit-msg evm0 "Hello from evm0"
|
||||
# Emit VAA from evm1
|
||||
ts-node orchestrator.ts emit-msg evm1 "Hello from evm1"
|
||||
|
||||
# Submit evm0 VAA to evm1
|
||||
ts-node orchestrator.ts submit-vaa evm1 evm0 latest
|
||||
ts-node orchestrator.ts submit-vaa evm0 evm1 latest
|
||||
|
||||
# Wait a couple blocks for confirmation
|
||||
sleep 3
|
||||
|
||||
# Get Current Messages from evm0 and evm1
|
||||
ts-node orchestrator.ts get-msg evm0
|
||||
ts-node orchestrator.ts get-msg evm1
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["node"],
|
||||
"moduleResolution": "node",
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"networks": {
|
||||
"eth0": {
|
||||
"evm0": {
|
||||
"type": "evm",
|
||||
"wormholeChainId": 2,
|
||||
"rpc": "http://localhost:8545",
|
||||
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
|
||||
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
|
||||
},
|
||||
"eth1": {
|
||||
"evm1": {
|
||||
"type": "evm",
|
||||
"wormholeChainId": 4,
|
||||
"rpc": "http://localhost:8546",
|
||||
|
@ -18,8 +18,8 @@
|
|||
"type": "solana",
|
||||
"wormholeChainId": 1,
|
||||
"rpc": "http://localhost:8899",
|
||||
"privateKey": "",
|
||||
"bridgeAddress": ""
|
||||
"privateKey": "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
|
||||
"bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
|
||||
}
|
||||
},
|
||||
"wormhole": {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Start EVM Chain 0
|
||||
npx pm2 delete evm0 2> /dev/null || true
|
||||
npx pm2 start 'npx 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 delete evm1 2> /dev/null || true
|
||||
npx pm2 start 'npx ganache -p 8546 -m "myth like bonus scare over problem client lizard pioneer submit female collect" --block-time 1' --name evm1
|
||||
|
||||
cd wormhole/ethereum
|
||||
|
||||
#Install Wormhole Eth Dependencies
|
||||
make .env 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_eth_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
|
||||
perl -pi -e 's/CHAIN_ID=0x4/CHAIN_ID=0x2/g' .env && perl -pi -e 's/8546/8545/g' truffle-config.js
|
|
@ -1,52 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Run Guardiand
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# dev.v2 for now (until we make a release)
|
||||
DOCKER_IMAGE="ghcr.io/certusone/guardiand:dev.v2"
|
||||
|
||||
DOCKER_FLAGS=
|
||||
HOST=
|
||||
TERRAD_HOST=
|
||||
if [ "$(uname -m)" = "arm64" ]; then
|
||||
DOCKER_FLAGS="-p 7070:7070 -p 7071:7071 -p 7073:7073 --platform linux/amd64"
|
||||
HOST="host.docker.internal"
|
||||
TERRAD_HOST="host.docker.internal"
|
||||
else
|
||||
DOCKER_FLAGS="--network host"
|
||||
TERRAD_HOST="terra-terrad"
|
||||
HOST="localhost"
|
||||
fi
|
||||
|
||||
docker run --rm --name guardiand $DOCKER_FLAGS --hostname guardian-0 --cap-add=IPC_LOCK "$DOCKER_IMAGE" node \
|
||||
--unsafeDevMode --guardianKey /bridge.key --publicRPC "[::]:7070" --publicWeb "[::]:7071" --adminSocket /admin.sock --dataDir /data \
|
||||
--ethRPC ws://$HOST:8545 \
|
||||
--ethContract "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" \
|
||||
--bscRPC ws://$HOST:8546 \
|
||||
--bscContract "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" \
|
||||
--polygonRPC ws://$HOST:8545 \
|
||||
--avalancheRPC ws://$HOST:8545 \
|
||||
--auroraRPC ws://$HOST:8545 \
|
||||
--fantomRPC ws://$HOST:8545 \
|
||||
--oasisRPC ws://$HOST:8545 \
|
||||
--karuraRPC ws://$HOST:8545 \
|
||||
--acalaRPC ws://$HOST:8545 \
|
||||
--klaytnRPC ws://$HOST:8545 \
|
||||
--celoRPC ws://$HOST:8545 \
|
||||
--moonbeamRPC ws://$HOST:8545 \
|
||||
--neonRPC ws://$HOST:8545 \
|
||||
--terraWS ws://$HOST:8545 \
|
||||
--terra2WS ws://$HOST:8545 \
|
||||
--terraLCD https://$TERRAD_HOST:1317 \
|
||||
--terra2LCD http://$HOST:1317 \
|
||||
--terraContract terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 \
|
||||
--terra2Contract terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 \
|
||||
--solanaContract Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o \
|
||||
--solanaWS ws://$HOST:8900 \
|
||||
--solanaRPC http://$HOST:8899 \
|
||||
--algorandIndexerRPC ws://$HOST:8545 \
|
||||
--algorandIndexerToken "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
--algorandAlgodToken "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
|
||||
--algorandAlgodRPC https://$HOST:4001 \
|
||||
--algorandAppID "4"
|
|
@ -4,10 +4,10 @@
|
|||
"description": "A simple template for getting started with xDapps.",
|
||||
"main": "starter.js",
|
||||
"scripts": {
|
||||
"setup": "sh setup.sh",
|
||||
"wormhole": "npm run setup && sh wormhole.sh",
|
||||
"evm": "npm run setup && sh evm.sh",
|
||||
"solana": "npm run setup && sh solana.sh",
|
||||
"setup": "bash setup.bash",
|
||||
"wormhole": "npm run setup && bash wormhole.bash",
|
||||
"evm": "npm run setup && bash evm.bash",
|
||||
"solana": "npm run setup && bash solana-binary-deploy.bash",
|
||||
"cleanup": "npx pm2 kill"
|
||||
},
|
||||
"keywords": [],
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Check if wormhole/ repo exists.
|
||||
# If it doesn't then clone
|
||||
if [ ! -d "./wormhole" ]
|
||||
then
|
||||
git clone https://github.com/certusone/wormhole
|
||||
fi
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Start Solana
|
||||
npx pm2 stop solana 2> /dev/null || true
|
||||
|
||||
npx pm2 start "solana-test-validator" --name solana -- -r \
|
||||
--bpf-program Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o ./solana-accounts/core/core_bridge.so \
|
||||
--account FKoMTctsC7vJbEqyRiiPskPnuQx2tX1kurmvWByq5uZP ./solana-accounts/core/bridge_config.json \
|
||||
--account GXBsgBD3LDn3vkRZF6TfY5RqgajVZ4W5bMAdiAaaUARs ./solana-accounts/core/fee_collector.json \
|
||||
--account 6MxkvoEwgB9EqQRLNhvYaPGhfcLtBtpBqdQugr3AZUgD ./solana-accounts/core/guardian_set.json \
|
||||
--bpf-program B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE ./solana-accounts/token/token_bridge.so \
|
||||
--account 3GwVs8GSLdo4RUsoXTkGQhojauQ1sXcDNjm7LSDicw19 ./solana-accounts/token/token_config.json \
|
||||
--account 7UqWgfVW1TrjrqauMfDoNMcw8kEStSsQXWNoT2BbhDS5 ./solana-accounts/token/emitter_eth.json \
|
||||
--account BmRvjCA2cQ1qUNAMVAnPgmjATSBPa2pxE3Q7bRoSGFED ./solana-accounts/token/emitter_bsc.json
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Start guardiand
|
||||
|
||||
npx pm2 delete guardiand 2> /dev/null || true
|
||||
npx pm2 start './guardiand.sh' --name guardiand
|
Loading…
Reference in New Issue