aptos working in messenger v1

This commit is contained in:
spacemandev 2022-12-19 00:27:59 -06:00
parent 4dcb18a929
commit 1c957b0b04
32 changed files with 7275 additions and 1638 deletions

View File

@ -27,4 +27,4 @@ If you see transactions failing due to nonce mismatch errors, restart your local
This is intermittent and likely caused by the js lib and evm chain being out of sync. This is intermittent and likely caused by the js lib and evm chain being out of sync.
#### Transaction Underpriced Issues #### Transaction Underpriced Issues
Transactions failing with the message `transaction underpriced` is an intermittent issue. Restart the evm chains and rerun `npm run test`. If the issue persists, you may need to manually set gas prices when calling the Messenger contract in the `send_msg` logic in `orchestrator.js`. Transactions failing with the message `transaction underpriced` is an intermittent issue. Restart the evm chains and rerun `npm run test`. If the issue persists, you may need to manually set gas prices when calling the Messenger contract in the `send_msg` logic in `orchestrator.js`.

View File

@ -1,18 +0,0 @@
/*
module core_messages::counter {
struct Counter has key, store {
count: u64
}
public entry fun init_counter(counter: &signer) {
//use aptos_framework::account;
//let (counter_acc, _) = account::create_resource_account(messenger, b"Counter");
move_to(counter, Counter { count: 0} );
}
public entry fun increment() acquires Counter {
let counter = borrow_global_mut<Counter>(@core_messages);
counter.count = counter.count + 1;
}
}
*/

View File

@ -2,22 +2,67 @@
module core_messages::messenger { module core_messages::messenger {
use wormhole::wormhole; use wormhole::wormhole;
use aptos_framework::coin; use aptos_framework::coin;
use std::table::{Self, Table};
use wormhole::u16::U16;
use wormhole::external_address::ExternalAddress;
use aptos_framework::signer;
use aptos_framework::account;
use std::string::{Self, String};
struct State has key { const E_ONLY_CORE_MESSAGES_CAN_INIT:u64 = 0;
emitter_cap: wormhole::emitter::EmitterCapability, const E_ONLY_ADMIN:u64 = 1;
const E_VAA_ALREADY_CONSUMED:u64 = 2;
const E_VAA_EMMITTER_NOT_REGISTERED:u64 = 3;
struct MessengerAdminCapability has key {
// The ability to make changes to the State Resource Account
resource_signer_cap: account::SignerCapability,
} }
public entry fun init_messenger(core_messages: &signer) { struct State has key {
// Admin Address
admin: address,
// The ability to send wormhole messages
emitter_cap: wormhole::emitter::EmitterCapability,
// Mapping of bridge contracts on other chains
registered_emitters: Table<U16, ExternalAddress>,
// Current Message
current_message: String,
// Consumed VAAs
consumed_vaas: Table<vector<u8>, bool>,
}
public entry fun init_messenger(core_messages: &signer, admin: address) {
// Requires the private key of Core Messages to have signed this message
// This is to make sure the state get stored under core messages resource account
assert!(signer::address_of(core_messages) == @core_messages, E_ONLY_CORE_MESSAGES_CAN_INIT);
let (resource_signer, signer_cap) = account::create_resource_account(core_messages, b"messenger_state");
// Register ourselves as a wormhole emitter. This gives back an // Register ourselves as a wormhole emitter. This gives back an
// `EmitterCapability` which will be required to send messages through // `EmitterCapability` which will be required to send messages through
// wormhole. // wormhole.
let emitter_cap = wormhole::register_emitter(); let emitter_cap = wormhole::register_emitter();
move_to(core_messages, State { emitter_cap }); move_to(&resource_signer, State {
admin,
emitter_cap,
registered_emitters: table::new(),
current_message: string::utf8(b"uninitalized"),
consumed_vaas: table::new()
});
move_to(core_messages, MessengerAdminCapability { resource_signer_cap: signer_cap } );
} }
public entry fun send_message(user: &signer, payload: vector<u8>) acquires State { public entry fun send_message(user: &signer, payload: vector<u8>) acquires State {
// Fetch the Resource Account that has state
let state_resource_account = account::create_resource_address(&@core_messages, b"messenger_state");
// Retrieve emitter capability from the state // Retrieve emitter capability from the state
let emitter_cap = &mut borrow_global_mut<State>(@core_messages).emitter_cap; let emitter_cap = &mut borrow_global_mut<State>(state_resource_account).emitter_cap;
// Set nonce to 0 (this field is not interesting for regular messages, // Set nonce to 0 (this field is not interesting for regular messages,
// only batch VAAs) // only batch VAAs)
@ -33,4 +78,44 @@ module core_messages::messenger {
fee_coins fee_coins
); );
} }
public entry fun register_emitter(user:&signer, chainID: u64, external_address:vector<u8>) acquires State {
let chain_id = wormhole::u16::from_u64(chainID);
let foreign_address = wormhole::external_address::from_bytes(external_address);
// Fetch the Resource Account that has state
let state_resource_account = account::create_resource_address(&@core_messages, b"messenger_state");
// Retrieve emitter capability from the state
let admin_address = &borrow_global<State>(state_resource_account).admin;
assert!(*admin_address == signer::address_of(user), E_ONLY_ADMIN);
//Get Registered Emitters
let state = borrow_global_mut<State>(state_resource_account);
table::upsert(&mut state.registered_emitters, chain_id, foreign_address);
}
public entry fun receive_message(vaa_bytes: vector<u8>) acquires State {
// Verify the wormhole message
let vaa = wormhole::vaa::parse_and_verify(vaa_bytes);
// Fetch the Resource Account that has state
let state_resource_account = account::create_resource_address(&@core_messages, b"messenger_state");
let state = borrow_global_mut<State>(state_resource_account);
// Check the VAA has not been consumed already
assert!(!table::contains(&state.consumed_vaas, wormhole::vaa::get_hash(&vaa)), E_VAA_ALREADY_CONSUMED);
// Check the emitter chain is registered
assert!(*table::borrow(&state.registered_emitters, wormhole::vaa::get_emitter_chain(&vaa)) == wormhole::vaa::get_emitter_address(&vaa), E_VAA_EMMITTER_NOT_REGISTERED);
// Set the current message to the vaa message
state.current_message = string::utf8(wormhole::vaa::get_payload(&vaa));
// Store the hash of the vaa in the consumed VAAs
table::upsert(&mut state.consumed_vaas, wormhole::vaa::get_hash(&vaa), true);
wormhole::vaa::destroy(vaa);
}
} }

View File

@ -1,86 +0,0 @@
/*
/// A simple contracts that demonstrates how to send messages with wormhole.
module core_messages::sender {
use wormhole::wormhole;
use aptos_framework::coin;
struct State has key {
emitter_cap: wormhole::emitter::EmitterCapability,
}
entry fun init_module(core_messages: &signer) {
// Register ourselves as a wormhole emitter. This gives back an
// `EmitterCapability` which will be required to send messages through
// wormhole.
let emitter_cap = wormhole::register_emitter();
move_to(core_messages, State { emitter_cap });
}
#[test_only]
/// Initialise module for testing.
public fun init_module_test() {
use aptos_framework::account;
// recover the signer for the module's account
let signer_cap = account::create_test_signer_cap(@core_messages);
let signer = account::create_signer_with_capability(&signer_cap);
// then call the initialiser
init_module(&signer)
}
public entry fun send_message(user: &signer, payload: vector<u8>) acquires State {
// Retrieve emitter capability from the state
let emitter_cap = &mut borrow_global_mut<State>(@core_messages).emitter_cap;
// Set nonce to 0 (this field is not interesting for regular messages,
// only batch VAAs)
let nonce: u64 = 0;
let message_fee = wormhole::state::get_message_fee();
let fee_coins = coin::withdraw(user, message_fee);
let _sequence = wormhole::publish_message(
emitter_cap,
nonce,
payload,
fee_coins
);
}
}
#[test_only]
module core_messages::sender_test {
use wormhole::wormhole;
use core_messages::sender;
use aptos_framework::account;
use aptos_framework::aptos_coin::{Self, AptosCoin};
use aptos_framework::coin;
use aptos_framework::signer;
use aptos_framework::timestamp;
#[test(aptos_framework = @aptos_framework, user = @0x111)]
public fun test_send_message(aptos_framework: &signer, user: &signer) {
let message_fee = 100;
timestamp::set_time_has_started_for_testing(aptos_framework);
wormhole::init_test(
22,
1,
x"0000000000000000000000000000000000000000000000000000000000000004",
x"beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe",
message_fee
);
sender::init_module_test();
let (burn_cap, mint_cap) = aptos_coin::initialize_for_test(aptos_framework);
// create user account and airdrop coins
account::create_account_for_test(signer::address_of(user));
coin::register<AptosCoin>(user);
coin::deposit(signer::address_of(user), coin::mint(message_fee, &mint_cap));
sender::send_message(user, b"hi mom");
coin::destroy_mint_cap(mint_cap);
coin::destroy_burn_cap(burn_cap);
}
}
*/

