aptos working in messenger v1
This commit is contained in:
parent
4dcb18a929
commit
1c957b0b04
|
@ -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;
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -2,22 +2,67 @@
|
|||
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};
|
||||
|
||||
struct State has key {
|
||||
emitter_cap: wormhole::emitter::EmitterCapability,
|
||||
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,
|
||||
}
|
||||
|
||||
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
|
||||
// `EmitterCapability` which will be required to send messages through
|
||||
// wormhole.
|
||||
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 {
|
||||
// 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>(@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,
|
||||
// only batch VAAs)
|
||||
|
@ -33,4 +78,44 @@ module core_messages::messenger {
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -1,13 +1,21 @@
|
|||
import fs from 'fs';
|
||||
import { AptosClient } from "aptos";
|
||||
import { AptosAccount, AptosClient, Types } from "aptos";
|
||||
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 program = new Command();
|
||||
|
||||
const aptosModuleAddress = "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b"; // Unlike EVM, this is hardcoded
|
||||
const solanaProgramAddress = ""; // Unlike EVM, this is hardcoded
|
||||
|
||||
program
|
||||
.name('xMessenger')
|
||||
|
@ -27,24 +35,164 @@ program
|
|||
|
||||
switch(config.networks[network].type){
|
||||
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);
|
||||
console.log(`Deployed @ ${txnHash}`);
|
||||
break;
|
||||
case "solana":
|
||||
console.log("Not supported yet");
|
||||
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":
|
||||
console.log("Not supported yet");
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Deploy finished!`);
|
||||
});
|
||||
|
||||
// register network
|
||||
// send msg
|
||||
// submit 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;
|
||||
}
|
||||
|
||||
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();
|
|
@ -8,7 +8,10 @@
|
|||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.4",
|
||||
"@types/node": "^18.11.10",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"aptos": "^1.4.0",
|
||||
"commander": "^9.4.1"
|
||||
"commander": "^9.4.1",
|
||||
"ethers": "^5.7.2",
|
||||
"node-fetch": "2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,11 @@ import {
|
|||
generateSignAndSubmitEntryFunction,
|
||||
hexToUint8Array,
|
||||
} from "@certusone/wormhole-sdk";
|
||||
import { AptosAccount, AptosClient } from "aptos";
|
||||
import {
|
||||
AptosAccount,
|
||||
AptosClient,
|
||||
Types,
|
||||
} from "aptos";
|
||||
import { promisify } from "util";
|
||||
const exec = promisify(require("child_process").exec);
|
||||
|
||||
|
@ -16,6 +20,7 @@ export class AptosMessenger {
|
|||
max_gas_amount: "30000",
|
||||
};
|
||||
coreMessages = "";
|
||||
bridgeAddress = "";
|
||||
|
||||
constructor(nodeUrl: string, coreMessages: string) {
|
||||
this.client = new AptosClient(nodeUrl);
|
||||
|
@ -31,22 +36,92 @@ export class AptosMessenger {
|
|||
|
||||
console.log("Initalizing Aptos Messenger module...");
|
||||
// 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 payload = {
|
||||
const payload:Types.EntryFunctionPayload = {
|
||||
function: `${this.coreMessages}::messenger::init_messenger`,
|
||||
type_arguments: [],
|
||||
arguments: [],
|
||||
arguments: [
|
||||
sender.address()
|
||||
],
|
||||
};
|
||||
|
||||
const tx = await generateSignAndSubmitEntryFunction(
|
||||
client,
|
||||
this.client,
|
||||
sender,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
export * from './aptos';
|
||||
export * from './evm';
|
||||
export * from './solana';
|
|
@ -1,32 +1,35 @@
|
|||
{
|
||||
"networks": {
|
||||
"evm0": {
|
||||
"eth": {
|
||||
"type": "evm",
|
||||
"wormholeChainId": 2,
|
||||
"rpc": "http://localhost:8545",
|
||||
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
|
||||
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
|
||||
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550",
|
||||
"deployedAddress": "0xeea2Fc1D255Fd28aA15c6c2324Ad40B03267f9c5"
|
||||
},
|
||||
"evm1": {
|
||||
"bsc": {
|
||||
"type": "evm",
|
||||
"wormholeChainId": 4,
|
||||
"rpc": "http://localhost:8546",
|
||||
"privateKey": "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d",
|
||||
"bridgeAddress": "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550"
|
||||
},
|
||||
"sol0": {
|
||||
"solana": {
|
||||
"type": "solana",
|
||||
"wormholeChainId": 1,
|
||||
"rpc": "http://localhost:8899",
|
||||
"privateKey": "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
|
||||
"bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
|
||||
"bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o",
|
||||
"deployedAddress": "24FoTeX7BKbhTh3UF3feWusoAVKDPWZneiEqhXLVzZPL"
|
||||
},
|
||||
"aptos": {
|
||||
"type": "aptos",
|
||||
"wormholeChainId": 22,
|
||||
"rpc": "http://localhost:8080",
|
||||
"privateKey": "537c1f91e56891445b491068f519b705f8c0f1a1e66111816dd5d4aa85b8113d",
|
||||
"bridgeAddress": "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017"
|
||||
"bridgeAddress": "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017",
|
||||
"deployedAddress": "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b"
|
||||
}
|
||||
},
|
||||
"wormhole": {
|
||||
|
|
|
@ -937,6 +937,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
||||
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":
|
||||
version "18.11.10"
|
||||
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"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e"
|
||||
integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==
|
||||
|
@ -1741,6 +1749,15 @@ form-data@4.0.0, form-data@^4.0.0:
|
|||
combined-stream "^1.0.8"
|
||||
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:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
build/
|
|
@ -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"
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
"_format": "ethers-rs-sol-cache-3",
|
||||
"paths": {
|
||||
"artifacts": "out",
|
||||
"build_infos": "out/build-info",
|
||||
"sources": "src",
|
||||
"tests": "test",
|
||||
"scripts": "script",
|
||||
|
@ -11,8 +12,8 @@
|
|||
},
|
||||
"files": {
|
||||
"src/Messenger.sol": {
|
||||
"lastModificationDate": 1659683988145,
|
||||
"contentHash": "b21dd2ab010d42c4abc588eed32658bd",
|
||||
"lastModificationDate": 1671431118697,
|
||||
"contentHash": "17b03174437201be7b7f56e2bd0d92e4",
|
||||
"sourceName": "src/Messenger.sol",
|
||||
"solcConfig": {
|
||||
"settings": {
|
||||
|
@ -32,7 +33,8 @@
|
|||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
"evm.methodIdentifiers",
|
||||
"metadata"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -52,7 +54,7 @@
|
|||
}
|
||||
},
|
||||
"src/Wormhole/IWormhole.sol": {
|
||||
"lastModificationDate": 1659683988146,
|
||||
"lastModificationDate": 1665515840999,
|
||||
"contentHash": "7c930d4b68538e731af28a8d1979f44e",
|
||||
"sourceName": "src/Wormhole/IWormhole.sol",
|
||||
"solcConfig": {
|
||||
|
@ -73,7 +75,8 @@
|
|||
"abi",
|
||||
"evm.bytecode",
|
||||
"evm.deployedBytecode",
|
||||
"evm.methodIdentifiers"
|
||||
"evm.methodIdentifiers",
|
||||
"metadata"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -92,7 +95,7 @@
|
|||
}
|
||||
},
|
||||
"src/Wormhole/Structs.sol": {
|
||||
"lastModificationDate": 1659683988147,
|
||||
"lastModificationDate": 1665515841000,
|
||||
"contentHash": "4e824cc204959f4fcab06c4e806448c4",
|
||||
"sourceName": "src/Wormhole/Structs.sol",
|
||||
"solcConfig": {
|
||||
|
@ -113,7 +116,8 @@
|
|||
"abi",
|
||||
"evm.bytecode",
|
||||
"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
|
@ -11,19 +11,64 @@
|
|||
"linkReferences": {}
|
||||
},
|
||||
"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": {
|
||||
"absolutePath": "src/Wormhole/Structs.sol",
|
||||
"id": 331,
|
||||
"id": 333,
|
||||
"exportedSymbols": {
|
||||
"Structs": [
|
||||
330
|
||||
332
|
||||
]
|
||||
},
|
||||
"nodeType": "SourceUnit",
|
||||
"src": "63:551:2",
|
||||
"nodes": [
|
||||
{
|
||||
"id": 282,
|
||||
"id": 284,
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "63:23:2",
|
||||
"literals": [
|
||||
|
@ -34,24 +79,24 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": 330,
|
||||
"id": 332,
|
||||
"nodeType": "ContractDefinition",
|
||||
"src": "88:526:2",
|
||||
"nodes": [
|
||||
{
|
||||
"id": 289,
|
||||
"id": 291,
|
||||
"nodeType": "StructDefinition",
|
||||
"src": "109:96:2",
|
||||
"canonicalName": "Structs.Provider",
|
||||
"members": [
|
||||
{
|
||||
"constant": false,
|
||||
"id": 284,
|
||||
"id": 286,
|
||||
"mutability": "mutable",
|
||||
"name": "chainId",
|
||||
"nameLocation": "136:7:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 289,
|
||||
"scope": 291,
|
||||
"src": "129:14:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -60,7 +105,7 @@
|
|||
"typeString": "uint16"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 283,
|
||||
"id": 285,
|
||||
"name": "uint16",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "129:6:2",
|
||||
|
@ -73,12 +118,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 286,
|
||||
"id": 288,
|
||||
"mutability": "mutable",
|
||||
"name": "governanceChainId",
|
||||
"nameLocation": "154:17:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 289,
|
||||
"scope": 291,
|
||||
"src": "147:24:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -87,7 +132,7 @@
|
|||
"typeString": "uint16"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 285,
|
||||
"id": 287,
|
||||
"name": "uint16",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "147:6:2",
|
||||
|
@ -100,12 +145,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 288,
|
||||
"id": 290,
|
||||
"mutability": "mutable",
|
||||
"name": "governanceContract",
|
||||
"nameLocation": "183:18:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 289,
|
||||
"scope": 291,
|
||||
"src": "175:26:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -114,7 +159,7 @@
|
|||
"typeString": "bytes32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 287,
|
||||
"id": 289,
|
||||
"name": "bytes32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "175:7:2",
|
||||
|
@ -128,23 +173,23 @@
|
|||
],
|
||||
"name": "Provider",
|
||||
"nameLocation": "116:8:2",
|
||||
"scope": 330,
|
||||
"scope": 332,
|
||||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"id": 295,
|
||||
"id": 297,
|
||||
"nodeType": "StructDefinition",
|
||||
"src": "208:66:2",
|
||||
"canonicalName": "Structs.GuardianSet",
|
||||
"members": [
|
||||
{
|
||||
"constant": false,
|
||||
"id": 292,
|
||||
"id": 294,
|
||||
"mutability": "mutable",
|
||||
"name": "keys",
|
||||
"nameLocation": "241:4:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 295,
|
||||
"scope": 297,
|
||||
"src": "231:14:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -154,7 +199,7 @@
|
|||
},
|
||||
"typeName": {
|
||||
"baseType": {
|
||||
"id": 290,
|
||||
"id": 292,
|
||||
"name": "address",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "231:7:2",
|
||||
|
@ -164,7 +209,7 @@
|
|||
"typeString": "address"
|
||||
}
|
||||
},
|
||||
"id": 291,
|
||||
"id": 293,
|
||||
"nodeType": "ArrayTypeName",
|
||||
"src": "231:9:2",
|
||||
"typeDescriptions": {
|
||||
|
@ -176,12 +221,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 294,
|
||||
"id": 296,
|
||||
"mutability": "mutable",
|
||||
"name": "expirationTime",
|
||||
"nameLocation": "256:14:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 295,
|
||||
"scope": 297,
|
||||
"src": "249:21:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -190,7 +235,7 @@
|
|||
"typeString": "uint32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 293,
|
||||
"id": 295,
|
||||
"name": "uint32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "249:6:2",
|
||||
|
@ -204,23 +249,23 @@
|
|||
],
|
||||
"name": "GuardianSet",
|
||||
"nameLocation": "215:11:2",
|
||||
"scope": 330,
|
||||
"scope": 332,
|
||||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"id": 304,
|
||||
"id": 306,
|
||||
"nodeType": "StructDefinition",
|
||||
"src": "277:81:2",
|
||||
"canonicalName": "Structs.Signature",
|
||||
"members": [
|
||||
{
|
||||
"constant": false,
|
||||
"id": 297,
|
||||
"id": 299,
|
||||
"mutability": "mutable",
|
||||
"name": "r",
|
||||
"nameLocation": "306:1:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 304,
|
||||
"scope": 306,
|
||||
"src": "298:9:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -229,7 +274,7 @@
|
|||
"typeString": "bytes32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 296,
|
||||
"id": 298,
|
||||
"name": "bytes32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "298:7:2",
|
||||
|
@ -242,12 +287,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 299,
|
||||
"id": 301,
|
||||
"mutability": "mutable",
|
||||
"name": "s",
|
||||
"nameLocation": "319:1:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 304,
|
||||
"scope": 306,
|
||||
"src": "311:9:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -256,7 +301,7 @@
|
|||
"typeString": "bytes32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 298,
|
||||
"id": 300,
|
||||
"name": "bytes32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "311:7:2",
|
||||
|
@ -269,12 +314,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 301,
|
||||
"id": 303,
|
||||
"mutability": "mutable",
|
||||
"name": "v",
|
||||
"nameLocation": "330:1:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 304,
|
||||
"scope": 306,
|
||||
"src": "324:7:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -283,7 +328,7 @@
|
|||
"typeString": "uint8"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 300,
|
||||
"id": 302,
|
||||
"name": "uint8",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "324:5:2",
|
||||
|
@ -296,12 +341,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 303,
|
||||
"id": 305,
|
||||
"mutability": "mutable",
|
||||
"name": "guardianIndex",
|
||||
"nameLocation": "341:13:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 304,
|
||||
"scope": 306,
|
||||
"src": "335:19:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -310,7 +355,7 @@
|
|||
"typeString": "uint8"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 302,
|
||||
"id": 304,
|
||||
"name": "uint8",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "335:5:2",
|
||||
|
@ -324,23 +369,23 @@
|
|||
],
|
||||
"name": "Signature",
|
||||
"nameLocation": "284:9:2",
|
||||
"scope": 330,
|
||||
"scope": 332,
|
||||
"visibility": "public"
|
||||
},
|
||||
{
|
||||
"id": 329,
|
||||
"id": 331,
|
||||
"nodeType": "StructDefinition",
|
||||
"src": "361:251:2",
|
||||
"canonicalName": "Structs.VM",
|
||||
"members": [
|
||||
{
|
||||
"constant": false,
|
||||
"id": 306,
|
||||
"id": 308,
|
||||
"mutability": "mutable",
|
||||
"name": "version",
|
||||
"nameLocation": "381:7:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "375:13:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -349,7 +394,7 @@
|
|||
"typeString": "uint8"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 305,
|
||||
"id": 307,
|
||||
"name": "uint8",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "375:5:2",
|
||||
|
@ -362,12 +407,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 308,
|
||||
"id": 310,
|
||||
"mutability": "mutable",
|
||||
"name": "timestamp",
|
||||
"nameLocation": "399:9:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "392:16:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -376,7 +421,7 @@
|
|||
"typeString": "uint32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 307,
|
||||
"id": 309,
|
||||
"name": "uint32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "392:6:2",
|
||||
|
@ -389,12 +434,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 310,
|
||||
"id": 312,
|
||||
"mutability": "mutable",
|
||||
"name": "nonce",
|
||||
"nameLocation": "419:5:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "412:12:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -403,7 +448,7 @@
|
|||
"typeString": "uint32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 309,
|
||||
"id": 311,
|
||||
"name": "uint32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "412:6:2",
|
||||
|
@ -416,12 +461,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 312,
|
||||
"id": 314,
|
||||
"mutability": "mutable",
|
||||
"name": "emitterChainId",
|
||||
"nameLocation": "435:14:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "428:21:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -430,7 +475,7 @@
|
|||
"typeString": "uint16"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 311,
|
||||
"id": 313,
|
||||
"name": "uint16",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "428:6:2",
|
||||
|
@ -443,12 +488,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 314,
|
||||
"id": 316,
|
||||
"mutability": "mutable",
|
||||
"name": "emitterAddress",
|
||||
"nameLocation": "461:14:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "453:22:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -457,7 +502,7 @@
|
|||
"typeString": "bytes32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 313,
|
||||
"id": 315,
|
||||
"name": "bytes32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "453:7:2",
|
||||
|
@ -470,12 +515,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 316,
|
||||
"id": 318,
|
||||
"mutability": "mutable",
|
||||
"name": "sequence",
|
||||
"nameLocation": "486:8:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "479:15:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -484,7 +529,7 @@
|
|||
"typeString": "uint64"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 315,
|
||||
"id": 317,
|
||||
"name": "uint64",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "479:6:2",
|
||||
|
@ -497,12 +542,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 318,
|
||||
"id": 320,
|
||||
"mutability": "mutable",
|
||||
"name": "consistencyLevel",
|
||||
"nameLocation": "504:16:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "498:22:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -511,7 +556,7 @@
|
|||
"typeString": "uint8"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 317,
|
||||
"id": 319,
|
||||
"name": "uint8",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "498:5:2",
|
||||
|
@ -524,12 +569,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 320,
|
||||
"id": 322,
|
||||
"mutability": "mutable",
|
||||
"name": "payload",
|
||||
"nameLocation": "530:7:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "524:13:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -538,7 +583,7 @@
|
|||
"typeString": "bytes"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 319,
|
||||
"id": 321,
|
||||
"name": "bytes",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "524:5:2",
|
||||
|
@ -551,12 +596,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 322,
|
||||
"id": 324,
|
||||
"mutability": "mutable",
|
||||
"name": "guardianSetIndex",
|
||||
"nameLocation": "549:16:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "542:23:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -565,7 +610,7 @@
|
|||
"typeString": "uint32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 321,
|
||||
"id": 323,
|
||||
"name": "uint32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "542:6:2",
|
||||
|
@ -578,42 +623,42 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 326,
|
||||
"id": 328,
|
||||
"mutability": "mutable",
|
||||
"name": "signatures",
|
||||
"nameLocation": "581:10:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "569:22:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"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[]"
|
||||
},
|
||||
"typeName": {
|
||||
"baseType": {
|
||||
"id": 324,
|
||||
"id": 326,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode": {
|
||||
"id": 323,
|
||||
"id": 325,
|
||||
"name": "Signature",
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 304,
|
||||
"referencedDeclaration": 306,
|
||||
"src": "569:9:2"
|
||||
},
|
||||
"referencedDeclaration": 304,
|
||||
"referencedDeclaration": 306,
|
||||
"src": "569:9:2",
|
||||
"typeDescriptions": {
|
||||
"typeIdentifier": "t_struct$_Signature_$304_storage_ptr",
|
||||
"typeIdentifier": "t_struct$_Signature_$306_storage_ptr",
|
||||
"typeString": "struct Structs.Signature"
|
||||
}
|
||||
},
|
||||
"id": 325,
|
||||
"id": 327,
|
||||
"nodeType": "ArrayTypeName",
|
||||
"src": "569:11:2",
|
||||
"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[]"
|
||||
}
|
||||
},
|
||||
|
@ -621,12 +666,12 @@
|
|||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 328,
|
||||
"id": 330,
|
||||
"mutability": "mutable",
|
||||
"name": "hash",
|
||||
"nameLocation": "604:4:2",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 329,
|
||||
"scope": 331,
|
||||
"src": "596:12:2",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
|
@ -635,7 +680,7 @@
|
|||
"typeString": "bytes32"
|
||||
},
|
||||
"typeName": {
|
||||
"id": 327,
|
||||
"id": 329,
|
||||
"name": "bytes32",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "596:7:2",
|
||||
|
@ -649,7 +694,7 @@
|
|||
],
|
||||
"name": "VM",
|
||||
"nameLocation": "368:2:2",
|
||||
"scope": 330,
|
||||
"scope": 332,
|
||||
"visibility": "public"
|
||||
}
|
||||
],
|
||||
|
@ -660,11 +705,11 @@
|
|||
"contractKind": "interface",
|
||||
"fullyImplemented": true,
|
||||
"linearizedBaseContracts": [
|
||||
330
|
||||
332
|
||||
],
|
||||
"name": "Structs",
|
||||
"nameLocation": "98:7:2",
|
||||
"scope": 331,
|
||||
"scope": 333,
|
||||
"usedErrors": []
|
||||
}
|
||||
],
|
||||
|
|
|
@ -5,7 +5,7 @@ import "./Wormhole/IWormhole.sol";
|
|||
|
||||
contract Messenger {
|
||||
string private current_msg;
|
||||
address private wormhole_core_bridge_address;
|
||||
IWormhole core_bridge;
|
||||
uint32 nonce = 0;
|
||||
mapping(uint16 => bytes32) _applicationContracts;
|
||||
address owner;
|
||||
|
@ -13,10 +13,9 @@ contract Messenger {
|
|||
|
||||
constructor(address _core_bridge_address){
|
||||
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) {
|
||||
sequence = core_bridge.publishMessage(nonce, str, 1);
|
||||
|
|
|
@ -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');
|
||||
}
|
|
@ -1,17 +1,19 @@
|
|||
import * as fs from 'fs';
|
||||
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 fetch from 'node-fetch';
|
||||
import {getEmitterAddress as getEmitterAddressAptos} from './aptos';
|
||||
|
||||
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'];
|
||||
const bridgeAddress = config.networks[chain]['bridgeAddress'];
|
||||
|
||||
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) => {
|
||||
if (err) {
|
||||
throw new Error(err.message);
|
||||
|
@ -61,9 +63,11 @@ export async function registerApp(src:string, target:string){
|
|||
targetEmitter = getEmitterAddressEth(targetDeploymentInfo['address']);
|
||||
break;
|
||||
case 'solana':
|
||||
setDefaultWasm("node"); // *sigh*
|
||||
targetEmitter = await getEmitterAddressSolana(targetDeploymentInfo['address']);
|
||||
break;
|
||||
case 'aptos':
|
||||
targetEmitter = await getEmitterAddressAptos(targetNetwork.rpc, targetDeploymentInfo['address']);
|
||||
break;
|
||||
}
|
||||
|
||||
const emitterBuffer = Buffer.from(targetEmitter, 'hex');
|
||||
|
@ -111,7 +115,7 @@ export async function sendMsg(src:string, msg:string){
|
|||
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 emitterAddr = getEmitterAddressEth(srcDeploymentInfo['address']);
|
||||
|
||||
|
|
|
@ -5,11 +5,10 @@ import fetch from 'node-fetch';
|
|||
import {
|
||||
getEmitterAddressEth,
|
||||
getEmitterAddressSolana,
|
||||
importCoreWasm,
|
||||
parseSequenceFromLogSolana,
|
||||
postVaaSolanaWithRetry,
|
||||
setDefaultWasm,
|
||||
getSignedVAAHash,
|
||||
parseVaa,
|
||||
} from '@certusone/wormhole-sdk';
|
||||
import * as anchor from '@project-serum/anchor';
|
||||
import { findProgramAddressSync } from '@project-serum/anchor/dist/cjs/utils/pubkey';
|
||||
|
@ -190,7 +189,6 @@ export async function sendMsg(src:string, msg:string){
|
|||
.rpc();
|
||||
|
||||
const seq = parseSequenceFromLogSolana(await messenger.provider.connection.getTransaction(tx))
|
||||
setDefaultWasm("node"); // *sigh*
|
||||
const emitterAddr = await getEmitterAddressSolana(messenger.programId.toString()); //same as whDerivedEmitter
|
||||
|
||||
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){
|
||||
setDefaultWasm("node"); //WASM will be removed very soon, but until then, all the solana functions rely on it
|
||||
|
||||
const srcNetwork = config.networks[src];
|
||||
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
|
||||
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 = parse_vaa(Buffer.from(vaa, 'base64'));
|
||||
const parsed_vaa = parseVaa(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")));
|
||||
|
||||
// Account that we stored the registered foreign emitter
|
||||
let emitterAddressAcc = findProgramAddressSync([
|
||||
Buffer.from("EmitterAddress"),
|
||||
byteify.serializeUint16(parsed_vaa.emitter_chain)
|
||||
byteify.serializeUint16(parsed_vaa.emitterChain)
|
||||
], messenger.programId)[0];
|
||||
|
||||
// A blank account we're creating just to keep track of already processed messages
|
||||
let processedVaaKey = findProgramAddressSync([
|
||||
Buffer.from(getEmitterAddressEth(targetDeploymentInfo.address), "hex"),
|
||||
byteify.serializeUint16(parsed_vaa.emitter_chain),
|
||||
byteify.serializeUint64(parsed_vaa.sequence)
|
||||
byteify.serializeUint16(parsed_vaa.emitterChain),
|
||||
byteify.serializeUint64(Number(parsed_vaa.sequence))
|
||||
], messenger.programId)[0];
|
||||
|
||||
// Account where the core bridge stored the vaa after the signatures checked out
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Command } from 'commander';
|
|||
import * as fs from 'fs';
|
||||
import * as evm from './handlers/evm';
|
||||
import * as solana from './handlers/solana';
|
||||
import * as aptos from './handlers/aptos';
|
||||
|
||||
const config = JSON.parse(fs.readFileSync('./xdapp.config.json').toString())
|
||||
|
||||
|
@ -29,6 +30,9 @@ program
|
|||
case "solana":
|
||||
await solana.deploy(network);
|
||||
break;
|
||||
case 'aptos':
|
||||
await aptos.deploy(network);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Deploy finished!`);
|
||||
|
@ -56,6 +60,10 @@ program
|
|||
break;
|
||||
case "solana":
|
||||
await solana.registerApp(src, target);
|
||||
break;
|
||||
case "aptos":
|
||||
await aptos.registerApp(src, target);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Foreign Network ${target} registered on ${src}`);
|
||||
|
@ -82,6 +90,9 @@ program
|
|||
case "solana":
|
||||
await solana.sendMsg(src, msg);
|
||||
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.`)
|
||||
} catch (e){
|
||||
|
@ -113,6 +124,9 @@ program
|
|||
case "solana":
|
||||
await solana.submitVaa(src,target,idx);
|
||||
break;
|
||||
case "aptos":
|
||||
await aptos.submitVaa(src, target, idx);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Submitted VAA #${idx} from ${target} to chain ${src}`);
|
||||
|
@ -140,6 +154,9 @@ program
|
|||
case "solana":
|
||||
msg = await solana.getCurrentMsg(src);
|
||||
break;
|
||||
case "aptos":
|
||||
msg = await aptos.getCurrentMsg(src);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Current Message on Network ${src} is ${msg}`);
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
"author": "Dev Bharel",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.6.0",
|
||||
"@certusone/wormhole-sdk": "^0.9.6",
|
||||
"@project-serum/anchor": "^0.25.0",
|
||||
"@solana/web3.js": "^1.64.0",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"aptos": "^1.4.0",
|
||||
"byteify": "^2.0.10",
|
||||
"commander": "^9.4.0",
|
||||
"ethers": "^5.6.9",
|
||||
|
|
|
@ -14,9 +14,9 @@ import { ethers } from "ethers";
|
|||
import { Connection as SolanaConnection } from "@solana/web3.js";
|
||||
import { BaseVAA } from "./utils";
|
||||
import { TextDecoder } from "util";
|
||||
import { parseVaa } from "@certusone/wormhole-sdk";
|
||||
|
||||
// todo: do we need this in the plugin or just the relayer??
|
||||
whSdk.setDefaultWasm("node");
|
||||
|
||||
function create(
|
||||
commonConfig: CommonPluginEnv,
|
||||
|
@ -165,8 +165,7 @@ export class MessengerRelayerPlugin implements Plugin<VAA> {
|
|||
|
||||
async parseVAA(vaa: Buffer | Uint8Array): Promise<BaseVAA> {
|
||||
try {
|
||||
const { parse_vaa } = await whSdk.importCoreWasm();
|
||||
return parse_vaa(new Uint8Array(vaa)) as BaseVAA;
|
||||
return parseVaa(new Uint8Array(vaa)) as any as BaseVAA;
|
||||
} catch (e) {
|
||||
this.logger.error("Failed to parse vaa");
|
||||
throw e;
|
||||
|
|
|
@ -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
|
|
@ -20,6 +20,13 @@
|
|||
"rpc": "http://localhost:8899",
|
||||
"privateKey": "J2D4pwDred8P9ioyPEZVLPht885AeYpifsFGUyuzVmiKQosAvmZP4EegaKFrSprBC5vVP1xTvu61vYDWsxBNsYx",
|
||||
"bridgeAddress": "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
|
||||
},
|
||||
"aptos": {
|
||||
"type": "aptos",
|
||||
"wormholeChainId": 22,
|
||||
"rpc": "http://localhost:8080",
|
||||
"privateKey": "537c1f91e56891445b491068f519b705f8c0f1a1e66111816dd5d4aa85b8113d",
|
||||
"bridgeAddress": "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017"
|
||||
}
|
||||
},
|
||||
"wormhole": {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -6,5 +6,4 @@ set -euo pipefail
|
|||
npx pm2 delete aptos 2> /dev/null || true
|
||||
npx pm2 start 'aptos node run-local-testnet --with-faucet --force-restart --assume-yes' --name aptos
|
||||
sleep 15
|
||||
cd wormhole/aptos/scripts && bash deploy devnet && cd ../../../
|
||||
|
||||
cd wormhole/aptos/scripts && bash deploy devnet && worm aptos faucet && bash register_devnet && cd ../../../
|
|
@ -46,5 +46,5 @@ docker run --rm --name guardiand $DOCKER_FLAGS --hostname guardian-0 --cap-add=I
|
|||
--algorandAlgodRPC https://$HOST:4001 \
|
||||
--algorandAppID "4" \
|
||||
--aptosRPC http://$HOST:8080 \
|
||||
--aptosAccount "277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b" \
|
||||
--aptosHandle "0x277fa055b6a73c42c0662d5236c65c864ccbf2d4abd21f174a30c8b786eab84b::state::WormholeMessageHandle" \
|
||||
--aptosAccount "de0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017" \
|
||||
--aptosHandle "0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017::state::WormholeMessageHandle"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"scripts": {
|
||||
"setup": "bash setup.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",
|
||||
"solana": "npm run setup && bash solana-binary-deploy.bash",
|
||||
"aptos": "npm run setup && bash aptos.bash",
|
||||
|
|
|
@ -7,5 +7,7 @@ then
|
|||
git clone https://github.com/wormhole-foundation/wormhole
|
||||
cd wormhole/clients/js
|
||||
make install
|
||||
cd ../../../
|
||||
cd ../../scripts
|
||||
bash guardian-set-init.sh
|
||||
cd ../../
|
||||
fi
|
||||
|
|
Loading…
Reference in New Issue