wormhole/sui/examples/coins/sources/coin.move

211 lines
9.1 KiB
Plaintext

// Example wrapped coin for testing purposes
#[test_only]
module coins::coin {
use sui::object::{Self};
use sui::package::{Self};
use sui::transfer::{Self};
use sui::tx_context::{Self, TxContext};
use token_bridge::create_wrapped::{Self};
struct COIN has drop {}
fun init(witness: COIN, ctx: &mut TxContext) {
use token_bridge::version_control::{V__0_2_0 as V__CURRENT};
transfer::public_transfer(
create_wrapped::prepare_registration<COIN, V__CURRENT>(
witness,
// TODO: create a version of this for each decimal to be used
8,
ctx
),
tx_context::sender(ctx)
);
}
#[test_only]
/// NOTE: Even though this module is `#[test_only]`, this method is tagged
/// with the same macro as a trick to allow another method within this
/// module to call `init` using OTW.
public fun init_test_only(ctx: &mut TxContext) {
init(COIN {}, ctx);
// This will be created and sent to the transaction sender
// automatically when the contract is published.
transfer::public_transfer(
package::test_publish(object::id_from_address(@coins), ctx),
tx_context::sender(ctx)
);
}
}
#[test_only]
module coins::coin_tests {
use sui::coin::{Self};
use sui::package::{UpgradeCap};
use sui::test_scenario::{Self};
use token_bridge::create_wrapped::{Self, WrappedAssetSetup};
use token_bridge::state::{Self};
use token_bridge::token_bridge_scenario::{
register_dummy_emitter,
return_state,
set_up_wormhole_and_token_bridge,
take_state,
two_people
};
use token_bridge::token_registry::{Self};
use token_bridge::vaa::{Self};
use token_bridge::wrapped_asset::{Self};
use wormhole::bytes32::{Self};
use wormhole::external_address::{Self};
use wormhole::wormhole_scenario::{parse_and_verify_vaa};
use token_bridge::version_control::{V__0_2_0 as V__CURRENT};
use coins::coin::{COIN};
// +------------------------------------------------------------------------------+
// | Wormhole VAA v1 | nonce: 1 | time: 1 |
// | guardian set #0 | #22080291 | consistency: 0 |
// |------------------------------------------------------------------------------|
// | Signature: |
// | #0: 80366065746148420220f25a6275097370e8db40984529a6676b7a5fc9fe... |
// |------------------------------------------------------------------------------|
// | Emitter: 0x00000000000000000000000000000000deadbeef (Ethereum) |
// |==============================================================================|
// | Token attestation |
// | decimals: 12 |
// | Token: 0x00000000000000000000000000000000beefface (Ethereum) |
// | Symbol: BEEF |
// | Name: Beef face Token |
// +------------------------------------------------------------------------------+
const VAA: vector<u8> =
x"0100000000010080366065746148420220f25a6275097370e8db40984529a6676b7a5fc9feb11755ec49ca626b858ddfde88d15601f85ab7683c5f161413b0412143241c700aff010000000100000001000200000000000000000000000000000000000000000000000000000000deadbeef000000000150eb23000200000000000000000000000000000000000000000000000000000000beefface00020c424545460000000000000000000000000000000000000000000000000000000042656566206661636520546f6b656e0000000000000000000000000000000000";
// +------------------------------------------------------------------------------+
// | Wormhole VAA v1 | nonce: 69 | time: 0 |
// | guardian set #0 | #1 | consistency: 15 |
// |------------------------------------------------------------------------------|
// | Signature: |
// | #0: b0571650590e147fce4eb60105e0463522c1244a97bd5dcb365d3e7bc7f3... |
// |------------------------------------------------------------------------------|
// | Emitter: 0x00000000000000000000000000000000deadbeef (Ethereum) |
// |==============================================================================|
// | Token attestation |
// | decimals: 12 |
// | Token: 0x00000000000000000000000000000000beefface (Ethereum) |
// | Symbol: BEEF??? and profit |
// | Name: Beef face Token??? and profit |
// +------------------------------------------------------------------------------+
const UPDATED_VAA: vector<u8> =
x"0100000000010062f4dcd21bbbc4af8b8baaa2da3a0b168efc4c975de5b828c7a3c710b67a0a0d476d10a74aba7a7867866daf97d1372d8e6ee62ccc5ae522e3e603c67fa23787000000000000000045000200000000000000000000000000000000000000000000000000000000deadbeef00000000000000010f0200000000000000000000000000000000000000000000000000000000beefface00020c424545463f3f3f20616e642070726f666974000000000000000000000000000042656566206661636520546f6b656e3f3f3f20616e642070726f666974000000";
#[test]
public fun test_complete_and_update_attestation() {
let (caller, coin_deployer) = two_people();
let my_scenario = test_scenario::begin(caller);
let scenario = &mut my_scenario;
// Set up contracts.
let wormhole_fee = 350;
set_up_wormhole_and_token_bridge(scenario, wormhole_fee);
// Register foreign emitter on chain ID == 2.
let expected_source_chain = 2;
register_dummy_emitter(scenario, expected_source_chain);
// Ignore effects. Make sure `coin_deployer` receives
// `WrappedAssetSetup`.
test_scenario::next_tx(scenario, coin_deployer);
// Publish coin.
coins::coin::init_test_only(test_scenario::ctx(scenario));
// Ignore effects.
test_scenario::next_tx(scenario, coin_deployer);
let wrapped_asset_setup =
test_scenario::take_from_address<WrappedAssetSetup<COIN, V__CURRENT>>(
scenario,
coin_deployer
);
let token_bridge_state = take_state(scenario);
let verified_vaa = parse_and_verify_vaa(scenario, VAA);
let msg = vaa::verify_only_once(&mut token_bridge_state, verified_vaa);
let coin_meta = test_scenario::take_shared(scenario);
// Ignore effects.
test_scenario::next_tx(scenario, caller);
create_wrapped::complete_registration(
&mut token_bridge_state,
&mut coin_meta,
wrapped_asset_setup,
test_scenario::take_from_address<UpgradeCap>(
scenario,
coin_deployer
),
msg
);
// Check registry.
{
let verified = state::verified_asset<COIN>(&token_bridge_state);
assert!(token_bridge::token_registry::is_wrapped<COIN>(&verified), 0);
let registry = state::borrow_token_registry(&token_bridge_state);
let asset =
token_registry::borrow_wrapped<COIN>(registry);
assert!(wrapped_asset::total_supply(asset) == 0, 0);
// Decimals are capped for this wrapped asset.
assert!(coin::get_decimals(&coin_meta) == 8, 0);
// Check metadata against asset metadata.
let info = wrapped_asset::info(asset);
assert!(wrapped_asset::token_chain(info) == 2, 0);
assert!(wrapped_asset::token_address(info) == external_address::new(bytes32::from_bytes(x"00000000000000000000000000000000beefface")), 0);
assert!(
wrapped_asset::native_decimals(info) == 12,
0
);
assert!(coin::get_symbol(&coin_meta) == std::ascii::string(b"BEEF"), 0);
assert!(coin::get_name(&coin_meta) == std::string::utf8(b"Beef face Token"), 0);
};
let verified_vaa =
parse_and_verify_vaa(scenario, UPDATED_VAA);
let msg = vaa::verify_only_once(&mut token_bridge_state, verified_vaa);
// Ignore effects.
test_scenario::next_tx(scenario, caller);
// Now update metadata.
create_wrapped::update_attestation<COIN>(&mut token_bridge_state, &mut coin_meta, msg);
// Check updated name and symbol.
assert!(
coin::get_name(&coin_meta) == std::string::utf8(b"Beef face Token??? and profit"),
0
);
assert!(
coin::get_symbol(&coin_meta) == std::ascii::string(b"BEEF??? and profit"),
0
);
// Clean up.
return_state(token_bridge_state);
test_scenario::return_shared(coin_meta);
// Done.
test_scenario::end(my_scenario);
}
}