View File

@ -1,13 +1,21 @@
import fs from 'fs'; import fs from 'fs';
import { AptosClient } from "aptos"; import { AptosAccount, AptosClient, Types } from "aptos";
import { Command } from 'commander'; import { Command } from 'commander';
import { AptosMessenger } from './sdk'; import { AptosMessenger, EVMMessenger } from './sdk';
import {
tryNativeToUint8Array,
generateSignAndSubmitEntryFunction,
hexToUint8Array,
parseSequenceFromLogAptos,
getEmitterAddressSolana,
getEmitterAddressEth,
} from '@certusone/wormhole-sdk';
import fetch from 'node-fetch';
import ethers from 'ethers';
const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString()) const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString())
const program = new Command(); const program = new Command();
const aptosModuleAddress = "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b"; // Unlike EVM, this is hardcoded
const solanaProgramAddress = ""; // Unlike EVM, this is hardcoded
program program
.name('xMessenger') .name('xMessenger')
@ -27,24 +35,164 @@ program
switch(config.networks[network].type){ switch(config.networks[network].type){
case "aptos": case "aptos":
let aptosMessenger = new AptosMessenger(config.networks[network].rpc, aptosModuleAddress); let aptosMessenger = new AptosMessenger(config.networks[network].rpc, config.networks[network].deployedAddress);
const txnHash = await aptosMessenger.deploy(config.networks[network].privateKey); const txnHash = await aptosMessenger.deploy(config.networks[network].privateKey);
console.log(`Deployed @ ${txnHash}`); console.log(`Deployed @ ${txnHash}`);
break; break;
case "solana": case "solana":
console.log("Not supported yet"); console.log("Not supported yet");
break; break;
case "evm":
let evmMesenger = new EVMMessenger(config.networks[network].rpc, config.networks[network].bridgeAddress);
await evmMesenger.deploy(network, config.networks[network].privateKey);
break;
}
console.log(`Deploy finished!`);
});
// register network
program
.command('register-network')
.argument("<network>", "The source network")
.argument("<network>", "The foreign network to be registered")
.action(async (src, target) => {
if(!config.networks[src]){
console.error(`ERROR: ${src} not found in xdapp.config.json`);
return;
}
switch(config.networks[src].type){
case "aptos":
let aptosMessenger = new AptosMessenger(config.networks[src].rpc, config.networks[src].deployedAddress);
let targetAddress = tryNativeToUint8Array(config.networks[target].deployedAddress, config.networks[target].wormholeChainId)
const payload = aptosMessenger.registerNetwork(config.networks[src].bridgeAddress, config.networks[target].wormholeChainId, targetAddress);
const tx = await generateSignAndSubmitEntryFunction(
aptosMessenger.client,
new AptosAccount(hexToUint8Array(config.networks[src].privateKey)),
payload
);
const res = await aptosMessenger.client.waitForTransactionWithResult(tx.hash);
console.log(`Registered @ ${tx.hash}`);
break;
case "solana":
console.log("Not supported yet");
break;
case "evm":
console.log("Not supported yet")
break;
}
});
// send msg
program
.command('send-msg')
.argument("<network>", "The source network")
.argument("<msg>", "The message to be emitted")
.action(async (src, message) => {
if(!config.networks[src]){
console.error(`ERROR: ${src} not found in xdapp.config.json`);
return;
}
switch(config.networks[src].type){
case "aptos":
let aptosMessenger = new AptosMessenger(config.networks[src].rpc, config.networks[src].deployedAddress);
const payload = aptosMessenger.sendMessage(message);
const tx = (await generateSignAndSubmitEntryFunction(
aptosMessenger.client,
new AptosAccount(hexToUint8Array(config.networks[src].privateKey)),
payload
) as Types.UserTransaction);
const res = await aptosMessenger.client.waitForTransactionWithResult(tx.hash);
console.log(`Sent Messagage @ ${tx.hash}`);
let seq = parseSequenceFromLogAptos(config.networks[src].bridgeAddress, tx);
let emitter = await aptosMessenger.getEmitterAddress();
console.log(await getEmitterAddressSolana(config.networks['solana'].deployedAddress));
console.log(
"Searching for: ",
`${config.wormhole.restAddress}/v1/signed_vaa/${config.networks[src].wormholeChainId}/${emitter}/${seq}`
);
let vaaBytes = undefined;
while (!vaaBytes) {
vaaBytes = (await (
await fetch(
`${config.wormhole.restAddress}/v1/signed_vaa/${config.networks[src].wormholeChainId}/${emitter}/${seq}`
)
).json()).vaaBytes;
await new Promise((r) => setTimeout(r, 1000)); // Poll guardiand every sec for message
}
console.log("VAA: ", vaaBytes);
break;
case "solana":
console.log("Not supported yet");
break;
case "evm": case "evm":
console.log("Not supported yet"); console.log("Not supported yet");
break; break;
} }
console.log(`Deploy finished!`);
}); });
// register network
// send msg
// submit msg // submit msg
// get msg //AQAAAAABALtgDWjywCNRnmIfNU+IkWYUqbzl730v55syJzPmlCwvf3lz9V6Ax9p7ZhMX7kMufwqxNBCkDHlatY5mh5w0cuUAY5+tlgAAAAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAaGVsbG8=
program
.command('submit-vaa')
.argument("<network>", "The source network")
.argument("<vaa>", "The message to be emitted")
.action(async (src, vaa) => {
if(!config.networks[src]){
console.error(`ERROR: ${src} not found in xdapp.config.json`);
return;
}
program.parse(); switch(config.networks[src].type){
case "aptos":
let aptosMessenger = new AptosMessenger(config.networks[src].rpc, config.networks[src].deployedAddress);
const payload = aptosMessenger.submitMessage(vaa);
const tx = (await generateSignAndSubmitEntryFunction(
aptosMessenger.client,
new AptosAccount(hexToUint8Array(config.networks[src].privateKey)),
payload
) as Types.UserTransaction);
const res = await aptosMessenger.client.waitForTransactionWithResult(tx.hash);
console.log(`Submitted @ ${tx.hash}`);
break;
case "solana":
console.log("Not supported yet");
break;
case "evm":
console.log("Not supported yet");
break;
}
});
// get msg
program
.command('get-msg')
.argument('<network>', 'The network to fetch the message from')
.action(async (network) => {
if(!config.networks[network]){
console.error(`ERROR: ${network} not found in xdapp.config.json`);
return;
}
console.log(`Fetching current message on ${network}...`);
switch(config.networks[network].type){
case "aptos":
let aptosMessenger = new AptosMessenger(config.networks[network].rpc, config.networks[network].deployedAddress);
console.log(await aptosMessenger.getMessage());
break;
case "solana":
console.log("Not supported yet");
break;
case "evm":
console.log("Not supported yet");
break;
}
});
program.parse();

View File

@ -8,7 +8,10 @@
"dependencies": { "dependencies": {
"@certusone/wormhole-sdk": "^0.9.4", "@certusone/wormhole-sdk": "^0.9.4",
"@types/node": "^18.11.10", "@types/node": "^18.11.10",
"@types/node-fetch": "^2.6.2",
"aptos": "^1.4.0", "aptos": "^1.4.0",
"commander": "^9.4.1" "commander": "^9.4.1",
"ethers": "^5.7.2",
"node-fetch": "2"
} }
} }

View File

