211 lines
7.0 KiB
Plaintext
211 lines
7.0 KiB
Plaintext
module wormhole::wormhole {
|
|
use std::vector;
|
|
use aptos_framework::account;
|
|
use aptos_framework::coin::{Self, Coin};
|
|
use aptos_framework::aptos_coin::{AptosCoin};
|
|
use wormhole::structs::{create_guardian, create_guardian_set, Guardian};
|
|
use wormhole::state;
|
|
use deployer::deployer;
|
|
use wormhole::u16;
|
|
use wormhole::u32::{Self, U32};
|
|
use wormhole::emitter;
|
|
use wormhole::external_address::{Self};
|
|
use std::signer;
|
|
|
|
const E_INSUFFICIENT_FEE: u64 = 0;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Sending messages
|
|
|
|
public fun publish_message(
|
|
emitter_cap: &mut emitter::EmitterCapability,
|
|
nonce: u64,
|
|
payload: vector<u8>,
|
|
message_fee: Coin<AptosCoin>
|
|
): u64 {
|
|
// ensure that provided fee is sufficient to cover message fees
|
|
let expected_fee = state::get_message_fee();
|
|
assert!(expected_fee <= coin::value(&message_fee), E_INSUFFICIENT_FEE);
|
|
// deposit the fees into the wormhole account
|
|
coin::deposit(@wormhole, message_fee);
|
|
let sequence = emitter::use_sequence(emitter_cap);
|
|
state::publish_event(
|
|
emitter::get_emitter(emitter_cap),
|
|
sequence,
|
|
nonce,
|
|
payload,
|
|
);
|
|
sequence
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Emitter registration
|
|
|
|
public fun register_emitter(): emitter::EmitterCapability {
|
|
state::new_emitter()
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Contract initialization
|
|
|
|
/// Initializes the contract. Note that this function takes additional
|
|
/// arguments, so the native `init_module` function (which takes no
|
|
/// arguments) cannot be used.
|
|
/// Can only be called by the deployer (checked by the
|
|
/// `deployer::claim_signer_capability` function).
|
|
public entry fun init(
|
|
deployer: &signer,
|
|
chain_id: u64,
|
|
governance_chain_id: u64,
|
|
governance_contract: vector<u8>,
|
|
initial_guardians: vector<vector<u8>>
|
|
) {
|
|
// account::SignerCapability can't be copied, so once it's stored into
|
|
// state, the init function can no longer be called (since
|
|
// the deployer signer capability must have been unlocked).
|
|
let signer_cap = deployer::claim_signer_capability(deployer, @wormhole);
|
|
let message_fee = 0;
|
|
let guardians: vector<Guardian> = vector[];
|
|
|
|
vector::reverse(&mut initial_guardians);
|
|
while (!vector::is_empty(&initial_guardians)) {
|
|
vector::push_back(&mut guardians, create_guardian(vector::pop_back(&mut initial_guardians)));
|
|
};
|
|
|
|
init_internal(
|
|
signer_cap,
|
|
chain_id,
|
|
governance_chain_id,
|
|
governance_contract,
|
|
guardians,
|
|
u32::from_u64(86400),
|
|
message_fee
|
|
)
|
|
}
|
|
|
|
fun init_internal(
|
|
signer_cap: account::SignerCapability,
|
|
chain_id: u64,
|
|
governance_chain_id: u64,
|
|
governance_contract: vector<u8>,
|
|
initial_guardians: vector<Guardian>,
|
|
guardian_set_expiry: U32,
|
|
message_fee: u64,
|
|
) {
|
|
let wormhole = account::create_signer_with_capability(&signer_cap);
|
|
state::init_wormhole_state(
|
|
&wormhole,
|
|
u16::from_u64(chain_id),
|
|
u16::from_u64(governance_chain_id),
|
|
external_address::from_bytes(governance_contract),
|
|
guardian_set_expiry,
|
|
message_fee,
|
|
signer_cap
|
|
);
|
|
state::init_message_handles(&wormhole);
|
|
state::store_guardian_set(
|
|
create_guardian_set(
|
|
u32::from_u64(0),
|
|
initial_guardians
|
|
)
|
|
);
|
|
// register wormhole to be able to receive fees
|
|
// `aptos_account::create_account` is a permissionless operation that
|
|
// performs aptos coin registration too, so it's possible that this is
|
|
// already performed, in which case we just skip
|
|
// (thanks ottersec for point this out)
|
|
if (!coin::is_account_registered<AptosCoin>(signer::address_of(&wormhole))) {
|
|
coin::register<AptosCoin>(&wormhole);
|
|
};
|
|
}
|
|
|
|
#[test_only]
|
|
/// Initialise a dummy contract for testing. Returns the wormhole signer.
|
|
public fun init_test(
|
|
chain_id: u64,
|
|
governance_chain_id: u64,
|
|
governance_contract: vector<u8>,
|
|
initial_guardian: vector<u8>,
|
|
message_fee: u64,
|
|
): signer {
|
|
let deployer = account::create_account_for_test(@deployer);
|
|
let (wormhole, signer_cap) = account::create_resource_account(&deployer, b"wormhole");
|
|
init_internal(
|
|
signer_cap,
|
|
chain_id,
|
|
governance_chain_id,
|
|
governance_contract,
|
|
vector[create_guardian(initial_guardian)],
|
|
u32::from_u64(86400),
|
|
message_fee
|
|
);
|
|
wormhole
|
|
}
|
|
}
|
|
|
|
#[test_only]
|
|
module wormhole::wormhole_test {
|
|
use std::hash;
|
|
use wormhole::wormhole;
|
|
use wormhole::keccak256::keccak256;
|
|
use aptos_framework::aptos_coin::{Self};
|
|
use aptos_framework::coin;
|
|
|
|
// public so we an re-use this in token_bridge test
|
|
public fun setup(message_fee: u64) {
|
|
let aptos_framework = std::account::create_account_for_test(@aptos_framework);
|
|
std::timestamp::set_time_has_started_for_testing(&aptos_framework);
|
|
wormhole::init_test(
|
|
22,
|
|
1,
|
|
x"0000000000000000000000000000000000000000000000000000000000000004",
|
|
x"beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe",
|
|
message_fee
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
public fun test_hash() {
|
|
assert!(hash::sha3_256(vector[0]) == x"5d53469f20fef4f8eab52b88044ede69c77a6a68a60728609fc4a65ff531e7d0", 0);
|
|
assert!(keccak256(vector[0]) == x"bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a", 0);
|
|
}
|
|
|
|
#[test(aptos_framework = @aptos_framework)]
|
|
public fun test_publish_message(aptos_framework: &signer) {
|
|
setup(100);
|
|
|
|
let (burn_cap, mint_cap) = aptos_coin::initialize_for_test(aptos_framework);
|
|
let fees = coin::mint(100, &mint_cap);
|
|
|
|
let emitter_cap = wormhole::register_emitter();
|
|
|
|
wormhole::publish_message(
|
|
&mut emitter_cap,
|
|
0,
|
|
b"hi mom",
|
|
fees
|
|
);
|
|
|
|
//TODO - check if event is actually emitted?
|
|
|
|
wormhole::emitter::destroy_emitter_cap(emitter_cap);
|
|
coin::destroy_mint_cap(mint_cap);
|
|
coin::destroy_burn_cap(burn_cap);
|
|
}
|
|
|
|
#[test]
|
|
#[expected_failure(abort_code = 0x0, location = wormhole::wormhole)]
|
|
public fun test_publish_message_insufficient_fee() {
|
|
setup(100);
|
|
let emitter_cap = wormhole::register_emitter();
|
|
|
|
wormhole::publish_message(
|
|
&mut emitter_cap,
|
|
0,
|
|
b"hi mom",
|
|
coin::zero()
|
|
);
|
|
wormhole::emitter::destroy_emitter_cap(emitter_cap);
|
|
}
|
|
}
|