@ -2,7 +2,11 @@ import {
generateSignAndSubmitEntryFunction, generateSignAndSubmitEntryFunction,
hexToUint8Array, hexToUint8Array,
} from "@certusone/wormhole-sdk"; } from "@certusone/wormhole-sdk";
import { AptosAccount, AptosClient } from "aptos"; import {
AptosAccount,
AptosClient,
Types,
} from "aptos";
import { promisify } from "util"; import { promisify } from "util";
const exec = promisify(require("child_process").exec); const exec = promisify(require("child_process").exec);
@ -16,6 +20,7 @@ export class AptosMessenger {
max_gas_amount: "30000", max_gas_amount: "30000",
}; };
coreMessages = ""; coreMessages = "";
bridgeAddress = "";
constructor(nodeUrl: string, coreMessages: string) { constructor(nodeUrl: string, coreMessages: string) {
this.client = new AptosClient(nodeUrl); this.client = new AptosClient(nodeUrl);
@ -31,22 +36,92 @@ export class AptosMessenger {
console.log("Initalizing Aptos Messenger module..."); console.log("Initalizing Aptos Messenger module...");
// Initialize the module to register its emitter capability // Initialize the module to register its emitter capability
const APTOS_NODE_URL = "http://localhost:8080/";
const client = new AptosClient(APTOS_NODE_URL);
const sender = new AptosAccount(hexToUint8Array(privateKey)); const sender = new AptosAccount(hexToUint8Array(privateKey));
const payload:Types.EntryFunctionPayload = {
const payload = {
function: `${this.coreMessages}::messenger::init_messenger`, function: `${this.coreMessages}::messenger::init_messenger`,
type_arguments: [], type_arguments: [],
arguments: [], arguments: [
sender.address()
],
}; };
const tx = await generateSignAndSubmitEntryFunction( const tx = await generateSignAndSubmitEntryFunction(
client, this.client,
sender, sender,
payload payload
); );
const res = await client.waitForTransactionWithResult(tx.hash);
console.log(JSON.stringify(res, null, 2)); const res = await this.client.waitForTransactionWithResult(tx.hash);
//console.log(JSON.stringify(res, null, 2));
return res.hash; return res.hash;
} }
public async getEmitterAddress(): Promise<string> {
let resourceAccAddress = AptosAccount.getResourceAccountAddress(
`${this.coreMessages}`,
Buffer.from("messenger_state")
);
let state = await this.client.getAccountResource(
resourceAccAddress,
`${this.coreMessages}::messenger::State`
);
console.log(state);
return Number((state.data as any).emitter_cap.emitter).toString(16).padStart(64, '0');
}
// Regster Network
public registerNetwork(bridgeAddress:string, chainID: number, foreignAddress: Buffer | Uint8Array):Types.EntryFunctionPayload {
const payload = {
function: `${this.coreMessages}::messenger::register_emitter`,
type_arguments: [],
arguments: [
chainID,
Buffer.from(foreignAddress)
],
}
return payload;
}
// Emit Message
public sendMessage(message:String) {
const payload = {
function: `${this.coreMessages}::messenger::send_message`,
type_arguments: [],
arguments: [
Buffer.from(message)
],
}
return payload;
}
// Submit Message
public submitMessage(message: string) {
const payload = {
function: `${this.coreMessages}::messenger::receive_message`,
type_arguments: [],
arguments: [
Buffer.from(message, 'base64')
],
}
return payload;
}
// Get Message
public async getMessage() {
let resourceAccAddress = AptosAccount.getResourceAccountAddress(
`${this.coreMessages}`,
Buffer.from("messenger_state")
);
let state = await this.client.getAccountResource(
resourceAccAddress,
`${this.coreMessages}::messenger::State`
);
return (state.data as any).current_message;
}
} }

View File

@ -1 +1,3 @@
export * from './aptos'; export * from './aptos';
export * from './evm';
export * from './solana';

View File

@ -1,35 +1,38 @@
{ {
"networks": { "networks": {
"evm0": { "eth": {
"type": "evm", "type": "evm",
"wormholeChainId": 2, "wormholeChainId": 2,
"rpc": "http://localhost:8545", "rpc": "http://localhost:8545",
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", "privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" "bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550",
}, "deployedAddress": "0xeea2Fc1D255Fd28aA15c6c2324Ad40B03267f9c5"
"evm1": {
"type": "evm",
"wormholeChainId": 4,
"rpc": "http://localhost:8546",
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
},
"sol0": {
"type": "solana",
"wormholeChainId": 1,
"rpc": "http://localhost:8899",
"privateKey": "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
"bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
},
"aptos": {
"type": "aptos",
"wormholeChainId": 22,
"rpc": "http://localhost:8080",
"privateKey": "537c1f91e56891445b491068f519b705f8c0f1a1e66111816dd5d4aa85b8113d",
"bridgeAddress": "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017"
}
}, },
"wormhole": { "bsc": {
"restAddress": "http://localhost:7071" "type": "evm",
"wormholeChainId": 4,
"rpc": "http://localhost:8546",
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
},
"solana": {
"type": "solana",
"wormholeChainId": 1,
"rpc": "http://localhost:8899",
"privateKey": "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
"bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o",
"deployedAddress": "24FoTeX7BKbhTh3UF3feWusoAVKDPWZneiEqhXLVzZPL"
},
"aptos": {
"type": "aptos",
"wormholeChainId": 22,
"rpc": "http://localhost:8080",
"privateKey": "537c1f91e56891445b491068f519b705f8c0f1a1e66111816dd5d4aa85b8113d",
"bridgeAddress": "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017",
"deployedAddress": "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b"
} }
},
"wormhole": {
"restAddress": "http://localhost:7071"
}
} }

View File

@ -937,6 +937,14 @@
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
"@types/node-fetch@^2.6.2":
version "2.6.2"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da"
integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==
dependencies:
"@types/node" "*"
form-data "^3.0.0"
"@types/node@*", "@types/node@>=13.7.0", "@types/node@^18.0.3", "@types/node@^18.11.10": "@types/node@*", "@types/node@>=13.7.0", "@types/node@^18.0.3", "@types/node@^18.11.10":
version "18.11.10" version "18.11.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.10.tgz#4c64759f3c2343b7e6c4b9caf761c7a3a05cee34" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.10.tgz#4c64759f3c2343b7e6c4b9caf761c7a3a05cee34"
@ -1655,7 +1663,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1:
ethjs-util "0.1.6" ethjs-util "0.1.6"
rlp "^2.2.3" rlp "^2.2.3"
ethers@5.7.2, ethers@^5.6.4: ethers@5.7.2, ethers@^5.6.4, ethers@^5.7.2:
version "5.7.2" version "5.7.2"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e"
integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==
@ -1741,6 +1749,15 @@ form-data@4.0.0, form-data@^4.0.0:
combined-stream "^1.0.8" combined-stream "^1.0.8"
mime-types "^2.1.12" mime-types "^2.1.12"
form-data@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
fs.realpath@^1.0.0: fs.realpath@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"

View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,18 @@
[package]
name = 'messenger'
version = '1.0.0'
[dependencies.AptosFramework]
git = 'https://github.com/aptos-labs/aptos-core.git'
rev = 'main'
subdir = 'aptos-move/framework/aptos-framework'
[dependencies.Wormhole]
git = 'https://github.com/wormhole-foundation/wormhole'
rev = 'main'
subdir = 'aptos/wormhole'
[addresses]
wormhole = "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017"
deployer = "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b"
core_messages = "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b"

View File

@ -0,0 +1,121 @@
/// A simple contracts that demonstrates how to send messages with wormhole.
module core_messages::messenger {
use wormhole::wormhole;
use aptos_framework::coin;
use std::table::{Self, Table};
use wormhole::u16::U16;
use wormhole::external_address::ExternalAddress;
use aptos_framework::signer;
use aptos_framework::account;
use std::string::{Self, String};
const E_ONLY_CORE_MESSAGES_CAN_INIT:u64 = 0;
const E_ONLY_ADMIN:u64 = 1;
const E_VAA_ALREADY_CONSUMED:u64 = 2;
const E_VAA_EMMITTER_NOT_REGISTERED:u64 = 3;
struct MessengerAdminCapability has key {
// The ability to make changes to the State Resource Account
resource_signer_cap: account::SignerCapability,
}
struct State has key {
// Admin Address
admin: address,
// The ability to send wormhole messages
emitter_cap: wormhole::emitter::EmitterCapability,
// Mapping of bridge contracts on other chains
registered_emitters: Table<U16, ExternalAddress>,
// Current Message
current_message: String,
// Consumed VAAs
consumed_vaas: Table<vector<u8>, bool>,
}
public entry fun init_messenger(core_messages: &signer, admin: address) {
// Requires the private key of Core Messages to have signed this message
// This is to make sure the state get stored under core messages resource account
assert!(signer::address_of(core_messages) == @core_messages, E_ONLY_CORE_MESSAGES_CAN_INIT);
let (resource_signer, signer_cap) = account::create_resource_account(core_messages, b"messenger_state");
// Register ourselves as a wormhole emitter. This gives back an
// `EmitterCapability` which will be required to send messages through
// wormhole.
let emitter_cap = wormhole::register_emitter();
move_to(&resource_signer, State {
admin,
emitter_cap,
registered_emitters: table::new(),
current_message: string::utf8(b"uninitalized"),
consumed_vaas: table::new()
});
move_to(core_messages, MessengerAdminCapability { resource_signer_cap: signer_cap } );
}
public entry fun send_message(user: &signer, payload: vector<u8>) acquires State {
// Fetch the Resource Account that has state
let state_resource_account = account::create_resource_address(&@core_messages, b"messenger_state");
// Retrieve emitter capability from the state
let emitter_cap = &mut borrow_global_mut<State>(state_resource_account).emitter_cap;
// Set nonce to 0 (this field is not interesting for regular messages,
// only batch VAAs)
let nonce: u64 = 0;
let message_fee = wormhole::state::get_message_fee();
let fee_coins = coin::withdraw(user, message_fee);
let _sequence = wormhole::publish_message(
emitter_cap,
nonce,
payload,
fee_coins
);
}
public entry fun register_emitter(user:&signer, chainID: u64, external_address:vector<u8>) acquires State {
let chain_id = wormhole::u16::from_u64(chainID);
let foreign_address = wormhole::external_address::from_bytes(external_address);
// Fetch the Resource Account that has state
let state_resource_account = account::create_resource_address(&@core_messages, b"messenger_state");
// Retrieve emitter capability from the state
let admin_address = &borrow_global<State>(state_resource_account).admin;
assert!(*admin_address == signer::address_of(user), E_ONLY_ADMIN);
//Get Registered Emitters
let state = borrow_global_mut<State>(state_resource_account);
table::upsert(&mut state.registered_emitters, chain_id, foreign_address);
}
public entry fun receive_message(vaa_bytes: vector<u8>) acquires State {
// Verify the wormhole message
let vaa = wormhole::vaa::parse_and_verify(vaa_bytes);
// Fetch the Resource Account that has state
let state_resource_account = account::create_resource_address(&@core_messages, b"messenger_state");
let state = borrow_global_mut<State>(state_resource_account);
// Check the VAA has not been consumed already
assert!(!table::contains(&state.consumed_vaas, wormhole::vaa::get_hash(&vaa)), E_VAA_ALREADY_CONSUMED);
// Check the emitter chain is registered
assert!(*table::borrow(&state.registered_emitters, wormhole::vaa::get_emitter_chain(&vaa)) == wormhole::vaa::get_emitter_address(&vaa), E_VAA_EMMITTER_NOT_REGISTERED);
// Set the current message to the vaa message
state.current_message = string::utf8(wormhole::vaa::get_payload(&vaa));
// Store the hash of the vaa in the consumed VAAs
table::upsert(&mut state.consumed_vaas, wormhole::vaa::get_hash(&vaa), true);
wormhole::vaa::destroy(vaa);
}
}

View File

@ -2,6 +2,7 @@
"_format": "ethers-rs-sol-cache-3", "_format": "ethers-rs-sol-cache-3",
"paths": { "paths": {
"artifacts": "out", "artifacts": "out",
"build_infos": "out/build-info",
"sources": "src", "sources": "src",
"tests": "test", "tests": "test",
"scripts": "script", "scripts": "script",
@ -11,8 +12,8 @@
}, },
"files": { "files": {
"src/Messenger.sol": { "src/Messenger.sol": {
"lastModificationDate": 1659683988145, "lastModificationDate": 1671431118697,
"contentHash": "b21dd2ab010d42c4abc588eed32658bd", "contentHash": "17b03174437201be7b7f56e2bd0d92e4",
"sourceName": "src/Messenger.sol", "sourceName": "src/Messenger.sol",
"solcConfig": { "solcConfig": {
"settings": { "settings": {
@ -32,7 +33,8 @@
"abi", "abi",
"evm.bytecode", "evm.bytecode",
"evm.deployedBytecode", "evm.deployedBytecode",
"evm.methodIdentifiers" "evm.methodIdentifiers",
"metadata"
] ]
} }
}, },
@ -52,7 +54,7 @@
} }
}, },
"src/Wormhole/IWormhole.sol": { "src/Wormhole/IWormhole.sol": {
"lastModificationDate": 1659683988146, "lastModificationDate": 1665515840999,
"contentHash": "7c930d4b68538e731af28a8d1979f44e", "contentHash": "7c930d4b68538e731af28a8d1979f44e",
"sourceName": "src/Wormhole/IWormhole.sol", "sourceName": "src/Wormhole/IWormhole.sol",
"solcConfig": { "solcConfig": {
@ -73,7 +75,8 @@
"abi", "abi",
"evm.bytecode", "evm.bytecode",
"evm.deployedBytecode", "evm.deployedBytecode",
"evm.methodIdentifiers" "evm.methodIdentifiers",
"metadata"
] ]
} }
}, },
@ -92,7 +95,7 @@
} }
}, },
"src/Wormhole/Structs.sol": { "src/Wormhole/Structs.sol": {
"lastModificationDate": 1659683988147, "lastModificationDate": 1665515841000,
"contentHash": "4e824cc204959f4fcab06c4e806448c4", "contentHash": "4e824cc204959f4fcab06c4e806448c4",
"sourceName": "src/Wormhole/Structs.sol", "sourceName": "src/Wormhole/Structs.sol",
"solcConfig": { "solcConfig": {
@ -113,7 +116,8 @@
"abi", "abi",
"evm.bytecode", "evm.bytecode",
"evm.deployedBytecode", "evm.deployedBytecode",
"evm.methodIdentifiers" "evm.methodIdentifiers",
"metadata"
] ]
} }
}, },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -11,19 +11,64 @@
"linkReferences": {} "linkReferences": {}
}, },
"methodIdentifiers": {}, "methodIdentifiers": {},
"rawMetadata": "{\"compiler\":{\"version\":\"0.8.10+commit.fc410830\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/Wormhole/Structs.sol\":\"Structs\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"src/Wormhole/Structs.sol\":{\"keccak256\":\"0xf6067f3a7ac8ccd239a50aa2ef5620ffe31bc86a3757571e13e57a3a0f476b37\",\"license\":\"Apache 2\",\"urls\":[\"bzz-raw://813db91e92feacdf21da3986e1a59d38befc34103cd09e61d30471c228e3a6f2\",\"dweb:/ipfs/QmWeRrqvbite8YCHu97Lsta1Y3TR9WzQ9k2spaF6S3VQZZ\"]}},\"version\":1}",
"metadata": {
"compiler": {
"version": "0.8.10+commit.fc410830"
},
"language": "Solidity",
"output": {
"abi": [],
"devdoc": {
"kind": "dev",
"methods": {},
"version": 1
},
"userdoc": {
"kind": "user",
"methods": {},
"version": 1
}
},
"settings": {
"remappings": [],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"bytecodeHash": "ipfs"
},
"compilationTarget": {
"src/Wormhole/Structs.sol": "Structs"
},
"libraries": {}
},
"sources": {
"src/Wormhole/Structs.sol": {
"keccak256": "0xf6067f3a7ac8ccd239a50aa2ef5620ffe31bc86a3757571e13e57a3a0f476b37",
"urls": [
"bzz-raw://813db91e92feacdf21da3986e1a59d38befc34103cd09e61d30471c228e3a6f2",
"dweb:/ipfs/QmWeRrqvbite8YCHu97Lsta1Y3TR9WzQ9k2spaF6S3VQZZ"
],
"license": "Apache 2"
}
},
"version": 1
},
"ast": { "ast": {
"absolutePath": "src/Wormhole/Structs.sol", "absolutePath": "src/Wormhole/Structs.sol",
"id": 331, "id": 333,
"exportedSymbols": { "exportedSymbols": {
"Structs": [ "Structs": [
330 332
] ]
}, },
"nodeType": "SourceUnit", "nodeType": "SourceUnit",
"src": "63:551:2", "src": "63:551:2",
"nodes": [ "nodes": [
{ {
"id": 282, "id": 284,
"nodeType": "PragmaDirective", "nodeType": "PragmaDirective",
"src": "63:23:2", "src": "63:23:2",
"literals": [ "literals": [
@ -34,24 +79,24 @@
] ]
}, },
{ {
"id": 330, "id": 332,
"nodeType": "ContractDefinition", "nodeType": "ContractDefinition",
"src": "88:526:2", "src": "88:526:2",
"nodes": [ "nodes": [
{ {
"id": 289, "id": 291,
"nodeType": "StructDefinition", "nodeType": "StructDefinition",
"src": "109:96:2", "src": "109:96:2",
"canonicalName": "Structs.Provider", "canonicalName": "Structs.Provider",
"members": [ "members": [
{ {
"constant": false, "constant": false,
"id": 284, "id": 286,
"mutability": "mutable", "mutability": "mutable",
"name": "chainId", "name": "chainId",
"nameLocation": "136:7:2", "nameLocation": "136:7:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 289, "scope": 291,
"src": "129:14:2", "src": "129:14:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -60,7 +105,7 @@
"typeString": "uint16" "typeString": "uint16"
}, },
"typeName": { "typeName": {
"id": 283, "id": 285,
"name": "uint16", "name": "uint16",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "129:6:2", "src": "129:6:2",
@ -73,12 +118,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 286, "id": 288,
"mutability": "mutable", "mutability": "mutable",
"name": "governanceChainId", "name": "governanceChainId",
"nameLocation": "154:17:2", "nameLocation": "154:17:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 289, "scope": 291,
"src": "147:24:2", "src": "147:24:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -87,7 +132,7 @@
"typeString": "uint16" "typeString": "uint16"
}, },
"typeName": { "typeName": {
"id": 285, "id": 287,
"name": "uint16", "name": "uint16",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "147:6:2", "src": "147:6:2",
@ -100,12 +145,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 288, "id": 290,
"mutability": "mutable", "mutability": "mutable",
"name": "governanceContract", "name": "governanceContract",
"nameLocation": "183:18:2", "nameLocation": "183:18:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 289, "scope": 291,
"src": "175:26:2", "src": "175:26:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -114,7 +159,7 @@
"typeString": "bytes32" "typeString": "bytes32"
}, },
"typeName": { "typeName": {
"id": 287, "id": 289,
"name": "bytes32", "name": "bytes32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "175:7:2", "src": "175:7:2",
@ -128,23 +173,23 @@
], ],
"name": "Provider", "name": "Provider",
"nameLocation": "116:8:2", "nameLocation": "116:8:2",
"scope": 330, "scope": 332,
"visibility": "public" "visibility": "public"
}, },
{ {
"id": 295, "id": 297,
"nodeType": "StructDefinition", "nodeType": "StructDefinition",
"src": "208:66:2", "src": "208:66:2",
"canonicalName": "Structs.GuardianSet", "canonicalName": "Structs.GuardianSet",
"members": [ "members": [
{ {
"constant": false, "constant": false,
"id": 292, "id": 294,
"mutability": "mutable", "mutability": "mutable",
"name": "keys", "name": "keys",
"nameLocation": "241:4:2", "nameLocation": "241:4:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 295, "scope": 297,
"src": "231:14:2", "src": "231:14:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -154,7 +199,7 @@
}, },
"typeName": { "typeName": {
"baseType": { "baseType": {
"id": 290, "id": 292,
"name": "address", "name": "address",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "231:7:2", "src": "231:7:2",
@ -164,7 +209,7 @@
"typeString": "address" "typeString": "address"
} }
}, },
"id": 291, "id": 293,
"nodeType": "ArrayTypeName", "nodeType": "ArrayTypeName",
"src": "231:9:2", "src": "231:9:2",
"typeDescriptions": { "typeDescriptions": {
@ -176,12 +221,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 294, "id": 296,
"mutability": "mutable", "mutability": "mutable",
"name": "expirationTime", "name": "expirationTime",
"nameLocation": "256:14:2", "nameLocation": "256:14:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 295, "scope": 297,
"src": "249:21:2", "src": "249:21:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -190,7 +235,7 @@
"typeString": "uint32" "typeString": "uint32"
}, },
"typeName": { "typeName": {
"id": 293, "id": 295,
"name": "uint32", "name": "uint32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "249:6:2", "src": "249:6:2",
@ -204,23 +249,23 @@
], ],
"name": "GuardianSet", "name": "GuardianSet",
"nameLocation": "215:11:2", "nameLocation": "215:11:2",
"scope": 330, "scope": 332,
"visibility": "public" "visibility": "public"
}, },
{ {
"id": 304, "id": 306,
"nodeType": "StructDefinition", "nodeType": "StructDefinition",
"src": "277:81:2", "src": "277:81:2",
"canonicalName": "Structs.Signature", "canonicalName": "Structs.Signature",
"members": [ "members": [
{ {
"constant": false, "constant": false,
"id": 297, "id": 299,
"mutability": "mutable", "mutability": "mutable",
"name": "r", "name": "r",
"nameLocation": "306:1:2", "nameLocation": "306:1:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 304, "scope": 306,
"src": "298:9:2", "src": "298:9:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -229,7 +274,7 @@
"typeString": "bytes32" "typeString": "bytes32"
}, },
"typeName": { "typeName": {
"id": 296, "id": 298,
"name": "bytes32", "name": "bytes32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "298:7:2", "src": "298:7:2",
@ -242,12 +287,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 299, "id": 301,
"mutability": "mutable", "mutability": "mutable",
"name": "s", "name": "s",
"nameLocation": "319:1:2", "nameLocation": "319:1:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 304, "scope": 306,
"src": "311:9:2", "src": "311:9:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -256,7 +301,7 @@
"typeString": "bytes32" "typeString": "bytes32"
}, },
"typeName": { "typeName": {
"id": 298, "id": 300,
"name": "bytes32", "name": "bytes32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "311:7:2", "src": "311:7:2",
@ -269,12 +314,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 301, "id": 303,
"mutability": "mutable", "mutability": "mutable",
"name": "v", "name": "v",
"nameLocation": "330:1:2", "nameLocation": "330:1:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 304, "scope": 306,
"src": "324:7:2", "src": "324:7:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -283,7 +328,7 @@
"typeString": "uint8" "typeString": "uint8"
}, },
"typeName": { "typeName": {
"id": 300, "id": 302,
"name": "uint8", "name": "uint8",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "324:5:2", "src": "324:5:2",
@ -296,12 +341,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 303, "id": 305,
"mutability": "mutable", "mutability": "mutable",
"name": "guardianIndex", "name": "guardianIndex",
"nameLocation": "341:13:2", "nameLocation": "341:13:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 304, "scope": 306,
"src": "335:19:2", "src": "335:19:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -310,7 +355,7 @@
"typeString": "uint8" "typeString": "uint8"
}, },
"typeName": { "typeName": {
"id": 302, "id": 304,
"name": "uint8", "name": "uint8",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "335:5:2", "src": "335:5:2",
@ -324,23 +369,23 @@
], ],
"name": "Signature", "name": "Signature",
"nameLocation": "284:9:2", "nameLocation": "284:9:2",
"scope": 330, "scope": 332,
"visibility": "public" "visibility": "public"
}, },
{ {
"id": 329, "id": 331,
"nodeType": "StructDefinition", "nodeType": "StructDefinition",
"src": "361:251:2", "src": "361:251:2",
"canonicalName": "Structs.VM", "canonicalName": "Structs.VM",
"members": [ "members": [
{ {
"constant": false, "constant": false,
"id": 306, "id": 308,
"mutability": "mutable", "mutability": "mutable",
"name": "version", "name": "version",
"nameLocation": "381:7:2", "nameLocation": "381:7:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "375:13:2", "src": "375:13:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -349,7 +394,7 @@
"typeString": "uint8" "typeString": "uint8"
}, },
"typeName": { "typeName": {
"id": 305, "id": 307,
"name": "uint8", "name": "uint8",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "375:5:2", "src": "375:5:2",
@ -362,12 +407,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 308, "id": 310,
"mutability": "mutable", "mutability": "mutable",
"name": "timestamp", "name": "timestamp",
"nameLocation": "399:9:2", "nameLocation": "399:9:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "392:16:2", "src": "392:16:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -376,7 +421,7 @@
"typeString": "uint32" "typeString": "uint32"
}, },
"typeName": { "typeName": {
"id": 307, "id": 309,
"name": "uint32", "name": "uint32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "392:6:2", "src": "392:6:2",
@ -389,12 +434,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 310, "id": 312,
"mutability": "mutable", "mutability": "mutable",
"name": "nonce", "name": "nonce",
"nameLocation": "419:5:2", "nameLocation": "419:5:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "412:12:2", "src": "412:12:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -403,7 +448,7 @@
"typeString": "uint32" "typeString": "uint32"
}, },
"typeName": { "typeName": {
"id": 309, "id": 311,
"name": "uint32", "name": "uint32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "412:6:2", "src": "412:6:2",
@ -416,12 +461,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 312, "id": 314,
"mutability": "mutable", "mutability": "mutable",
"name": "emitterChainId", "name": "emitterChainId",
"nameLocation": "435:14:2", "nameLocation": "435:14:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "428:21:2", "src": "428:21:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -430,7 +475,7 @@
"typeString": "uint16" "typeString": "uint16"
}, },
"typeName": { "typeName": {
"id": 311, "id": 313,
"name": "uint16", "name": "uint16",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "428:6:2", "src": "428:6:2",
@ -443,12 +488,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 314, "id": 316,
"mutability": "mutable", "mutability": "mutable",
"name": "emitterAddress", "name": "emitterAddress",
"nameLocation": "461:14:2", "nameLocation": "461:14:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "453:22:2", "src": "453:22:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -457,7 +502,7 @@
"typeString": "bytes32" "typeString": "bytes32"
}, },
"typeName": { "typeName": {
"id": 313, "id": 315,
"name": "bytes32", "name": "bytes32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "453:7:2", "src": "453:7:2",
@ -470,12 +515,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 316, "id": 318,
"mutability": "mutable", "mutability": "mutable",
"name": "sequence", "name": "sequence",
"nameLocation": "486:8:2", "nameLocation": "486:8:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "479:15:2", "src": "479:15:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -484,7 +529,7 @@
"typeString": "uint64" "typeString": "uint64"
}, },
"typeName": { "typeName": {
"id": 315, "id": 317,
"name": "uint64", "name": "uint64",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "479:6:2", "src": "479:6:2",
@ -497,12 +542,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 318, "id": 320,
"mutability": "mutable", "mutability": "mutable",
"name": "consistencyLevel", "name": "consistencyLevel",
"nameLocation": "504:16:2", "nameLocation": "504:16:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "498:22:2", "src": "498:22:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -511,7 +556,7 @@
"typeString": "uint8" "typeString": "uint8"
}, },
"typeName": { "typeName": {
"id": 317, "id": 319,
"name": "uint8", "name": "uint8",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "498:5:2", "src": "498:5:2",
@ -524,12 +569,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 320, "id": 322,
"mutability": "mutable", "mutability": "mutable",
"name": "payload", "name": "payload",
"nameLocation": "530:7:2", "nameLocation": "530:7:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "524:13:2", "src": "524:13:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -538,7 +583,7 @@
"typeString": "bytes" "typeString": "bytes"
}, },
"typeName": { "typeName": {
"id": 319, "id": 321,
"name": "bytes", "name": "bytes",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "524:5:2", "src": "524:5:2",
@ -551,12 +596,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 322, "id": 324,
"mutability": "mutable", "mutability": "mutable",
"name": "guardianSetIndex", "name": "guardianSetIndex",
"nameLocation": "549:16:2", "nameLocation": "549:16:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "542:23:2", "src": "542:23:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -565,7 +610,7 @@
"typeString": "uint32" "typeString": "uint32"
}, },
"typeName": { "typeName": {
"id": 321, "id": 323,
"name": "uint32", "name": "uint32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "542:6:2", "src": "542:6:2",
@ -578,42 +623,42 @@
}, },
{ {
"constant": false, "constant": false,
"id": 326, "id": 328,
"mutability": "mutable", "mutability": "mutable",
"name": "signatures", "name": "signatures",
"nameLocation": "581:10:2", "nameLocation": "581:10:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "569:22:2", "src": "569:22:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
"typeDescriptions": { "typeDescriptions": {
"typeIdentifier": "t_array$_t_struct$_Signature_$304_storage_$dyn_storage_ptr", "typeIdentifier": "t_array$_t_struct$_Signature_$306_storage_$dyn_storage_ptr",
"typeString": "struct Structs.Signature[]" "typeString": "struct Structs.Signature[]"
}, },
"typeName": { "typeName": {
"baseType": { "baseType": {
"id": 324, "id": 326,
"nodeType": "UserDefinedTypeName", "nodeType": "UserDefinedTypeName",
"pathNode": { "pathNode": {
"id": 323, "id": 325,
"name": "Signature", "name": "Signature",
"nodeType": "IdentifierPath", "nodeType": "IdentifierPath",
"referencedDeclaration": 304, "referencedDeclaration": 306,
"src": "569:9:2" "src": "569:9:2"
}, },
"referencedDeclaration": 304, "referencedDeclaration": 306,
"src": "569:9:2", "src": "569:9:2",
"typeDescriptions": { "typeDescriptions": {
"typeIdentifier": "t_struct$_Signature_$304_storage_ptr", "typeIdentifier": "t_struct$_Signature_$306_storage_ptr",
"typeString": "struct Structs.Signature" "typeString": "struct Structs.Signature"
} }
}, },
"id": 325, "id": 327,
"nodeType": "ArrayTypeName", "nodeType": "ArrayTypeName",
"src": "569:11:2", "src": "569:11:2",
"typeDescriptions": { "typeDescriptions": {
"typeIdentifier": "t_array$_t_struct$_Signature_$304_storage_$dyn_storage_ptr", "typeIdentifier": "t_array$_t_struct$_Signature_$306_storage_$dyn_storage_ptr",
"typeString": "struct Structs.Signature[]" "typeString": "struct Structs.Signature[]"
} }
}, },
@ -621,12 +666,12 @@
}, },
{ {
"constant": false, "constant": false,
"id": 328, "id": 330,
"mutability": "mutable", "mutability": "mutable",
"name": "hash", "name": "hash",
"nameLocation": "604:4:2", "nameLocation": "604:4:2",
"nodeType": "VariableDeclaration", "nodeType": "VariableDeclaration",
"scope": 329, "scope": 331,
"src": "596:12:2", "src": "596:12:2",
"stateVariable": false, "stateVariable": false,
"storageLocation": "default", "storageLocation": "default",
@ -635,7 +680,7 @@
"typeString": "bytes32" "typeString": "bytes32"
}, },
"typeName": { "typeName": {
"id": 327, "id": 329,
"name": "bytes32", "name": "bytes32",
"nodeType": "ElementaryTypeName", "nodeType": "ElementaryTypeName",
"src": "596:7:2", "src": "596:7:2",
@ -649,7 +694,7 @@
], ],
"name": "VM", "name": "VM",
"nameLocation": "368:2:2", "nameLocation": "368:2:2",
"scope": 330, "scope": 332,
"visibility": "public" "visibility": "public"
} }
], ],
@ -660,11 +705,11 @@
"contractKind": "interface", "contractKind": "interface",
"fullyImplemented": true, "fullyImplemented": true,
"linearizedBaseContracts": [ "linearizedBaseContracts": [
330 332
], ],
"name": "Structs", "name": "Structs",
"nameLocation": "98:7:2", "nameLocation": "98:7:2",
"scope": 331, "scope": 333,
"usedErrors": [] "usedErrors": []
} }
], ],

View File

@ -5,7 +5,7 @@ import "./Wormhole/IWormhole.sol";
contract Messenger { contract Messenger {
string private current_msg; string private current_msg;
address private wormhole_core_bridge_address; IWormhole core_bridge;
uint32 nonce = 0; uint32 nonce = 0;
mapping(uint16 => bytes32) _applicationContracts; mapping(uint16 => bytes32) _applicationContracts;
address owner; address owner;
@ -13,10 +13,9 @@ contract Messenger {
constructor(address _core_bridge_address){ constructor(address _core_bridge_address){
owner = msg.sender; owner = msg.sender;
wormhole_core_bridge_address = _core_bridge_address; core_bridge = IWormhole(_core_bridge_address);
} }
IWormhole core_bridge = IWormhole(wormhole_core_bridge_address);
function sendMsg(bytes memory str) public returns (uint64 sequence) { function sendMsg(bytes memory str) public returns (uint64 sequence) {
sequence = core_bridge.publishMessage(nonce, str, 1); sequence = core_bridge.publishMessage(nonce, str, 1);

View File

@ -0,0 +1,242 @@
import {
generateSignAndSubmitEntryFunction,
getEmitterAddressEth,
getEmitterAddressSolana,
hexToUint8Array,
parseSequenceFromLogAptos,
} from "@certusone/wormhole-sdk";
import {
AptosAccount,
AptosClient,
Types,
} from "aptos";
import { promisify } from "util";
const exec = promisify(require("child_process").exec);
import * as fs from 'fs';
import fetch from "node-fetch";
const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString());
const coreMessages = "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b";
export async function deploy(src:string){
const privateKey = config.networks[src].privateKey;
const rpc = config.networks[src].rpc;
let cmd = `cd chains/aptos && aptos move compile --save-metadata && aptos move publish --private-key ${privateKey} --url ${rpc} --assume-yes`;
const { stdout, stderr } = await exec(cmd);
//console.log(stdout);
console.log("Initalizing Aptos Messenger module...");
// Initialize the module to register its emitter capability
const sender = new AptosAccount(hexToUint8Array(privateKey));
const payload:Types.EntryFunctionPayload = {
function: `${coreMessages}::messenger::init_messenger`,
type_arguments: [],
arguments: [
sender.address()
],
};
const client = new AptosClient(rpc);
const tx = await generateSignAndSubmitEntryFunction(
client,
sender,
payload
);
const res = await client.waitForTransactionWithResult(tx.hash);
//console.log(JSON.stringify(res, null, 2));
fs.writeFileSync(`./deployinfo/${src}.deploy.json`, JSON.stringify({
address: coreMessages,
vaas: []
}, null, 4))
return res.hash;
}
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;
case 'aptos':
targetEmitter = await getEmitterAddress(config.networks[src].rpc, targetDeploymentInfo['address']);
break;
}
const payload = {
function: `${coreMessages}::messenger::register_emitter`,
type_arguments: [],
arguments: [
targetNetwork.wormholeChainId,
Buffer.from(targetEmitter, 'hex')
],
}
const client = new AptosClient(srcNetwork.rpc);
const tx = await generateSignAndSubmitEntryFunction(
client,
new AptosAccount(hexToUint8Array(config.networks[src].privateKey)),
payload
);
const res = await client.waitForTransactionWithResult(tx.hash);
console.log(`Registered @ ${tx.hash}`);
}
export async function sendMsg(src:string, msg:string){
const client = new AptosClient(config.networks[src].rpc);
const payload = {
function: `${coreMessages}::messenger::send_message`,
type_arguments: [],
arguments: [
Buffer.from(msg)
],
}
const tx = (await generateSignAndSubmitEntryFunction(
client,
new AptosAccount(hexToUint8Array(config.networks[src].privateKey)),
payload
) as Types.UserTransaction);
const res = await client.waitForTransactionWithResult(tx.hash);
console.log(`Sent Messagage @ ${tx.hash}`);
let seq = parseSequenceFromLogAptos(config.networks[src].bridgeAddress, tx);
let emitter = await getEmitterAddress(config.networks[src].rpc, coreMessages);
console.log(
"Searching for: ",
`${config.wormhole.restAddress}/v1/signed_vaa/${config.networks[src].wormholeChainId}/${emitter}/${seq}`
);
let vaaBytes = undefined;
while (!vaaBytes) {
vaaBytes = (await (
await fetch(
`${config.wormhole.restAddress}/v1/signed_vaa/${config.networks[src].wormholeChainId}/${emitter}/${seq}`
)
).json()).vaaBytes;
await new Promise((r) => setTimeout(r, 1000)); // Poll guardiand every sec for message
}
console.log("VAA: ", vaaBytes);
let srcDeploymentInfo = JSON.parse(fs.readFileSync(`./deployinfo/${src}.deploy.json`).toString());
if(!srcDeploymentInfo['vaas']){
srcDeploymentInfo['vaas'] = [vaaBytes]
} else {
srcDeploymentInfo['vaas'].push(vaaBytes)
}
fs.writeFileSync(
`./deployinfo/${src}.deploy.json`,
JSON.stringify(srcDeploymentInfo, null, 4)
);
return vaaBytes;
}
export async function submitVaa(src:string, target:string, idx: string){
const srcNetwork = config.networks[src];
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 payload = {
function: `${coreMessages}::messenger::receive_message`,
type_arguments: [],
arguments: [
Buffer.from(vaa, 'base64')
],
}
const client = new AptosClient(srcNetwork.rpc);
const tx = (await generateSignAndSubmitEntryFunction(
client,
new AptosAccount(hexToUint8Array(config.networks[src].privateKey)),
payload
) as Types.UserTransaction);
const res = await client.waitForTransactionWithResult(tx.hash);
console.log(`Submitted @ ${tx.hash}`);
return tx.hash;
}
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`);
}
let resourceAccAddress = AptosAccount.getResourceAccountAddress(
`${coreMessages}`,
Buffer.from("messenger_state")
);
const client = new AptosClient(srcNetwork.rpc);
let state = await client.getAccountResource(
resourceAccAddress,
`${coreMessages}::messenger::State`
);
return (state.data as any).current_message;
}
export async function getEmitterAddress(rpc: string, deployedContractAddress:string): Promise<string> {
let resourceAccAddress = AptosAccount.getResourceAccountAddress(
`${deployedContractAddress}`,
Buffer.from("messenger_state")
);
const client = new AptosClient(rpc);
let state = await client.getAccountResource(
resourceAccAddress,
`${deployedContractAddress}::messenger::State`
);
return Number((state.data as any).emitter_cap.emitter).toString(16).padStart(64, '0');
}

View File

@ -1,17 +1,19 @@
import * as fs from 'fs'; import * as fs from 'fs';
import { exec } from "child_process"; import { exec } from "child_process";
import { getEmitterAddressEth, getEmitterAddressSolana, parseSequenceFromLogEth, setDefaultWasm } from '@certusone/wormhole-sdk'; import { getEmitterAddressEth, getEmitterAddressSolana, parseSequenceFromLogEth } from '@certusone/wormhole-sdk';
import * as ethers from 'ethers'; import * as ethers from 'ethers';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import {getEmitterAddress as getEmitterAddressAptos} from './aptos';
const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString()); const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString());
export async function deploy(chain: string){ export async function deploy(chain: string){
const rpc = config.networks[chain]['rpc']; const rpc = config.networks[chain]['rpc'];
const privateKey = config.networks[chain]['privateKey']; const privateKey = config.networks[chain]['privateKey'];
const bridgeAddress = config.networks[chain]['bridgeAddress'];
exec( exec(
`cd chains/evm && forge build && forge create --legacy --rpc-url ${rpc} --private-key ${privateKey} src/Messenger.sol:Messenger && exit`, `cd chains/evm && forge build && forge create --legacy --rpc-url ${rpc} --private-key ${privateKey} src/Messenger.sol:Messenger --constructor-args ${bridgeAddress} && exit`,
(err, out, errStr) => { (err, out, errStr) => {
if (err) { if (err) {
throw new Error(err.message); throw new Error(err.message);
@ -61,9 +63,11 @@ export async function registerApp(src:string, target:string){
targetEmitter = getEmitterAddressEth(targetDeploymentInfo['address']); targetEmitter = getEmitterAddressEth(targetDeploymentInfo['address']);
break; break;
case 'solana': case 'solana':
setDefaultWasm("node"); // *sigh*
targetEmitter = await getEmitterAddressSolana(targetDeploymentInfo['address']); targetEmitter = await getEmitterAddressSolana(targetDeploymentInfo['address']);
break; break;
case 'aptos':
targetEmitter = await getEmitterAddressAptos(targetNetwork.rpc, targetDeploymentInfo['address']);
break;
} }
const emitterBuffer = Buffer.from(targetEmitter, 'hex'); const emitterBuffer = Buffer.from(targetEmitter, 'hex');
@ -110,8 +114,8 @@ export async function sendMsg(src:string, msg:string){
).abi, ).abi,
signer signer
); );
const tx = await (await messenger.sendMsg(Buffer.from(msg))).wait(); const tx = await (await messenger.sendMsg(Buffer.from(msg), {gasLimit: 150000})).wait();
const seq = parseSequenceFromLogEth(tx, srcNetwork['bridgeAddress']); const seq = parseSequenceFromLogEth(tx, srcNetwork['bridgeAddress']);
const emitterAddr = getEmitterAddressEth(srcDeploymentInfo['address']); const emitterAddr = getEmitterAddressEth(srcDeploymentInfo['address']);

View File

@ -5,11 +5,10 @@ import fetch from 'node-fetch';
import { import {
getEmitterAddressEth, getEmitterAddressEth,
getEmitterAddressSolana, getEmitterAddressSolana,
importCoreWasm,
parseSequenceFromLogSolana, parseSequenceFromLogSolana,
postVaaSolanaWithRetry, postVaaSolanaWithRetry,
setDefaultWasm, getSignedVAAHash,
getSignedVAAHash, parseVaa,
} from '@certusone/wormhole-sdk'; } from '@certusone/wormhole-sdk';
import * as anchor from '@project-serum/anchor'; import * as anchor from '@project-serum/anchor';
import { findProgramAddressSync } from '@project-serum/anchor/dist/cjs/utils/pubkey'; import { findProgramAddressSync } from '@project-serum/anchor/dist/cjs/utils/pubkey';
@ -190,7 +189,6 @@ export async function sendMsg(src:string, msg:string){
.rpc(); .rpc();
const seq = parseSequenceFromLogSolana(await messenger.provider.connection.getTransaction(tx)) const seq = parseSequenceFromLogSolana(await messenger.provider.connection.getTransaction(tx))
setDefaultWasm("node"); // *sigh*
const emitterAddr = await getEmitterAddressSolana(messenger.programId.toString()); //same as whDerivedEmitter const emitterAddr = await getEmitterAddressSolana(messenger.programId.toString()); //same as whDerivedEmitter
await new Promise((r) => setTimeout(r, 5000)); // Wait for guardian to pick up message await new Promise((r) => setTimeout(r, 5000)); // Wait for guardian to pick up message
@ -222,7 +220,6 @@ export async function sendMsg(src:string, msg:string){
} }
export async function submitVaa(src:string, target:string, idx:string){ export async function submitVaa(src:string, target:string, idx:string){
setDefaultWasm("node"); //WASM will be removed very soon, but until then, all the solana functions rely on it
const srcNetwork = config.networks[src]; const srcNetwork = config.networks[src];
let srcDeploymentInfo; let srcDeploymentInfo;
@ -270,23 +267,21 @@ export async function submitVaa(src:string, target:string, idx:string){
// Then we submit to our program to go through the program's checks // Then we submit to our program to go through the program's checks
await new Promise((r) => setTimeout(r, 5000)); await new Promise((r) => setTimeout(r, 5000));
const { parse_vaa } = await importCoreWasm(); //this function can only be imported from the WASM right now, not directly const parsed_vaa = parseVaa(Buffer.from(vaa, 'base64'));
const parsed_vaa = parse_vaa(Buffer.from(vaa, 'base64'));
const vaaHash = getVaaHash(parsed_vaa); //await getSignedVAAHash(Buffer.from(vaa, "base64")); const vaaHash = getVaaHash(parsed_vaa); //await getSignedVAAHash(Buffer.from(vaa, "base64"));
//console.log("Hash: ", vaaHash, await getSignedVAAHash(Buffer.from(vaa, "base64"))); //console.log("Hash: ", vaaHash, await getSignedVAAHash(Buffer.from(vaa, "base64")));
// Account that we stored the registered foreign emitter // Account that we stored the registered foreign emitter
let emitterAddressAcc = findProgramAddressSync([ let emitterAddressAcc = findProgramAddressSync([
Buffer.from("EmitterAddress"), Buffer.from("EmitterAddress"),
byteify.serializeUint16(parsed_vaa.emitter_chain) byteify.serializeUint16(parsed_vaa.emitterChain)
], messenger.programId)[0]; ], messenger.programId)[0];
// A blank account we're creating just to keep track of already processed messages // A blank account we're creating just to keep track of already processed messages
let processedVaaKey = findProgramAddressSync([ let processedVaaKey = findProgramAddressSync([
Buffer.from(getEmitterAddressEth(targetDeploymentInfo.address), "hex"), Buffer.from(getEmitterAddressEth(targetDeploymentInfo.address), "hex"),
byteify.serializeUint16(parsed_vaa.emitter_chain), byteify.serializeUint16(parsed_vaa.emitterChain),
byteify.serializeUint64(parsed_vaa.sequence) byteify.serializeUint64(Number(parsed_vaa.sequence))
], messenger.programId)[0]; ], messenger.programId)[0];
// Account where the core bridge stored the vaa after the signatures checked out // Account where the core bridge stored the vaa after the signatures checked out

View File

@ -2,6 +2,7 @@ import { Command } from 'commander';
import * as fs from 'fs'; import * as fs from 'fs';
import * as evm from './handlers/evm'; import * as evm from './handlers/evm';
import * as solana from './handlers/solana'; import * as solana from './handlers/solana';
import * as aptos from './handlers/aptos';
const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString()) const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString())
@ -29,6 +30,9 @@ program
case "solana": case "solana":
await solana.deploy(network); await solana.deploy(network);
break; break;
case 'aptos':
await aptos.deploy(network);
break;
} }
console.log(`Deploy finished!`); console.log(`Deploy finished!`);
@ -56,6 +60,10 @@ program
break; break;
case "solana": case "solana":
await solana.registerApp(src, target); await solana.registerApp(src, target);
break;
case "aptos":
await aptos.registerApp(src, target);
break;
} }
console.log(`Foreign Network ${target} registered on ${src}`); console.log(`Foreign Network ${target} registered on ${src}`);
@ -82,6 +90,9 @@ program
case "solana": case "solana":
await solana.sendMsg(src, msg); await solana.sendMsg(src, msg);
break; break;
case "aptos":
await aptos.sendMsg(src, msg);
break;
} }
console.log(`Emitted VAA on ${src} network. Submit it using \`submit-vaa\` command on a target network.`) console.log(`Emitted VAA on ${src} network. Submit it using \`submit-vaa\` command on a target network.`)
} catch (e){ } catch (e){
@ -113,6 +124,9 @@ program
case "solana": case "solana":
await solana.submitVaa(src,target,idx); await solana.submitVaa(src,target,idx);
break; break;
case "aptos":
await aptos.submitVaa(src, target, idx);
break;
} }
console.log(`Submitted VAA #${idx} from ${target} to chain ${src}`); console.log(`Submitted VAA #${idx} from ${target} to chain ${src}`);
@ -140,6 +154,9 @@ program
case "solana": case "solana":
msg = await solana.getCurrentMsg(src); msg = await solana.getCurrentMsg(src);
break; break;
case "aptos":
msg = await aptos.getCurrentMsg(src);
break;
} }
console.log(`Current Message on Network ${src} is ${msg}`); console.log(`Current Message on Network ${src} is ${msg}`);

View File

@ -6,10 +6,11 @@
"author": "Dev Bharel", "author": "Dev Bharel",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@certusone/wormhole-sdk": "^0.6.0", "@certusone/wormhole-sdk": "^0.9.6",
"@project-serum/anchor": "^0.25.0", "@project-serum/anchor": "^0.25.0",
"@solana/web3.js": "^1.64.0", "@solana/web3.js": "^1.64.0",
"@types/node-fetch": "^2.6.2", "@types/node-fetch": "^2.6.2",
"aptos": "^1.4.0",
"byteify": "^2.0.10", "byteify": "^2.0.10",
"commander": "^9.4.0", "commander": "^9.4.0",
"ethers": "^5.6.9", "ethers": "^5.6.9",

View File

@ -14,9 +14,9 @@ import { ethers } from "ethers";
import { Connection as SolanaConnection } from "@solana/web3.js"; import { Connection as SolanaConnection } from "@solana/web3.js";
import { BaseVAA } from "./utils"; import { BaseVAA } from "./utils";
import { TextDecoder } from "util"; import { TextDecoder } from "util";
import { parseVaa } from "@certusone/wormhole-sdk";
// todo: do we need this in the plugin or just the relayer?? // todo: do we need this in the plugin or just the relayer??
whSdk.setDefaultWasm("node");
function create( function create(
commonConfig: CommonPluginEnv, commonConfig: CommonPluginEnv,
@ -165,8 +165,7 @@ export class MessengerRelayerPlugin implements Plugin<VAA> {
async parseVAA(vaa: Buffer | Uint8Array): Promise<BaseVAA> { async parseVAA(vaa: Buffer | Uint8Array): Promise<BaseVAA> {
try { try {
const { parse_vaa } = await whSdk.importCoreWasm(); return parseVaa(new Uint8Array(vaa)) as any as BaseVAA;
return parse_vaa(new Uint8Array(vaa)) as BaseVAA;
} catch (e) { } catch (e) {
this.logger.error("Failed to parse vaa"); this.logger.error("Failed to parse vaa");
throw e; throw e;

View File

@ -0,0 +1,26 @@
# Install Deps
yarn
# Deploy evm0 and aptos
ts-node orchestrator.ts deploy evm0
ts-node orchestrator.ts deploy aptos
# Register evm0 on aptos and vice versa
ts-node orchestrator.ts register-network evm0 aptos
ts-node orchestrator.ts register-network aptos evm0
# Emit VAA from evm0
ts-node orchestrator.ts emit-msg evm0 "Hello from evm0"
# Emit VAA from aptos
ts-node orchestrator.ts emit-msg aptos "Hello from aptos"
# Submit evm0 VAA to aptos
ts-node orchestrator.ts submit-vaa aptos evm0 latest
ts-node orchestrator.ts submit-vaa evm0 aptos latest
# Wait a couple blocks for confirmation
sleep 3
# Get Current Messages from evm0 and aptos
ts-node orchestrator.ts get-msg evm0
ts-node orchestrator.ts get-msg aptos

View File

@ -20,6 +20,13 @@
"rpc": "http://localhost:8899", "rpc": "http://localhost:8899",
"privateKey": "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx", "privateKey": "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
"bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o" "bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
},
"aptos": {
"type": "aptos",
"wormholeChainId": 22,
"rpc": "http://localhost:8080",
"privateKey": "537c1f91e56891445b491068f519b705f8c0f1a1e66111816dd5d4aa85b8113d",
"bridgeAddress": "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017"
} }
}, },
"wormhole": { "wormhole": {

File diff suppressed because it is too large Load Diff

3133
projects/messenger/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
@ -6,5 +6,4 @@ set -euo pipefail
npx pm2 delete aptos 2> /dev/null || true npx pm2 delete aptos 2> /dev/null || true
npx pm2 start 'aptos node run-local-testnet --with-faucet --force-restart --assume-yes' --name aptos npx pm2 start 'aptos node run-local-testnet --with-faucet --force-restart --assume-yes' --name aptos
sleep 15 sleep 15
cd wormhole/aptos/scripts && bash deploy devnet && cd ../../../ cd wormhole/aptos/scripts && bash deploy devnet && worm aptos faucet && bash register_devnet && cd ../../../

View File

@ -46,5 +46,5 @@ docker run --rm --name guardiand $DOCKER_FLAGS --hostname guardian-0 --cap-add=I
--algorandAlgodRPC https://$HOST:4001 \ --algorandAlgodRPC https://$HOST:4001 \
--algorandAppID "4" \ --algorandAppID "4" \
--aptosRPC http://$HOST:8080 \ --aptosRPC http://$HOST:8080 \
--aptosAccount "277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b" \ --aptosAccount "de0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017" \
--aptosHandle "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::state::WormholeMessageHandle" \ --aptosHandle "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017::state::WormholeMessageHandle"

View File

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"setup": "bash setup.bash", "setup": "bash setup.bash",
"wormhole": "npm run setup && bash wormhole.bash", "wormhole": "npm run setup && bash wormhole.bash",
"spy": "npm run setup && bash spy_guardiand.bash", "spy": "npm run setup && bash spy.bash",
"evm": "npm run setup && bash evm.bash", "evm": "npm run setup && bash evm.bash",
"solana": "npm run setup && bash solana-binary-deploy.bash", "solana": "npm run setup && bash solana-binary-deploy.bash",
"aptos": "npm run setup && bash aptos.bash", "aptos": "npm run setup && bash aptos.bash",

View File

@ -7,5 +7,7 @@ then
git clone https://github.com/wormhole-foundation/wormhole git clone https://github.com/wormhole-foundation/wormhole
cd wormhole/clients/js cd wormhole/clients/js
make install make install
cd ../../../ cd ../../scripts
bash guardian-set-init.sh
cd ../../
fi fi