From dbc52a11f773891b0f431c707e9a1f005115ff14 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Mon, 13 Oct 2025 00:36:37 -0400 Subject: [PATCH 01/24] Dynamic dispatch support for CCIP Receiver contracts --- .../ccip/ccip/sources/receiver_registry.move | 45 +- contracts/ccip/ccip_offramp/Move.toml | 7 + .../ccip/ccip_offramp/sources/offramp.move | 5 + .../mock/burn_mint_dispatchable_receiver.move | 182 +++++ .../lock_release_dispatchable_receiver.move | 182 +++++ .../mock/managed_dispatchable_receiver.move | 189 +++++ .../ccip_offramp/tests/mock/mock_token.move | 49 ++ .../tests/mock/non_dispatchable_receiver.move | 207 +++++ .../mock/regulated_dispatchable_receiver.move | 189 +++++ .../offramp_burn_mint_receiver_test.move | 640 ++++++++++++++++ .../offramp_lock_release_receiver_test.move | 641 ++++++++++++++++ .../tests/offramp_managed_receiver_test.move | 715 ++++++++++++++++++ .../offramp_regulated_receiver_test.move | 429 +++++++++++ .../ccip/ccip_offramp/tests/offramp_test.move | 352 ++++++++- .../sources/burn_mint_token_pool.move | 62 ++ .../sources/lock_release_token_pool.move | 65 ++ .../sources/managed_token_pool.move | 57 ++ .../sources/regulated_token_pool.move | 60 ++ .../tests/regulated_token_pool_test.move | 41 + .../token_pool/sources/token_pool.move | 27 + .../managed_token/sources/managed_token.move | 29 + .../sources/regulated_token.move | 24 + 22 files changed, 4162 insertions(+), 35 deletions(-) create mode 100644 contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move create mode 100644 contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move create mode 100644 contracts/ccip/ccip_offramp/tests/mock/managed_dispatchable_receiver.move create mode 100644 contracts/ccip/ccip_offramp/tests/mock/mock_token.move create mode 100644 contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move create mode 100644 contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move create mode 100644 contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move create mode 100644 contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move create mode 100644 contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move create mode 100644 contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index 734ae430..353636ca 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -5,13 +5,15 @@ module ccip::receiver_registry { use std::error; use std::event::{Self, EventHandle}; use std::function_info::{Self, FunctionInfo}; + use std::table::{Self, Table}; use std::type_info::{Self, TypeInfo}; use std::fungible_asset::{Self, Metadata}; - use std::object::{Self, ExtendRef, Object, TransferRef}; + use std::object::{Self, ExtendRef, Object, TransferRef, ObjectCore}; use std::option::{Self, Option}; use std::signer; use std::string::{Self, String}; + use ccip::auth; use ccip::client; use ccip::state_object; @@ -32,6 +34,10 @@ module ccip::receiver_registry { executing_input: Option } + struct CCIPReceiveState has key { + executing_receivers: Table + } + #[event] struct ReceiverRegistered has store, drop { receiver_address: address, @@ -45,6 +51,7 @@ module ccip::receiver_registry { const E_NON_EMPTY_INPUT: u64 = 5; const E_PROOF_TYPE_ACCOUNT_MISMATCH: u64 = 6; const E_PROOF_TYPE_MODULE_MISMATCH: u64 = 7; + const E_UNAUTHORIZED: u64 = 8; #[view] public fun type_and_version(): String { @@ -65,6 +72,10 @@ module ccip::receiver_registry { }; move_to(&state_object_signer, state); + + move_to( + &state_object_signer, CCIPReceiveState { executing_receivers: table::new() } + ); } public fun register_receiver( @@ -143,6 +154,13 @@ module ccip::receiver_registry { exists(receiver_address) } + #[view] + public fun is_executing_receiver_in_progress( + receiver_address: address + ): bool acquires CCIPReceiveState { + borrow_ccip_receive_state_mut().executing_receivers.contains(receiver_address) + } + public fun get_receiver_input( receiver_address: address, _proof: ProofType ): client::Any2AptosMessage acquires CCIPReceiverRegistration { @@ -163,7 +181,7 @@ module ccip::receiver_registry { public(friend) fun start_receive( receiver_address: address, message: client::Any2AptosMessage - ): Object acquires CCIPReceiverRegistration { + ): Object acquires CCIPReceiverRegistration, CCIPReceiveState { let registration = get_registration_mut(receiver_address); assert!( @@ -173,16 +191,22 @@ module ccip::receiver_registry { registration.executing_input.fill(message); + borrow_ccip_receive_state_mut().executing_receivers.add(receiver_address, true); + registration.dispatch_metadata } - public(friend) fun finish_receive(receiver_address: address) acquires CCIPReceiverRegistration { + public(friend) fun finish_receive( + receiver_address: address + ) acquires CCIPReceiverRegistration, CCIPReceiveState { let registration = get_registration_mut(receiver_address); assert!( registration.executing_input.is_none(), error::invalid_state(E_NON_EMPTY_INPUT) ); + + borrow_ccip_receive_state_mut().executing_receivers.remove(receiver_address); } inline fun borrow_state(): &ReceiverRegistryState { @@ -193,6 +217,10 @@ module ccip::receiver_registry { borrow_global_mut(state_object::object_address()) } + inline fun borrow_ccip_receive_state_mut(): &mut CCIPReceiveState { + borrow_global_mut(state_object::object_address()) + } + inline fun get_registration_mut(receiver_address: address): &mut CCIPReceiverRegistration { assert!( exists(receiver_address), @@ -201,6 +229,17 @@ module ccip::receiver_registry { borrow_global_mut(receiver_address) } + // ============================= Migrations ============================= + + public fun initialize_ccip_receive_state(caller: &signer) { + auth::assert_only_owner(signer::address_of(caller)); + + move_to( + &state_object::object_signer(), + CCIPReceiveState { executing_receivers: table::new() } + ); + } + #[test_only] public fun init_module_for_testing(publisher: &signer) { init_module(publisher); diff --git a/contracts/ccip/ccip_offramp/Move.toml b/contracts/ccip/ccip_offramp/Move.toml index b518bea5..d67daf8b 100644 --- a/contracts/ccip/ccip_offramp/Move.toml +++ b/contracts/ccip/ccip_offramp/Move.toml @@ -18,8 +18,13 @@ mcms_register_entrypoints = "0x4001" ccip_token_pool = "0x8d62e11f76e6e92563c59e7a5e842a540f8c6c3a4ed8a32f40a5ad3425b55f86" burn_mint_token_pool = "0x8e03eb21315649c06acb9a860a72c2b8cef5bd36775402008b89af397756dad7" lock_release_token_pool = "0x2e1f4cc8fbc2c7ccd2c67ff453e00526919098304d70708ef504af944d6fede8" +managed_token_pool = "0xc0a1d7586bddbd46c9b3445cf9ad82c020dcb82818e6092c9683b51bfecc6633" +regulated_token_pool = "0xb761d8e8425c11486ecb38444aab3493baf7c45381ce973a0bc99618c35021d5" burn_mint_local_token = "0x15c084d10b071a4b180c8d050e421a533bd07d13f9d9386335709da567183768" lock_release_local_token = "0x6d1c246126d36fea774b12486de0a3737997f1b9b23806c67ca5ce72859ff5fa" +managed_token = "0xfda529bc9c3e1cd8bd3df66bd96bb20a36553ed454c909a96e6a0dadb728e896" +regulated_token = "0xb3cec8e3442cafe0c378411012bbcae6787bfc0fbdd528ee9a00aaaf0c88d1b6" +admin = "0x100" [dependencies] AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", rev = "837d04bd9bd0dd7156da4252bcfc1d080ed591ec", subdir = "aptos-move/framework/aptos-framework" } @@ -28,3 +33,5 @@ ChainlinkCCIP = { local = "../ccip" } [dev-dependencies] BurnMintTokenPool = { local = "../ccip_token_pools/burn_mint_token_pool", addr_subst = {} } LockReleaseTokenPool = { local = "../ccip_token_pools/lock_release_token_pool", addr_subst = {} } +ManagedTokenPool = { local = "../ccip_token_pools/managed_token_pool", addr_subst = {} } +RegulatedTokenPool = { local = "../ccip_token_pools/regulated_token_pool", addr_subst = {} } diff --git a/contracts/ccip/ccip_offramp/sources/offramp.move b/contracts/ccip/ccip_offramp/sources/offramp.move index ff3a7ef8..b902144d 100644 --- a/contracts/ccip/ccip_offramp/sources/offramp.move +++ b/contracts/ccip/ccip_offramp/sources/offramp.move @@ -1806,4 +1806,9 @@ module ccip_offramp::offramp { public fun merkle_root_merkle_root(root: &MerkleRoot): vector { root.merkle_root } + + #[test_only] + public fun source_chain_config_on_ramp(config: &SourceChainConfig): vector { + config.on_ramp + } } diff --git a/contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move new file mode 100644 index 00000000..920158c0 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move @@ -0,0 +1,182 @@ +#[test_only] +/// The `dispatchable_receiver` is designed to be used with dispatchable tokens +/// with pool type `burn_mint_token_pool`. +module ccip_offramp::burn_mint_dispatchable_receiver { + use std::account; + use std::event; + use std::object::{Self, Object}; + use std::option::{Self, Option}; + use std::string::{Self, String}; + use std::fungible_asset::{Metadata}; + use std::primary_fungible_store; + use std::from_bcs; + use std::signer; + + use ccip::client; + use ccip::receiver_registry; + use burn_mint_token_pool::burn_mint_token_pool; + + #[event] + struct ReceivedMessage has store, drop { + message: String + } + + #[event] + struct ForwardedTokens has store, drop { + final_recipient: address + } + + #[event] + struct ReceivedTokensOnly has store, drop { + token_count: u64 + } + + struct CCIPReceiverState has key { + signer_cap: account::SignerCapability, + received_message_handle: event::EventHandle, + forwarded_tokens_handle: event::EventHandle, + received_tokens_only_handle: event::EventHandle + } + + const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; + const E_UNAUTHORIZED: u64 = 2; + const E_INVALID_TOKEN_ADDRESS: u64 = 3; + const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + + #[view] + public fun type_and_version(): String { + string::utf8(b"BurnMintDispatchableReceiver 1.6.0") + } + + const MODULE_NAME: vector = b"burn_mint_dispatchable_receiver"; + + fun init_module(publisher: &signer) { + // Create a signer capability for the receiver account + let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); + + // Create a unique handle for each event type + let received_message_handle = + account::new_event_handle(publisher); + let forwarded_tokens_handle = + account::new_event_handle(publisher); + let received_tokens_only_handle = + account::new_event_handle(publisher); + + // Move all state into the single resource struct + move_to( + publisher, + CCIPReceiverState { + signer_cap, + received_message_handle, + forwarded_tokens_handle, + received_tokens_only_handle + } + ); + + receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); + } + + struct CCIPReceiverProof has drop {} + + public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + /* load state and rebuild a signer for the resource account */ + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let message = + receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); + + let data = client::get_data(&message); + + let dest_token_amounts = client::get_dest_token_amounts(&message); + + if (dest_token_amounts.length() != 0 && data.length() != 0) { + let final_recipient = from_bcs::to_address(data); + + for (i in 0..dest_token_amounts.length()) { + let token_amount_ref = &dest_token_amounts[i]; + let amount = client::get_amount(token_amount_ref); + + // For dispatchable tokens, we need to call into token pool's `transfer` function + burn_mint_token_pool::transfer(&state_signer, final_recipient, amount); + }; + + event::emit(ForwardedTokens { final_recipient }); + event::emit_event( + &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + ); + + } else if (data.length() != 0) { + + // Convert the vector to a string + let message = string::utf8(data); + + event::emit(ReceivedMessage { message }); + event::emit_event( + &mut state.received_message_handle, ReceivedMessage { message } + ); + + } else if (dest_token_amounts.length() != 0) { + // Tokens only (no forwarding data) - keep them at receiver + // Emit event to prove receiver was called + let token_count = dest_token_amounts.length(); + event::emit(ReceivedTokensOnly { token_count }); + event::emit_event( + &mut state.received_tokens_only_handle, + ReceivedTokensOnly { token_count } + ); + }; + + // Simple abort condition for testing + if (data == b"abort") { + abort 1 + }; + + option::none() + } + + public entry fun withdraw_token( + sender: &signer, recipient: address, token_address: address + ) acquires CCIPReceiverState { + assert!( + exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT + ); + assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); + + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let fa_token = object::address_to_object(token_address); + let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); + + // Check if there are tokens available to withdraw + assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); + + primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); + } + + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } + + public fun get_received_message_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.received_message_handle) + } + + public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.forwarded_tokens_handle) + } + + public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle( + &state.received_tokens_only_handle + ) + } + + public fun received_message_get_message(event: &ReceivedMessage): String { + event.message + } +} diff --git a/contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move new file mode 100644 index 00000000..ff7aff45 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move @@ -0,0 +1,182 @@ +#[test_only] +/// The `dispatchable_receiver` is designed to be used with dispatchable tokens +/// with pool type `lock_release_token_pool`. +module ccip_offramp::lock_release_dispatchable_receiver { + use std::account; + use std::event; + use std::object::{Self, Object}; + use std::option::{Self, Option}; + use std::string::{Self, String}; + use std::fungible_asset::{Metadata}; + use std::primary_fungible_store; + use std::from_bcs; + use std::signer; + + use ccip::client; + use ccip::receiver_registry; + use lock_release_token_pool::lock_release_token_pool; + + #[event] + struct ReceivedMessage has store, drop { + message: String + } + + #[event] + struct ForwardedTokens has store, drop { + final_recipient: address + } + + #[event] + struct ReceivedTokensOnly has store, drop { + token_count: u64 + } + + struct CCIPReceiverState has key { + signer_cap: account::SignerCapability, + received_message_handle: event::EventHandle, + forwarded_tokens_handle: event::EventHandle, + received_tokens_only_handle: event::EventHandle + } + + const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; + const E_UNAUTHORIZED: u64 = 2; + const E_INVALID_TOKEN_ADDRESS: u64 = 3; + const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + + #[view] + public fun type_and_version(): String { + string::utf8(b"LockReleaseDispatchableReceiver 1.6.0") + } + + const MODULE_NAME: vector = b"lock_release_dispatchable_receiver"; + + fun init_module(publisher: &signer) { + // Create a signer capability for the receiver account + let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); + + // Create a unique handle for each event type + let received_message_handle = + account::new_event_handle(publisher); + let forwarded_tokens_handle = + account::new_event_handle(publisher); + let received_tokens_only_handle = + account::new_event_handle(publisher); + + // Move all state into the single resource struct + move_to( + publisher, + CCIPReceiverState { + signer_cap, + received_message_handle, + forwarded_tokens_handle, + received_tokens_only_handle + } + ); + + receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); + } + + struct CCIPReceiverProof has drop {} + + public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + /* load state and rebuild a signer for the resource account */ + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let message = + receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); + + let data = client::get_data(&message); + + let dest_token_amounts = client::get_dest_token_amounts(&message); + + if (dest_token_amounts.length() != 0 && data.length() != 0) { + let final_recipient = from_bcs::to_address(data); + + for (i in 0..dest_token_amounts.length()) { + let token_amount_ref = &dest_token_amounts[i]; + let amount = client::get_amount(token_amount_ref); + + // For dispatchable tokens, we need to call into token pool's `transfer` function + lock_release_token_pool::transfer(&state_signer, final_recipient, amount); + }; + + event::emit(ForwardedTokens { final_recipient }); + event::emit_event( + &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + ); + + } else if (data.length() != 0) { + + // Convert the vector to a string + let message = string::utf8(data); + + event::emit(ReceivedMessage { message }); + event::emit_event( + &mut state.received_message_handle, ReceivedMessage { message } + ); + + } else if (dest_token_amounts.length() != 0) { + // Tokens only (no forwarding data) - keep them at receiver + // Emit event to prove receiver was called + let token_count = dest_token_amounts.length(); + event::emit(ReceivedTokensOnly { token_count }); + event::emit_event( + &mut state.received_tokens_only_handle, + ReceivedTokensOnly { token_count } + ); + }; + + // Simple abort condition for testing + if (data == b"abort") { + abort 1 + }; + + option::none() + } + + public entry fun withdraw_token( + sender: &signer, recipient: address, token_address: address + ) acquires CCIPReceiverState { + assert!( + exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT + ); + assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); + + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let fa_token = object::address_to_object(token_address); + let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); + + // Check if there are tokens available to withdraw + assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); + + primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); + } + + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } + + public fun get_received_message_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.received_message_handle) + } + + public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.forwarded_tokens_handle) + } + + public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle( + &state.received_tokens_only_handle + ) + } + + public fun received_message_get_message(event: &ReceivedMessage): String { + event.message + } +} diff --git a/contracts/ccip/ccip_offramp/tests/mock/managed_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/managed_dispatchable_receiver.move new file mode 100644 index 00000000..c94e5313 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/mock/managed_dispatchable_receiver.move @@ -0,0 +1,189 @@ +#[test_only] +/// The `dispatchable_receiver` is designed to be used with dispatchable tokens +/// with pool type `managed_token_pool`. +module ccip_offramp::managed_dispatchable_receiver { + use std::account; + use std::event; + use std::object::{Self, Object}; + use std::option::{Self, Option}; + use std::string::{Self, String}; + use std::fungible_asset::{Metadata}; + use std::primary_fungible_store; + use std::from_bcs; + use std::signer; + + use ccip::client; + use ccip::receiver_registry; + use managed_token_pool::managed_token_pool; + + #[event] + struct ReceivedMessage has store, drop { + message: String + } + + #[event] + struct ForwardedTokens has store, drop { + final_recipient: address + } + + #[event] + struct ReceivedTokensOnly has store, drop { + token_count: u64 + } + + struct CCIPReceiverState has key { + signer_cap: account::SignerCapability, + received_message_handle: event::EventHandle, + forwarded_tokens_handle: event::EventHandle, + received_tokens_only_handle: event::EventHandle + } + + const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; + const E_UNAUTHORIZED: u64 = 2; + const E_INVALID_TOKEN_ADDRESS: u64 = 3; + const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + + #[view] + public fun type_and_version(): String { + string::utf8(b"ManagedDispatchableReceiver 1.6.0") + } + + #[view] + public fun get_state_address(): address acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + signer::address_of(&state_signer) + } + + const MODULE_NAME: vector = b"managed_dispatchable_receiver"; + + fun init_module(publisher: &signer) { + // Create a signer capability for the receiver account + let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); + + // Create a unique handle for each event type + let received_message_handle = + account::new_event_handle(publisher); + let forwarded_tokens_handle = + account::new_event_handle(publisher); + let received_tokens_only_handle = + account::new_event_handle(publisher); + + // Move all state into the single resource struct + move_to( + publisher, + CCIPReceiverState { + signer_cap, + received_message_handle, + forwarded_tokens_handle, + received_tokens_only_handle + } + ); + + receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); + } + + struct CCIPReceiverProof has drop {} + + public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + /* load state and rebuild a signer for the resource account */ + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let message = + receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); + + let data = client::get_data(&message); + + let dest_token_amounts = client::get_dest_token_amounts(&message); + + if (dest_token_amounts.length() != 0 && data.length() != 0) { + let final_recipient = from_bcs::to_address(data); + + for (i in 0..dest_token_amounts.length()) { + let token_amount_ref = &dest_token_amounts[i]; + let amount = client::get_amount(token_amount_ref); + + // For dispatchable tokens, we need to call into token pool's `transfer` function + managed_token_pool::transfer(&state_signer, final_recipient, amount); + }; + + event::emit(ForwardedTokens { final_recipient }); + event::emit_event( + &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + ); + + } else if (data.length() != 0) { + + // Convert the vector to a string + let message = string::utf8(data); + + event::emit(ReceivedMessage { message }); + event::emit_event( + &mut state.received_message_handle, ReceivedMessage { message } + ); + + } else if (dest_token_amounts.length() != 0) { + // Tokens only (no forwarding data) - keep them at receiver + // Emit event to prove receiver was called + let token_count = dest_token_amounts.length(); + event::emit(ReceivedTokensOnly { token_count }); + event::emit_event( + &mut state.received_tokens_only_handle, + ReceivedTokensOnly { token_count } + ); + }; + + // Simple abort condition for testing + if (data == b"abort") { + abort 1 + }; + + option::none() + } + + public entry fun withdraw_token( + sender: &signer, recipient: address, token_address: address + ) acquires CCIPReceiverState { + assert!( + exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT + ); + assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); + + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let fa_token = object::address_to_object(token_address); + let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); + + // Check if there are tokens available to withdraw + assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); + + primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); + } + + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } + + public fun get_received_message_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.received_message_handle) + } + + public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.forwarded_tokens_handle) + } + + public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle( + &state.received_tokens_only_handle + ) + } + + public fun received_message_get_message(event: &ReceivedMessage): String { + event.message + } +} diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_token.move b/contracts/ccip/ccip_offramp/tests/mock/mock_token.move new file mode 100644 index 00000000..4c6d292c --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_token.move @@ -0,0 +1,49 @@ +#[test_only] +module ccip_offramp::mock_token { + use std::fungible_asset::{Self, FungibleAsset, TransferRef}; + use std::object::{Object, ConstructorRef}; + use std::string::{Self}; + use std::option::{Self}; + use std::function_info; + use std::dispatchable_fungible_asset; + + public fun add_dynamic_dispatch_function( + ccip_onramp_signer: &signer, constructor_ref: &ConstructorRef + ) { + let deposit = + function_info::new_function_info( + ccip_onramp_signer, + string::utf8(b"mock_token"), + string::utf8(b"deposit") + ); + let withdraw = + function_info::new_function_info( + ccip_onramp_signer, + string::utf8(b"mock_token"), + string::utf8(b"withdraw") + ); + dispatchable_fungible_asset::register_dispatch_functions( + constructor_ref, + option::some(withdraw), + option::some(deposit), + option::none() + ); + } + + public fun deposit( + store: Object, fa: FungibleAsset, transfer_ref: &TransferRef + ) { + std::debug::print(&std::string::utf8(b"custom lock_or_burn called")); + fungible_asset::deposit_with_ref(transfer_ref, store, fa); + std::debug::print(&std::string::utf8(b"custom lock_or_burn done")); + } + + public fun withdraw( + store: Object, amount: u64, transfer_ref: &TransferRef + ): FungibleAsset { + std::debug::print(&std::string::utf8(b"custom release_or_mint called")); + let fa = fungible_asset::withdraw_with_ref(transfer_ref, store, amount); + std::debug::print(&std::string::utf8(b"custom release_or_mint done")); + fa + } +} diff --git a/contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move new file mode 100644 index 00000000..26ef1632 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move @@ -0,0 +1,207 @@ +#[test_only] +/// The `non_dispatchable_receiver` module should only be used with non-dispatchable tokens. +module ccip_offramp::non_dispatchable_receiver { + use std::account; + use std::event; + use std::object::{Self, Object}; + use std::option::{Self, Option}; + use std::string::{Self, String}; + use std::fungible_asset::{Self, Metadata}; + use std::primary_fungible_store; + use std::from_bcs; + use std::signer; + + use ccip::client; + use ccip::receiver_registry; + + #[event] + struct ReceivedMessage has store, drop { + message: String + } + + #[event] + struct ForwardedTokens has store, drop { + final_recipient: address + } + + #[event] + struct ReceivedTokensOnly has store, drop { + token_count: u64 + } + + struct CCIPReceiverState has key { + signer_cap: account::SignerCapability, + received_message_handle: event::EventHandle, + forwarded_tokens_handle: event::EventHandle, + received_tokens_only_handle: event::EventHandle + } + + const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; + const E_UNAUTHORIZED: u64 = 2; + const E_INVALID_TOKEN_ADDRESS: u64 = 3; + const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + + #[view] + public fun type_and_version(): String { + string::utf8(b"NonDispatchableReceiver 1.6.0") + } + + const MODULE_NAME: vector = b"non_dispatchable_receiver"; + + fun init_module(publisher: &signer) { + // Create a signer capability for the receiver account + let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); + + // Create a unique handle for each event type + let received_message_handle = + account::new_event_handle(publisher); + let forwarded_tokens_handle = + account::new_event_handle(publisher); + let received_tokens_only_handle = + account::new_event_handle(publisher); + + // Move all state into the single resource struct + move_to( + publisher, + CCIPReceiverState { + signer_cap, + received_message_handle, + forwarded_tokens_handle, + received_tokens_only_handle + } + ); + + receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); + } + + struct CCIPReceiverProof has drop {} + + public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + /* load state and rebuild a signer for the resource account */ + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let message = + receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); + + let data = client::get_data(&message); + + let dest_token_amounts = client::get_dest_token_amounts(&message); + + if (dest_token_amounts.length() != 0 && data.length() != 0) { + let final_recipient = from_bcs::to_address(data); + + for (i in 0..dest_token_amounts.length()) { + let token_amount_ref = &dest_token_amounts[i]; + let token_addr = client::get_token(token_amount_ref); + let amount = client::get_amount(token_amount_ref); + + // Implement the token transfer logic here + + let fa_token = object::address_to_object(token_addr); + let fa_store_sender = + primary_fungible_store::ensure_primary_store_exists( + @ccip_offramp, fa_token + ); + let fa_store_receiver = + primary_fungible_store::ensure_primary_store_exists( + final_recipient, fa_token + ); + + // For non-dispatchable tokens, we need to use `fungible_asset::transfer` + fungible_asset::transfer( + &state_signer, + fa_store_sender, + fa_store_receiver, + amount + ); + }; + + event::emit(ForwardedTokens { final_recipient }); + event::emit_event( + &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + ); + } else if (data.length() != 0) { + // Convert the vector to a string + let message = string::utf8(data); + + event::emit(ReceivedMessage { message }); + event::emit_event( + &mut state.received_message_handle, ReceivedMessage { message } + ); + + } else if (dest_token_amounts.length() != 0) { + // Tokens only (no forwarding data) - keep them at receiver + // Emit event to prove receiver was called + let token_count = dest_token_amounts.length(); + event::emit(ReceivedTokensOnly { token_count }); + event::emit_event( + &mut state.received_tokens_only_handle, + ReceivedTokensOnly { token_count } + ); + }; + + // Simple abort condition for testing + if (data == b"abort") { + abort 1 + }; + + option::none() + } + + public entry fun withdraw_token( + sender: &signer, recipient: address, token_address: address + ) acquires CCIPReceiverState { + assert!( + exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT + ); + assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); + + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let fa_token = object::address_to_object(token_address); + let fa_store_sender = + primary_fungible_store::ensure_primary_store_exists(@ccip_offramp, fa_token); + let fa_store_receiver = + primary_fungible_store::ensure_primary_store_exists(recipient, fa_token); + + let balance = fungible_asset::balance(fa_store_sender); + + // Check if there are tokens available to withdraw + assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); + + // For non-dispatchable tokens, we need to use `fungible_asset::transfer` + fungible_asset::transfer( + &state_signer, + fa_store_sender, + fa_store_receiver, + balance + ); + } + + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } + + public fun get_received_message_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.received_message_handle) + } + + public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.forwarded_tokens_handle) + } + + public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle( + &state.received_tokens_only_handle + ) + } + + public fun received_message_get_message(event: &ReceivedMessage): String { + event.message + } +} diff --git a/contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move new file mode 100644 index 00000000..34e6eae4 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move @@ -0,0 +1,189 @@ +#[test_only] +/// The `dispatchable_receiver` is designed to be used with dispatchable tokens +/// with pool type `regulated_token_pool`. +module ccip_offramp::regulated_dispatchable_receiver { + use std::account; + use std::event; + use std::object::{Self, Object}; + use std::option::{Self, Option}; + use std::string::{Self, String}; + use std::fungible_asset::{Metadata}; + use std::primary_fungible_store; + use std::from_bcs; + use std::signer; + + use ccip::client; + use ccip::receiver_registry; + use regulated_token_pool::regulated_token_pool; + + #[event] + struct ReceivedMessage has store, drop { + message: String + } + + #[event] + struct ForwardedTokens has store, drop { + final_recipient: address + } + + #[event] + struct ReceivedTokensOnly has store, drop { + token_count: u64 + } + + struct CCIPReceiverState has key { + signer_cap: account::SignerCapability, + received_message_handle: event::EventHandle, + forwarded_tokens_handle: event::EventHandle, + received_tokens_only_handle: event::EventHandle + } + + const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; + const E_UNAUTHORIZED: u64 = 2; + const E_INVALID_TOKEN_ADDRESS: u64 = 3; + const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + + #[view] + public fun type_and_version(): String { + string::utf8(b"RegulatedDispatchableReceiver 1.6.0") + } + + #[view] + public fun get_state_address(): address acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + signer::address_of(&state_signer) + } + + const MODULE_NAME: vector = b"regulated_dispatchable_receiver"; + + fun init_module(publisher: &signer) { + // Create a signer capability for the receiver account + let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); + + // Create a unique handle for each event type + let received_message_handle = + account::new_event_handle(publisher); + let forwarded_tokens_handle = + account::new_event_handle(publisher); + let received_tokens_only_handle = + account::new_event_handle(publisher); + + // Move all state into the single resource struct + move_to( + publisher, + CCIPReceiverState { + signer_cap, + received_message_handle, + forwarded_tokens_handle, + received_tokens_only_handle + } + ); + + receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); + } + + struct CCIPReceiverProof has drop {} + + public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + /* load state and rebuild a signer for the resource account */ + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let message = + receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); + + let data = client::get_data(&message); + + let dest_token_amounts = client::get_dest_token_amounts(&message); + + if (dest_token_amounts.length() != 0 && data.length() != 0) { + let final_recipient = from_bcs::to_address(data); + + for (i in 0..dest_token_amounts.length()) { + let token_amount_ref = &dest_token_amounts[i]; + let amount = client::get_amount(token_amount_ref); + + // For dispatchable tokens, we need to call into token pool's `transfer` function + regulated_token_pool::transfer(&state_signer, final_recipient, amount); + }; + + event::emit(ForwardedTokens { final_recipient }); + event::emit_event( + &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + ); + + } else if (data.length() != 0) { + + // Convert the vector to a string + let message = string::utf8(data); + + event::emit(ReceivedMessage { message }); + event::emit_event( + &mut state.received_message_handle, ReceivedMessage { message } + ); + + } else if (dest_token_amounts.length() != 0) { + // Tokens only (no forwarding data) - keep them at receiver + // Emit event to prove receiver was called + let token_count = dest_token_amounts.length(); + event::emit(ReceivedTokensOnly { token_count }); + event::emit_event( + &mut state.received_tokens_only_handle, + ReceivedTokensOnly { token_count } + ); + }; + + // Simple abort condition for testing + if (data == b"abort") { + abort 1 + }; + + option::none() + } + + public entry fun withdraw_token( + sender: &signer, recipient: address, token_address: address + ) acquires CCIPReceiverState { + assert!( + exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT + ); + assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); + + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let fa_token = object::address_to_object(token_address); + let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); + + // Check if there are tokens available to withdraw + assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); + + primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); + } + + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } + + public fun get_received_message_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.received_message_handle) + } + + public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle(&state.forwarded_tokens_handle) + } + + public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + event::emitted_events_by_handle( + &state.received_tokens_only_handle + ) + } + + public fun received_message_get_message(event: &ReceivedMessage): String { + event.message + } +} diff --git a/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move new file mode 100644 index 00000000..ad5adc9b --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move @@ -0,0 +1,640 @@ +#[test_only] +module ccip_offramp::offramp_burn_mint_receiver_test { + use std::account; + use std::fungible_asset; + use std::object; + use std::primary_fungible_store; + use std::signer; + use std::string; + use std::bcs; + use std::timestamp; + + use burn_mint_token_pool::burn_mint_token_pool; + use ccip_offramp::offramp_test; + use ccip_offramp::offramp; + use ccip_offramp::non_dispatchable_receiver; + use ccip_offramp::burn_mint_dispatchable_receiver; + use ccip::receiver_registry; + + const BURN_MINT_TOKEN_POOL: u8 = 0; + const BURN_MINT_TOKEN_SEED: vector = b"TestToken"; + const EVM_SOURCE_CHAIN_SELECTOR: u64 = 909606746561742123; + const MOCK_EVM_ADDRESS_VECTOR: vector = x"4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"; + const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; + const GAS_LIMIT: u64 = 1000000; + + fun setup_non_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + non_dispatchable_receiver::test_init_module(ccip_offramp); + } + + fun setup_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + burn_mint_dispatchable_receiver::test_init_module(ccip_offramp); + } + + struct TestMessage has drop { + message: offramp::Any2AptosRampMessage, + merkle_root: vector, + proofs: vector> + } + + fun create_and_commit_message( + message_id: vector, + sequence_number: u64, + receiver: address, + data: vector, + token_amounts: vector + ): TestMessage { + let static_config = offramp::get_static_config(); + let dest_chain_selector = offramp::chain_selector(&static_config); + + let header = + offramp::test_create_ramp_message_header( + message_id, + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + sequence_number, + 0 + ); + + let message = + offramp::test_create_any2aptos_ramp_message( + header, + EVM_SENDER, + data, + receiver, + (GAS_LIMIT as u256), + token_amounts + ); + + let source_chain_config = + offramp::get_source_chain_config(EVM_SOURCE_CHAIN_SELECTOR); + let on_ramp = offramp::source_chain_config_on_ramp(&source_chain_config); + + let metadata_hash = + offramp::test_calculate_metadata_hash( + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + on_ramp + ); + + let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); + let merkle_root = message_hash; + let proofs = vector[]; + + offramp::test_add_root(merkle_root, timestamp::now_seconds() - 3700); + + TestMessage { message, merkle_root, proofs } + } + + fun execute_message_and_verify_success( + sequence_number: u64, + test_message: TestMessage, + offchain_token_data: vector> + ) { + let TestMessage { message, merkle_root: _, proofs } = test_message; + + let report = + offramp::test_create_execution_report( + EVM_SOURCE_CHAIN_SELECTOR, + message, + offchain_token_data, + proofs + ); + + offramp::test_execute_single_report(report); + + let execution_state = + offramp::get_execution_state(EVM_SOURCE_CHAIN_SELECTOR, sequence_number); + assert!(execution_state == 2); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_non_dispatchable_token_transfer_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false + ); + let token_addr = object::object_address(&token_obj); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 100000 + ); + + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000001", + 1, + @ccip_offramp, // receiver + vector[], + vector[token_amounts] + ); + + execute_message_and_verify_success(1, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 100000); + + let tokens_only_events = + non_dispatchable_receiver::get_received_tokens_only_events(); + assert!(tokens_only_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_non_dispatchable_message_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false + ); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + let test_data = b"Hello from EVM chain!"; + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000002", + 2, + @ccip_offramp, // receiver + test_data, + vector[] + ); + + execute_message_and_verify_success(2, test_message, vector[]); + + let received_events = non_dispatchable_receiver::get_received_message_events(); + assert!(received_events.length() == 1); + + let event = received_events.borrow(0); + let event_message = + non_dispatchable_receiver::received_message_get_message(event); + assert!(event_message == string::utf8(test_data)); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + recipient = @0x999, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_receiver_non_dispatchable_tokens_with_forwarding( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + recipient: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false + ); + let token_addr = object::object_address(&token_obj); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + let recipient_addr = signer::address_of(recipient); + account::create_account_for_test(recipient_addr); + + // Sending 200,000 tokens to receiver contract first + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 200000 + ); + + let test_data = bcs::to_bytes(&recipient_addr); + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000003", + 3, // sequence number + @ccip_offramp, // receiver + test_data, + vector[token_amounts] + ); + + execute_message_and_verify_success(3, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 0); + + let recipient_store = + primary_fungible_store::primary_store(recipient_addr, token_obj); + let recipient_balance = fungible_asset::balance(recipient_store); + assert!(recipient_balance == 200000); + + let forwarded_events = non_dispatchable_receiver::get_forwarded_tokens_events(); + assert!(forwarded_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_token_transfer_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 100000 + ); + + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000004", + 4, // sequence number + @ccip_offramp, // receiver + vector[], + vector[token_amounts] + ); + + execute_message_and_verify_success(4, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 100000); + + let tokens_only_events = + burn_mint_dispatchable_receiver::get_received_tokens_only_events(); + assert!(tokens_only_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_message_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + true + ); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let test_data = b"Hello from EVM chain!"; + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000005", + 5, // sequence number + @ccip_offramp, // receiver + test_data, + vector[] + ); + + execute_message_and_verify_success(5, test_message, vector[]); + + let received_events = + burn_mint_dispatchable_receiver::get_received_message_events(); + assert!(received_events.length() == 1); + + let event = received_events.borrow(0); + let event_message = + burn_mint_dispatchable_receiver::received_message_get_message(event); + assert!(event_message == string::utf8(test_data)); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + recipient = @0x999, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_receiver_dispatchable_tokens_with_forwarding( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + recipient: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let recipient_addr = signer::address_of(recipient); + account::create_account_for_test(recipient_addr); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 200000 + ); + + let test_data = bcs::to_bytes(&recipient_addr); + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000006", + 6, // sequence number + @ccip_offramp, // receiver + test_data, + vector[token_amounts] + ); + + execute_message_and_verify_success(6, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 0); + + let recipient_store = + primary_fungible_store::primary_store(recipient_addr, token_obj); + let recipient_balance = fungible_asset::balance(recipient_store); + assert!(recipient_balance == 200000); + + let forwarded_events = + burn_mint_dispatchable_receiver::get_forwarded_tokens_events(); + assert!(forwarded_events.length() == 1); + } + + // ================================================================ + // | Tests for execution context enforcement | + // ================================================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ), + expected_failure( + abort_code = 327689, location = burn_mint_token_pool::burn_mint_token_pool + ) + ] + fun test_transfer_outside_ccip_receive_fails( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + true + ); + + setup_dispatchable_receiver(owner, ccip_offramp); + + // Try to transfer tokens directly without ccip_receive context + // This should fail because is_executing_receiver_in_progress is false + burn_mint_token_pool::transfer(ccip_offramp, @0x999, 100000); + } +} diff --git a/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move new file mode 100644 index 00000000..fffd44f5 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move @@ -0,0 +1,641 @@ +#[test_only] +module ccip_offramp::offramp_lock_release_receiver_test { + use std::account; + use std::fungible_asset; + use std::object; + use std::primary_fungible_store; + use std::signer; + use std::string; + use std::bcs; + use std::timestamp; + + use lock_release_token_pool::lock_release_token_pool; + use ccip_offramp::offramp_test; + use ccip_offramp::offramp; + use ccip_offramp::non_dispatchable_receiver; + use ccip_offramp::lock_release_dispatchable_receiver; + use ccip::receiver_registry; + + const LOCK_RELEASE_TOKEN_POOL: u8 = 1; + const LOCK_RELEASE_TOKEN_SEED: vector = b"LockReleaseToken"; + const EVM_SOURCE_CHAIN_SELECTOR: u64 = 909606746561742123; + const MOCK_EVM_ADDRESS_VECTOR: vector = x"4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"; + const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; + const GAS_LIMIT: u64 = 1000000; + + fun setup_non_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + non_dispatchable_receiver::test_init_module(ccip_offramp); + } + + fun setup_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + lock_release_dispatchable_receiver::test_init_module(ccip_offramp); + } + + struct TestMessage has drop { + message: offramp::Any2AptosRampMessage, + merkle_root: vector, + proofs: vector> + } + + fun create_and_commit_message( + message_id: vector, + sequence_number: u64, + receiver: address, + data: vector, + token_amounts: vector + ): TestMessage { + let static_config = offramp::get_static_config(); + let dest_chain_selector = offramp::chain_selector(&static_config); + + let header = + offramp::test_create_ramp_message_header( + message_id, + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + sequence_number, + 0 + ); + + let message = + offramp::test_create_any2aptos_ramp_message( + header, + EVM_SENDER, + data, + receiver, + (GAS_LIMIT as u256), + token_amounts + ); + + let source_chain_config = + offramp::get_source_chain_config(EVM_SOURCE_CHAIN_SELECTOR); + let on_ramp = offramp::source_chain_config_on_ramp(&source_chain_config); + + let metadata_hash = + offramp::test_calculate_metadata_hash( + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + on_ramp + ); + + let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); + let merkle_root = message_hash; + let proofs = vector[]; + + offramp::test_add_root(merkle_root, timestamp::now_seconds() - 3700); + + TestMessage { message, merkle_root, proofs } + } + + fun execute_message_and_verify_success( + sequence_number: u64, + test_message: TestMessage, + offchain_token_data: vector> + ) { + let TestMessage { message, merkle_root: _, proofs } = test_message; + + let report = + offramp::test_create_execution_report( + EVM_SOURCE_CHAIN_SELECTOR, + message, + offchain_token_data, + proofs + ); + + offramp::test_execute_single_report(report); + + let execution_state = + offramp::get_execution_state(EVM_SOURCE_CHAIN_SELECTOR, sequence_number); + assert!(execution_state == 2); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_non_dispatchable_token_transfer_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + false + ); + let token_addr = object::object_address(&token_obj); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 100000 + ); + + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000001", + 1, + @ccip_offramp, // receiver + vector[], + vector[token_amounts] + ); + + execute_message_and_verify_success(1, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 100000); + + let tokens_only_events = + non_dispatchable_receiver::get_received_tokens_only_events(); + assert!(tokens_only_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_non_dispatchable_message_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + false + ); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + let test_data = b"Hello from EVM chain!"; + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000002", + 2, + @ccip_offramp, // receiver + test_data, + vector[] + ); + + execute_message_and_verify_success(2, test_message, vector[]); + + let received_events = non_dispatchable_receiver::get_received_message_events(); + assert!(received_events.length() == 1); + + let event = received_events.borrow(0); + let event_message = + non_dispatchable_receiver::received_message_get_message(event); + assert!(event_message == string::utf8(test_data)); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + recipient = @0x999, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_receiver_non_dispatchable_tokens_with_forwarding( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + recipient: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + false + ); + let token_addr = object::object_address(&token_obj); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + let recipient_addr = signer::address_of(recipient); + account::create_account_for_test(recipient_addr); + + // Sending 200,000 tokens to receiver contract first + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 200000 + ); + + let test_data = bcs::to_bytes(&recipient_addr); + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000003", + 3, // sequence number + @ccip_offramp, // receiver + test_data, + vector[token_amounts] + ); + + execute_message_and_verify_success(3, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 0); + + let recipient_store = + primary_fungible_store::primary_store(recipient_addr, token_obj); + let recipient_balance = fungible_asset::balance(recipient_store); + assert!(recipient_balance == 200000); + + let forwarded_events = non_dispatchable_receiver::get_forwarded_tokens_events(); + assert!(forwarded_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_token_transfer_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 100000 + ); + + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000004", + 4, // sequence number + @ccip_offramp, // receiver + vector[], + vector[token_amounts] + ); + + execute_message_and_verify_success(4, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 100000); + + let tokens_only_events = + lock_release_dispatchable_receiver::get_received_tokens_only_events(); + assert!(tokens_only_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_message_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + true + ); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let test_data = b"Hello from EVM chain!"; + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000005", + 5, // sequence number + @ccip_offramp, // receiver + test_data, + vector[] + ); + + execute_message_and_verify_success(5, test_message, vector[]); + + let received_events = + lock_release_dispatchable_receiver::get_received_message_events(); + assert!(received_events.length() == 1); + + let event = received_events.borrow(0); + let event_message = + lock_release_dispatchable_receiver::received_message_get_message(event); + assert!(event_message == string::utf8(test_data)); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + recipient = @0x999, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_receiver_dispatchable_tokens_with_forwarding( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + recipient: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let recipient_addr = signer::address_of(recipient); + account::create_account_for_test(recipient_addr); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 200000 + ); + + let test_data = bcs::to_bytes(&recipient_addr); + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000006", + 6, // sequence number + @ccip_offramp, // receiver + test_data, + vector[token_amounts] + ); + + execute_message_and_verify_success(6, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 0); + + let recipient_store = + primary_fungible_store::primary_store(recipient_addr, token_obj); + let recipient_balance = fungible_asset::balance(recipient_store); + assert!(recipient_balance == 200000); + + let forwarded_events = + lock_release_dispatchable_receiver::get_forwarded_tokens_events(); + assert!(forwarded_events.length() == 1); + } + + // ================================================================ + // | Tests for execution context enforcement | + // ================================================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ), + expected_failure( + abort_code = 327691, + location = lock_release_token_pool::lock_release_token_pool + ) + ] + fun test_transfer_outside_ccip_receive_fails( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + true + ); + + setup_dispatchable_receiver(owner, ccip_offramp); + + // Try to transfer tokens directly without ccip_receive context + // This should fail because is_executing_receiver_in_progress is false + lock_release_token_pool::transfer(ccip_offramp, @0x999, 100000); + } +} diff --git a/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move new file mode 100644 index 00000000..b9889317 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move @@ -0,0 +1,715 @@ +#[test_only] +module ccip_offramp::offramp_managed_receiver_test { + use std::account; + use std::fungible_asset; + use std::object; + use std::primary_fungible_store; + use std::signer; + use std::bcs; + use std::string; + use std::timestamp; + + use ccip_offramp::offramp_test; + use ccip_offramp::offramp; + use ccip_offramp::non_dispatchable_receiver; + use ccip_offramp::managed_dispatchable_receiver; + use ccip::receiver_registry; + use managed_token::managed_token; + use managed_token_pool::managed_token_pool; + + const MANAGED_TOKEN_POOL: u8 = 2; + const MANAGED_TOKEN_SEED: vector = b"ManagedToken"; + + const EVM_SOURCE_CHAIN_SELECTOR: u64 = 909606746561742123; + const MOCK_EVM_ADDRESS_VECTOR: vector = x"4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"; + const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; + const GAS_LIMIT: u64 = 1000000; + + fun setup_non_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + non_dispatchable_receiver::test_init_module(ccip_offramp); + } + + fun setup_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + managed_dispatchable_receiver::test_init_module(ccip_offramp); + } + + struct TestMessage has drop { + message: offramp::Any2AptosRampMessage, + merkle_root: vector, + proofs: vector> + } + + fun create_and_commit_message( + message_id: vector, + sequence_number: u64, + receiver: address, + data: vector, + token_amounts: vector + ): TestMessage { + let static_config = offramp::get_static_config(); + let dest_chain_selector = offramp::chain_selector(&static_config); + + let header = + offramp::test_create_ramp_message_header( + message_id, + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + sequence_number, + 0 + ); + + let message = + offramp::test_create_any2aptos_ramp_message( + header, + EVM_SENDER, + data, + receiver, + (GAS_LIMIT as u256), + token_amounts + ); + + let source_chain_config = + offramp::get_source_chain_config(EVM_SOURCE_CHAIN_SELECTOR); + let on_ramp = offramp::source_chain_config_on_ramp(&source_chain_config); + + let metadata_hash = + offramp::test_calculate_metadata_hash( + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + on_ramp + ); + + let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); + let merkle_root = message_hash; + let proofs = vector[]; + + offramp::test_add_root(merkle_root, timestamp::now_seconds() - 3700); + + TestMessage { message, merkle_root, proofs } + } + + fun execute_message_and_verify_success( + sequence_number: u64, + test_message: TestMessage, + offchain_token_data: vector> + ) { + let TestMessage { message, merkle_root: _, proofs } = test_message; + + let report = + offramp::test_create_execution_report( + EVM_SOURCE_CHAIN_SELECTOR, + message, + offchain_token_data, + proofs + ); + + offramp::test_execute_single_report(report); + + let execution_state = + offramp::get_execution_state(EVM_SOURCE_CHAIN_SELECTOR, sequence_number); + assert!(execution_state == 2); + } + + // ======================== NON DISPATCHABLE TESTS ======================== + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_non_dispatchable_token_transfer_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + MANAGED_TOKEN_POOL, + MANAGED_TOKEN_SEED, + false + ); + let token_addr = object::object_address(&token_obj); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + // Add to allowlist for release_or_mint + let pool_address = managed_token_pool::get_store_address(); + managed_token::apply_allowed_minter_updates( + owner, vector[], vector[pool_address] + ); + + // Add to allowlist for lock_or_burn + let pool_address = managed_token_pool::get_store_address(); + managed_token::apply_allowed_burner_updates( + owner, vector[], vector[pool_address] + ); + + // // Grant receiver state signer minter and burner role for transfer during forwarding + // let state_address = managed_dispatchable_receiver::get_state_address(); + // managed_token::apply_allowed_minter_updates(owner, vector[], vector[state_address]); + // managed_token::apply_allowed_burner_updates(owner, vector[], vector[state_address]); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 100000 + ); + + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000004", + 4, // sequence number + @ccip_offramp, // receiver + vector[], + vector[token_amounts] + ); + + execute_message_and_verify_success(4, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 100000); + + let tokens_only_events = + non_dispatchable_receiver::get_received_tokens_only_events(); + assert!(tokens_only_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_non_dispatchable_message_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + MANAGED_TOKEN_POOL, + MANAGED_TOKEN_SEED, + false + ); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + // Add to allowlist for lock_or_burn/release_or_mint + let pool_address = managed_token_pool::get_store_address(); + managed_token::apply_allowed_burner_updates( + owner, vector[], vector[pool_address] + ); + managed_token::apply_allowed_minter_updates( + owner, vector[], vector[pool_address] + ); + + let test_data = b"Hello from EVM chain!"; + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000002", + 2, + @ccip_offramp, // receiver + test_data, + vector[] + ); + + execute_message_and_verify_success(2, test_message, vector[]); + + let received_events = non_dispatchable_receiver::get_received_message_events(); + assert!(received_events.length() == 1); + + let event = received_events.borrow(0); + let event_message = + non_dispatchable_receiver::received_message_get_message(event); + assert!(event_message == string::utf8(test_data)); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + recipient = @0x999, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_receiver_non_dispatchable_tokens_with_forwarding( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + recipient: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + MANAGED_TOKEN_POOL, + MANAGED_TOKEN_SEED, + false + ); + let token_addr = object::object_address(&token_obj); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + // Add to allowlist for lock_or_burn/release_or_mint + let pool_address = managed_token_pool::get_store_address(); + managed_token::apply_allowed_burner_updates( + owner, vector[], vector[pool_address] + ); + managed_token::apply_allowed_minter_updates( + owner, vector[], vector[pool_address] + ); + + let recipient_addr = signer::address_of(recipient); + account::create_account_for_test(recipient_addr); + + // Sending 200,000 tokens to receiver contract first + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 200000 + ); + + let test_data = bcs::to_bytes(&recipient_addr); + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000003", + 3, // sequence number + @ccip_offramp, // receiver + test_data, + vector[token_amounts] + ); + + execute_message_and_verify_success(3, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 0); + + let recipient_store = + primary_fungible_store::primary_store(recipient_addr, token_obj); + let recipient_balance = fungible_asset::balance(recipient_store); + assert!(recipient_balance == 200000); + + let forwarded_events = non_dispatchable_receiver::get_forwarded_tokens_events(); + assert!(forwarded_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_token_transfer_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + MANAGED_TOKEN_POOL, + MANAGED_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + // Add to allowlist for lock_or_burn/release_or_mint + let pool_address = managed_token_pool::get_store_address(); + managed_token::apply_allowed_minter_updates( + owner, vector[], vector[pool_address] + ); + managed_token::apply_allowed_burner_updates( + owner, vector[], vector[pool_address] + ); + + // Grant receiver state signer minter and burner role for transfer during forwarding + let state_address = managed_dispatchable_receiver::get_state_address(); + managed_token::apply_allowed_minter_updates( + owner, vector[], vector[state_address] + ); + managed_token::apply_allowed_burner_updates( + owner, vector[], vector[state_address] + ); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 100000 + ); + + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000004", + 4, // sequence number + @ccip_offramp, // receiver + vector[], + vector[token_amounts] + ); + + execute_message_and_verify_success(4, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 100000); + + let tokens_only_events = + managed_dispatchable_receiver::get_received_tokens_only_events(); + assert!(tokens_only_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_message_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + MANAGED_TOKEN_POOL, + MANAGED_TOKEN_SEED, + true + ); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let test_data = b"Hello from EVM chain!"; + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000005", + 5, // sequence number + @ccip_offramp, // receiver + test_data, + vector[] + ); + + execute_message_and_verify_success(5, test_message, vector[]); + + let received_events = + managed_dispatchable_receiver::get_received_message_events(); + assert!(received_events.length() == 1); + + let event = received_events.borrow(0); + let event_message = + managed_dispatchable_receiver::received_message_get_message(event); + assert!(event_message == string::utf8(test_data)); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + recipient = @0x999, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_receiver_dispatchable_tokens_with_forwarding( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + recipient: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + MANAGED_TOKEN_POOL, + MANAGED_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + // Add to allowlist for lock_or_burn/release_or_mint + let pool_address = managed_token_pool::get_store_address(); + managed_token::apply_allowed_minter_updates( + owner, vector[], vector[pool_address] + ); + managed_token::apply_allowed_burner_updates( + owner, vector[], vector[pool_address] + ); + + // Grant receiver state signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for transfer during forwarding + let state_address = managed_dispatchable_receiver::get_state_address(); + managed_token::apply_allowed_minter_updates( + owner, vector[], vector[state_address] + ); + managed_token::apply_allowed_burner_updates( + owner, vector[], vector[state_address] + ); + + let recipient_addr = signer::address_of(recipient); + account::create_account_for_test(recipient_addr); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 200000 + ); + + let test_data = bcs::to_bytes(&recipient_addr); + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000006", + 6, // sequence number + @ccip_offramp, // receiver + test_data, + vector[token_amounts] + ); + + execute_message_and_verify_success(6, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 0); + + let recipient_store = + primary_fungible_store::primary_store(recipient_addr, token_obj); + let recipient_balance = fungible_asset::balance(recipient_store); + assert!(recipient_balance == 200000); + + let forwarded_events = + managed_dispatchable_receiver::get_forwarded_tokens_events(); + assert!(forwarded_events.length() == 1); + } + + // ================================================================ + // | Tests for execution context enforcement | + // ================================================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ), + expected_failure( + abort_code = 327689, location = managed_token_pool::managed_token_pool + ) + ] + fun test_transfer_outside_ccip_receive_fails( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + MANAGED_TOKEN_POOL, + MANAGED_TOKEN_SEED, + false + ); + + setup_non_dispatchable_receiver(owner, ccip_offramp); + + // Try to transfer tokens directly without ccip_receive context + // This should fail because is_executing_receiver_in_progress is false + managed_token_pool::transfer(ccip_offramp, @0x999, 100000); + } +} diff --git a/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move new file mode 100644 index 00000000..20a6a7d8 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move @@ -0,0 +1,429 @@ +#[test_only] +/// Regulated token is always dispatchable, therefore we test the dispatchable token transfer only +module ccip_offramp::offramp_regulated_receiver_test { + use std::account; + use std::fungible_asset; + use std::object; + use std::primary_fungible_store; + use std::signer; + use std::timestamp; + + use ccip_offramp::offramp_test; + use ccip_offramp::offramp; + use ccip_offramp::non_dispatchable_receiver; + use ccip_offramp::regulated_dispatchable_receiver; + use ccip::receiver_registry; + use regulated_token::regulated_token; + use regulated_token_pool::regulated_token_pool; + + const REGULATED_TOKEN_POOL: u8 = 3; + const REGULATED_TOKEN_SEED: vector = b"RegulatedToken"; + + const EVM_SOURCE_CHAIN_SELECTOR: u64 = 909606746561742123; + const MOCK_EVM_ADDRESS_VECTOR: vector = x"4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"; + const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; + const GAS_LIMIT: u64 = 1000000; + + fun setup_non_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + non_dispatchable_receiver::test_init_module(ccip_offramp); + } + + fun setup_dispatchable_receiver( + owner: &signer, ccip_offramp: &signer + ) { + account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); + receiver_registry::init_module_for_testing(owner); + regulated_dispatchable_receiver::test_init_module(ccip_offramp); + } + + struct TestMessage has drop { + message: offramp::Any2AptosRampMessage, + merkle_root: vector, + proofs: vector> + } + + fun create_and_commit_message( + message_id: vector, + sequence_number: u64, + receiver: address, + data: vector, + token_amounts: vector + ): TestMessage { + let static_config = offramp::get_static_config(); + let dest_chain_selector = offramp::chain_selector(&static_config); + + let header = + offramp::test_create_ramp_message_header( + message_id, + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + sequence_number, + 0 + ); + + let message = + offramp::test_create_any2aptos_ramp_message( + header, + EVM_SENDER, + data, + receiver, + (GAS_LIMIT as u256), + token_amounts + ); + + let source_chain_config = + offramp::get_source_chain_config(EVM_SOURCE_CHAIN_SELECTOR); + let on_ramp = offramp::source_chain_config_on_ramp(&source_chain_config); + + let metadata_hash = + offramp::test_calculate_metadata_hash( + EVM_SOURCE_CHAIN_SELECTOR, + dest_chain_selector, + on_ramp + ); + + let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); + let merkle_root = message_hash; + let proofs = vector[]; + + offramp::test_add_root(merkle_root, timestamp::now_seconds() - 3700); + + TestMessage { message, merkle_root, proofs } + } + + fun execute_message_and_verify_success( + sequence_number: u64, + test_message: TestMessage, + offchain_token_data: vector> + ) { + let TestMessage { message, merkle_root: _, proofs } = test_message; + + let report = + offramp::test_create_execution_report( + EVM_SOURCE_CHAIN_SELECTOR, + message, + offchain_token_data, + proofs + ); + + offramp::test_execute_single_report(report); + + let execution_state = + offramp::get_execution_state(EVM_SOURCE_CHAIN_SELECTOR, sequence_number); + assert!(execution_state == 2); + } + + // ======================== DISPATCHABLE TESTS ======================== // + + // Regulated token is always dispatchable, therefore we test the dispatchable token transfer only + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_token_transfer_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + REGULATED_TOKEN_POOL, + REGULATED_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + // Grant pool signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for release_or_mint + let pool_address = regulated_token_pool::get_store_address(); + regulated_token::grant_role(owner, 6, pool_address); + + // Grant receiver state signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for transfer during forwarding + let state_signer_address = regulated_dispatchable_receiver::get_state_address(); + regulated_token::grant_role(owner, 6, state_signer_address); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 100000 + ); + + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000004", + 4, // sequence number + @ccip_offramp, // receiver + vector[], + vector[token_amounts] + ); + + execute_message_and_verify_success(4, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 100000); + + let tokens_only_events = + regulated_dispatchable_receiver::get_received_tokens_only_events(); + assert!(tokens_only_events.length() == 1); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_execute_dispatchable_message_only( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + REGULATED_TOKEN_POOL, + REGULATED_TOKEN_SEED, + true + ); + + setup_dispatchable_receiver(owner, ccip_offramp); + + let test_data = b"Hello from EVM chain!"; + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000005", + 5, // sequence number + @ccip_offramp, // receiver + test_data, + vector[] + ); + + execute_message_and_verify_success(5, test_message, vector[]); + + let received_events = + regulated_dispatchable_receiver::get_received_message_events(); + assert!(received_events.length() == 1); + + let event = received_events.borrow(0); + let event_message = + regulated_dispatchable_receiver::received_message_get_message(event); + assert!(event_message == std::string::utf8(test_data)); + } + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + recipient = @0x999, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_receiver_dispatchable_tokens_with_forwarding( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + recipient: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + REGULATED_TOKEN_POOL, + REGULATED_TOKEN_SEED, + true + ); + let token_addr = object::object_address(&token_obj); + + setup_dispatchable_receiver(owner, ccip_offramp); + + // Grant pool signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for release_or_mint + let pool_address = regulated_token_pool::get_store_address(); + regulated_token::grant_role(owner, 6, pool_address); + + // Grant receiver state signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for transfer during forwarding + let state_signer_address = regulated_dispatchable_receiver::get_state_address(); + regulated_token::grant_role(owner, 6, state_signer_address); + + let recipient_addr = signer::address_of(recipient); + account::create_account_for_test(recipient_addr); + + let token_amounts = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + 200000 + ); + + let test_data = std::bcs::to_bytes(&recipient_addr); + let test_message = + create_and_commit_message( + x"0000000000000000000000000000000000000000000000000000000000000006", + 6, // sequence number + @ccip_offramp, // receiver + test_data, + vector[token_amounts] + ); + + execute_message_and_verify_success(6, test_message, vector[vector[]]); + + let token_obj = object::address_to_object(token_addr); + + let receiver_store = + primary_fungible_store::primary_store(@ccip_offramp, token_obj); + let receiver_balance = fungible_asset::balance(receiver_store); + assert!(receiver_balance == 0); + + let recipient_store = + primary_fungible_store::primary_store(recipient_addr, token_obj); + let recipient_balance = fungible_asset::balance(recipient_store); + assert!(recipient_balance == 200000); + + let forwarded_events = + regulated_dispatchable_receiver::get_forwarded_tokens_events(); + assert!(forwarded_events.length() == 1); + } + + // ================================================================ + // | Tests for execution context enforcement | + // ================================================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @admin, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ), + expected_failure( + abort_code = 327689, location = regulated_token_pool::regulated_token_pool + ) + ] + fun test_transfer_outside_ccip_receive_fails( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + let (_owner_addr, _token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + REGULATED_TOKEN_POOL, + REGULATED_TOKEN_SEED, + true + ); + + setup_dispatchable_receiver(owner, ccip_offramp); + + // Try to transfer tokens directly without ccip_receive context + // This should fail because is_executing_receiver_in_progress is false + regulated_token_pool::transfer(ccip_offramp, @0x999, 100000); + } +} diff --git a/contracts/ccip/ccip_offramp/tests/offramp_test.move b/contracts/ccip/ccip_offramp/tests/offramp_test.move index 4eac8c72..1d3f846c 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_test.move @@ -10,6 +10,7 @@ module ccip_offramp::offramp_test { use aptos_framework::primary_fungible_store; use aptos_framework::timestamp; use ccip_offramp::bcs_helper; + use ccip_offramp::mock_token; use ccip::merkle_proof; use ccip::token_admin_registry; @@ -23,6 +24,10 @@ module ccip_offramp::offramp_test { use burn_mint_token_pool::burn_mint_token_pool; use lock_release_token_pool::lock_release_token_pool; + use managed_token::managed_token; + use managed_token_pool::managed_token_pool; + use regulated_token_pool::regulated_token_pool; + use regulated_token::regulated_token; const CHAIN_ID: u8 = 100; const EVM_SOURCE_CHAIN_SELECTOR: u64 = 909606746561742123; @@ -41,9 +46,13 @@ module ccip_offramp::offramp_test { const BURN_MINT_TOKEN_POOL: u8 = 0; const LOCK_RELEASE_TOKEN_POOL: u8 = 1; + const MANAGED_TOKEN_POOL: u8 = 2; + const REGULATED_TOKEN_POOL: u8 = 3; const BURN_MINT_TOKEN_SEED: vector = b"TestToken"; const LOCK_RELEASE_TOKEN_SEED: vector = b"LockReleaseToken"; + const MANAGED_TOKEN_SEED: vector = b"ManagedToken"; + const REGULATED_TOKEN_SEED: vector = b"RegulatedToken"; const MOCK_EVM_ADDRESS: address = @0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97; const MOCK_EVM_ADDRESS_VECTOR: vector = x"4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"; @@ -61,15 +70,20 @@ module ccip_offramp::offramp_test { timestamp::update_global_time_for_test_secs(timestamp_seconds); } - fun setup( + public fun setup( aptos_framework: &signer, ccip: &signer, ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer, pool_type: u8, - seed: vector + seed: vector, + is_dispatchable: bool ): (address, Object) { let owner_addr = signer::address_of(owner); account::create_account_for_test(signer::address_of(burn_mint_token_pool)); @@ -124,10 +138,16 @@ module ccip_offramp::offramp_test { let (token_obj, token_addr) = create_test_token_and_pool( owner, + ccip_offramp, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, pool_type, - seed + seed, + is_dispatchable ); // Initialize fee quoter @@ -153,10 +173,16 @@ module ccip_offramp::offramp_test { fun create_test_token_and_pool( owner: &signer, + ccip_offramp_signer: &signer, burn_mint_token_pool: &signer, lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer, pool_type: u8, - seed: vector + seed: vector, + is_dispatchable: bool ): (Object, address) { let constructor_ref = object::create_named_object(owner, seed); @@ -178,6 +204,13 @@ module ccip_offramp::offramp_test { let burn_ref = fungible_asset::generate_burn_ref(&constructor_ref); let transfer_ref = fungible_asset::generate_transfer_ref(&constructor_ref); + // Add dynamic dispatch function to the token if it is dispatchable + if (is_dispatchable) { + mock_token::add_dynamic_dispatch_function( + ccip_offramp_signer, &constructor_ref + ); + }; + let token_addr = object::object_address(&metadata); if (pool_type == BURN_MINT_TOKEN_POOL) { @@ -210,7 +243,7 @@ module ccip_offramp::offramp_test { token_addr, signer::address_of(burn_mint_token_pool) ); - } else { + } else if (pool_type == LOCK_RELEASE_TOKEN_POOL) { lock_release_token_pool::test_init_module(lock_release_token_pool); lock_release_token_pool::initialize( owner, @@ -244,17 +277,145 @@ module ccip_offramp::offramp_test { token_addr, signer::address_of(lock_release_token_pool) ); + } else if (pool_type == MANAGED_TOKEN_POOL) { + let seed = b"MT"; + let _constructor_ref = &object::create_named_object(owner, seed); + let _managed_token_pool_constructor_ref = + &object::create_named_object(owner, b"ManagedTokenPool"); + + managed_token::init_module_for_testing(managed_token); + managed_token::initialize( + owner, + option::none(), + string::utf8(b"Managed Token"), + string::utf8(seed), + 6, + string::utf8(b"https://managedtoken.com/images/pic.png"), + string::utf8(b"https://managedtoken.com") + ); + + managed_token_pool::test_init_module(managed_token_pool); + managed_token_pool::apply_chain_updates( + owner, + vector[], + vector[EVM_SOURCE_CHAIN_SELECTOR], + vector[vector[MOCK_EVM_ADDRESS_VECTOR]], + vector[MOCK_EVM_ADDRESS_VECTOR] + ); + managed_token_pool::set_chain_rate_limiter_config( + owner, + EVM_SOURCE_CHAIN_SELECTOR, + true, + OUTBOUND_CAPACITY, + OUTBOUND_RATE, + true, + INBOUND_CAPACITY, + INBOUND_RATE + ); + + token_addr = managed_token::token_metadata(); + metadata = object::address_to_object(token_addr); + + // Set admin for token + token_admin_registry::propose_administrator( + owner, token_addr, signer::address_of(owner) + ); + token_admin_registry::accept_admin_role(owner, token_addr); + token_admin_registry::set_pool( + owner, + token_addr, + signer::address_of(managed_token_pool) + ); + // Fund managed token pool + primary_fungible_store::mint( + &mint_ref, + managed_token_pool::get_store_address(), + 1000 + ); + } else if (pool_type == REGULATED_TOKEN_POOL) { + account::create_account_for_test(signer::address_of(owner)); + account::create_account_for_test(signer::address_of(regulated_token_pool)); + account::create_account_for_test(signer::address_of(regulated_token)); + + // Create an object at @regulated_token for the ownable functionality + let regulated_token_pool_constructor_ref = + object::create_named_object(owner, b"regulated_token_pool"); + account::create_account_for_test( + object::address_from_constructor_ref( + ®ulated_token_pool_constructor_ref + ) + ); + + // Setup regulated token first (use admin as the object creator) + let regulated_token_constructor_ref = + object::create_named_object(owner, b"regulated_token"); + account::create_account_for_test( + object::address_from_constructor_ref(®ulated_token_constructor_ref) + ); + + regulated_token::init_module_for_testing(regulated_token); + regulated_token::initialize( + owner, + option::none(), + string::utf8(b"Regulated Token"), + string::utf8(b"RT"), + 6, + string::utf8( + b"https://regulatedtoken.com/images/pic.png" + ), + string::utf8(b"https://regulatedtoken.com") + ); + + regulated_token_pool::test_init_module(regulated_token_pool); + regulated_token_pool::apply_chain_updates( + owner, + vector[], + vector[EVM_SOURCE_CHAIN_SELECTOR], + vector[vector[MOCK_EVM_ADDRESS_VECTOR]], + vector[MOCK_EVM_ADDRESS_VECTOR] + ); + regulated_token_pool::set_chain_rate_limiter_config( + owner, + EVM_SOURCE_CHAIN_SELECTOR, + true, + OUTBOUND_CAPACITY, + OUTBOUND_RATE, + true, + INBOUND_CAPACITY, + INBOUND_RATE + ); + + token_addr = regulated_token::token_address(); + metadata = regulated_token::token_metadata(); + + // Set admin for token + token_admin_registry::propose_administrator( + owner, token_addr, signer::address_of(owner) + ); + token_admin_registry::accept_admin_role(owner, token_addr); + token_admin_registry::set_pool( + owner, + token_addr, + signer::address_of(regulated_token_pool) + ); + + // Fund regulated token pool + primary_fungible_store::mint( + &mint_ref, + regulated_token_pool::get_store_address(), + 1000 + ); }; let mint_ref = fungible_asset::generate_mint_ref(&constructor_ref); let burn_ref = fungible_asset::generate_burn_ref(&constructor_ref); let transfer_ref = fungible_asset::generate_transfer_ref(&constructor_ref); - // Fund lock/release token pool + // Fund lock/release token pool with sufficient liquidity for tests primary_fungible_store::mint( &mint_ref, lock_release_token_pool::get_store_address(), - 1000 + 10000000 // 10M tokens for test liquidity ); move_to( @@ -354,7 +515,11 @@ module ccip_offramp::offramp_test { ccip_offramp = @ccip_offramp, owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token ) ] fun test_initialize( @@ -363,7 +528,11 @@ module ccip_offramp::offramp_test { ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, - lock_release_token_pool: &signer + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer ) { setup( aptos_framework, @@ -372,8 +541,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ); // Verify initialization was successful @@ -762,7 +936,11 @@ module ccip_offramp::offramp_test { ccip_offramp = @ccip_offramp, owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token ) ] fun test_commit_and_execute( @@ -771,7 +949,11 @@ module ccip_offramp::offramp_test { ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, - lock_release_token_pool: &signer + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer ) { setup( aptos_framework, @@ -780,8 +962,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ); let config_digest = x"000aed76a87f048dab766bc14ecdbb966f4253e309d742585062a75abfc16c38"; @@ -943,7 +1130,11 @@ module ccip_offramp::offramp_test { ccip_offramp = @ccip_offramp, owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token ) ] fun test_manually_execute( @@ -952,7 +1143,11 @@ module ccip_offramp::offramp_test { ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, - lock_release_token_pool: &signer + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer ) { setup( aptos_framework, @@ -961,8 +1156,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ); let merkle_root = @@ -985,6 +1185,10 @@ module ccip_offramp::offramp_test { owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token, receiver = @0xbed8 ) ] @@ -995,6 +1199,10 @@ module ccip_offramp::offramp_test { owner: &signer, burn_mint_token_pool: &signer, lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer, receiver: &signer ) { test_execute_single_report_with_token_transfer( @@ -1004,9 +1212,14 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, receiver, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ) } @@ -1018,6 +1231,10 @@ module ccip_offramp::offramp_test { owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token, receiver = @0xbed8 ) ] @@ -1028,6 +1245,10 @@ module ccip_offramp::offramp_test { owner: &signer, burn_mint_token_pool: &signer, lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer, receiver: &signer ) { test_execute_single_report_with_token_transfer( @@ -1037,9 +1258,14 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, receiver, LOCK_RELEASE_TOKEN_POOL, - LOCK_RELEASE_TOKEN_SEED + LOCK_RELEASE_TOKEN_SEED, + false ) } @@ -1052,9 +1278,14 @@ module ccip_offramp::offramp_test { owner: &signer, burn_mint_token_pool: &signer, lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer, receiver: &signer, pool_type: u8, - token_seed: vector + token_seed: vector, + is_dispatchable: bool ) { let (_owner_addr, token_obj) = setup( @@ -1064,8 +1295,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, pool_type, - token_seed + token_seed, + is_dispatchable ); let token_addr = object::object_address(&token_obj); @@ -1167,7 +1403,11 @@ module ccip_offramp::offramp_test { ccip_offramp = @ccip_offramp, owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token ) ] fun test_transfer_ownership_flow( @@ -1176,7 +1416,11 @@ module ccip_offramp::offramp_test { ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, - lock_release_token_pool: &signer + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer ) { setup( aptos_framework, @@ -1185,8 +1429,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ); let new_owner = signer::address_of(aptos_framework); account::create_account_for_test(new_owner); @@ -1207,7 +1456,11 @@ module ccip_offramp::offramp_test { ccip_offramp = @ccip_offramp, owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token ) ] fun test_getters( @@ -1216,7 +1469,11 @@ module ccip_offramp::offramp_test { ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, - lock_release_token_pool: &signer + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer ) { setup( aptos_framework, @@ -1225,8 +1482,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ); let latest_price_sequence_number = offramp::get_latest_price_sequence_number(); @@ -1247,7 +1509,11 @@ module ccip_offramp::offramp_test { ccip_offramp = @ccip_offramp, owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token ) ] #[expected_failure(abort_code = 65540, location = ccip_offramp::offramp)] @@ -1257,7 +1523,11 @@ module ccip_offramp::offramp_test { ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, - lock_release_token_pool: &signer + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer ) { setup( aptos_framework, @@ -1266,8 +1536,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ); // E_UNKNOWN_SOURCE_CHAIN_SELECTOR @@ -1281,7 +1556,11 @@ module ccip_offramp::offramp_test { ccip_offramp = @ccip_offramp, owner = @0x100, burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token ) ] #[expected_failure(abort_code = 65550, location = ccip_offramp::offramp)] @@ -1291,7 +1570,11 @@ module ccip_offramp::offramp_test { ccip_offramp: &signer, owner: &signer, burn_mint_token_pool: &signer, - lock_release_token_pool: &signer + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer ) { setup( aptos_framework, @@ -1300,8 +1583,13 @@ module ccip_offramp::offramp_test { owner, burn_mint_token_pool, lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED + BURN_MINT_TOKEN_SEED, + false ); // E_INVALID_ROOT diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index e633bf13..17bd6c8b 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -10,6 +10,7 @@ module burn_mint_token_pool::burn_mint_token_pool { use aptos_framework::fungible_asset::{BurnRef, MintRef}; use ccip::token_admin_registry; + use ccip::receiver_registry; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -34,6 +35,10 @@ module burn_mint_token_pool::burn_mint_token_pool { mint_ref: Option } + struct BurnMintTokenPoolEvents has key, store { + token_pool_events: token_pool::TokenPoolEvents + } + const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; @@ -42,6 +47,7 @@ module burn_mint_token_pool::burn_mint_token_pool { const E_UNKNOWN_FUNCTION: u64 = 6; const E_MINT_REF_NOT_SET: u64 = 7; const E_BURN_REF_NOT_SET: u64 = 8; + const E_NOT_EXECUTING_RECEIVER: u64 = 9; // ================================================================ // | Init | @@ -139,6 +145,32 @@ module burn_mint_token_pool::burn_mint_token_pool { }; move_to(&store_signer, pool); + + move_to( + &store_signer, + BurnMintTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(&store_signer) + } + ); + } + + public fun initialize_token_pool_events(caller: &signer) acquires BurnMintTokenPoolState { + assert_can_initialize(signer::address_of(caller)); + + let store_signer = + &account::create_signer_with_capability(&borrow_pool().store_signer_cap); + + assert!( + !exists(signer::address_of(store_signer)), + error::already_exists(E_ALREADY_INITIALIZED) + ); + + move_to( + store_signer, + BurnMintTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(store_signer) + } + ); } // ================================================================ @@ -355,6 +387,32 @@ module burn_mint_token_pool::burn_mint_token_pool { fa } + /// Caller must be the receiver contract address when `ccip_receive` is called. + /// Transfer the fungible asset from the receiver to `to` address. + public fun transfer( + receiver: &signer, to: address, amount: u64 + ) acquires BurnMintTokenPoolState, BurnMintTokenPoolEvents { + let receiver_addr = signer::address_of(receiver); + assert!( + receiver_registry::is_executing_receiver_in_progress(receiver_addr), + error::permission_denied(E_NOT_EXECUTING_RECEIVER) + ); + + let pool = borrow_pool_mut(); + assert!(pool.burn_ref.is_some(), E_BURN_REF_NOT_SET); + assert!(pool.mint_ref.is_some(), E_MINT_REF_NOT_SET); + + primary_fungible_store::burn(pool.burn_ref.borrow(), receiver_addr, amount); + primary_fungible_store::mint(pool.mint_ref.borrow(), to, amount); + + token_pool::emit_transfer( + &mut borrow_mut_events().token_pool_events, + receiver_addr, + to, + amount + ); + } + // ================================================================ // | Rate limit config | // ================================================================ @@ -477,6 +535,10 @@ module burn_mint_token_pool::burn_mint_token_pool { borrow_global_mut(store_address()) } + inline fun borrow_mut_events(): &mut BurnMintTokenPoolEvents { + borrow_global_mut(store_address()) + } + // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index c384eceb..374e9225 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -9,6 +9,7 @@ module lock_release_token_pool::lock_release_token_pool { use std::signer; use std::string::{Self, String}; + use ccip::receiver_registry; use ccip::token_admin_registry; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; @@ -34,6 +35,10 @@ module lock_release_token_pool::lock_release_token_pool { rebalancer: address } + struct LockReleaseTokenPoolEvents has key, store { + token_pool_events: token_pool::TokenPoolEvents + } + const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; @@ -44,6 +49,7 @@ module lock_release_token_pool::lock_release_token_pool { const E_UNAUTHORIZED: u64 = 8; const E_INSUFFICIENT_LIQUIDITY: u64 = 9; const E_TRANSFER_REF_NOT_SET: u64 = 10; + const E_NOT_EXECUTING_RECEIVER: u64 = 11; // ================================================================ // | Init | @@ -156,6 +162,32 @@ module lock_release_token_pool::lock_release_token_pool { rebalancer }; move_to(&store_signer, pool); + + move_to( + &store_signer, + LockReleaseTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(&store_signer) + } + ); + } + + public fun initialize_token_pool_events(caller: &signer) acquires LockReleaseTokenPoolState { + assert_can_initialize(signer::address_of(caller)); + + let store_signer = + &account::create_signer_with_capability(&borrow_pool().store_signer_cap); + + assert!( + !exists(signer::address_of(store_signer)), + error::already_exists(E_ALREADY_INITIALIZED) + ); + + move_to( + store_signer, + LockReleaseTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(store_signer) + } + ); } // ================================================================ @@ -423,6 +455,35 @@ module lock_release_token_pool::lock_release_token_pool { fa } + /// Caller must be the receiver contract address when `ccip_receive` is called. + /// Transfer the fungible asset from the receiver to `to` address. + public fun transfer( + caller: &signer, to: address, amount: u64 + ) acquires LockReleaseTokenPoolState, LockReleaseTokenPoolEvents { + let caller_addr = signer::address_of(caller); + assert!( + receiver_registry::is_executing_receiver_in_progress(caller_addr), + error::permission_denied(E_NOT_EXECUTING_RECEIVER) + ); + + let pool = borrow_pool_mut(); + assert!(pool.transfer_ref.is_some(), E_TRANSFER_REF_NOT_SET); + + primary_fungible_store::transfer_with_ref( + pool.transfer_ref.borrow(), + caller_addr, + to, + amount + ); + + token_pool::emit_transfer( + &mut borrow_mut_events().token_pool_events, + caller_addr, + to, + amount + ); + } + // ================================================================ // | Rate limit config | // ================================================================ @@ -662,6 +723,10 @@ module lock_release_token_pool::lock_release_token_pool { borrow_global_mut(store_address()) } + inline fun borrow_mut_events(): &mut LockReleaseTokenPoolEvents { + borrow_global_mut(store_address()) + } + // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index a9f6ee23..a160ea38 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -10,6 +10,7 @@ module managed_token_pool::managed_token_pool { use managed_token::managed_token; + use ccip::receiver_registry; use ccip::token_admin_registry; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; @@ -27,12 +28,17 @@ module managed_token_pool::managed_token_pool { store_signer_address: address } + struct ManagedTokenPoolEvents has key, store { + token_pool_events: token_pool::TokenPoolEvents + } + const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; const E_LOCAL_TOKEN_MISMATCH: u64 = 4; const E_INVALID_ARGUMENTS: u64 = 5; const E_UNKNOWN_FUNCTION: u64 = 6; + const E_NOT_EXECUTING_RECEIVER: u64 = 9; // ================================================================ // | Init | @@ -91,6 +97,33 @@ module managed_token_pool::managed_token_pool { }; move_to(&store_signer, pool); + + move_to( + &store_signer, + ManagedTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(&store_signer) + } + ); + } + + public fun initialize_token_pool_events(caller: &signer) acquires ManagedTokenPoolState { + let pool = borrow_pool_mut(); + ownable::assert_only_owner(signer::address_of(caller), &pool.ownable_state); + + let store_signer = + &account::create_signer_with_capability(&pool.store_signer_cap); + + assert!( + !exists(signer::address_of(store_signer)), + error::already_exists(E_ALREADY_INITIALIZED) + ); + + move_to( + store_signer, + ManagedTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(store_signer) + } + ); } // ================================================================ @@ -319,6 +352,26 @@ module managed_token_pool::managed_token_pool { fa } + /// Caller must be the receiver contract address when `ccip_receive` is called. + /// Transfer the fungible asset from the receiver to `to` address. + public fun transfer(caller: &signer, to: address, amount: u64) acquires ManagedTokenPoolEvents { + let caller_addr = signer::address_of(caller); + + assert!( + receiver_registry::is_executing_receiver_in_progress(caller_addr), + error::permission_denied(E_NOT_EXECUTING_RECEIVER) + ); + + managed_token::bridge_transfer(caller, to, amount); + + token_pool::emit_transfer( + &mut borrow_mut_events().token_pool_events, + caller_addr, + to, + amount + ); + } + // ================================================================ // | Rate limit config | // ================================================================ @@ -426,6 +479,10 @@ module managed_token_pool::managed_token_pool { borrow_global_mut(store_address()) } + inline fun borrow_mut_events(): &mut ManagedTokenPoolEvents { + borrow_global_mut(store_address()) + } + // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index 09593040..4bfeb96c 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -10,6 +10,7 @@ module regulated_token_pool::regulated_token_pool { use regulated_token::regulated_token::{Self}; + use ccip::receiver_registry; use ccip::token_admin_registry; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; @@ -27,12 +28,18 @@ module regulated_token_pool::regulated_token_pool { store_signer_address: address } + struct RegulatedTokenPoolEvents has key, store { + token_pool_events: token_pool::TokenPoolEvents + } + const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; const E_LOCAL_TOKEN_MISMATCH: u64 = 4; const E_INVALID_ARGUMENTS: u64 = 5; const E_UNKNOWN_FUNCTION: u64 = 6; + const E_NOT_REGISTERED_RECEIVER: u64 = 7; + const E_NOT_EXECUTING_RECEIVER: u64 = 9; // ================================================================ // | Init | @@ -89,6 +96,33 @@ module regulated_token_pool::regulated_token_pool { }; move_to(&store_signer, pool); + + move_to( + &store_signer, + RegulatedTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(&store_signer) + } + ); + } + + public fun initialize_token_pool_events(caller: &signer) acquires RegulatedTokenPoolState { + let pool = borrow_pool_mut(); + ownable::assert_only_owner(signer::address_of(caller), &pool.ownable_state); + + let store_signer = + &account::create_signer_with_capability(&pool.store_signer_cap); + + assert!( + !exists(signer::address_of(store_signer)), + error::already_exists(E_ALREADY_INITIALIZED) + ); + + move_to( + store_signer, + RegulatedTokenPoolEvents { + token_pool_events: token_pool::create_transfer_events(store_signer) + } + ); } // ================================================================ @@ -308,6 +342,28 @@ module regulated_token_pool::regulated_token_pool { fa } + /// Caller must be the receiver contract address when `ccip_receive` is called. + /// Transfer the fungible asset from the receiver to `to` address. + public fun transfer(caller: &signer, to: address, amount: u64) acquires RegulatedTokenPoolEvents { + let caller_addr = signer::address_of(caller); + + assert!( + receiver_registry::is_executing_receiver_in_progress(caller_addr), + error::permission_denied(E_NOT_EXECUTING_RECEIVER) + ); + + // Call into regulated_token to perform transfer using TransferRef + // The caller (receiver) must have tokens and the bridge_transfer will check permissions + regulated_token::bridge_transfer(caller, to, amount); + + token_pool::emit_transfer( + &mut borrow_mut_events().token_pool_events, + caller_addr, + to, + amount + ); + } + // ================================================================ // | Rate limit config | // ================================================================ @@ -415,6 +471,10 @@ module regulated_token_pool::regulated_token_pool { borrow_global_mut(store_address()) } + inline fun borrow_mut_events(): &mut RegulatedTokenPoolEvents { + borrow_global_mut(store_address()) + } + // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move index feded37d..50a960b6 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move @@ -10,6 +10,7 @@ module regulated_token_pool::regulated_token_pool_test { use ccip::state_object; use ccip::auth; use ccip::token_admin_registry; + use ccip::receiver_registry; use regulated_token::regulated_token; use regulated_token_pool::regulated_token_pool; @@ -793,4 +794,44 @@ module regulated_token_pool::regulated_token_pool_test { assert!(regulated_token_pool::pending_transfer_to().is_none()); assert!(regulated_token_pool::pending_transfer_accepted().is_none()); } + + // ================================================================ + // | Tests for execution context enforcement | + // ================================================================ + + #[ + test( + admin = @admin, + regulated_token = @regulated_token, + regulated_token_pool = @regulated_token_pool, + framework = @aptos_framework, + ccip = @ccip, + random_signer = @0x999 + ), + expected_failure( + abort_code = 327689, location = regulated_token_pool::regulated_token_pool + ) + ] + fun test_transfer_outside_ccip_receive_fails( + admin: &signer, + regulated_token: &signer, + regulated_token_pool: &signer, + framework: &signer, + ccip: &signer, + random_signer: &signer + ) { + setup( + admin, + regulated_token, + regulated_token_pool, + framework, + ccip + ); + + receiver_registry::init_module_for_testing(admin); + + // Try to transfer tokens directly without ccip_receive context + // This should fail because is_executing_receiver_in_progress is false + regulated_token_pool::transfer(random_signer, @0x777, 100000); + } } diff --git a/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move b/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move index b7dc5b2e..70d21df2 100644 --- a/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move +++ b/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move @@ -35,6 +35,10 @@ module ccip_token_pool::token_pool { rebalancer_set_events: EventHandle } + struct TokenPoolEvents has key, store { + transfer_events: EventHandle + } + struct RemoteChainConfig has store, drop, copy { remote_token_address: vector, remote_pools: vector> @@ -108,6 +112,13 @@ module ccip_token_pool::token_pool { new_rebalancer: address } + #[event] + struct Transfer has store, drop { + from: address, + to: address, + amount: u64 + } + const E_NOT_ALLOWED_CALLER: u64 = 1; const E_UNKNOWN_FUNGIBLE_ASSET: u64 = 2; const E_UNKNOWN_REMOTE_CHAIN_SELECTOR: u64 = 3; @@ -149,6 +160,10 @@ module ccip_token_pool::token_pool { } } + public fun create_transfer_events(event_account: &signer): TokenPoolEvents { + TokenPoolEvents { transfer_events: account::new_event_handle(event_account) } + } + #[view] public fun get_router(): address { @ccip @@ -481,6 +496,18 @@ module ccip_token_pool::token_pool { ); } + public fun emit_transfer( + events: &mut TokenPoolEvents, + from: address, + to: address, + amount: u64 + ) { + event::emit_event( + &mut events.transfer_events, + Transfer { from, to, amount } + ); + } + // ================================================================ // | Decimals | // ================================================================ diff --git a/contracts/managed_token/sources/managed_token.move b/contracts/managed_token/sources/managed_token.move index 2dfb4360..71da13b3 100644 --- a/contracts/managed_token/sources/managed_token.move +++ b/contracts/managed_token/sources/managed_token.move @@ -336,6 +336,35 @@ module managed_token::managed_token { ); } + public fun bridge_transfer( + caller: &signer, to: address, amount: u64 + ) acquires TokenMetadataRefs, TokenState { + let caller_addr = signer::address_of(caller); + let state = &mut TokenState[token_state_address_internal()]; + + // Must be allowed as both minter and burner to transfer + assert_is_allowed_minter(caller_addr, state); + assert_is_allowed_burner(caller_addr, state); + + if (amount == 0) { return }; + + primary_fungible_store::transfer_with_ref( + &borrow_token_metadata_refs(state).transfer_ref, + caller_addr, + to, + amount + ); + + event::emit_event( + &mut state.burn_events, + Burn { burner: caller_addr, from: caller_addr, amount } + ); + event::emit_event( + &mut state.mint_events, + Mint { minter: caller_addr, to, amount } + ); + } + inline fun assert_is_allowed_minter( caller: address, state: &TokenState ) { diff --git a/contracts/regulated_token/sources/regulated_token.move b/contracts/regulated_token/sources/regulated_token.move index 0b5ea744..91fd2c64 100644 --- a/contracts/regulated_token/sources/regulated_token.move +++ b/contracts/regulated_token/sources/regulated_token.move @@ -114,6 +114,13 @@ module regulated_token::regulated_token { amount: u64 } + #[event] + struct BridgeTransfer has drop, store { + caller: address, + to: address, + amount: u64 + } + #[event] struct MinterAdded has drop, store { admin: address, @@ -592,6 +599,23 @@ module regulated_token::regulated_token { } } + public fun bridge_transfer( + caller: &signer, to: address, amount: u64 + ) acquires TokenMetadataRefs, TokenState { + let caller_addr = signer::address_of(caller); + let state_obj = token_state_object_internal(); + let token_state = &TokenState[object::object_address(&state_obj)]; + + assert_not_paused(token_state); + assert_bridge_minter_or_burner(caller, state_obj); + assert_not_frozen(caller_addr, token_state); + assert_not_frozen(to, token_state); + + primary_fungible_store::transfer_with_ref(&borrow_token_metadata_refs().transfer_ref, caller_addr, to, amount); + + event::emit(BridgeTransfer { caller: caller_addr, to, amount }); + } + /// Bridge-specific function to mint tokens directly as `FungibleAsset`. /// Required because this token has dynamic dispatch enabled /// as minting to pool and calling `fungible_asset::withdraw()` reverts. From 8d5480513858d475283af0f9728884ac7d9699d3 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Mon, 13 Oct 2025 10:26:58 -0400 Subject: [PATCH 02/24] Update bindings --- .../receiver_registry/receiver_registry.go | 42 ++++++++++++++++++- .../burn_mint_token_pool.go | 22 +++++++++- .../lock_release_token_pool.go | 22 +++++++++- .../managed_token_pool/managed_token_pool.go | 22 +++++++++- .../regulated_token_pool.go | 35 ++++++++++++---- .../token_pool/token_pool/token_pool.go | 16 ++++++- .../managed_token/managed_token.go | 13 +++++- .../regulated_token/regulated_token.go | 19 ++++++++- 8 files changed, 177 insertions(+), 14 deletions(-) diff --git a/bindings/ccip/receiver_registry/receiver_registry.go b/bindings/ccip/receiver_registry/receiver_registry.go index e1253ff5..c922b3fe 100644 --- a/bindings/ccip/receiver_registry/receiver_registry.go +++ b/bindings/ccip/receiver_registry/receiver_registry.go @@ -24,6 +24,7 @@ var ( type ReceiverRegistryInterface interface { TypeAndVersion(opts *bind.CallOpts) (string, error) IsRegisteredReceiver(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) + IsExecutingReceiverInProgress(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) // Encoder returns the encoder implementation of this module. Encoder() ReceiverRegistryEncoder @@ -32,10 +33,12 @@ type ReceiverRegistryInterface interface { type ReceiverRegistryEncoder interface { TypeAndVersion() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) IsRegisteredReceiver(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + IsExecutingReceiverInProgress(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) FinishReceive(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + InitializeCCIPReceiveState() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"ccip","module":"receiver_registry","name":"finish_receive","parameters":[{"name":"receiver_address","type":"address"}]}]` +const FunctionInfo = `[{"package":"ccip","module":"receiver_registry","name":"finish_receive","parameters":[{"name":"receiver_address","type":"address"}]},{"package":"ccip","module":"receiver_registry","name":"initialize_ccip_receive_state","parameters":null}]` func NewReceiverRegistry(address aptos.AccountAddress, client aptos.AptosRpcClient) ReceiverRegistryInterface { contract := bind.NewBoundContract(address, "ccip", "receiver_registry", client) @@ -54,6 +57,7 @@ const ( E_NON_EMPTY_INPUT uint64 = 5 E_PROOF_TYPE_ACCOUNT_MISMATCH uint64 = 6 E_PROOF_TYPE_MODULE_MISMATCH uint64 = 7 + E_UNAUTHORIZED uint64 = 8 ) // Structs @@ -65,6 +69,9 @@ type CCIPReceiverRegistration struct { DispatchMetadata bind.StdObject `move:"aptos_framework::object::Object"` } +type CCIPReceiveState struct { +} + type ReceiverRegistered struct { ReceiverAddress aptos.AccountAddress `move:"address"` ReceiverModuleName []byte `move:"vector"` @@ -125,6 +132,27 @@ func (c ReceiverRegistryContract) IsRegisteredReceiver(opts *bind.CallOpts, rece return r0, nil } +func (c ReceiverRegistryContract) IsExecutingReceiverInProgress(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) { + module, function, typeTags, args, err := c.receiverRegistryEncoder.IsExecutingReceiverInProgress(receiverAddress) + if err != nil { + return *new(bool), err + } + + callData, err := c.Call(opts, module, function, typeTags, args) + if err != nil { + return *new(bool), err + } + + var ( + r0 bool + ) + + if err := codec.DecodeAptosJsonArray(callData, &r0); err != nil { + return *new(bool), err + } + return r0, nil +} + // Entry Functions // Encoder @@ -144,6 +172,14 @@ func (c receiverRegistryEncoder) IsRegisteredReceiver(receiverAddress aptos.Acco }) } +func (c receiverRegistryEncoder) IsExecutingReceiverInProgress(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("is_executing_receiver_in_progress", nil, []string{ + "address", + }, []any{ + receiverAddress, + }) +} + func (c receiverRegistryEncoder) FinishReceive(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("finish_receive", nil, []string{ "address", @@ -151,3 +187,7 @@ func (c receiverRegistryEncoder) FinishReceive(receiverAddress aptos.AccountAddr receiverAddress, }) } + +func (c receiverRegistryEncoder) InitializeCCIPReceiveState() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("initialize_ccip_receive_state", nil, []string{}, []any{}) +} diff --git a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go index 7b572c9a..45aa274a 100644 --- a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go +++ b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go @@ -86,13 +86,15 @@ type BurnMintTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertCanInitialize(callerAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"accept_ownership","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"store_address","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"accept_ownership","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"store_address","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewBurnMintTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) BurnMintTokenPoolInterface { contract := bind.NewBoundContract(address, "burn_mint_token_pool", "burn_mint_token_pool", client) @@ -112,6 +114,7 @@ const ( E_UNKNOWN_FUNCTION uint64 = 6 E_MINT_REF_NOT_SET uint64 = 7 E_BURN_REF_NOT_SET uint64 = 8 + E_NOT_EXECUTING_RECEIVER uint64 = 9 ) // Structs @@ -123,6 +126,9 @@ type BurnMintTokenPoolState struct { StoreSignerAddress aptos.AccountAddress `move:"address"` } +type BurnMintTokenPoolEvents struct { +} + type CallbackProof struct { } @@ -835,6 +841,20 @@ func (c burnMintTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddre }) } +func (c burnMintTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) +} + +func (c burnMintTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("transfer", nil, []string{ + "address", + "u64", + }, []any{ + to, + amount, + }) +} + func (c burnMintTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go index 073a4a9d..3a795570 100644 --- a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go +++ b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go @@ -100,13 +100,15 @@ type LockReleaseTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertCanInitialize(callerAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"accept_ownership","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"provide_liquidity","parameters":[{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_rebalancer","parameters":[{"name":"rebalancer","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"store_address","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"withdraw_liquidity","parameters":[{"name":"amount","type":"u64"}]}]` +const FunctionInfo = `[{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"accept_ownership","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"provide_liquidity","parameters":[{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_rebalancer","parameters":[{"name":"rebalancer","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"store_address","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"withdraw_liquidity","parameters":[{"name":"amount","type":"u64"}]}]` func NewLockReleaseTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) LockReleaseTokenPoolInterface { contract := bind.NewBoundContract(address, "lock_release_token_pool", "lock_release_token_pool", client) @@ -128,6 +130,7 @@ const ( E_UNAUTHORIZED uint64 = 8 E_INSUFFICIENT_LIQUIDITY uint64 = 9 E_TRANSFER_REF_NOT_SET uint64 = 10 + E_NOT_EXECUTING_RECEIVER uint64 = 11 ) // Structs @@ -140,6 +143,9 @@ type LockReleaseTokenPoolState struct { Rebalancer aptos.AccountAddress `move:"address"` } +type LockReleaseTokenPoolEvents struct { +} + type CallbackProof struct { } @@ -1003,6 +1009,20 @@ func (c lockReleaseTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAd }) } +func (c lockReleaseTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) +} + +func (c lockReleaseTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("transfer", nil, []string{ + "address", + "u64", + }, []any{ + to, + amount, + }) +} + func (c lockReleaseTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go index 70628575..740f6291 100644 --- a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go +++ b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go @@ -86,12 +86,14 @@ type ManagedTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"managed_token_pool","module":"managed_token_pool","name":"accept_ownership","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"store_address","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"managed_token_pool","module":"managed_token_pool","name":"accept_ownership","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"store_address","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewManagedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) ManagedTokenPoolInterface { contract := bind.NewBoundContract(address, "managed_token_pool", "managed_token_pool", client) @@ -109,6 +111,7 @@ const ( E_LOCAL_TOKEN_MISMATCH uint64 = 4 E_INVALID_ARGUMENTS uint64 = 5 E_UNKNOWN_FUNCTION uint64 = 6 + E_NOT_EXECUTING_RECEIVER uint64 = 9 ) // Structs @@ -117,6 +120,9 @@ type ManagedTokenPoolState struct { StoreSignerAddress aptos.AccountAddress `move:"address"` } +type ManagedTokenPoolEvents struct { +} + type CallbackProof struct { } @@ -829,6 +835,20 @@ func (c managedTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddres }) } +func (c managedTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) +} + +func (c managedTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("transfer", nil, []string{ + "address", + "u64", + }, []any{ + to, + amount, + }) +} + func (c managedTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go index 8467f139..cf91b09c 100644 --- a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go +++ b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go @@ -86,12 +86,14 @@ type RegulatedTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"regulated_token_pool","module":"regulated_token_pool","name":"accept_ownership","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"store_address","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"regulated_token_pool","module":"regulated_token_pool","name":"accept_ownership","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"store_address","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewRegulatedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) RegulatedTokenPoolInterface { contract := bind.NewBoundContract(address, "regulated_token_pool", "regulated_token_pool", client) @@ -103,12 +105,14 @@ func NewRegulatedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcCl // Constants const ( - E_NOT_PUBLISHER uint64 = 1 - E_ALREADY_INITIALIZED uint64 = 2 - E_INVALID_FUNGIBLE_ASSET uint64 = 3 - E_LOCAL_TOKEN_MISMATCH uint64 = 4 - E_INVALID_ARGUMENTS uint64 = 5 - E_UNKNOWN_FUNCTION uint64 = 6 + E_NOT_PUBLISHER uint64 = 1 + E_ALREADY_INITIALIZED uint64 = 2 + E_INVALID_FUNGIBLE_ASSET uint64 = 3 + E_LOCAL_TOKEN_MISMATCH uint64 = 4 + E_INVALID_ARGUMENTS uint64 = 5 + E_UNKNOWN_FUNCTION uint64 = 6 + E_NOT_REGISTERED_RECEIVER uint64 = 7 + E_NOT_EXECUTING_RECEIVER uint64 = 9 ) // Structs @@ -117,6 +121,9 @@ type RegulatedTokenPoolState struct { StoreSignerAddress aptos.AccountAddress `move:"address"` } +type RegulatedTokenPoolEvents struct { +} + type CallbackProof struct { } @@ -829,6 +836,20 @@ func (c regulatedTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddr }) } +func (c regulatedTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) +} + +func (c regulatedTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("transfer", nil, []string{ + "address", + "u64", + }, []any{ + to, + amount, + }) +} + func (c regulatedTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go b/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go index edef7121..a22fe013 100644 --- a/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go +++ b/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go @@ -37,9 +37,10 @@ type TokenPoolEncoder interface { CalculateLocalAmount(remoteAmount *big.Int, remoteDecimals byte, localDecimals byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) CalculateLocalAmountInternal(remoteAmount *big.Int, remoteDecimals byte, localDecimals byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) Initialize(localToken aptos.AccountAddress, allowlist []aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + CreateTransferEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"ccip_token_pool","module":"token_pool","name":"initialize","parameters":[{"name":"local_token","type":"address"},{"name":"allowlist","type":"vector\u003caddress\u003e"}]}]` +const FunctionInfo = `[{"package":"ccip_token_pool","module":"token_pool","name":"create_transfer_events","parameters":null},{"package":"ccip_token_pool","module":"token_pool","name":"initialize","parameters":[{"name":"local_token","type":"address"},{"name":"allowlist","type":"vector\u003caddress\u003e"}]}]` func NewTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) TokenPoolInterface { contract := bind.NewBoundContract(address, "ccip_token_pool", "token_pool", client) @@ -71,6 +72,9 @@ type TokenPoolState struct { FaMetadata bind.StdObject `move:"aptos_framework::object::Object"` } +type TokenPoolEvents struct { +} + type RemoteChainConfig struct { RemoteTokenAddress []byte `move:"vector"` RemotePools [][]byte `move:"vector>"` @@ -133,6 +137,12 @@ type RebalancerSet struct { NewRebalancer aptos.AccountAddress `move:"address"` } +type Transfer struct { + From aptos.AccountAddress `move:"address"` + To aptos.AccountAddress `move:"address"` + Amount uint64 `move:"u64"` +} + type TokenPoolContract struct { *bind.BoundContract tokenPoolEncoder @@ -284,3 +294,7 @@ func (c tokenPoolEncoder) Initialize(localToken aptos.AccountAddress, allowlist allowlist, }) } + +func (c tokenPoolEncoder) CreateTransferEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("create_transfer_events", nil, []string{}, []any{}) +} diff --git a/bindings/managed_token/managed_token/managed_token.go b/bindings/managed_token/managed_token/managed_token.go index 2208de88..aef01b7a 100644 --- a/bindings/managed_token/managed_token/managed_token.go +++ b/bindings/managed_token/managed_token/managed_token.go @@ -70,9 +70,10 @@ type ManagedTokenEncoder interface { AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TokenStateAddressInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"managed_token","module":"managed_token","name":"accept_ownership","parameters":null},{"package":"managed_token","module":"managed_token","name":"apply_allowed_burner_updates","parameters":[{"name":"burners_to_remove","type":"vector\u003caddress\u003e"},{"name":"burners_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"apply_allowed_minter_updates","parameters":[{"name":"minters_to_remove","type":"vector\u003caddress\u003e"},{"name":"minters_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token","module":"managed_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"managed_token","module":"managed_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"token_state_address_internal","parameters":null},{"package":"managed_token","module":"managed_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"managed_token","module":"managed_token","name":"accept_ownership","parameters":null},{"package":"managed_token","module":"managed_token","name":"apply_allowed_burner_updates","parameters":[{"name":"burners_to_remove","type":"vector\u003caddress\u003e"},{"name":"burners_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"apply_allowed_minter_updates","parameters":[{"name":"minters_to_remove","type":"vector\u003caddress\u003e"},{"name":"minters_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"bridge_transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token","module":"managed_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"managed_token","module":"managed_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"token_state_address_internal","parameters":null},{"package":"managed_token","module":"managed_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewManagedToken(address aptos.AccountAddress, client aptos.AptosRpcClient) ManagedTokenInterface { contract := bind.NewBoundContract(address, "managed_token", "managed_token", client) @@ -606,3 +607,13 @@ func (c managedTokenEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddress) ( func (c managedTokenEncoder) TokenStateAddressInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("token_state_address_internal", nil, []string{}, []any{}) } + +func (c managedTokenEncoder) BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("bridge_transfer", nil, []string{ + "address", + "u64", + }, []any{ + to, + amount, + }) +} diff --git a/bindings/regulated_token/regulated_token/regulated_token.go b/bindings/regulated_token/regulated_token/regulated_token.go index cc14b559..c41c1915 100644 --- a/bindings/regulated_token/regulated_token/regulated_token.go +++ b/bindings/regulated_token/regulated_token/regulated_token.go @@ -135,6 +135,7 @@ type RegulatedTokenEncoder interface { TokenStateAddressInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TokenMetadataFromStateObj(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TokenMetadataInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertPauser(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertUnpauser(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertFreezer(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -144,7 +145,7 @@ type RegulatedTokenEncoder interface { AssertBurnerAndGetType(burner aptos.AccountAddress, stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"regulated_token","module":"regulated_token","name":"accept_admin","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"accept_ownership","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"apply_role_updates","parameters":[{"name":"role_number","type":"u8"},{"name":"addresses_to_remove","type":"vector\u003caddress\u003e"},{"name":"addresses_to_add","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_bridge_minter_or_burner","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_burner_and_get_type","parameters":[{"name":"burner","type":"address"},{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_freezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_pauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_recovery_role","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unfreezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unpauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_burn_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_recover_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"burn_frozen_funds","parameters":[{"name":"from","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"grant_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"regulated_token","module":"regulated_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"pause","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"recover_frozen_funds","parameters":[{"name":"from","type":"address"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"recover_tokens","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"revoke_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_from_state_obj","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_address_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_object_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"transfer_admin","parameters":[{"name":"new_admin","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"unpause","parameters":null}]` +const FunctionInfo = `[{"package":"regulated_token","module":"regulated_token","name":"accept_admin","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"accept_ownership","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"apply_role_updates","parameters":[{"name":"role_number","type":"u8"},{"name":"addresses_to_remove","type":"vector\u003caddress\u003e"},{"name":"addresses_to_add","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_bridge_minter_or_burner","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_burner_and_get_type","parameters":[{"name":"burner","type":"address"},{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_freezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_pauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_recovery_role","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unfreezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unpauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_burn_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_recover_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"bridge_transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"burn_frozen_funds","parameters":[{"name":"from","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"grant_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"regulated_token","module":"regulated_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"pause","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"recover_frozen_funds","parameters":[{"name":"from","type":"address"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"recover_tokens","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"revoke_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_from_state_obj","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_address_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_object_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"transfer_admin","parameters":[{"name":"new_admin","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"unpause","parameters":null}]` func NewRegulatedToken(address aptos.AccountAddress, client aptos.AptosRpcClient) RegulatedTokenInterface { contract := bind.NewBoundContract(address, "regulated_token", "regulated_token", client) @@ -229,6 +230,12 @@ type BridgeBurn struct { Amount uint64 `move:"u64"` } +type BridgeTransfer struct { + Caller aptos.AccountAddress `move:"address"` + To aptos.AccountAddress `move:"address"` + Amount uint64 `move:"u64"` +} + type MinterAdded struct { Admin aptos.AccountAddress `move:"address"` Minter aptos.AccountAddress `move:"address"` @@ -1442,6 +1449,16 @@ func (c regulatedTokenEncoder) TokenMetadataInternal() (bind.ModuleInformation, return c.BoundContract.Encode("token_metadata_internal", nil, []string{}, []any{}) } +func (c regulatedTokenEncoder) BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("bridge_transfer", nil, []string{ + "address", + "u64", + }, []any{ + to, + amount, + }) +} + func (c regulatedTokenEncoder) AssertPauser(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("assert_pauser", nil, []string{ "address", From d5d5d697e2cdf0daa64cac418c4c6a3bfbc9a0dc Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Mon, 13 Oct 2025 10:39:57 -0400 Subject: [PATCH 03/24] Fmt --- contracts/regulated_token/sources/regulated_token.move | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contracts/regulated_token/sources/regulated_token.move b/contracts/regulated_token/sources/regulated_token.move index 91fd2c64..6cf31489 100644 --- a/contracts/regulated_token/sources/regulated_token.move +++ b/contracts/regulated_token/sources/regulated_token.move @@ -611,7 +611,12 @@ module regulated_token::regulated_token { assert_not_frozen(caller_addr, token_state); assert_not_frozen(to, token_state); - primary_fungible_store::transfer_with_ref(&borrow_token_metadata_refs().transfer_ref, caller_addr, to, amount); + primary_fungible_store::transfer_with_ref( + &borrow_token_metadata_refs().transfer_ref, + caller_addr, + to, + amount + ); event::emit(BridgeTransfer { caller: caller_addr, to, amount }); } From 11d1792c79472e85d1db3d6fee10a28d8c68dd09 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Sun, 26 Oct 2025 17:17:01 -0400 Subject: [PATCH 04/24] Use Function closures for token pool lock/burn release/mint hooks --- .../receiver_registry/receiver_registry.go | 21 +- .../token_admin_registry.go | 53 ++++- .../burn_mint_token_pool.go | 21 +- .../lock_release_token_pool.go | 21 +- .../managed_token_pool/managed_token_pool.go | 21 +- .../regulated_token_pool.go | 21 +- .../token_pool/token_pool/token_pool.go | 16 +- .../managed_token/managed_token.go | 13 +- .../regulated_token/regulated_token.go | 19 +- .../ccip/sources/receiver_dispatcher.move | 9 + .../ccip/ccip/sources/receiver_registry.move | 88 +++++--- .../ccip/sources/token_admin_dispatcher.move | 51 +++++ .../ccip/sources/token_admin_registry.move | 124 ++++++++++- .../ccip/ccip_offramp/sources/offramp.move | 25 ++- .../mock/burn_mint_dispatchable_receiver.move | 182 --------------- .../lock_release_dispatchable_receiver.move | 182 --------------- ..._receiver.move => mock_ccip_receiver.move} | 59 ++--- .../tests/mock/non_dispatchable_receiver.move | 207 ------------------ .../mock/regulated_dispatchable_receiver.move | 189 ---------------- .../offramp_burn_mint_receiver_test.move | 121 ++-------- .../offramp_lock_release_receiver_test.move | 114 ++-------- .../tests/offramp_managed_receiver_test.move | 112 ++-------- .../offramp_regulated_receiver_test.move | 96 +------- .../sources/burn_mint_token_pool.move | 123 ++++++----- .../sources/lock_release_token_pool.move | 120 +++++----- .../sources/managed_token_pool.move | 138 +++++++----- .../sources/regulated_token_pool.move | 120 +++++----- .../tests/regulated_token_pool_test.move | 41 ---- .../token_pool/sources/token_pool.move | 27 --- .../sources/usdc_token_pool.move | 125 ++++++++++- .../managed_token/sources/managed_token.move | 29 --- .../sources/regulated_token.move | 29 --- 32 files changed, 842 insertions(+), 1675 deletions(-) delete mode 100644 contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move delete mode 100644 contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move rename contracts/ccip/ccip_offramp/tests/mock/{managed_dispatchable_receiver.move => mock_ccip_receiver.move} (83%) delete mode 100644 contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move delete mode 100644 contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move diff --git a/bindings/ccip/receiver_registry/receiver_registry.go b/bindings/ccip/receiver_registry/receiver_registry.go index c922b3fe..fc7ee891 100644 --- a/bindings/ccip/receiver_registry/receiver_registry.go +++ b/bindings/ccip/receiver_registry/receiver_registry.go @@ -24,7 +24,7 @@ var ( type ReceiverRegistryInterface interface { TypeAndVersion(opts *bind.CallOpts) (string, error) IsRegisteredReceiver(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) - IsExecutingReceiverInProgress(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) + IsRegisteredReceiverV2(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) // Encoder returns the encoder implementation of this module. Encoder() ReceiverRegistryEncoder @@ -33,12 +33,11 @@ type ReceiverRegistryInterface interface { type ReceiverRegistryEncoder interface { TypeAndVersion() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) IsRegisteredReceiver(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - IsExecutingReceiverInProgress(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + IsRegisteredReceiverV2(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) FinishReceive(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - InitializeCCIPReceiveState() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"ccip","module":"receiver_registry","name":"finish_receive","parameters":[{"name":"receiver_address","type":"address"}]},{"package":"ccip","module":"receiver_registry","name":"initialize_ccip_receive_state","parameters":null}]` +const FunctionInfo = `[{"package":"ccip","module":"receiver_registry","name":"finish_receive","parameters":[{"name":"receiver_address","type":"address"}]}]` func NewReceiverRegistry(address aptos.AccountAddress, client aptos.AptosRpcClient) ReceiverRegistryInterface { contract := bind.NewBoundContract(address, "ccip", "receiver_registry", client) @@ -69,7 +68,7 @@ type CCIPReceiverRegistration struct { DispatchMetadata bind.StdObject `move:"aptos_framework::object::Object"` } -type CCIPReceiveState struct { +type CCIPReceiverRegistrationV2 struct { } type ReceiverRegistered struct { @@ -132,8 +131,8 @@ func (c ReceiverRegistryContract) IsRegisteredReceiver(opts *bind.CallOpts, rece return r0, nil } -func (c ReceiverRegistryContract) IsExecutingReceiverInProgress(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) { - module, function, typeTags, args, err := c.receiverRegistryEncoder.IsExecutingReceiverInProgress(receiverAddress) +func (c ReceiverRegistryContract) IsRegisteredReceiverV2(opts *bind.CallOpts, receiverAddress aptos.AccountAddress) (bool, error) { + module, function, typeTags, args, err := c.receiverRegistryEncoder.IsRegisteredReceiverV2(receiverAddress) if err != nil { return *new(bool), err } @@ -172,8 +171,8 @@ func (c receiverRegistryEncoder) IsRegisteredReceiver(receiverAddress aptos.Acco }) } -func (c receiverRegistryEncoder) IsExecutingReceiverInProgress(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("is_executing_receiver_in_progress", nil, []string{ +func (c receiverRegistryEncoder) IsRegisteredReceiverV2(receiverAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("is_registered_receiver_v2", nil, []string{ "address", }, []any{ receiverAddress, @@ -187,7 +186,3 @@ func (c receiverRegistryEncoder) FinishReceive(receiverAddress aptos.AccountAddr receiverAddress, }) } - -func (c receiverRegistryEncoder) InitializeCCIPReceiveState() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("initialize_ccip_receive_state", nil, []string{}, []any{}) -} diff --git a/bindings/ccip/token_admin_registry/token_admin_registry.go b/bindings/ccip/token_admin_registry/token_admin_registry.go index 6974b4b1..63455917 100644 --- a/bindings/ccip/token_admin_registry/token_admin_registry.go +++ b/bindings/ccip/token_admin_registry/token_admin_registry.go @@ -26,6 +26,7 @@ type TokenAdminRegistryInterface interface { GetPools(opts *bind.CallOpts, localTokens []aptos.AccountAddress) ([]aptos.AccountAddress, error) GetPool(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, error) GetPoolLocalToken(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (aptos.AccountAddress, error) + GetPoolLocalTokenV2(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (aptos.AccountAddress, error) GetTokenConfig(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, aptos.AccountAddress, aptos.AccountAddress, error) GetAllConfiguredTokens(opts *bind.CallOpts, startKey aptos.AccountAddress, maxCount uint64) ([]aptos.AccountAddress, aptos.AccountAddress, bool, error) IsAdministrator(opts *bind.CallOpts, localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bool, error) @@ -45,6 +46,7 @@ type TokenAdminRegistryEncoder interface { GetPools(localTokens []aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetPool(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetPoolLocalToken(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + GetPoolLocalTokenV2(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetTokenConfig(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetAllConfiguredTokens(startKey aptos.AccountAddress, maxCount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) IsAdministrator(localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -53,6 +55,7 @@ type TokenAdminRegistryEncoder interface { ProposeAdministrator(localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TransferAdminRole(localToken aptos.AccountAddress, newAdmin aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptAdminRole(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + NewLockOrBurnOutputV1(destTokenAddress []byte, destPoolData []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StartLockOrBurn(tokenPoolAddress aptos.AccountAddress, sender aptos.AccountAddress, remoteChainSelector uint64, receiver []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) FinishLockOrBurn(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) FinishReleaseOrMint(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -60,7 +63,7 @@ type TokenAdminRegistryEncoder interface { RegisterMCMSEntrypoint() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"ccip","module":"token_admin_registry","name":"accept_admin_role","parameters":[{"name":"local_token","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_release_or_mint","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"propose_administrator","parameters":[{"name":"local_token","type":"address"},{"name":"administrator","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"register_mcms_entrypoint","parameters":null},{"package":"ccip","module":"token_admin_registry","name":"set_pool","parameters":[{"name":"local_token","type":"address"},{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"start_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"},{"name":"sender","type":"address"},{"name":"remote_chain_selector","type":"u64"},{"name":"receiver","type":"vector\u003cu8\u003e"}]},{"package":"ccip","module":"token_admin_registry","name":"transfer_admin_role","parameters":[{"name":"local_token","type":"address"},{"name":"new_admin","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"unregister_pool","parameters":[{"name":"local_token","type":"address"}]}]` +const FunctionInfo = `[{"package":"ccip","module":"token_admin_registry","name":"accept_admin_role","parameters":[{"name":"local_token","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_release_or_mint","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"new_lock_or_burn_output_v1","parameters":[{"name":"dest_token_address","type":"vector\u003cu8\u003e"},{"name":"dest_pool_data","type":"vector\u003cu8\u003e"}]},{"package":"ccip","module":"token_admin_registry","name":"propose_administrator","parameters":[{"name":"local_token","type":"address"},{"name":"administrator","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"register_mcms_entrypoint","parameters":null},{"package":"ccip","module":"token_admin_registry","name":"set_pool","parameters":[{"name":"local_token","type":"address"},{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"start_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"},{"name":"sender","type":"address"},{"name":"remote_chain_selector","type":"u64"},{"name":"receiver","type":"vector\u003cu8\u003e"}]},{"package":"ccip","module":"token_admin_registry","name":"transfer_admin_role","parameters":[{"name":"local_token","type":"address"},{"name":"new_admin","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"unregister_pool","parameters":[{"name":"local_token","type":"address"}]}]` func NewTokenAdminRegistry(address aptos.AccountAddress, client aptos.AptosRpcClient) TokenAdminRegistryInterface { contract := bind.NewBoundContract(address, "ccip", "token_admin_registry", client) @@ -101,6 +104,7 @@ const ( E_ADMIN_NOT_SET_FOR_TOKEN uint64 = 27 E_ADMIN_ALREADY_SET_FOR_TOKEN uint64 = 28 E_ZERO_ADDRESS uint64 = 29 + E_POOL_NOT_REGISTERED uint64 = 30 ) // Structs @@ -150,6 +154,14 @@ type ReleaseOrMintOutputV1 struct { DestinationAmount uint64 `move:"u64"` } +type TokenPoolCallbacks struct { +} + +type TokenPoolConfig struct { + Callbacks TokenPoolCallbacks `move:"TokenPoolCallbacks"` + LocalToken aptos.AccountAddress `move:"address"` +} + type PoolSet struct { LocalToken aptos.AccountAddress `move:"address"` PreviousPoolAddress aptos.AccountAddress `move:"address"` @@ -272,6 +284,27 @@ func (c TokenAdminRegistryContract) GetPoolLocalToken(opts *bind.CallOpts, token return r0, nil } +func (c TokenAdminRegistryContract) GetPoolLocalTokenV2(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (aptos.AccountAddress, error) { + module, function, typeTags, args, err := c.tokenAdminRegistryEncoder.GetPoolLocalTokenV2(tokenPoolAddress) + if err != nil { + return *new(aptos.AccountAddress), err + } + + callData, err := c.Call(opts, module, function, typeTags, args) + if err != nil { + return *new(aptos.AccountAddress), err + } + + var ( + r0 aptos.AccountAddress + ) + + if err := codec.DecodeAptosJsonArray(callData, &r0); err != nil { + return *new(aptos.AccountAddress), err + } + return r0, nil +} + func (c TokenAdminRegistryContract) GetTokenConfig(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, aptos.AccountAddress, aptos.AccountAddress, error) { module, function, typeTags, args, err := c.tokenAdminRegistryEncoder.GetTokenConfig(localToken) if err != nil { @@ -419,6 +452,14 @@ func (c tokenAdminRegistryEncoder) GetPoolLocalToken(tokenPoolAddress aptos.Acco }) } +func (c tokenAdminRegistryEncoder) GetPoolLocalTokenV2(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("get_pool_local_token_v2", nil, []string{ + "address", + }, []any{ + tokenPoolAddress, + }) +} + func (c tokenAdminRegistryEncoder) GetTokenConfig(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("get_token_config", nil, []string{ "address", @@ -493,6 +534,16 @@ func (c tokenAdminRegistryEncoder) AcceptAdminRole(localToken aptos.AccountAddre }) } +func (c tokenAdminRegistryEncoder) NewLockOrBurnOutputV1(destTokenAddress []byte, destPoolData []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("new_lock_or_burn_output_v1", nil, []string{ + "vector", + "vector", + }, []any{ + destTokenAddress, + destPoolData, + }) +} + func (c tokenAdminRegistryEncoder) StartLockOrBurn(tokenPoolAddress aptos.AccountAddress, sender aptos.AccountAddress, remoteChainSelector uint64, receiver []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("start_lock_or_burn", nil, []string{ "address", diff --git a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go index 45aa274a..75051943 100644 --- a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go +++ b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go @@ -86,15 +86,13 @@ type BurnMintTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertCanInitialize(callerAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"accept_ownership","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"store_address","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"accept_ownership","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"store_address","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewBurnMintTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) BurnMintTokenPoolInterface { contract := bind.NewBoundContract(address, "burn_mint_token_pool", "burn_mint_token_pool", client) @@ -126,9 +124,6 @@ type BurnMintTokenPoolState struct { StoreSignerAddress aptos.AccountAddress `move:"address"` } -type BurnMintTokenPoolEvents struct { -} - type CallbackProof struct { } @@ -841,20 +836,6 @@ func (c burnMintTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddre }) } -func (c burnMintTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) -} - -func (c burnMintTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("transfer", nil, []string{ - "address", - "u64", - }, []any{ - to, - amount, - }) -} - func (c burnMintTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go index 3a795570..69affcf9 100644 --- a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go +++ b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go @@ -100,15 +100,13 @@ type LockReleaseTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertCanInitialize(callerAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"accept_ownership","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"provide_liquidity","parameters":[{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_rebalancer","parameters":[{"name":"rebalancer","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"store_address","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"withdraw_liquidity","parameters":[{"name":"amount","type":"u64"}]}]` +const FunctionInfo = `[{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"accept_ownership","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"provide_liquidity","parameters":[{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_rebalancer","parameters":[{"name":"rebalancer","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"store_address","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"withdraw_liquidity","parameters":[{"name":"amount","type":"u64"}]}]` func NewLockReleaseTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) LockReleaseTokenPoolInterface { contract := bind.NewBoundContract(address, "lock_release_token_pool", "lock_release_token_pool", client) @@ -143,9 +141,6 @@ type LockReleaseTokenPoolState struct { Rebalancer aptos.AccountAddress `move:"address"` } -type LockReleaseTokenPoolEvents struct { -} - type CallbackProof struct { } @@ -1009,20 +1004,6 @@ func (c lockReleaseTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAd }) } -func (c lockReleaseTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) -} - -func (c lockReleaseTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("transfer", nil, []string{ - "address", - "u64", - }, []any{ - to, - amount, - }) -} - func (c lockReleaseTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go index 740f6291..50152df1 100644 --- a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go +++ b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go @@ -86,14 +86,12 @@ type ManagedTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"managed_token_pool","module":"managed_token_pool","name":"accept_ownership","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"store_address","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"managed_token_pool","module":"managed_token_pool","name":"accept_ownership","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"store_address","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewManagedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) ManagedTokenPoolInterface { contract := bind.NewBoundContract(address, "managed_token_pool", "managed_token_pool", client) @@ -120,9 +118,6 @@ type ManagedTokenPoolState struct { StoreSignerAddress aptos.AccountAddress `move:"address"` } -type ManagedTokenPoolEvents struct { -} - type CallbackProof struct { } @@ -835,20 +830,6 @@ func (c managedTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddres }) } -func (c managedTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) -} - -func (c managedTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("transfer", nil, []string{ - "address", - "u64", - }, []any{ - to, - amount, - }) -} - func (c managedTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go index cf91b09c..f4c30bc2 100644 --- a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go +++ b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go @@ -86,14 +86,12 @@ type RegulatedTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"regulated_token_pool","module":"regulated_token_pool","name":"accept_ownership","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"initialize_token_pool_events","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"store_address","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"regulated_token_pool","module":"regulated_token_pool","name":"accept_ownership","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"store_address","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewRegulatedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) RegulatedTokenPoolInterface { contract := bind.NewBoundContract(address, "regulated_token_pool", "regulated_token_pool", client) @@ -121,9 +119,6 @@ type RegulatedTokenPoolState struct { StoreSignerAddress aptos.AccountAddress `move:"address"` } -type RegulatedTokenPoolEvents struct { -} - type CallbackProof struct { } @@ -836,20 +831,6 @@ func (c regulatedTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddr }) } -func (c regulatedTokenPoolEncoder) InitializeTokenPoolEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("initialize_token_pool_events", nil, []string{}, []any{}) -} - -func (c regulatedTokenPoolEncoder) Transfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("transfer", nil, []string{ - "address", - "u64", - }, []any{ - to, - amount, - }) -} - func (c regulatedTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go b/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go index a22fe013..edef7121 100644 --- a/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go +++ b/bindings/ccip_token_pools/token_pool/token_pool/token_pool.go @@ -37,10 +37,9 @@ type TokenPoolEncoder interface { CalculateLocalAmount(remoteAmount *big.Int, remoteDecimals byte, localDecimals byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) CalculateLocalAmountInternal(remoteAmount *big.Int, remoteDecimals byte, localDecimals byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) Initialize(localToken aptos.AccountAddress, allowlist []aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - CreateTransferEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"ccip_token_pool","module":"token_pool","name":"create_transfer_events","parameters":null},{"package":"ccip_token_pool","module":"token_pool","name":"initialize","parameters":[{"name":"local_token","type":"address"},{"name":"allowlist","type":"vector\u003caddress\u003e"}]}]` +const FunctionInfo = `[{"package":"ccip_token_pool","module":"token_pool","name":"initialize","parameters":[{"name":"local_token","type":"address"},{"name":"allowlist","type":"vector\u003caddress\u003e"}]}]` func NewTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) TokenPoolInterface { contract := bind.NewBoundContract(address, "ccip_token_pool", "token_pool", client) @@ -72,9 +71,6 @@ type TokenPoolState struct { FaMetadata bind.StdObject `move:"aptos_framework::object::Object"` } -type TokenPoolEvents struct { -} - type RemoteChainConfig struct { RemoteTokenAddress []byte `move:"vector"` RemotePools [][]byte `move:"vector>"` @@ -137,12 +133,6 @@ type RebalancerSet struct { NewRebalancer aptos.AccountAddress `move:"address"` } -type Transfer struct { - From aptos.AccountAddress `move:"address"` - To aptos.AccountAddress `move:"address"` - Amount uint64 `move:"u64"` -} - type TokenPoolContract struct { *bind.BoundContract tokenPoolEncoder @@ -294,7 +284,3 @@ func (c tokenPoolEncoder) Initialize(localToken aptos.AccountAddress, allowlist allowlist, }) } - -func (c tokenPoolEncoder) CreateTransferEvents() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("create_transfer_events", nil, []string{}, []any{}) -} diff --git a/bindings/managed_token/managed_token/managed_token.go b/bindings/managed_token/managed_token/managed_token.go index aef01b7a..2208de88 100644 --- a/bindings/managed_token/managed_token/managed_token.go +++ b/bindings/managed_token/managed_token/managed_token.go @@ -70,10 +70,9 @@ type ManagedTokenEncoder interface { AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TokenStateAddressInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"managed_token","module":"managed_token","name":"accept_ownership","parameters":null},{"package":"managed_token","module":"managed_token","name":"apply_allowed_burner_updates","parameters":[{"name":"burners_to_remove","type":"vector\u003caddress\u003e"},{"name":"burners_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"apply_allowed_minter_updates","parameters":[{"name":"minters_to_remove","type":"vector\u003caddress\u003e"},{"name":"minters_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"bridge_transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token","module":"managed_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"managed_token","module":"managed_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"token_state_address_internal","parameters":null},{"package":"managed_token","module":"managed_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"managed_token","module":"managed_token","name":"accept_ownership","parameters":null},{"package":"managed_token","module":"managed_token","name":"apply_allowed_burner_updates","parameters":[{"name":"burners_to_remove","type":"vector\u003caddress\u003e"},{"name":"burners_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"apply_allowed_minter_updates","parameters":[{"name":"minters_to_remove","type":"vector\u003caddress\u003e"},{"name":"minters_to_add","type":"vector\u003caddress\u003e"}]},{"package":"managed_token","module":"managed_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token","module":"managed_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"managed_token","module":"managed_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"managed_token","module":"managed_token","name":"token_state_address_internal","parameters":null},{"package":"managed_token","module":"managed_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewManagedToken(address aptos.AccountAddress, client aptos.AptosRpcClient) ManagedTokenInterface { contract := bind.NewBoundContract(address, "managed_token", "managed_token", client) @@ -607,13 +606,3 @@ func (c managedTokenEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddress) ( func (c managedTokenEncoder) TokenStateAddressInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("token_state_address_internal", nil, []string{}, []any{}) } - -func (c managedTokenEncoder) BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("bridge_transfer", nil, []string{ - "address", - "u64", - }, []any{ - to, - amount, - }) -} diff --git a/bindings/regulated_token/regulated_token/regulated_token.go b/bindings/regulated_token/regulated_token/regulated_token.go index c41c1915..cc14b559 100644 --- a/bindings/regulated_token/regulated_token/regulated_token.go +++ b/bindings/regulated_token/regulated_token/regulated_token.go @@ -135,7 +135,6 @@ type RegulatedTokenEncoder interface { TokenStateAddressInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TokenMetadataFromStateObj(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TokenMetadataInternal() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertPauser(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertUnpauser(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertFreezer(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -145,7 +144,7 @@ type RegulatedTokenEncoder interface { AssertBurnerAndGetType(burner aptos.AccountAddress, stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"regulated_token","module":"regulated_token","name":"accept_admin","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"accept_ownership","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"apply_role_updates","parameters":[{"name":"role_number","type":"u8"},{"name":"addresses_to_remove","type":"vector\u003caddress\u003e"},{"name":"addresses_to_add","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_bridge_minter_or_burner","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_burner_and_get_type","parameters":[{"name":"burner","type":"address"},{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_freezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_pauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_recovery_role","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unfreezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unpauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_burn_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_recover_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"bridge_transfer","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"burn_frozen_funds","parameters":[{"name":"from","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"grant_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"regulated_token","module":"regulated_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"pause","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"recover_frozen_funds","parameters":[{"name":"from","type":"address"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"recover_tokens","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"revoke_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_from_state_obj","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_address_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_object_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"transfer_admin","parameters":[{"name":"new_admin","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"unpause","parameters":null}]` +const FunctionInfo = `[{"package":"regulated_token","module":"regulated_token","name":"accept_admin","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"accept_ownership","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"apply_role_updates","parameters":[{"name":"role_number","type":"u8"},{"name":"addresses_to_remove","type":"vector\u003caddress\u003e"},{"name":"addresses_to_add","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_bridge_minter_or_burner","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_burner_and_get_type","parameters":[{"name":"burner","type":"address"},{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_freezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_pauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_recovery_role","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unfreezer","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"assert_unpauser","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_burn_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"batch_recover_frozen_funds","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"burn","parameters":[{"name":"from","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"burn_frozen_funds","parameters":[{"name":"from","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"freeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"grant_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"initialize","parameters":[{"name":"max_supply","type":"0x1::option::Option\u003cu128\u003e"},{"name":"name","type":"0x1::string::String"},{"name":"symbol","type":"0x1::string::String"},{"name":"decimals","type":"u8"},{"name":"icon","type":"0x1::string::String"},{"name":"project","type":"0x1::string::String"}]},{"package":"regulated_token","module":"regulated_token","name":"mint","parameters":[{"name":"to","type":"address"},{"name":"amount","type":"u64"}]},{"package":"regulated_token","module":"regulated_token","name":"pause","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"recover_frozen_funds","parameters":[{"name":"from","type":"address"},{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"recover_tokens","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"revoke_role","parameters":[{"name":"role_number","type":"u8"},{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_from_state_obj","parameters":[{"name":"state_obj","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"token_metadata_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_address_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"token_state_object_internal","parameters":null},{"package":"regulated_token","module":"regulated_token","name":"transfer_admin","parameters":[{"name":"new_admin","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_account","parameters":[{"name":"account","type":"address"}]},{"package":"regulated_token","module":"regulated_token","name":"unfreeze_accounts","parameters":[{"name":"accounts","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token","module":"regulated_token","name":"unpause","parameters":null}]` func NewRegulatedToken(address aptos.AccountAddress, client aptos.AptosRpcClient) RegulatedTokenInterface { contract := bind.NewBoundContract(address, "regulated_token", "regulated_token", client) @@ -230,12 +229,6 @@ type BridgeBurn struct { Amount uint64 `move:"u64"` } -type BridgeTransfer struct { - Caller aptos.AccountAddress `move:"address"` - To aptos.AccountAddress `move:"address"` - Amount uint64 `move:"u64"` -} - type MinterAdded struct { Admin aptos.AccountAddress `move:"address"` Minter aptos.AccountAddress `move:"address"` @@ -1449,16 +1442,6 @@ func (c regulatedTokenEncoder) TokenMetadataInternal() (bind.ModuleInformation, return c.BoundContract.Encode("token_metadata_internal", nil, []string{}, []any{}) } -func (c regulatedTokenEncoder) BridgeTransfer(to aptos.AccountAddress, amount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("bridge_transfer", nil, []string{ - "address", - "u64", - }, []any{ - to, - amount, - }) -} - func (c regulatedTokenEncoder) AssertPauser(stateObj aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("assert_pauser", nil, []string{ "address", diff --git a/contracts/ccip/ccip/sources/receiver_dispatcher.move b/contracts/ccip/ccip/sources/receiver_dispatcher.move index ac5b0cb1..8b0eb783 100644 --- a/contracts/ccip/ccip/sources/receiver_dispatcher.move +++ b/contracts/ccip/ccip/sources/receiver_dispatcher.move @@ -16,4 +16,13 @@ module ccip::receiver_dispatcher { dispatchable_fungible_asset::derived_supply(dispatch_metadata); receiver_registry::finish_receive(receiver_address); } + + /// Invoke receiver's callback without token dispatchable hooks + public fun dispatch_receive_v2( + caller: &signer, receiver_address: address, message: client::Any2AptosMessage + ) { + auth::assert_is_allowed_offramp(signer::address_of(caller)); + + receiver_registry::invoke_ccip_receive_v2(receiver_address, message); + } } diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index 353636ca..87b499d5 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -5,15 +5,13 @@ module ccip::receiver_registry { use std::error; use std::event::{Self, EventHandle}; use std::function_info::{Self, FunctionInfo}; - use std::table::{Self, Table}; use std::type_info::{Self, TypeInfo}; use std::fungible_asset::{Self, Metadata}; - use std::object::{Self, ExtendRef, Object, TransferRef, ObjectCore}; + use std::object::{Self, ExtendRef, Object, TransferRef}; use std::option::{Self, Option}; use std::signer; use std::string::{Self, String}; - use ccip::auth; use ccip::client; use ccip::state_object; @@ -34,8 +32,9 @@ module ccip::receiver_registry { executing_input: Option } - struct CCIPReceiveState has key { - executing_receivers: Table + struct CCIPReceiverRegistrationV2 has key { + callback: |client::Any2AptosMessage| has drop + copy + store, + proof_typeinfo: TypeInfo, } #[event] @@ -72,10 +71,6 @@ module ccip::receiver_registry { }; move_to(&state_object_signer, state); - - move_to( - &state_object_signer, CCIPReceiveState { executing_receivers: table::new() } - ); } public fun register_receiver( @@ -149,16 +144,48 @@ module ccip::receiver_registry { ); } + public fun register_receiver_v2( + receiver_account: &signer, + receiver_module_name: vector, + callback: |client::Any2AptosMessage| has drop + copy + store, + _proof: ProofType + ) acquires ReceiverRegistryState { + let receiver_address = signer::address_of(receiver_account); + assert!( + !exists(receiver_address), + error::invalid_argument(E_ALREADY_REGISTERED) + ); + + let proof_typeinfo = type_info::type_of(); + assert!( + proof_typeinfo.account_address() == receiver_address, + E_PROOF_TYPE_ACCOUNT_MISMATCH + ); + assert!( + proof_typeinfo.module_name() == receiver_module_name, + E_PROOF_TYPE_MODULE_MISMATCH + ); + + move_to( + receiver_account, + CCIPReceiverRegistrationV2 { callback, proof_typeinfo } + ); + + let state = borrow_state_mut(); + event::emit_event( + &mut state.receiver_registered_events, + ReceiverRegistered { receiver_address, receiver_module_name } + ); + } + #[view] public fun is_registered_receiver(receiver_address: address): bool { exists(receiver_address) } #[view] - public fun is_executing_receiver_in_progress( - receiver_address: address - ): bool acquires CCIPReceiveState { - borrow_ccip_receive_state_mut().executing_receivers.contains(receiver_address) + public fun is_registered_receiver_v2(receiver_address: address): bool { + exists(receiver_address) } public fun get_receiver_input( @@ -181,7 +208,7 @@ module ccip::receiver_registry { public(friend) fun start_receive( receiver_address: address, message: client::Any2AptosMessage - ): Object acquires CCIPReceiverRegistration, CCIPReceiveState { + ): Object acquires CCIPReceiverRegistration { let registration = get_registration_mut(receiver_address); assert!( @@ -191,22 +218,32 @@ module ccip::receiver_registry { registration.executing_input.fill(message); - borrow_ccip_receive_state_mut().executing_receivers.add(receiver_address, true); - registration.dispatch_metadata } public(friend) fun finish_receive( receiver_address: address - ) acquires CCIPReceiverRegistration, CCIPReceiveState { + ) acquires CCIPReceiverRegistration { let registration = get_registration_mut(receiver_address); assert!( registration.executing_input.is_none(), error::invalid_state(E_NON_EMPTY_INPUT) ); + } - borrow_ccip_receive_state_mut().executing_receivers.remove(receiver_address); + public(friend) fun invoke_ccip_receive_v2( + receiver_address: address, + message: client::Any2AptosMessage + ) acquires CCIPReceiverRegistrationV2 { + assert!( + exists(receiver_address), + error::invalid_argument(E_UNKNOWN_RECEIVER) + ); + + let registration = borrow_global(receiver_address); + + (registration.callback)(message); } inline fun borrow_state(): &ReceiverRegistryState { @@ -217,10 +254,6 @@ module ccip::receiver_registry { borrow_global_mut(state_object::object_address()) } - inline fun borrow_ccip_receive_state_mut(): &mut CCIPReceiveState { - borrow_global_mut(state_object::object_address()) - } - inline fun get_registration_mut(receiver_address: address): &mut CCIPReceiverRegistration { assert!( exists(receiver_address), @@ -229,17 +262,6 @@ module ccip::receiver_registry { borrow_global_mut(receiver_address) } - // ============================= Migrations ============================= - - public fun initialize_ccip_receive_state(caller: &signer) { - auth::assert_only_owner(signer::address_of(caller)); - - move_to( - &state_object::object_signer(), - CCIPReceiveState { executing_receivers: table::new() } - ); - } - #[test_only] public fun init_module_for_testing(publisher: &signer) { init_module(publisher); diff --git a/contracts/ccip/ccip/sources/token_admin_dispatcher.move b/contracts/ccip/ccip/sources/token_admin_dispatcher.move index 7645fbfe..f0bae95f 100644 --- a/contracts/ccip/ccip/sources/token_admin_dispatcher.move +++ b/contracts/ccip/ccip/sources/token_admin_dispatcher.move @@ -66,4 +66,55 @@ module ccip::token_admin_dispatcher { (fa, destination_amount) } + + // ============================================ + // V2 Closure-Based Dispatch Functions + // ============================================ + + public fun dispatch_lock_or_burn_v2( + caller: &signer, + token_pool_address: address, + fa: FungibleAsset, + sender: address, + remote_chain_selector: u64, + receiver: vector + ): (vector, vector) { + token_admin_registry::lock_or_burn_v2( + caller, + token_pool_address, + fa, + sender, + remote_chain_selector, + receiver + ) + } + + public fun dispatch_release_or_mint_v2( + caller: &signer, + token_pool_address: address, + sender: vector, + receiver: address, + source_amount: u256, + local_token: address, + remote_chain_selector: u64, + source_pool_address: vector, + source_pool_data: vector, + offchain_token_data: vector + ): (FungibleAsset, u64) { + let (fa, destination_amount) = + token_admin_registry::release_or_mint_v2( + caller, + token_pool_address, + sender, + receiver, + source_amount, + local_token, + remote_chain_selector, + source_pool_address, + source_pool_data, + offchain_token_data + ); + + (fa, destination_amount) + } } diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index f890d0e1..77c6aa21 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -86,6 +86,22 @@ module ccip::token_admin_registry { struct ReleaseOrMintOutputV1 has store, drop { destination_amount: u64 } + public fun new_lock_or_burn_output_v1( + dest_token_address: vector, + dest_pool_data: vector + ): LockOrBurnOutputV1 { + LockOrBurnOutputV1 { dest_token_address, dest_pool_data } + } + + struct TokenPoolCallbacks has drop, copy, store { + lock_or_burn: |fungible_asset::FungibleAsset, LockOrBurnInputV1| LockOrBurnOutputV1 has drop + copy + store, + release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop + copy + store, + } + + struct TokenPoolConfig has key { + callbacks: TokenPoolCallbacks, + local_token: address + } #[event] struct PoolSet has store, drop { @@ -142,6 +158,7 @@ module ccip::token_admin_registry { const E_ADMIN_NOT_SET_FOR_TOKEN: u64 = 27; const E_ADMIN_ALREADY_SET_FOR_TOKEN: u64 = 28; const E_ZERO_ADDRESS: u64 = 29; + const E_POOL_NOT_REGISTERED: u64 = 30; #[view] public fun type_and_version(): String { @@ -221,6 +238,12 @@ module ccip::token_admin_registry { get_registration(token_pool_address).local_token } + #[view] + /// Returns the local token address for the token pool. + public fun get_pool_local_token_v2(token_pool_address: address): address acquires TokenPoolConfig { + TokenPoolConfig[token_pool_address].local_token + } + #[view] /// returns (token_pool_address, administrator, pending_administrator) public fun get_token_config( @@ -393,6 +416,43 @@ module ccip::token_admin_registry { ); } + public fun register_pool_v2( + token_pool_account: &signer, + token_pool_module_name: vector, + local_token: address, + lock_or_burn: |fungible_asset::FungibleAsset, LockOrBurnInputV1| LockOrBurnOutputV1 has drop + copy + store, + release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop + copy + store, + _proof: ProofType + ) { + let token_pool_address = signer::address_of(token_pool_account); + assert!( + !exists(token_pool_address), + error::invalid_argument(E_ALREADY_REGISTERED) + ); + assert!( + object::object_exists(local_token), + error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) + ); + + let proof_typeinfo = type_info::type_of(); + assert!( + proof_typeinfo.account_address() == token_pool_address, + error::invalid_argument(E_PROOF_NOT_AT_TOKEN_POOL_ADDRESS) + ); + assert!( + proof_typeinfo.module_name() == token_pool_module_name, + error::invalid_argument(E_PROOF_NOT_IN_TOKEN_POOL_MODULE) + ); + + move_to( + token_pool_account, + TokenPoolConfig { + callbacks: TokenPoolCallbacks { lock_or_burn, release_or_mint }, + local_token + } + ); + } + public entry fun unregister_pool( caller: &signer, local_token: address ) acquires TokenAdminRegistryState, TokenPoolRegistration { @@ -439,7 +499,7 @@ module ccip::token_admin_registry { public entry fun set_pool( caller: &signer, local_token: address, token_pool_address: address - ) acquires TokenAdminRegistryState, TokenPoolRegistration { + ) acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolConfig { assert!( object::object_exists(local_token), error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) @@ -447,8 +507,16 @@ module ccip::token_admin_registry { let caller_addr = signer::address_of(caller); + let pool_local_token = if (exists(token_pool_address)) { + get_pool_local_token_v2(token_pool_address) + } else if (exists(token_pool_address)) { + get_registration(token_pool_address).local_token + } else { + abort error::invalid_argument(E_POOL_NOT_REGISTERED) + }; + assert!( - get_registration(token_pool_address).local_token == local_token, + pool_local_token == local_token, error::invalid_argument(E_INVALID_TOKEN_FOR_POOL) ); @@ -992,6 +1060,56 @@ module ccip::token_admin_registry { output.destination_amount } + public(friend) fun lock_or_burn_v2( + caller: &signer, + token_pool_address: address, + fa: fungible_asset::FungibleAsset, + sender: address, + remote_chain_selector: u64, + receiver: vector + ): (vector, vector) acquires TokenPoolConfig { + auth::assert_is_allowed_onramp(signer::address_of(caller)); + + let pool_config = &TokenPoolConfig[token_pool_address]; + let input = LockOrBurnInputV1 { + sender, + remote_chain_selector, + receiver + }; + + let output = (pool_config.callbacks.lock_or_burn)(fa, input); + (output.dest_token_address, output.dest_pool_data) + } + + public(friend) fun release_or_mint_v2( + caller: &signer, + token_pool_address: address, + sender: vector, + receiver: address, + source_amount: u256, + local_token: address, + remote_chain_selector: u64, + source_pool_address: vector, + source_pool_data: vector, + offchain_token_data: vector + ): (fungible_asset::FungibleAsset, u64) acquires TokenPoolConfig { + auth::assert_is_allowed_offramp(signer::address_of(caller)); + + let pool_config = &TokenPoolConfig[token_pool_address]; + let input = ReleaseOrMintInputV1 { + sender, + receiver, + source_amount, + local_token, + remote_chain_selector, + source_pool_address, + source_pool_data, + offchain_token_data + }; + + (pool_config.callbacks.release_or_mint)(input) + } + inline fun borrow_state(): &TokenAdminRegistryState { borrow_global(state_object::object_address()) } @@ -1020,7 +1138,7 @@ module ccip::token_admin_registry { public fun mcms_entrypoint( _metadata: Object - ): option::Option acquires TokenAdminRegistryState, TokenPoolRegistration { + ): option::Option acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolConfig { let (caller, function, data) = mcms_registry::get_callback_params(@ccip, McmsCallback {}); diff --git a/contracts/ccip/ccip_offramp/sources/offramp.move b/contracts/ccip/ccip_offramp/sources/offramp.move index b902144d..253dc63f 100644 --- a/contracts/ccip/ccip_offramp/sources/offramp.move +++ b/contracts/ccip/ccip_offramp/sources/offramp.move @@ -806,8 +806,14 @@ module ccip_offramp::offramp { // module. // ref: https://github.com/smartcontractkit/chainlink-ccip/blob/875e982e6437dc126710d8224dd7c792a197bea6/chains/evm/contracts/offRamp/OffRamp.sol#L633 - if ((!message.data.is_empty() || message.gas_limit != 0) - && receiver_registry::is_registered_receiver(message.receiver)) { + let is_v1_receiver = receiver_registry::is_registered_receiver(message.receiver); + let is_v2_receiver = + receiver_registry::is_registered_receiver_v2(message.receiver); + + if ((!message.data.is_empty() + || message.gas_limit != 0) + && (is_v1_receiver + || is_v2_receiver)) { let state_signer = account::create_signer_with_capability(&state.state_signer_cap); @@ -825,9 +831,16 @@ module ccip_offramp::offramp { dest_token_amounts ); - receiver_dispatcher::dispatch_receive( - &state_signer, message.receiver, any2aptos_message - ) + // Use V2 dispatch if available, else V1 + if (is_v2_receiver) { + receiver_dispatcher::dispatch_receive_v2( + &state_signer, message.receiver, any2aptos_message + ) + } else { + receiver_dispatcher::dispatch_receive( + &state_signer, message.receiver, any2aptos_message + ) + } }; } @@ -894,7 +907,7 @@ module ccip_offramp::offramp { account::create_signer_with_capability(&state.state_signer_cap); let (fa, local_amount) = - token_admin_dispatcher::dispatch_release_or_mint( + token_admin_dispatcher::dispatch_release_or_mint_v2( &state_signer, token_pool_address, sender, diff --git a/contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move deleted file mode 100644 index 920158c0..00000000 --- a/contracts/ccip/ccip_offramp/tests/mock/burn_mint_dispatchable_receiver.move +++ /dev/null @@ -1,182 +0,0 @@ -#[test_only] -/// The `dispatchable_receiver` is designed to be used with dispatchable tokens -/// with pool type `burn_mint_token_pool`. -module ccip_offramp::burn_mint_dispatchable_receiver { - use std::account; - use std::event; - use std::object::{Self, Object}; - use std::option::{Self, Option}; - use std::string::{Self, String}; - use std::fungible_asset::{Metadata}; - use std::primary_fungible_store; - use std::from_bcs; - use std::signer; - - use ccip::client; - use ccip::receiver_registry; - use burn_mint_token_pool::burn_mint_token_pool; - - #[event] - struct ReceivedMessage has store, drop { - message: String - } - - #[event] - struct ForwardedTokens has store, drop { - final_recipient: address - } - - #[event] - struct ReceivedTokensOnly has store, drop { - token_count: u64 - } - - struct CCIPReceiverState has key { - signer_cap: account::SignerCapability, - received_message_handle: event::EventHandle, - forwarded_tokens_handle: event::EventHandle, - received_tokens_only_handle: event::EventHandle - } - - const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; - const E_UNAUTHORIZED: u64 = 2; - const E_INVALID_TOKEN_ADDRESS: u64 = 3; - const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; - - #[view] - public fun type_and_version(): String { - string::utf8(b"BurnMintDispatchableReceiver 1.6.0") - } - - const MODULE_NAME: vector = b"burn_mint_dispatchable_receiver"; - - fun init_module(publisher: &signer) { - // Create a signer capability for the receiver account - let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); - - // Create a unique handle for each event type - let received_message_handle = - account::new_event_handle(publisher); - let forwarded_tokens_handle = - account::new_event_handle(publisher); - let received_tokens_only_handle = - account::new_event_handle(publisher); - - // Move all state into the single resource struct - move_to( - publisher, - CCIPReceiverState { - signer_cap, - received_message_handle, - forwarded_tokens_handle, - received_tokens_only_handle - } - ); - - receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); - } - - struct CCIPReceiverProof has drop {} - - public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { - /* load state and rebuild a signer for the resource account */ - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let message = - receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); - - let data = client::get_data(&message); - - let dest_token_amounts = client::get_dest_token_amounts(&message); - - if (dest_token_amounts.length() != 0 && data.length() != 0) { - let final_recipient = from_bcs::to_address(data); - - for (i in 0..dest_token_amounts.length()) { - let token_amount_ref = &dest_token_amounts[i]; - let amount = client::get_amount(token_amount_ref); - - // For dispatchable tokens, we need to call into token pool's `transfer` function - burn_mint_token_pool::transfer(&state_signer, final_recipient, amount); - }; - - event::emit(ForwardedTokens { final_recipient }); - event::emit_event( - &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } - ); - - } else if (data.length() != 0) { - - // Convert the vector to a string - let message = string::utf8(data); - - event::emit(ReceivedMessage { message }); - event::emit_event( - &mut state.received_message_handle, ReceivedMessage { message } - ); - - } else if (dest_token_amounts.length() != 0) { - // Tokens only (no forwarding data) - keep them at receiver - // Emit event to prove receiver was called - let token_count = dest_token_amounts.length(); - event::emit(ReceivedTokensOnly { token_count }); - event::emit_event( - &mut state.received_tokens_only_handle, - ReceivedTokensOnly { token_count } - ); - }; - - // Simple abort condition for testing - if (data == b"abort") { - abort 1 - }; - - option::none() - } - - public entry fun withdraw_token( - sender: &signer, recipient: address, token_address: address - ) acquires CCIPReceiverState { - assert!( - exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT - ); - assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); - - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let fa_token = object::address_to_object(token_address); - let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); - - // Check if there are tokens available to withdraw - assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); - - primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); - } - - public fun test_init_module(publisher: &signer) { - init_module(publisher); - } - - public fun get_received_message_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.received_message_handle) - } - - public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.forwarded_tokens_handle) - } - - public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle( - &state.received_tokens_only_handle - ) - } - - public fun received_message_get_message(event: &ReceivedMessage): String { - event.message - } -} diff --git a/contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move deleted file mode 100644 index ff7aff45..00000000 --- a/contracts/ccip/ccip_offramp/tests/mock/lock_release_dispatchable_receiver.move +++ /dev/null @@ -1,182 +0,0 @@ -#[test_only] -/// The `dispatchable_receiver` is designed to be used with dispatchable tokens -/// with pool type `lock_release_token_pool`. -module ccip_offramp::lock_release_dispatchable_receiver { - use std::account; - use std::event; - use std::object::{Self, Object}; - use std::option::{Self, Option}; - use std::string::{Self, String}; - use std::fungible_asset::{Metadata}; - use std::primary_fungible_store; - use std::from_bcs; - use std::signer; - - use ccip::client; - use ccip::receiver_registry; - use lock_release_token_pool::lock_release_token_pool; - - #[event] - struct ReceivedMessage has store, drop { - message: String - } - - #[event] - struct ForwardedTokens has store, drop { - final_recipient: address - } - - #[event] - struct ReceivedTokensOnly has store, drop { - token_count: u64 - } - - struct CCIPReceiverState has key { - signer_cap: account::SignerCapability, - received_message_handle: event::EventHandle, - forwarded_tokens_handle: event::EventHandle, - received_tokens_only_handle: event::EventHandle - } - - const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; - const E_UNAUTHORIZED: u64 = 2; - const E_INVALID_TOKEN_ADDRESS: u64 = 3; - const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; - - #[view] - public fun type_and_version(): String { - string::utf8(b"LockReleaseDispatchableReceiver 1.6.0") - } - - const MODULE_NAME: vector = b"lock_release_dispatchable_receiver"; - - fun init_module(publisher: &signer) { - // Create a signer capability for the receiver account - let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); - - // Create a unique handle for each event type - let received_message_handle = - account::new_event_handle(publisher); - let forwarded_tokens_handle = - account::new_event_handle(publisher); - let received_tokens_only_handle = - account::new_event_handle(publisher); - - // Move all state into the single resource struct - move_to( - publisher, - CCIPReceiverState { - signer_cap, - received_message_handle, - forwarded_tokens_handle, - received_tokens_only_handle - } - ); - - receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); - } - - struct CCIPReceiverProof has drop {} - - public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { - /* load state and rebuild a signer for the resource account */ - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let message = - receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); - - let data = client::get_data(&message); - - let dest_token_amounts = client::get_dest_token_amounts(&message); - - if (dest_token_amounts.length() != 0 && data.length() != 0) { - let final_recipient = from_bcs::to_address(data); - - for (i in 0..dest_token_amounts.length()) { - let token_amount_ref = &dest_token_amounts[i]; - let amount = client::get_amount(token_amount_ref); - - // For dispatchable tokens, we need to call into token pool's `transfer` function - lock_release_token_pool::transfer(&state_signer, final_recipient, amount); - }; - - event::emit(ForwardedTokens { final_recipient }); - event::emit_event( - &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } - ); - - } else if (data.length() != 0) { - - // Convert the vector to a string - let message = string::utf8(data); - - event::emit(ReceivedMessage { message }); - event::emit_event( - &mut state.received_message_handle, ReceivedMessage { message } - ); - - } else if (dest_token_amounts.length() != 0) { - // Tokens only (no forwarding data) - keep them at receiver - // Emit event to prove receiver was called - let token_count = dest_token_amounts.length(); - event::emit(ReceivedTokensOnly { token_count }); - event::emit_event( - &mut state.received_tokens_only_handle, - ReceivedTokensOnly { token_count } - ); - }; - - // Simple abort condition for testing - if (data == b"abort") { - abort 1 - }; - - option::none() - } - - public entry fun withdraw_token( - sender: &signer, recipient: address, token_address: address - ) acquires CCIPReceiverState { - assert!( - exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT - ); - assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); - - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let fa_token = object::address_to_object(token_address); - let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); - - // Check if there are tokens available to withdraw - assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); - - primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); - } - - public fun test_init_module(publisher: &signer) { - init_module(publisher); - } - - public fun get_received_message_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.received_message_handle) - } - - public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.forwarded_tokens_handle) - } - - public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle( - &state.received_tokens_only_handle - ) - } - - public fun received_message_get_message(event: &ReceivedMessage): String { - event.message - } -} diff --git a/contracts/ccip/ccip_offramp/tests/mock/managed_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move similarity index 83% rename from contracts/ccip/ccip_offramp/tests/mock/managed_dispatchable_receiver.move rename to contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index c94e5313..013e6ee3 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/managed_dispatchable_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -1,11 +1,10 @@ #[test_only] -/// The `dispatchable_receiver` is designed to be used with dispatchable tokens -/// with pool type `managed_token_pool`. -module ccip_offramp::managed_dispatchable_receiver { +/// Compatible with dispatchable and non-dispatchable tokens +/// When transferring tokens, use `primary_fungible_store::transfer` as this triggers the dispatchable fungible asset hook +module ccip_offramp::mock_ccip_receiver { use std::account; use std::event; - use std::object::{Self, Object}; - use std::option::{Self, Option}; + use std::object::{Self}; use std::string::{Self, String}; use std::fungible_asset::{Metadata}; use std::primary_fungible_store; @@ -14,7 +13,6 @@ module ccip_offramp::managed_dispatchable_receiver { use ccip::client; use ccip::receiver_registry; - use managed_token_pool::managed_token_pool; #[event] struct ReceivedMessage has store, drop { @@ -45,17 +43,10 @@ module ccip_offramp::managed_dispatchable_receiver { #[view] public fun type_and_version(): String { - string::utf8(b"ManagedDispatchableReceiver 1.6.0") + string::utf8(b"MockCCIPReceiver 1.6.0") } - #[view] - public fun get_state_address(): address acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - signer::address_of(&state_signer) - } - - const MODULE_NAME: vector = b"managed_dispatchable_receiver"; + const MODULE_NAME: vector = b"mock_ccip_receiver"; fun init_module(publisher: &signer) { // Create a signer capability for the receiver account @@ -80,19 +71,28 @@ module ccip_offramp::managed_dispatchable_receiver { } ); - receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); + receiver_registry::register_receiver_v2( + publisher, + MODULE_NAME, + |message| ccip_receive(message), + CCIPReceiverProof {} + ); + } + + #[view] + public fun get_state_address(): address acquires CCIPReceiverState { + let state = borrow_global(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + signer::address_of(&state_signer) } struct CCIPReceiverProof has drop {} - public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + public fun ccip_receive(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ let state = borrow_global_mut(@ccip_offramp); let state_signer = account::create_signer_with_capability(&state.signer_cap); - let message = - receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); - let data = client::get_data(&message); let dest_token_amounts = client::get_dest_token_amounts(&message); @@ -102,19 +102,27 @@ module ccip_offramp::managed_dispatchable_receiver { for (i in 0..dest_token_amounts.length()) { let token_amount_ref = &dest_token_amounts[i]; + let token_addr = client::get_token(token_amount_ref); let amount = client::get_amount(token_amount_ref); - // For dispatchable tokens, we need to call into token pool's `transfer` function - managed_token_pool::transfer(&state_signer, final_recipient, amount); + // Implement the token transfer logic here + + let fa_token = object::address_to_object(token_addr); + + // Must use primary_fungible_store::transfer as token may be dispatchable + primary_fungible_store::transfer( + &state_signer, + fa_token, + final_recipient, + amount + ); }; event::emit(ForwardedTokens { final_recipient }); event::emit_event( &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } ); - } else if (data.length() != 0) { - // Convert the vector to a string let message = string::utf8(data); @@ -138,8 +146,6 @@ module ccip_offramp::managed_dispatchable_receiver { if (data == b"abort") { abort 1 }; - - option::none() } public entry fun withdraw_token( @@ -156,7 +162,6 @@ module ccip_offramp::managed_dispatchable_receiver { let fa_token = object::address_to_object(token_address); let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); - // Check if there are tokens available to withdraw assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); diff --git a/contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move deleted file mode 100644 index 26ef1632..00000000 --- a/contracts/ccip/ccip_offramp/tests/mock/non_dispatchable_receiver.move +++ /dev/null @@ -1,207 +0,0 @@ -#[test_only] -/// The `non_dispatchable_receiver` module should only be used with non-dispatchable tokens. -module ccip_offramp::non_dispatchable_receiver { - use std::account; - use std::event; - use std::object::{Self, Object}; - use std::option::{Self, Option}; - use std::string::{Self, String}; - use std::fungible_asset::{Self, Metadata}; - use std::primary_fungible_store; - use std::from_bcs; - use std::signer; - - use ccip::client; - use ccip::receiver_registry; - - #[event] - struct ReceivedMessage has store, drop { - message: String - } - - #[event] - struct ForwardedTokens has store, drop { - final_recipient: address - } - - #[event] - struct ReceivedTokensOnly has store, drop { - token_count: u64 - } - - struct CCIPReceiverState has key { - signer_cap: account::SignerCapability, - received_message_handle: event::EventHandle, - forwarded_tokens_handle: event::EventHandle, - received_tokens_only_handle: event::EventHandle - } - - const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; - const E_UNAUTHORIZED: u64 = 2; - const E_INVALID_TOKEN_ADDRESS: u64 = 3; - const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; - - #[view] - public fun type_and_version(): String { - string::utf8(b"NonDispatchableReceiver 1.6.0") - } - - const MODULE_NAME: vector = b"non_dispatchable_receiver"; - - fun init_module(publisher: &signer) { - // Create a signer capability for the receiver account - let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); - - // Create a unique handle for each event type - let received_message_handle = - account::new_event_handle(publisher); - let forwarded_tokens_handle = - account::new_event_handle(publisher); - let received_tokens_only_handle = - account::new_event_handle(publisher); - - // Move all state into the single resource struct - move_to( - publisher, - CCIPReceiverState { - signer_cap, - received_message_handle, - forwarded_tokens_handle, - received_tokens_only_handle - } - ); - - receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); - } - - struct CCIPReceiverProof has drop {} - - public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { - /* load state and rebuild a signer for the resource account */ - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let message = - receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); - - let data = client::get_data(&message); - - let dest_token_amounts = client::get_dest_token_amounts(&message); - - if (dest_token_amounts.length() != 0 && data.length() != 0) { - let final_recipient = from_bcs::to_address(data); - - for (i in 0..dest_token_amounts.length()) { - let token_amount_ref = &dest_token_amounts[i]; - let token_addr = client::get_token(token_amount_ref); - let amount = client::get_amount(token_amount_ref); - - // Implement the token transfer logic here - - let fa_token = object::address_to_object(token_addr); - let fa_store_sender = - primary_fungible_store::ensure_primary_store_exists( - @ccip_offramp, fa_token - ); - let fa_store_receiver = - primary_fungible_store::ensure_primary_store_exists( - final_recipient, fa_token - ); - - // For non-dispatchable tokens, we need to use `fungible_asset::transfer` - fungible_asset::transfer( - &state_signer, - fa_store_sender, - fa_store_receiver, - amount - ); - }; - - event::emit(ForwardedTokens { final_recipient }); - event::emit_event( - &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } - ); - } else if (data.length() != 0) { - // Convert the vector to a string - let message = string::utf8(data); - - event::emit(ReceivedMessage { message }); - event::emit_event( - &mut state.received_message_handle, ReceivedMessage { message } - ); - - } else if (dest_token_amounts.length() != 0) { - // Tokens only (no forwarding data) - keep them at receiver - // Emit event to prove receiver was called - let token_count = dest_token_amounts.length(); - event::emit(ReceivedTokensOnly { token_count }); - event::emit_event( - &mut state.received_tokens_only_handle, - ReceivedTokensOnly { token_count } - ); - }; - - // Simple abort condition for testing - if (data == b"abort") { - abort 1 - }; - - option::none() - } - - public entry fun withdraw_token( - sender: &signer, recipient: address, token_address: address - ) acquires CCIPReceiverState { - assert!( - exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT - ); - assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); - - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let fa_token = object::address_to_object(token_address); - let fa_store_sender = - primary_fungible_store::ensure_primary_store_exists(@ccip_offramp, fa_token); - let fa_store_receiver = - primary_fungible_store::ensure_primary_store_exists(recipient, fa_token); - - let balance = fungible_asset::balance(fa_store_sender); - - // Check if there are tokens available to withdraw - assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); - - // For non-dispatchable tokens, we need to use `fungible_asset::transfer` - fungible_asset::transfer( - &state_signer, - fa_store_sender, - fa_store_receiver, - balance - ); - } - - public fun test_init_module(publisher: &signer) { - init_module(publisher); - } - - public fun get_received_message_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.received_message_handle) - } - - public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.forwarded_tokens_handle) - } - - public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle( - &state.received_tokens_only_handle - ) - } - - public fun received_message_get_message(event: &ReceivedMessage): String { - event.message - } -} diff --git a/contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move deleted file mode 100644 index 34e6eae4..00000000 --- a/contracts/ccip/ccip_offramp/tests/mock/regulated_dispatchable_receiver.move +++ /dev/null @@ -1,189 +0,0 @@ -#[test_only] -/// The `dispatchable_receiver` is designed to be used with dispatchable tokens -/// with pool type `regulated_token_pool`. -module ccip_offramp::regulated_dispatchable_receiver { - use std::account; - use std::event; - use std::object::{Self, Object}; - use std::option::{Self, Option}; - use std::string::{Self, String}; - use std::fungible_asset::{Metadata}; - use std::primary_fungible_store; - use std::from_bcs; - use std::signer; - - use ccip::client; - use ccip::receiver_registry; - use regulated_token_pool::regulated_token_pool; - - #[event] - struct ReceivedMessage has store, drop { - message: String - } - - #[event] - struct ForwardedTokens has store, drop { - final_recipient: address - } - - #[event] - struct ReceivedTokensOnly has store, drop { - token_count: u64 - } - - struct CCIPReceiverState has key { - signer_cap: account::SignerCapability, - received_message_handle: event::EventHandle, - forwarded_tokens_handle: event::EventHandle, - received_tokens_only_handle: event::EventHandle - } - - const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; - const E_UNAUTHORIZED: u64 = 2; - const E_INVALID_TOKEN_ADDRESS: u64 = 3; - const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; - - #[view] - public fun type_and_version(): String { - string::utf8(b"RegulatedDispatchableReceiver 1.6.0") - } - - #[view] - public fun get_state_address(): address acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - signer::address_of(&state_signer) - } - - const MODULE_NAME: vector = b"regulated_dispatchable_receiver"; - - fun init_module(publisher: &signer) { - // Create a signer capability for the receiver account - let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); - - // Create a unique handle for each event type - let received_message_handle = - account::new_event_handle(publisher); - let forwarded_tokens_handle = - account::new_event_handle(publisher); - let received_tokens_only_handle = - account::new_event_handle(publisher); - - // Move all state into the single resource struct - move_to( - publisher, - CCIPReceiverState { - signer_cap, - received_message_handle, - forwarded_tokens_handle, - received_tokens_only_handle - } - ); - - receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); - } - - struct CCIPReceiverProof has drop {} - - public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { - /* load state and rebuild a signer for the resource account */ - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let message = - receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); - - let data = client::get_data(&message); - - let dest_token_amounts = client::get_dest_token_amounts(&message); - - if (dest_token_amounts.length() != 0 && data.length() != 0) { - let final_recipient = from_bcs::to_address(data); - - for (i in 0..dest_token_amounts.length()) { - let token_amount_ref = &dest_token_amounts[i]; - let amount = client::get_amount(token_amount_ref); - - // For dispatchable tokens, we need to call into token pool's `transfer` function - regulated_token_pool::transfer(&state_signer, final_recipient, amount); - }; - - event::emit(ForwardedTokens { final_recipient }); - event::emit_event( - &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } - ); - - } else if (data.length() != 0) { - - // Convert the vector to a string - let message = string::utf8(data); - - event::emit(ReceivedMessage { message }); - event::emit_event( - &mut state.received_message_handle, ReceivedMessage { message } - ); - - } else if (dest_token_amounts.length() != 0) { - // Tokens only (no forwarding data) - keep them at receiver - // Emit event to prove receiver was called - let token_count = dest_token_amounts.length(); - event::emit(ReceivedTokensOnly { token_count }); - event::emit_event( - &mut state.received_tokens_only_handle, - ReceivedTokensOnly { token_count } - ); - }; - - // Simple abort condition for testing - if (data == b"abort") { - abort 1 - }; - - option::none() - } - - public entry fun withdraw_token( - sender: &signer, recipient: address, token_address: address - ) acquires CCIPReceiverState { - assert!( - exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT - ); - assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); - - let state = borrow_global_mut(@ccip_offramp); - let state_signer = account::create_signer_with_capability(&state.signer_cap); - - let fa_token = object::address_to_object(token_address); - let balance = primary_fungible_store::balance(@ccip_offramp, fa_token); - - // Check if there are tokens available to withdraw - assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); - - primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); - } - - public fun test_init_module(publisher: &signer) { - init_module(publisher); - } - - public fun get_received_message_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.received_message_handle) - } - - public fun get_forwarded_tokens_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle(&state.forwarded_tokens_handle) - } - - public fun get_received_tokens_only_events(): vector acquires CCIPReceiverState { - let state = borrow_global(@ccip_offramp); - event::emitted_events_by_handle( - &state.received_tokens_only_handle - ) - } - - public fun received_message_get_message(event: &ReceivedMessage): String { - event.message - } -} diff --git a/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move index ad5adc9b..d96b0a70 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move @@ -9,11 +9,9 @@ module ccip_offramp::offramp_burn_mint_receiver_test { use std::bcs; use std::timestamp; - use burn_mint_token_pool::burn_mint_token_pool; use ccip_offramp::offramp_test; use ccip_offramp::offramp; - use ccip_offramp::non_dispatchable_receiver; - use ccip_offramp::burn_mint_dispatchable_receiver; + use ccip_offramp::mock_ccip_receiver; use ccip::receiver_registry; const BURN_MINT_TOKEN_POOL: u8 = 0; @@ -23,20 +21,10 @@ module ccip_offramp::offramp_burn_mint_receiver_test { const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; const GAS_LIMIT: u64 = 1000000; - fun setup_non_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { + fun setup_mock_ccip_receiver(owner: &signer, ccip_offramp: &signer) { account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); receiver_registry::init_module_for_testing(owner); - non_dispatchable_receiver::test_init_module(ccip_offramp); - } - - fun setup_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { - account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); - receiver_registry::init_module_for_testing(owner); - burn_mint_dispatchable_receiver::test_init_module(ccip_offramp); + mock_ccip_receiver::test_init_module(ccip_offramp); } struct TestMessage has drop { @@ -156,11 +144,11 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false // token is non-dispatchable ); let token_addr = object::object_address(&token_obj); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let token_amounts = offramp::test_create_any2aptos_token_transfer( @@ -188,8 +176,7 @@ module ccip_offramp::offramp_burn_mint_receiver_test { let receiver_balance = fungible_asset::balance(receiver_store); assert!(receiver_balance == 100000); - let tokens_only_events = - non_dispatchable_receiver::get_received_tokens_only_events(); + let tokens_only_events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(tokens_only_events.length() == 1); } @@ -233,10 +220,10 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false // token is non-dispatchable ); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let test_data = b"Hello from EVM chain!"; let test_message = @@ -250,12 +237,11 @@ module ccip_offramp::offramp_burn_mint_receiver_test { execute_message_and_verify_success(2, test_message, vector[]); - let received_events = non_dispatchable_receiver::get_received_message_events(); + let received_events = mock_ccip_receiver::get_received_message_events(); assert!(received_events.length() == 1); let event = received_events.borrow(0); - let event_message = - non_dispatchable_receiver::received_message_get_message(event); + let event_message = mock_ccip_receiver::received_message_get_message(event); assert!(event_message == string::utf8(test_data)); } @@ -301,11 +287,11 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false // token is non-dispatchable ); let token_addr = object::object_address(&token_obj); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let recipient_addr = signer::address_of(recipient); account::create_account_for_test(recipient_addr); @@ -344,7 +330,7 @@ module ccip_offramp::offramp_burn_mint_receiver_test { let recipient_balance = fungible_asset::balance(recipient_store); assert!(recipient_balance == 200000); - let forwarded_events = non_dispatchable_receiver::get_forwarded_tokens_events(); + let forwarded_events = mock_ccip_receiver::get_forwarded_tokens_events(); assert!(forwarded_events.length() == 1); } @@ -388,11 +374,11 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - true + true // token is dispatchable ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let token_amounts = offramp::test_create_any2aptos_token_transfer( @@ -420,8 +406,7 @@ module ccip_offramp::offramp_burn_mint_receiver_test { let receiver_balance = fungible_asset::balance(receiver_store); assert!(receiver_balance == 100000); - let tokens_only_events = - burn_mint_dispatchable_receiver::get_received_tokens_only_events(); + let tokens_only_events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(tokens_only_events.length() == 1); } @@ -465,10 +450,10 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - true + true // token is dispatchable ); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let test_data = b"Hello from EVM chain!"; let test_message = @@ -482,13 +467,11 @@ module ccip_offramp::offramp_burn_mint_receiver_test { execute_message_and_verify_success(5, test_message, vector[]); - let received_events = - burn_mint_dispatchable_receiver::get_received_message_events(); + let received_events = mock_ccip_receiver::get_received_message_events(); assert!(received_events.length() == 1); let event = received_events.borrow(0); - let event_message = - burn_mint_dispatchable_receiver::received_message_get_message(event); + let event_message = mock_ccip_receiver::received_message_get_message(event); assert!(event_message == string::utf8(test_data)); } @@ -534,11 +517,11 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - true + true // token is dispatchable ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let recipient_addr = signer::address_of(recipient); account::create_account_for_test(recipient_addr); @@ -576,65 +559,7 @@ module ccip_offramp::offramp_burn_mint_receiver_test { let recipient_balance = fungible_asset::balance(recipient_store); assert!(recipient_balance == 200000); - let forwarded_events = - burn_mint_dispatchable_receiver::get_forwarded_tokens_events(); + let forwarded_events = mock_ccip_receiver::get_forwarded_tokens_events(); assert!(forwarded_events.length() == 1); } - - // ================================================================ - // | Tests for execution context enforcement | - // ================================================================ - - #[ - test( - aptos_framework = @aptos_framework, - ccip = @ccip, - ccip_offramp = @ccip_offramp, - owner = @0x100, - burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool, - managed_token_pool = @managed_token_pool, - managed_token = @managed_token, - regulated_token_pool = @regulated_token_pool, - regulated_token = @regulated_token - ), - expected_failure( - abort_code = 327689, location = burn_mint_token_pool::burn_mint_token_pool - ) - ] - fun test_transfer_outside_ccip_receive_fails( - aptos_framework: &signer, - ccip: &signer, - ccip_offramp: &signer, - owner: &signer, - burn_mint_token_pool: &signer, - lock_release_token_pool: &signer, - managed_token_pool: &signer, - managed_token: &signer, - regulated_token_pool: &signer, - regulated_token: &signer - ) { - let (_owner_addr, _token_obj) = - offramp_test::setup( - aptos_framework, - ccip, - ccip_offramp, - owner, - burn_mint_token_pool, - lock_release_token_pool, - managed_token_pool, - managed_token, - regulated_token_pool, - regulated_token, - BURN_MINT_TOKEN_POOL, - BURN_MINT_TOKEN_SEED, - true - ); - - setup_dispatchable_receiver(owner, ccip_offramp); - - // Try to transfer tokens directly without ccip_receive context - // This should fail because is_executing_receiver_in_progress is false - burn_mint_token_pool::transfer(ccip_offramp, @0x999, 100000); - } } diff --git a/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move index fffd44f5..0438d265 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move @@ -9,11 +9,9 @@ module ccip_offramp::offramp_lock_release_receiver_test { use std::bcs; use std::timestamp; - use lock_release_token_pool::lock_release_token_pool; use ccip_offramp::offramp_test; use ccip_offramp::offramp; - use ccip_offramp::non_dispatchable_receiver; - use ccip_offramp::lock_release_dispatchable_receiver; + use ccip_offramp::mock_ccip_receiver; use ccip::receiver_registry; const LOCK_RELEASE_TOKEN_POOL: u8 = 1; @@ -23,20 +21,10 @@ module ccip_offramp::offramp_lock_release_receiver_test { const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; const GAS_LIMIT: u64 = 1000000; - fun setup_non_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { + fun setup_mock_ccip_receiver(owner: &signer, ccip_offramp: &signer) { account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); receiver_registry::init_module_for_testing(owner); - non_dispatchable_receiver::test_init_module(ccip_offramp); - } - - fun setup_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { - account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); - receiver_registry::init_module_for_testing(owner); - lock_release_dispatchable_receiver::test_init_module(ccip_offramp); + mock_ccip_receiver::test_init_module(ccip_offramp); } struct TestMessage has drop { @@ -160,7 +148,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let token_amounts = offramp::test_create_any2aptos_token_transfer( @@ -188,8 +176,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { let receiver_balance = fungible_asset::balance(receiver_store); assert!(receiver_balance == 100000); - let tokens_only_events = - non_dispatchable_receiver::get_received_tokens_only_events(); + let tokens_only_events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(tokens_only_events.length() == 1); } @@ -233,10 +220,10 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - false + false // token is non-dispatchable ); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let test_data = b"Hello from EVM chain!"; let test_message = @@ -250,12 +237,11 @@ module ccip_offramp::offramp_lock_release_receiver_test { execute_message_and_verify_success(2, test_message, vector[]); - let received_events = non_dispatchable_receiver::get_received_message_events(); + let received_events = mock_ccip_receiver::get_received_message_events(); assert!(received_events.length() == 1); let event = received_events.borrow(0); - let event_message = - non_dispatchable_receiver::received_message_get_message(event); + let event_message = mock_ccip_receiver::received_message_get_message(event); assert!(event_message == string::utf8(test_data)); } @@ -305,7 +291,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let recipient_addr = signer::address_of(recipient); account::create_account_for_test(recipient_addr); @@ -344,7 +330,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { let recipient_balance = fungible_asset::balance(recipient_store); assert!(recipient_balance == 200000); - let forwarded_events = non_dispatchable_receiver::get_forwarded_tokens_events(); + let forwarded_events = mock_ccip_receiver::get_forwarded_tokens_events(); assert!(forwarded_events.length() == 1); } @@ -392,7 +378,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let token_amounts = offramp::test_create_any2aptos_token_transfer( @@ -420,8 +406,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { let receiver_balance = fungible_asset::balance(receiver_store); assert!(receiver_balance == 100000); - let tokens_only_events = - lock_release_dispatchable_receiver::get_received_tokens_only_events(); + let tokens_only_events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(tokens_only_events.length() == 1); } @@ -468,7 +453,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { true ); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let test_data = b"Hello from EVM chain!"; let test_message = @@ -482,13 +467,11 @@ module ccip_offramp::offramp_lock_release_receiver_test { execute_message_and_verify_success(5, test_message, vector[]); - let received_events = - lock_release_dispatchable_receiver::get_received_message_events(); + let received_events = mock_ccip_receiver::get_received_message_events(); assert!(received_events.length() == 1); let event = received_events.borrow(0); - let event_message = - lock_release_dispatchable_receiver::received_message_get_message(event); + let event_message = mock_ccip_receiver::received_message_get_message(event); assert!(event_message == string::utf8(test_data)); } @@ -534,11 +517,11 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - true + true // token is dispatchable ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let recipient_addr = signer::address_of(recipient); account::create_account_for_test(recipient_addr); @@ -576,66 +559,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { let recipient_balance = fungible_asset::balance(recipient_store); assert!(recipient_balance == 200000); - let forwarded_events = - lock_release_dispatchable_receiver::get_forwarded_tokens_events(); + let forwarded_events = mock_ccip_receiver::get_forwarded_tokens_events(); assert!(forwarded_events.length() == 1); } - - // ================================================================ - // | Tests for execution context enforcement | - // ================================================================ - - #[ - test( - aptos_framework = @aptos_framework, - ccip = @ccip, - ccip_offramp = @ccip_offramp, - owner = @0x100, - burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool, - managed_token_pool = @managed_token_pool, - managed_token = @managed_token, - regulated_token_pool = @regulated_token_pool, - regulated_token = @regulated_token - ), - expected_failure( - abort_code = 327691, - location = lock_release_token_pool::lock_release_token_pool - ) - ] - fun test_transfer_outside_ccip_receive_fails( - aptos_framework: &signer, - ccip: &signer, - ccip_offramp: &signer, - owner: &signer, - burn_mint_token_pool: &signer, - lock_release_token_pool: &signer, - managed_token_pool: &signer, - managed_token: &signer, - regulated_token_pool: &signer, - regulated_token: &signer - ) { - let (_owner_addr, _token_obj) = - offramp_test::setup( - aptos_framework, - ccip, - ccip_offramp, - owner, - burn_mint_token_pool, - lock_release_token_pool, - managed_token_pool, - managed_token, - regulated_token_pool, - regulated_token, - LOCK_RELEASE_TOKEN_POOL, - LOCK_RELEASE_TOKEN_SEED, - true - ); - - setup_dispatchable_receiver(owner, ccip_offramp); - - // Try to transfer tokens directly without ccip_receive context - // This should fail because is_executing_receiver_in_progress is false - lock_release_token_pool::transfer(ccip_offramp, @0x999, 100000); - } } diff --git a/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move index b9889317..58bf1305 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move @@ -11,8 +11,7 @@ module ccip_offramp::offramp_managed_receiver_test { use ccip_offramp::offramp_test; use ccip_offramp::offramp; - use ccip_offramp::non_dispatchable_receiver; - use ccip_offramp::managed_dispatchable_receiver; + use ccip_offramp::mock_ccip_receiver; use ccip::receiver_registry; use managed_token::managed_token; use managed_token_pool::managed_token_pool; @@ -25,20 +24,10 @@ module ccip_offramp::offramp_managed_receiver_test { const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; const GAS_LIMIT: u64 = 1000000; - fun setup_non_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { + fun setup_mock_ccip_receiver(owner: &signer, ccip_offramp: &signer) { account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); receiver_registry::init_module_for_testing(owner); - non_dispatchable_receiver::test_init_module(ccip_offramp); - } - - fun setup_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { - account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); - receiver_registry::init_module_for_testing(owner); - managed_dispatchable_receiver::test_init_module(ccip_offramp); + mock_ccip_receiver::test_init_module(ccip_offramp); } struct TestMessage has drop { @@ -164,7 +153,7 @@ module ccip_offramp::offramp_managed_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); // Add to allowlist for release_or_mint let pool_address = managed_token_pool::get_store_address(); @@ -209,8 +198,7 @@ module ccip_offramp::offramp_managed_receiver_test { let receiver_balance = fungible_asset::balance(receiver_store); assert!(receiver_balance == 100000); - let tokens_only_events = - non_dispatchable_receiver::get_received_tokens_only_events(); + let tokens_only_events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(tokens_only_events.length() == 1); } @@ -257,7 +245,7 @@ module ccip_offramp::offramp_managed_receiver_test { false ); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); // Add to allowlist for lock_or_burn/release_or_mint let pool_address = managed_token_pool::get_store_address(); @@ -280,12 +268,11 @@ module ccip_offramp::offramp_managed_receiver_test { execute_message_and_verify_success(2, test_message, vector[]); - let received_events = non_dispatchable_receiver::get_received_message_events(); + let received_events = mock_ccip_receiver::get_received_message_events(); assert!(received_events.length() == 1); let event = received_events.borrow(0); - let event_message = - non_dispatchable_receiver::received_message_get_message(event); + let event_message = mock_ccip_receiver::received_message_get_message(event); assert!(event_message == string::utf8(test_data)); } @@ -335,7 +322,7 @@ module ccip_offramp::offramp_managed_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_non_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); // Add to allowlist for lock_or_burn/release_or_mint let pool_address = managed_token_pool::get_store_address(); @@ -383,7 +370,7 @@ module ccip_offramp::offramp_managed_receiver_test { let recipient_balance = fungible_asset::balance(recipient_store); assert!(recipient_balance == 200000); - let forwarded_events = non_dispatchable_receiver::get_forwarded_tokens_events(); + let forwarded_events = mock_ccip_receiver::get_forwarded_tokens_events(); assert!(forwarded_events.length() == 1); } @@ -431,7 +418,7 @@ module ccip_offramp::offramp_managed_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); // Add to allowlist for lock_or_burn/release_or_mint let pool_address = managed_token_pool::get_store_address(); @@ -443,7 +430,7 @@ module ccip_offramp::offramp_managed_receiver_test { ); // Grant receiver state signer minter and burner role for transfer during forwarding - let state_address = managed_dispatchable_receiver::get_state_address(); + let state_address = mock_ccip_receiver::get_state_address(); managed_token::apply_allowed_minter_updates( owner, vector[], vector[state_address] ); @@ -477,8 +464,7 @@ module ccip_offramp::offramp_managed_receiver_test { let receiver_balance = fungible_asset::balance(receiver_store); assert!(receiver_balance == 100000); - let tokens_only_events = - managed_dispatchable_receiver::get_received_tokens_only_events(); + let tokens_only_events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(tokens_only_events.length() == 1); } @@ -525,7 +511,7 @@ module ccip_offramp::offramp_managed_receiver_test { true ); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let test_data = b"Hello from EVM chain!"; let test_message = @@ -539,13 +525,11 @@ module ccip_offramp::offramp_managed_receiver_test { execute_message_and_verify_success(5, test_message, vector[]); - let received_events = - managed_dispatchable_receiver::get_received_message_events(); + let received_events = mock_ccip_receiver::get_received_message_events(); assert!(received_events.length() == 1); let event = received_events.borrow(0); - let event_message = - managed_dispatchable_receiver::received_message_get_message(event); + let event_message = mock_ccip_receiver::received_message_get_message(event); assert!(event_message == string::utf8(test_data)); } @@ -595,7 +579,7 @@ module ccip_offramp::offramp_managed_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); // Add to allowlist for lock_or_burn/release_or_mint let pool_address = managed_token_pool::get_store_address(); @@ -607,7 +591,7 @@ module ccip_offramp::offramp_managed_receiver_test { ); // Grant receiver state signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for transfer during forwarding - let state_address = managed_dispatchable_receiver::get_state_address(); + let state_address = mock_ccip_receiver::get_state_address(); managed_token::apply_allowed_minter_updates( owner, vector[], vector[state_address] ); @@ -651,65 +635,7 @@ module ccip_offramp::offramp_managed_receiver_test { let recipient_balance = fungible_asset::balance(recipient_store); assert!(recipient_balance == 200000); - let forwarded_events = - managed_dispatchable_receiver::get_forwarded_tokens_events(); + let forwarded_events = mock_ccip_receiver::get_forwarded_tokens_events(); assert!(forwarded_events.length() == 1); } - - // ================================================================ - // | Tests for execution context enforcement | - // ================================================================ - - #[ - test( - aptos_framework = @aptos_framework, - ccip = @ccip, - ccip_offramp = @ccip_offramp, - owner = @admin, - burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool, - managed_token_pool = @managed_token_pool, - managed_token = @managed_token, - regulated_token_pool = @regulated_token_pool, - regulated_token = @regulated_token - ), - expected_failure( - abort_code = 327689, location = managed_token_pool::managed_token_pool - ) - ] - fun test_transfer_outside_ccip_receive_fails( - aptos_framework: &signer, - ccip: &signer, - ccip_offramp: &signer, - owner: &signer, - burn_mint_token_pool: &signer, - lock_release_token_pool: &signer, - managed_token_pool: &signer, - managed_token: &signer, - regulated_token_pool: &signer, - regulated_token: &signer - ) { - let (_owner_addr, _token_obj) = - offramp_test::setup( - aptos_framework, - ccip, - ccip_offramp, - owner, - burn_mint_token_pool, - lock_release_token_pool, - managed_token_pool, - managed_token, - regulated_token_pool, - regulated_token, - MANAGED_TOKEN_POOL, - MANAGED_TOKEN_SEED, - false - ); - - setup_non_dispatchable_receiver(owner, ccip_offramp); - - // Try to transfer tokens directly without ccip_receive context - // This should fail because is_executing_receiver_in_progress is false - managed_token_pool::transfer(ccip_offramp, @0x999, 100000); - } } diff --git a/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move index 20a6a7d8..6f6f4fa7 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move @@ -10,8 +10,7 @@ module ccip_offramp::offramp_regulated_receiver_test { use ccip_offramp::offramp_test; use ccip_offramp::offramp; - use ccip_offramp::non_dispatchable_receiver; - use ccip_offramp::regulated_dispatchable_receiver; + use ccip_offramp::mock_ccip_receiver; use ccip::receiver_registry; use regulated_token::regulated_token; use regulated_token_pool::regulated_token_pool; @@ -24,20 +23,10 @@ module ccip_offramp::offramp_regulated_receiver_test { const EVM_SENDER: vector = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; const GAS_LIMIT: u64 = 1000000; - fun setup_non_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { + fun setup_mock_ccip_receiver(owner: &signer, ccip_offramp: &signer) { account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); receiver_registry::init_module_for_testing(owner); - non_dispatchable_receiver::test_init_module(ccip_offramp); - } - - fun setup_dispatchable_receiver( - owner: &signer, ccip_offramp: &signer - ) { - account::create_account_if_does_not_exist(signer::address_of(ccip_offramp)); - receiver_registry::init_module_for_testing(owner); - regulated_dispatchable_receiver::test_init_module(ccip_offramp); + mock_ccip_receiver::test_init_module(ccip_offramp); } struct TestMessage has drop { @@ -165,14 +154,14 @@ module ccip_offramp::offramp_regulated_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); // Grant pool signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for release_or_mint let pool_address = regulated_token_pool::get_store_address(); regulated_token::grant_role(owner, 6, pool_address); // Grant receiver state signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for transfer during forwarding - let state_signer_address = regulated_dispatchable_receiver::get_state_address(); + let state_signer_address = mock_ccip_receiver::get_state_address(); regulated_token::grant_role(owner, 6, state_signer_address); let token_amounts = @@ -201,8 +190,7 @@ module ccip_offramp::offramp_regulated_receiver_test { let receiver_balance = fungible_asset::balance(receiver_store); assert!(receiver_balance == 100000); - let tokens_only_events = - regulated_dispatchable_receiver::get_received_tokens_only_events(); + let tokens_only_events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(tokens_only_events.length() == 1); } @@ -249,7 +237,7 @@ module ccip_offramp::offramp_regulated_receiver_test { true ); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); let test_data = b"Hello from EVM chain!"; let test_message = @@ -263,13 +251,11 @@ module ccip_offramp::offramp_regulated_receiver_test { execute_message_and_verify_success(5, test_message, vector[]); - let received_events = - regulated_dispatchable_receiver::get_received_message_events(); + let received_events = mock_ccip_receiver::get_received_message_events(); assert!(received_events.length() == 1); let event = received_events.borrow(0); - let event_message = - regulated_dispatchable_receiver::received_message_get_message(event); + let event_message = mock_ccip_receiver::received_message_get_message(event); assert!(event_message == std::string::utf8(test_data)); } @@ -319,14 +305,14 @@ module ccip_offramp::offramp_regulated_receiver_test { ); let token_addr = object::object_address(&token_obj); - setup_dispatchable_receiver(owner, ccip_offramp); + setup_mock_ccip_receiver(owner, ccip_offramp); // Grant pool signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for release_or_mint let pool_address = regulated_token_pool::get_store_address(); regulated_token::grant_role(owner, 6, pool_address); // Grant receiver state signer BRIDGE_MINTER_OR_BURNER_ROLE (role 6) for transfer during forwarding - let state_signer_address = regulated_dispatchable_receiver::get_state_address(); + let state_signer_address = mock_ccip_receiver::get_state_address(); regulated_token::grant_role(owner, 6, state_signer_address); let recipient_addr = signer::address_of(recipient); @@ -365,65 +351,7 @@ module ccip_offramp::offramp_regulated_receiver_test { let recipient_balance = fungible_asset::balance(recipient_store); assert!(recipient_balance == 200000); - let forwarded_events = - regulated_dispatchable_receiver::get_forwarded_tokens_events(); + let forwarded_events = mock_ccip_receiver::get_forwarded_tokens_events(); assert!(forwarded_events.length() == 1); } - - // ================================================================ - // | Tests for execution context enforcement | - // ================================================================ - - #[ - test( - aptos_framework = @aptos_framework, - ccip = @ccip, - ccip_offramp = @ccip_offramp, - owner = @admin, - burn_mint_token_pool = @burn_mint_token_pool, - lock_release_token_pool = @lock_release_token_pool, - managed_token_pool = @managed_token_pool, - managed_token = @managed_token, - regulated_token_pool = @regulated_token_pool, - regulated_token = @regulated_token - ), - expected_failure( - abort_code = 327689, location = regulated_token_pool::regulated_token_pool - ) - ] - fun test_transfer_outside_ccip_receive_fails( - aptos_framework: &signer, - ccip: &signer, - ccip_offramp: &signer, - owner: &signer, - burn_mint_token_pool: &signer, - lock_release_token_pool: &signer, - managed_token_pool: &signer, - managed_token: &signer, - regulated_token_pool: &signer, - regulated_token: &signer - ) { - let (_owner_addr, _token_obj) = - offramp_test::setup( - aptos_framework, - ccip, - ccip_offramp, - owner, - burn_mint_token_pool, - lock_release_token_pool, - managed_token_pool, - managed_token, - regulated_token_pool, - regulated_token, - REGULATED_TOKEN_POOL, - REGULATED_TOKEN_SEED, - true - ); - - setup_dispatchable_receiver(owner, ccip_offramp); - - // Try to transfer tokens directly without ccip_receive context - // This should fail because is_executing_receiver_in_progress is false - regulated_token_pool::transfer(ccip_offramp, @0x999, 100000); - } } diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index 17bd6c8b..023fa3b4 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -9,8 +9,7 @@ module burn_mint_token_pool::burn_mint_token_pool { use std::string::{Self, String}; use aptos_framework::fungible_asset::{BurnRef, MintRef}; - use ccip::token_admin_registry; - use ccip::receiver_registry; + use ccip::token_admin_registry::{Self, ReleaseOrMintInputV1}; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -35,10 +34,6 @@ module burn_mint_token_pool::burn_mint_token_pool { mint_ref: Option } - struct BurnMintTokenPoolEvents has key, store { - token_pool_events: token_pool::TokenPoolEvents - } - const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; @@ -79,6 +74,7 @@ module burn_mint_token_pool::burn_mint_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; + // Register V1 pool (for backward compatibility) token_admin_registry::register_pool( publisher, token_pool_module_name, @@ -86,6 +82,18 @@ module burn_mint_token_pool::burn_mint_token_pool { CallbackProof {} ); + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + @burn_mint_local_token, + lock_or_burn_closure, + release_or_mint_closure, + CallbackProof {} + ); + // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = account::create_resource_account(publisher, STORE_OBJECT_SEED); @@ -145,32 +153,6 @@ module burn_mint_token_pool::burn_mint_token_pool { }; move_to(&store_signer, pool); - - move_to( - &store_signer, - BurnMintTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(&store_signer) - } - ); - } - - public fun initialize_token_pool_events(caller: &signer) acquires BurnMintTokenPoolState { - assert_can_initialize(signer::address_of(caller)); - - let store_signer = - &account::create_signer_with_capability(&borrow_pool().store_signer_cap); - - assert!( - !exists(signer::address_of(store_signer)), - error::already_exists(E_ALREADY_INITIALIZED) - ); - - move_to( - store_signer, - BurnMintTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(store_signer) - } - ); } // ================================================================ @@ -387,30 +369,69 @@ module burn_mint_token_pool::burn_mint_token_pool { fa } - /// Caller must be the receiver contract address when `ccip_receive` is called. - /// Transfer the fungible asset from the receiver to `to` address. - public fun transfer( - receiver: &signer, to: address, amount: u64 - ) acquires BurnMintTokenPoolState, BurnMintTokenPoolEvents { - let receiver_addr = signer::address_of(receiver); - assert!( - receiver_registry::is_executing_receiver_in_progress(receiver_addr), - error::permission_denied(E_NOT_EXECUTING_RECEIVER) + public fun lock_or_burn_v2( + fa: FungibleAsset, input: token_admin_registry::LockOrBurnInputV1 + ): token_admin_registry::LockOrBurnOutputV1 acquires BurnMintTokenPoolState { + let pool = borrow_pool_mut(); + let fa_amount = fungible_asset::amount(&fa); + + // Validate the operation (same as V1) + let dest_token_address = + token_pool::validate_lock_or_burn( + &mut pool.token_pool_state, + &fa, + &input, + fa_amount + ); + + // Burn the token + assert!(pool.burn_ref.is_some(), E_BURN_REF_NOT_SET); + fungible_asset::burn(pool.burn_ref.borrow(), fa); + + // Emit event + let remote_chain_selector = + token_admin_registry::get_lock_or_burn_remote_chain_selector(&input); + + token_pool::emit_locked_or_burned( + &mut pool.token_pool_state, fa_amount, remote_chain_selector ); + // Return output directly (no need to set in registry!) + token_admin_registry::new_lock_or_burn_output_v1( + dest_token_address, + b"" // empty dest_pool_data for burn/mint pools + ) + } + + /// V2 release_or_mint callback - receives input directly as parameter + public fun release_or_mint_v2( + input: ReleaseOrMintInputV1 + ): (FungibleAsset, u64) acquires BurnMintTokenPoolState { let pool = borrow_pool_mut(); - assert!(pool.burn_ref.is_some(), E_BURN_REF_NOT_SET); + let local_amount = + token_pool::calculate_release_or_mint_amount(&pool.token_pool_state, &input); + + // Validate the operation (same as V1) + token_pool::validate_release_or_mint( + &mut pool.token_pool_state, &input, local_amount + ); + + // Mint the amount for release assert!(pool.mint_ref.is_some(), E_MINT_REF_NOT_SET); + let fa = fungible_asset::mint(pool.mint_ref.borrow(), local_amount); - primary_fungible_store::burn(pool.burn_ref.borrow(), receiver_addr, amount); - primary_fungible_store::mint(pool.mint_ref.borrow(), to, amount); + let recipient = token_admin_registry::get_release_or_mint_receiver(&input); + let remote_chain_selector = + token_admin_registry::get_release_or_mint_remote_chain_selector(&input); - token_pool::emit_transfer( - &mut borrow_mut_events().token_pool_events, - receiver_addr, - to, - amount + token_pool::emit_released_or_minted( + &mut pool.token_pool_state, + recipient, + local_amount, + remote_chain_selector ); + + (fa, local_amount) } // ================================================================ @@ -535,10 +556,6 @@ module burn_mint_token_pool::burn_mint_token_pool { borrow_global_mut(store_address()) } - inline fun borrow_mut_events(): &mut BurnMintTokenPoolEvents { - borrow_global_mut(store_address()) - } - // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index 374e9225..b2843b60 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -9,7 +9,6 @@ module lock_release_token_pool::lock_release_token_pool { use std::signer; use std::string::{Self, String}; - use ccip::receiver_registry; use ccip::token_admin_registry; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; @@ -35,10 +34,6 @@ module lock_release_token_pool::lock_release_token_pool { rebalancer: address } - struct LockReleaseTokenPoolEvents has key, store { - token_pool_events: token_pool::TokenPoolEvents - } - const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; @@ -81,6 +76,7 @@ module lock_release_token_pool::lock_release_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; + // Register V1 pool (for backward compatibility) token_admin_registry::register_pool( publisher, token_pool_module_name, @@ -88,6 +84,18 @@ module lock_release_token_pool::lock_release_token_pool { CallbackProof {} ); + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + @lock_release_local_token, + lock_or_burn_closure, + release_or_mint_closure, + CallbackProof {} + ); + // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = account::create_resource_account(publisher, STORE_OBJECT_SEED); @@ -162,32 +170,6 @@ module lock_release_token_pool::lock_release_token_pool { rebalancer }; move_to(&store_signer, pool); - - move_to( - &store_signer, - LockReleaseTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(&store_signer) - } - ); - } - - public fun initialize_token_pool_events(caller: &signer) acquires LockReleaseTokenPoolState { - assert_can_initialize(signer::address_of(caller)); - - let store_signer = - &account::create_signer_with_capability(&borrow_pool().store_signer_cap); - - assert!( - !exists(signer::address_of(store_signer)), - error::already_exists(E_ALREADY_INITIALIZED) - ); - - move_to( - store_signer, - LockReleaseTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(store_signer) - } - ); } // ================================================================ @@ -455,33 +437,65 @@ module lock_release_token_pool::lock_release_token_pool { fa } - /// Caller must be the receiver contract address when `ccip_receive` is called. - /// Transfer the fungible asset from the receiver to `to` address. - public fun transfer( - caller: &signer, to: address, amount: u64 - ) acquires LockReleaseTokenPoolState, LockReleaseTokenPoolEvents { - let caller_addr = signer::address_of(caller); - assert!( - receiver_registry::is_executing_receiver_in_progress(caller_addr), - error::permission_denied(E_NOT_EXECUTING_RECEIVER) + public fun lock_or_burn_v2( + fa: FungibleAsset, input: token_admin_registry::LockOrBurnInputV1 + ): token_admin_registry::LockOrBurnOutputV1 acquires LockReleaseTokenPoolState { + let pool = borrow_pool_mut(); + let fa_amount = fungible_asset::amount(&fa); + + let dest_token_address = + token_pool::validate_lock_or_burn( + &mut pool.token_pool_state, + &fa, + &input, + fa_amount + ); + + // Lock the funds in the pool + primary_fungible_store::deposit(pool.store_signer_address, fa); + + let remote_chain_selector = + token_admin_registry::get_lock_or_burn_remote_chain_selector(&input); + + token_pool::emit_locked_or_burned( + &mut pool.token_pool_state, fa_amount, remote_chain_selector ); + token_admin_registry::new_lock_or_burn_output_v1( + dest_token_address, + token_pool::encode_local_decimals(&pool.token_pool_state) + ) + } + + public fun release_or_mint_v2( + input: token_admin_registry::ReleaseOrMintInputV1 + ): (FungibleAsset, u64) acquires LockReleaseTokenPoolState { let pool = borrow_pool_mut(); - assert!(pool.transfer_ref.is_some(), E_TRANSFER_REF_NOT_SET); + let local_amount = + token_pool::calculate_release_or_mint_amount(&pool.token_pool_state, &input); - primary_fungible_store::transfer_with_ref( - pool.transfer_ref.borrow(), - caller_addr, - to, - amount + token_pool::validate_release_or_mint( + &mut pool.token_pool_state, &input, local_amount ); - token_pool::emit_transfer( - &mut borrow_mut_events().token_pool_events, - caller_addr, - to, - amount + let store_signer = account::create_signer_with_capability(&pool.store_signer_cap); + let metadata = token_pool::get_fa_metadata(&pool.token_pool_state); + + // Withdraw the amount from the store for release + let fa = primary_fungible_store::withdraw(&store_signer, metadata, local_amount); + + let recipient = token_admin_registry::get_release_or_mint_receiver(&input); + let remote_chain_selector = + token_admin_registry::get_release_or_mint_remote_chain_selector(&input); + + token_pool::emit_released_or_minted( + &mut pool.token_pool_state, + recipient, + local_amount, + remote_chain_selector ); + + (fa, local_amount) } // ================================================================ @@ -723,10 +737,6 @@ module lock_release_token_pool::lock_release_token_pool { borrow_global_mut(store_address()) } - inline fun borrow_mut_events(): &mut LockReleaseTokenPoolEvents { - borrow_global_mut(store_address()) - } - // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index a160ea38..ddff6ea1 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -10,8 +10,12 @@ module managed_token_pool::managed_token_pool { use managed_token::managed_token; - use ccip::receiver_registry; - use ccip::token_admin_registry; + use ccip::token_admin_registry::{ + Self, + LockOrBurnInputV1, + LockOrBurnOutputV1, + ReleaseOrMintInputV1 + }; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -28,10 +32,6 @@ module managed_token_pool::managed_token_pool { store_signer_address: address } - struct ManagedTokenPoolEvents has key, store { - token_pool_events: token_pool::TokenPoolEvents - } - const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; @@ -66,6 +66,8 @@ module managed_token_pool::managed_token_pool { }; let managed_token_address = managed_token::token_metadata(); + + // Register V1 pool (for backward compatibility) token_admin_registry::register_pool( publisher, token_pool_module_name, @@ -73,6 +75,18 @@ module managed_token_pool::managed_token_pool { CallbackProof {} ); + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + managed_token_address, + lock_or_burn_closure, + release_or_mint_closure, + CallbackProof {} + ); + // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = account::create_resource_account(publisher, STORE_OBJECT_SEED); @@ -97,33 +111,6 @@ module managed_token_pool::managed_token_pool { }; move_to(&store_signer, pool); - - move_to( - &store_signer, - ManagedTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(&store_signer) - } - ); - } - - public fun initialize_token_pool_events(caller: &signer) acquires ManagedTokenPoolState { - let pool = borrow_pool_mut(); - ownable::assert_only_owner(signer::address_of(caller), &pool.ownable_state); - - let store_signer = - &account::create_signer_with_capability(&pool.store_signer_cap); - - assert!( - !exists(signer::address_of(store_signer)), - error::already_exists(E_ALREADY_INITIALIZED) - ); - - move_to( - store_signer, - ManagedTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(store_signer) - } - ); } // ================================================================ @@ -352,24 +339,79 @@ module managed_token_pool::managed_token_pool { fa } - /// Caller must be the receiver contract address when `ccip_receive` is called. - /// Transfer the fungible asset from the receiver to `to` address. - public fun transfer(caller: &signer, to: address, amount: u64) acquires ManagedTokenPoolEvents { - let caller_addr = signer::address_of(caller); + public fun lock_or_burn_v2( + fa: FungibleAsset, input: LockOrBurnInputV1 + ): LockOrBurnOutputV1 { + let pool = borrow_pool_mut(); + let fa_amount = fungible_asset::amount(&fa); - assert!( - receiver_registry::is_executing_receiver_in_progress(caller_addr), - error::permission_denied(E_NOT_EXECUTING_RECEIVER) + // This method validates various aspects of the lock or burn operation. If any of the + // validations fail, the transaction will abort. + let dest_token_address = + token_pool::validate_lock_or_burn( + &mut pool.token_pool_state, + &fa, + &input, + fa_amount + ); + + // Construct lock_or_burn output before we lose access to fa + let dest_pool_data = token_pool::encode_local_decimals(&pool.token_pool_state); + + // Burn the funds + let store = + primary_fungible_store::ensure_primary_store_exists( + pool.store_signer_address, fungible_asset::asset_metadata(&fa) + ); + let signer = &account::create_signer_with_capability(&pool.store_signer_cap); + fungible_asset::deposit(store, fa); + managed_token::burn(signer, pool.store_signer_address, fa_amount); + + let remote_chain_selector = + token_admin_registry::get_lock_or_burn_remote_chain_selector(&input); + + token_pool::emit_locked_or_burned( + &mut pool.token_pool_state, fa_amount, remote_chain_selector ); - managed_token::bridge_transfer(caller, to, amount); + token_admin_registry::new_lock_or_burn_output_v1( + dest_token_address, + token_pool::encode_local_decimals(&pool.token_pool_state) + ) + } + + public fun release_or_mint_v2(input: ReleaseOrMintInputV1): (FungibleAsset, u64) { + let pool = borrow_pool_mut(); + let local_amount = + token_pool::calculate_release_or_mint_amount(&pool.token_pool_state, &input); - token_pool::emit_transfer( - &mut borrow_mut_events().token_pool_events, - caller_addr, - to, - amount + token_pool::validate_release_or_mint( + &mut pool.token_pool_state, &input, local_amount ); + + // Mint the amount for release. + let local_token = token_admin_registry::get_release_or_mint_local_token(&input); + let metadata = object::address_to_object(local_token); + let store = + primary_fungible_store::ensure_primary_store_exists( + pool.store_signer_address, metadata + ); + let signer = &account::create_signer_with_capability(&pool.store_signer_cap); + managed_token::mint(signer, pool.store_signer_address, local_amount); + + let fa = fungible_asset::withdraw(signer, store, local_amount); + let recipient = token_admin_registry::get_release_or_mint_receiver(&input); + let remote_chain_selector = + token_admin_registry::get_release_or_mint_remote_chain_selector(&input); + + token_pool::emit_released_or_minted( + &mut pool.token_pool_state, + recipient, + local_amount, + remote_chain_selector + ); + + (fa, local_amount) } // ================================================================ @@ -479,10 +521,6 @@ module managed_token_pool::managed_token_pool { borrow_global_mut(store_address()) } - inline fun borrow_mut_events(): &mut ManagedTokenPoolEvents { - borrow_global_mut(store_address()) - } - // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index 4bfeb96c..67152c94 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -10,8 +10,7 @@ module regulated_token_pool::regulated_token_pool { use regulated_token::regulated_token::{Self}; - use ccip::receiver_registry; - use ccip::token_admin_registry; + use ccip::token_admin_registry::{Self, LockOrBurnInputV1, ReleaseOrMintInputV1}; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -28,10 +27,6 @@ module regulated_token_pool::regulated_token_pool { store_signer_address: address } - struct RegulatedTokenPoolEvents has key, store { - token_pool_events: token_pool::TokenPoolEvents - } - const E_NOT_PUBLISHER: u64 = 1; const E_ALREADY_INITIALIZED: u64 = 2; const E_INVALID_FUNGIBLE_ASSET: u64 = 3; @@ -67,6 +62,8 @@ module regulated_token_pool::regulated_token_pool { }; let regulated_token_address = regulated_token::token_address(); + + // Register V1 pool (for backward compatibility) token_admin_registry::register_pool( publisher, token_pool_module_name, @@ -74,6 +71,18 @@ module regulated_token_pool::regulated_token_pool { CallbackProof {} ); + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + regulated_token_address, + lock_or_burn_closure, + release_or_mint_closure, + CallbackProof {} + ); + // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = account::create_resource_account(publisher, STORE_OBJECT_SEED); @@ -96,33 +105,6 @@ module regulated_token_pool::regulated_token_pool { }; move_to(&store_signer, pool); - - move_to( - &store_signer, - RegulatedTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(&store_signer) - } - ); - } - - public fun initialize_token_pool_events(caller: &signer) acquires RegulatedTokenPoolState { - let pool = borrow_pool_mut(); - ownable::assert_only_owner(signer::address_of(caller), &pool.ownable_state); - - let store_signer = - &account::create_signer_with_capability(&pool.store_signer_cap); - - assert!( - !exists(signer::address_of(store_signer)), - error::already_exists(E_ALREADY_INITIALIZED) - ); - - move_to( - store_signer, - RegulatedTokenPoolEvents { - token_pool_events: token_pool::create_transfer_events(store_signer) - } - ); } // ================================================================ @@ -342,26 +324,64 @@ module regulated_token_pool::regulated_token_pool { fa } - /// Caller must be the receiver contract address when `ccip_receive` is called. - /// Transfer the fungible asset from the receiver to `to` address. - public fun transfer(caller: &signer, to: address, amount: u64) acquires RegulatedTokenPoolEvents { - let caller_addr = signer::address_of(caller); + public fun lock_or_burn_v2( + fa: FungibleAsset, input: LockOrBurnInputV1 + ): token_admin_registry::LockOrBurnOutputV1 acquires RegulatedTokenPoolState { + let pool = borrow_pool_mut(); + let fa_amount = fungible_asset::amount(&fa); - assert!( - receiver_registry::is_executing_receiver_in_progress(caller_addr), - error::permission_denied(E_NOT_EXECUTING_RECEIVER) + let dest_token_address = + token_pool::validate_lock_or_burn( + &mut pool.token_pool_state, + &fa, + &input, + fa_amount + ); + + let pool_signer = &account::create_signer_with_capability(&pool.store_signer_cap); + let sender = token_admin_registry::get_lock_or_burn_sender(&input); + regulated_token::bridge_burn(pool_signer, sender, fa); + + let remote_chain_selector = + token_admin_registry::get_lock_or_burn_remote_chain_selector(&input); + + token_pool::emit_locked_or_burned( + &mut pool.token_pool_state, fa_amount, remote_chain_selector + ); + + token_admin_registry::new_lock_or_burn_output_v1( + dest_token_address, + token_pool::encode_local_decimals(&pool.token_pool_state) + ) + } + + public fun release_or_mint_v2( + input: ReleaseOrMintInputV1 + ): (FungibleAsset, u64) acquires RegulatedTokenPoolState { + let pool = borrow_pool_mut(); + let local_amount = + token_pool::calculate_release_or_mint_amount(&pool.token_pool_state, &input); + + token_pool::validate_release_or_mint( + &mut pool.token_pool_state, &input, local_amount ); - // Call into regulated_token to perform transfer using TransferRef - // The caller (receiver) must have tokens and the bridge_transfer will check permissions - regulated_token::bridge_transfer(caller, to, amount); + // Mint the amount for release using regulated token's bridge mint function + let pool_signer = &account::create_signer_with_capability(&pool.store_signer_cap); + let receiver = token_admin_registry::get_release_or_mint_receiver(&input); + let fa = regulated_token::bridge_mint(pool_signer, receiver, local_amount); + + let remote_chain_selector = + token_admin_registry::get_release_or_mint_remote_chain_selector(&input); - token_pool::emit_transfer( - &mut borrow_mut_events().token_pool_events, - caller_addr, - to, - amount + token_pool::emit_released_or_minted( + &mut pool.token_pool_state, + receiver, + local_amount, + remote_chain_selector ); + + (fa, local_amount) } // ================================================================ @@ -471,10 +491,6 @@ module regulated_token_pool::regulated_token_pool { borrow_global_mut(store_address()) } - inline fun borrow_mut_events(): &mut RegulatedTokenPoolEvents { - borrow_global_mut(store_address()) - } - // ================================================================ // | Expose ownable | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move index 50a960b6..feded37d 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_test.move @@ -10,7 +10,6 @@ module regulated_token_pool::regulated_token_pool_test { use ccip::state_object; use ccip::auth; use ccip::token_admin_registry; - use ccip::receiver_registry; use regulated_token::regulated_token; use regulated_token_pool::regulated_token_pool; @@ -794,44 +793,4 @@ module regulated_token_pool::regulated_token_pool_test { assert!(regulated_token_pool::pending_transfer_to().is_none()); assert!(regulated_token_pool::pending_transfer_accepted().is_none()); } - - // ================================================================ - // | Tests for execution context enforcement | - // ================================================================ - - #[ - test( - admin = @admin, - regulated_token = @regulated_token, - regulated_token_pool = @regulated_token_pool, - framework = @aptos_framework, - ccip = @ccip, - random_signer = @0x999 - ), - expected_failure( - abort_code = 327689, location = regulated_token_pool::regulated_token_pool - ) - ] - fun test_transfer_outside_ccip_receive_fails( - admin: &signer, - regulated_token: &signer, - regulated_token_pool: &signer, - framework: &signer, - ccip: &signer, - random_signer: &signer - ) { - setup( - admin, - regulated_token, - regulated_token_pool, - framework, - ccip - ); - - receiver_registry::init_module_for_testing(admin); - - // Try to transfer tokens directly without ccip_receive context - // This should fail because is_executing_receiver_in_progress is false - regulated_token_pool::transfer(random_signer, @0x777, 100000); - } } diff --git a/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move b/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move index 70d21df2..b7dc5b2e 100644 --- a/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move +++ b/contracts/ccip/ccip_token_pools/token_pool/sources/token_pool.move @@ -35,10 +35,6 @@ module ccip_token_pool::token_pool { rebalancer_set_events: EventHandle } - struct TokenPoolEvents has key, store { - transfer_events: EventHandle - } - struct RemoteChainConfig has store, drop, copy { remote_token_address: vector, remote_pools: vector> @@ -112,13 +108,6 @@ module ccip_token_pool::token_pool { new_rebalancer: address } - #[event] - struct Transfer has store, drop { - from: address, - to: address, - amount: u64 - } - const E_NOT_ALLOWED_CALLER: u64 = 1; const E_UNKNOWN_FUNGIBLE_ASSET: u64 = 2; const E_UNKNOWN_REMOTE_CHAIN_SELECTOR: u64 = 3; @@ -160,10 +149,6 @@ module ccip_token_pool::token_pool { } } - public fun create_transfer_events(event_account: &signer): TokenPoolEvents { - TokenPoolEvents { transfer_events: account::new_event_handle(event_account) } - } - #[view] public fun get_router(): address { @ccip @@ -496,18 +481,6 @@ module ccip_token_pool::token_pool { ); } - public fun emit_transfer( - events: &mut TokenPoolEvents, - from: address, - to: address, - amount: u64 - ) { - event::emit_event( - &mut events.transfer_events, - Transfer { from, to, amount } - ); - } - // ================================================================ // | Decimals | // ================================================================ diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index 3cca95b9..e3aaf550 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -13,7 +13,12 @@ module usdc_token_pool::usdc_token_pool { use ccip::address; use ccip::eth_abi; - use ccip::token_admin_registry; + use ccip::token_admin_registry::{ + Self, + LockOrBurnInputV1, + ReleaseOrMintInputV1, + LockOrBurnOutputV1 + }; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -120,6 +125,18 @@ module usdc_token_pool::usdc_token_pool { CallbackProof {} ); + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + @local_token, + lock_or_burn_closure, + release_or_mint_closure, + CallbackProof {} + ); + // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = account::create_resource_account(publisher, STORE_OBJECT_SEED); @@ -491,6 +508,112 @@ module usdc_token_pool::usdc_token_pool { ); } + public fun lock_or_burn_v2( + fa: FungibleAsset, input: LockOrBurnInputV1 + ): LockOrBurnOutputV1 acquires USDCTokenPoolState { + let pool = borrow_pool_mut(); + let fa_amount = fungible_asset::amount(&fa); + + let dest_token_address = + token_pool::validate_lock_or_burn( + &mut pool.token_pool_state, + &fa, + &input, + fa_amount + ); + + let store_signer = account::create_signer_with_capability(&pool.store_signer_cap); + + let remote_chain_selector = + token_admin_registry::get_lock_or_burn_remote_chain_selector(&input); + assert!( + pool.chain_to_domain.contains(remote_chain_selector), + error::invalid_argument(E_DOMAIN_NOT_FOUND) + ); + + let remote_domain_info = pool.chain_to_domain.borrow(remote_chain_selector); + + assert!( + remote_domain_info.enabled, + error::invalid_argument(E_DOMAIN_DISABLED) + ); + + let mint_recipient_bytes = + token_admin_registry::get_lock_or_burn_receiver(&input); + let mint_recipient = from_bcs::to_address(mint_recipient_bytes); + let nonce = + token_messenger::deposit_for_burn_with_caller( + &store_signer, + fa, + remote_domain_info.domain_identifier, + mint_recipient, + from_bcs::to_address(remote_domain_info.allowed_caller) + ); + + let dest_pool_data = encode_dest_pool_data(pool.local_domain_identifier, nonce); + + token_pool::emit_locked_or_burned( + &mut pool.token_pool_state, fa_amount, remote_chain_selector + ); + + token_admin_registry::new_lock_or_burn_output_v1( + dest_token_address, dest_pool_data + ) + } + + public fun release_or_mint_v2( + input: ReleaseOrMintInputV1 + ): (FungibleAsset, u64) acquires USDCTokenPoolState { + let pool = borrow_pool_mut(); + let local_amount = + token_admin_registry::get_release_or_mint_source_amount(&input) as u64; + + token_pool::validate_release_or_mint( + &mut pool.token_pool_state, &input, local_amount + ); + + let store_signer = account::create_signer_with_capability(&pool.store_signer_cap); + + let (source_domain_identifier, nonce) = + decode_dest_pool_data( + token_admin_registry::get_release_or_mint_source_pool_data(&input) + ); + let offchain_token_data = + token_admin_registry::get_release_or_mint_offchain_token_data(&input); + + let (message_bytes, attestation) = + parse_message_and_attestation(offchain_token_data); + + validate_message( + &message_bytes, + source_domain_identifier, + nonce, + pool.local_domain_identifier + ); + + let receipt = + message_transmitter::receive_message( + &store_signer, &message_bytes, &attestation + ); + + assert!(token_messenger::handle_receive_message(receipt)); + + let recipient = token_admin_registry::get_release_or_mint_receiver(&input); + let remote_chain_selector = + token_admin_registry::get_release_or_mint_remote_chain_selector(&input); + + token_pool::emit_released_or_minted( + &mut pool.token_pool_state, + recipient, + local_amount, + remote_chain_selector + ); + + let fa_metadata = token_pool::get_fa_metadata(&pool.token_pool_state); + + (fungible_asset::zero(fa_metadata), local_amount) + } + // ================================================================ // | USDC Domains | // ================================================================ diff --git a/contracts/managed_token/sources/managed_token.move b/contracts/managed_token/sources/managed_token.move index 71da13b3..2dfb4360 100644 --- a/contracts/managed_token/sources/managed_token.move +++ b/contracts/managed_token/sources/managed_token.move @@ -336,35 +336,6 @@ module managed_token::managed_token { ); } - public fun bridge_transfer( - caller: &signer, to: address, amount: u64 - ) acquires TokenMetadataRefs, TokenState { - let caller_addr = signer::address_of(caller); - let state = &mut TokenState[token_state_address_internal()]; - - // Must be allowed as both minter and burner to transfer - assert_is_allowed_minter(caller_addr, state); - assert_is_allowed_burner(caller_addr, state); - - if (amount == 0) { return }; - - primary_fungible_store::transfer_with_ref( - &borrow_token_metadata_refs(state).transfer_ref, - caller_addr, - to, - amount - ); - - event::emit_event( - &mut state.burn_events, - Burn { burner: caller_addr, from: caller_addr, amount } - ); - event::emit_event( - &mut state.mint_events, - Mint { minter: caller_addr, to, amount } - ); - } - inline fun assert_is_allowed_minter( caller: address, state: &TokenState ) { diff --git a/contracts/regulated_token/sources/regulated_token.move b/contracts/regulated_token/sources/regulated_token.move index 6cf31489..0b5ea744 100644 --- a/contracts/regulated_token/sources/regulated_token.move +++ b/contracts/regulated_token/sources/regulated_token.move @@ -114,13 +114,6 @@ module regulated_token::regulated_token { amount: u64 } - #[event] - struct BridgeTransfer has drop, store { - caller: address, - to: address, - amount: u64 - } - #[event] struct MinterAdded has drop, store { admin: address, @@ -599,28 +592,6 @@ module regulated_token::regulated_token { } } - public fun bridge_transfer( - caller: &signer, to: address, amount: u64 - ) acquires TokenMetadataRefs, TokenState { - let caller_addr = signer::address_of(caller); - let state_obj = token_state_object_internal(); - let token_state = &TokenState[object::object_address(&state_obj)]; - - assert_not_paused(token_state); - assert_bridge_minter_or_burner(caller, state_obj); - assert_not_frozen(caller_addr, token_state); - assert_not_frozen(to, token_state); - - primary_fungible_store::transfer_with_ref( - &borrow_token_metadata_refs().transfer_ref, - caller_addr, - to, - amount - ); - - event::emit(BridgeTransfer { caller: caller_addr, to, amount }); - } - /// Bridge-specific function to mint tokens directly as `FungibleAsset`. /// Required because this token has dynamic dispatch enabled /// as minting to pool and calling `fungible_asset::withdraw()` reverts. From 5e02abfc3ce545747fd9d355e5b6ec2a6df52d10 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Tue, 25 Nov 2025 16:01:18 -0500 Subject: [PATCH 05/24] Update CCIP to handle v1 and v2 ccip receiver registration dispatch --- .../ccip/sources/token_admin_dispatcher.move | 57 ++++++++++++++----- .../ccip/sources/token_admin_registry.move | 57 ++++++++++++------- 2 files changed, 78 insertions(+), 36 deletions(-) diff --git a/contracts/ccip/ccip/sources/token_admin_dispatcher.move b/contracts/ccip/ccip/sources/token_admin_dispatcher.move index f0bae95f..28f05195 100644 --- a/contracts/ccip/ccip/sources/token_admin_dispatcher.move +++ b/contracts/ccip/ccip/sources/token_admin_dispatcher.move @@ -16,17 +16,29 @@ module ccip::token_admin_dispatcher { ): (vector, vector) { auth::assert_is_allowed_onramp(signer::address_of(caller)); - let dispatch_fungible_store = - token_admin_registry::start_lock_or_burn( + // Check for V2 first (preferred - uses closures) + if (token_admin_registry::has_token_pool_config(token_pool_address)) { + token_admin_registry::lock_or_burn_v2( + caller, token_pool_address, + fa, sender, remote_chain_selector, receiver - ); + ) + } else { + let dispatch_fungible_store = + token_admin_registry::start_lock_or_burn( + token_pool_address, + sender, + remote_chain_selector, + receiver + ); - dispatchable_fungible_asset::deposit(dispatch_fungible_store, fa); + dispatchable_fungible_asset::deposit(dispatch_fungible_store, fa); - token_admin_registry::finish_lock_or_burn(token_pool_address) + token_admin_registry::finish_lock_or_burn(token_pool_address) + } } public fun dispatch_release_or_mint( @@ -43,8 +55,9 @@ module ccip::token_admin_dispatcher { ): (FungibleAsset, u64) { auth::assert_is_allowed_offramp(signer::address_of(caller)); - let (dispatch_owner, dispatch_fungible_store) = - token_admin_registry::start_release_or_mint( + if (token_admin_registry::has_token_pool_config(token_pool_address)) { + token_admin_registry::release_or_mint_v2( + caller, token_pool_address, sender, receiver, @@ -54,17 +67,31 @@ module ccip::token_admin_dispatcher { source_pool_address, source_pool_data, offchain_token_data - ); + ) + } else { + let (dispatch_owner, dispatch_fungible_store) = + token_admin_registry::start_release_or_mint( + token_pool_address, + sender, + receiver, + source_amount, + local_token, + remote_chain_selector, + source_pool_address, + source_pool_data, + offchain_token_data + ); - let fa = - dispatchable_fungible_asset::withdraw( - &dispatch_owner, dispatch_fungible_store, 0 - ); + let fa = + dispatchable_fungible_asset::withdraw( + &dispatch_owner, dispatch_fungible_store, 0 + ); - let destination_amount = - token_admin_registry::finish_release_or_mint(token_pool_address); + let destination_amount = + token_admin_registry::finish_release_or_mint(token_pool_address); - (fa, destination_amount) + (fa, destination_amount) + } } // ============================================ diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index 29e50016..a7ec5063 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -86,16 +86,20 @@ module ccip::token_admin_registry { struct ReleaseOrMintOutputV1 has store, drop { destination_amount: u64 } + public fun new_lock_or_burn_output_v1( - dest_token_address: vector, - dest_pool_data: vector + dest_token_address: vector, dest_pool_data: vector ): LockOrBurnOutputV1 { LockOrBurnOutputV1 { dest_token_address, dest_pool_data } } struct TokenPoolCallbacks has drop, copy, store { - lock_or_burn: |fungible_asset::FungibleAsset, LockOrBurnInputV1| LockOrBurnOutputV1 has drop + copy + store, - release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop + copy + store, + lock_or_burn: | + fungible_asset::FungibleAsset, + LockOrBurnInputV1 + | LockOrBurnOutputV1 has drop + copy + store, + release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop + + copy + store } struct TokenPoolConfig has key { @@ -240,10 +244,18 @@ module ccip::token_admin_registry { #[view] /// Returns the local token address for the token pool. - public fun get_pool_local_token_v2(token_pool_address: address): address acquires TokenPoolConfig { + public fun get_pool_local_token_v2( + token_pool_address: address + ): address acquires TokenPoolConfig { TokenPoolConfig[token_pool_address].local_token } + #[view] + /// Returns true if token pool has TokenPoolConfig resource + public fun has_token_pool_config(token_pool_address: address): bool { + exists(token_pool_address) + } + #[view] /// returns (token_pool_address, administrator, pending_administrator) public fun get_token_config( @@ -420,8 +432,12 @@ module ccip::token_admin_registry { token_pool_account: &signer, token_pool_module_name: vector, local_token: address, - lock_or_burn: |fungible_asset::FungibleAsset, LockOrBurnInputV1| LockOrBurnOutputV1 has drop + copy + store, - release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop + copy + store, + lock_or_burn: | + fungible_asset::FungibleAsset, + LockOrBurnInputV1 + | LockOrBurnOutputV1 has drop + copy + store, + release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop + + copy + store, _proof: ProofType ) { let token_pool_address = signer::address_of(token_pool_account); @@ -507,13 +523,14 @@ module ccip::token_admin_registry { let caller_addr = signer::address_of(caller); - let pool_local_token = if (exists(token_pool_address)) { - get_pool_local_token_v2(token_pool_address) - } else if (exists(token_pool_address)) { - get_registration(token_pool_address).local_token - } else { - abort error::invalid_argument(E_POOL_NOT_REGISTERED) - }; + let pool_local_token = + if (exists(token_pool_address)) { + get_pool_local_token_v2(token_pool_address) + } else if (exists(token_pool_address)) { + get_registration(token_pool_address).local_token + } else { + abort error::invalid_argument(E_POOL_NOT_REGISTERED) + }; assert!( pool_local_token == local_token, @@ -1071,13 +1088,10 @@ module ccip::token_admin_registry { auth::assert_is_allowed_onramp(signer::address_of(caller)); let pool_config = &TokenPoolConfig[token_pool_address]; - let input = LockOrBurnInputV1 { - sender, - remote_chain_selector, - receiver - }; + let input = LockOrBurnInputV1 { sender, remote_chain_selector, receiver }; - let output = (pool_config.callbacks.lock_or_burn)(fa, input); + let output = (pool_config.callbacks.lock_or_burn) + (fa, input); (output.dest_token_address, output.dest_pool_data) } @@ -1107,7 +1121,8 @@ module ccip::token_admin_registry { offchain_token_data }; - (pool_config.callbacks.release_or_mint)(input) + (pool_config.callbacks.release_or_mint) + (input) } inline fun borrow_state(): &TokenAdminRegistryState { From b81e6ce8cc002419adefa325f9a4b813e2d9a5c1 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Tue, 25 Nov 2025 16:01:46 -0500 Subject: [PATCH 06/24] Update tests and pool modules to handle v1 and v2 ccip receive callback upgrade --- .../token_admin_registry.go | 31 +++++ .../ccip/sources/receiver_dispatcher.move | 21 ++- .../ccip/ccip/sources/receiver_registry.move | 15 +- .../ccip/sources/token_admin_dispatcher.move | 52 ------- .../ccip/ccip_offramp/sources/offramp.move | 25 +--- .../tests/mock/mock_ccip_receiver.move | 130 +++++++++++++++++- .../sources/burn_mint_token_pool.move | 59 ++++++++ .../tests/upgrade_v2.move | 50 +++++++ .../sources/lock_release_token_pool.move | 57 ++++++++ .../tests/upgrade_v2.move | 50 +++++++ .../sources/managed_token_pool.move | 58 ++++++++ .../managed_token_pool/tests/upgrade_v2.move | 44 ++++++ .../sources/regulated_token_pool.move | 55 ++++++++ .../tests/upgrade_v2.move | 44 ++++++ .../sources/usdc_token_pool.move | 6 + .../usdc_token_pool/tests/upgrade_v2.move | 50 +++++++ 16 files changed, 650 insertions(+), 97 deletions(-) create mode 100644 contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move create mode 100644 contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move create mode 100644 contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move create mode 100644 contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move create mode 100644 contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move diff --git a/bindings/ccip/token_admin_registry/token_admin_registry.go b/bindings/ccip/token_admin_registry/token_admin_registry.go index 63455917..dad08031 100644 --- a/bindings/ccip/token_admin_registry/token_admin_registry.go +++ b/bindings/ccip/token_admin_registry/token_admin_registry.go @@ -27,6 +27,7 @@ type TokenAdminRegistryInterface interface { GetPool(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, error) GetPoolLocalToken(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (aptos.AccountAddress, error) GetPoolLocalTokenV2(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (aptos.AccountAddress, error) + HasTokenPoolConfig(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (bool, error) GetTokenConfig(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, aptos.AccountAddress, aptos.AccountAddress, error) GetAllConfiguredTokens(opts *bind.CallOpts, startKey aptos.AccountAddress, maxCount uint64) ([]aptos.AccountAddress, aptos.AccountAddress, bool, error) IsAdministrator(opts *bind.CallOpts, localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bool, error) @@ -47,6 +48,7 @@ type TokenAdminRegistryEncoder interface { GetPool(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetPoolLocalToken(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetPoolLocalTokenV2(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + HasTokenPoolConfig(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetTokenConfig(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetAllConfiguredTokens(startKey aptos.AccountAddress, maxCount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) IsAdministrator(localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -305,6 +307,27 @@ func (c TokenAdminRegistryContract) GetPoolLocalTokenV2(opts *bind.CallOpts, tok return r0, nil } +func (c TokenAdminRegistryContract) HasTokenPoolConfig(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (bool, error) { + module, function, typeTags, args, err := c.tokenAdminRegistryEncoder.HasTokenPoolConfig(tokenPoolAddress) + if err != nil { + return *new(bool), err + } + + callData, err := c.Call(opts, module, function, typeTags, args) + if err != nil { + return *new(bool), err + } + + var ( + r0 bool + ) + + if err := codec.DecodeAptosJsonArray(callData, &r0); err != nil { + return *new(bool), err + } + return r0, nil +} + func (c TokenAdminRegistryContract) GetTokenConfig(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, aptos.AccountAddress, aptos.AccountAddress, error) { module, function, typeTags, args, err := c.tokenAdminRegistryEncoder.GetTokenConfig(localToken) if err != nil { @@ -460,6 +483,14 @@ func (c tokenAdminRegistryEncoder) GetPoolLocalTokenV2(tokenPoolAddress aptos.Ac }) } +func (c tokenAdminRegistryEncoder) HasTokenPoolConfig(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("has_token_pool_config", nil, []string{ + "address", + }, []any{ + tokenPoolAddress, + }) +} + func (c tokenAdminRegistryEncoder) GetTokenConfig(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("get_token_config", nil, []string{ "address", diff --git a/contracts/ccip/ccip/sources/receiver_dispatcher.move b/contracts/ccip/ccip/sources/receiver_dispatcher.move index 8b0eb783..1b5c4101 100644 --- a/contracts/ccip/ccip/sources/receiver_dispatcher.move +++ b/contracts/ccip/ccip/sources/receiver_dispatcher.move @@ -11,18 +11,13 @@ module ccip::receiver_dispatcher { ) { auth::assert_is_allowed_offramp(signer::address_of(caller)); - let dispatch_metadata = - receiver_registry::start_receive(receiver_address, message); - dispatchable_fungible_asset::derived_supply(dispatch_metadata); - receiver_registry::finish_receive(receiver_address); - } - - /// Invoke receiver's callback without token dispatchable hooks - public fun dispatch_receive_v2( - caller: &signer, receiver_address: address, message: client::Any2AptosMessage - ) { - auth::assert_is_allowed_offramp(signer::address_of(caller)); - - receiver_registry::invoke_ccip_receive_v2(receiver_address, message); + if (receiver_registry::is_registered_receiver_v2(receiver_address)) { + receiver_registry::invoke_ccip_receive_v2(receiver_address, message); + } else { + let dispatch_metadata = + receiver_registry::start_receive(receiver_address, message); + dispatchable_fungible_asset::derived_supply(dispatch_metadata); + receiver_registry::finish_receive(receiver_address); + } } } diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index fd4d2c8c..7860c2e0 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -34,7 +34,7 @@ module ccip::receiver_registry { struct CCIPReceiverRegistrationV2 has key { callback: |client::Any2AptosMessage| has drop + copy + store, - proof_typeinfo: TypeInfo, + proof_typeinfo: TypeInfo } #[event] @@ -167,7 +167,7 @@ module ccip::receiver_registry { ); move_to( - receiver_account, + receiver_account, CCIPReceiverRegistrationV2 { callback, proof_typeinfo } ); @@ -181,6 +181,7 @@ module ccip::receiver_registry { #[view] public fun is_registered_receiver(receiver_address: address): bool { exists(receiver_address) + || exists(receiver_address) } #[view] @@ -221,9 +222,7 @@ module ccip::receiver_registry { registration.dispatch_metadata } - public(friend) fun finish_receive( - receiver_address: address - ) acquires CCIPReceiverRegistration { + public(friend) fun finish_receive(receiver_address: address) acquires CCIPReceiverRegistration { let registration = get_registration_mut(receiver_address); assert!( @@ -233,8 +232,7 @@ module ccip::receiver_registry { } public(friend) fun invoke_ccip_receive_v2( - receiver_address: address, - message: client::Any2AptosMessage + receiver_address: address, message: client::Any2AptosMessage ) acquires CCIPReceiverRegistrationV2 { assert!( exists(receiver_address), @@ -242,8 +240,7 @@ module ccip::receiver_registry { ); let registration = borrow_global(receiver_address); - - (registration.callback)(message); + (registration.callback) (message); } inline fun borrow_state(): &ReceiverRegistryState { diff --git a/contracts/ccip/ccip/sources/token_admin_dispatcher.move b/contracts/ccip/ccip/sources/token_admin_dispatcher.move index 28f05195..bc0028bf 100644 --- a/contracts/ccip/ccip/sources/token_admin_dispatcher.move +++ b/contracts/ccip/ccip/sources/token_admin_dispatcher.move @@ -16,7 +16,6 @@ module ccip::token_admin_dispatcher { ): (vector, vector) { auth::assert_is_allowed_onramp(signer::address_of(caller)); - // Check for V2 first (preferred - uses closures) if (token_admin_registry::has_token_pool_config(token_pool_address)) { token_admin_registry::lock_or_burn_v2( caller, @@ -93,55 +92,4 @@ module ccip::token_admin_dispatcher { (fa, destination_amount) } } - - // ============================================ - // V2 Closure-Based Dispatch Functions - // ============================================ - - public fun dispatch_lock_or_burn_v2( - caller: &signer, - token_pool_address: address, - fa: FungibleAsset, - sender: address, - remote_chain_selector: u64, - receiver: vector - ): (vector, vector) { - token_admin_registry::lock_or_burn_v2( - caller, - token_pool_address, - fa, - sender, - remote_chain_selector, - receiver - ) - } - - public fun dispatch_release_or_mint_v2( - caller: &signer, - token_pool_address: address, - sender: vector, - receiver: address, - source_amount: u256, - local_token: address, - remote_chain_selector: u64, - source_pool_address: vector, - source_pool_data: vector, - offchain_token_data: vector - ): (FungibleAsset, u64) { - let (fa, destination_amount) = - token_admin_registry::release_or_mint_v2( - caller, - token_pool_address, - sender, - receiver, - source_amount, - local_token, - remote_chain_selector, - source_pool_address, - source_pool_data, - offchain_token_data - ); - - (fa, destination_amount) - } } diff --git a/contracts/ccip/ccip_offramp/sources/offramp.move b/contracts/ccip/ccip_offramp/sources/offramp.move index a0df4161..f0edd5de 100644 --- a/contracts/ccip/ccip_offramp/sources/offramp.move +++ b/contracts/ccip/ccip_offramp/sources/offramp.move @@ -808,14 +808,8 @@ module ccip_offramp::offramp { // module. // ref: https://github.com/smartcontractkit/chainlink-ccip/blob/875e982e6437dc126710d8224dd7c792a197bea6/chains/evm/contracts/offRamp/OffRamp.sol#L633 - let is_v1_receiver = receiver_registry::is_registered_receiver(message.receiver); - let is_v2_receiver = - receiver_registry::is_registered_receiver_v2(message.receiver); - - if ((!message.data.is_empty() - || message.gas_limit != 0) - && (is_v1_receiver - || is_v2_receiver)) { + if ((!message.data.is_empty() || message.gas_limit != 0) + && receiver_registry::is_registered_receiver(message.receiver)) { let state_signer = account::create_signer_with_capability(&state.state_signer_cap); @@ -833,16 +827,9 @@ module ccip_offramp::offramp { dest_token_amounts ); - // Use V2 dispatch if available, else V1 - if (is_v2_receiver) { - receiver_dispatcher::dispatch_receive_v2( - &state_signer, message.receiver, any2aptos_message - ) - } else { - receiver_dispatcher::dispatch_receive( - &state_signer, message.receiver, any2aptos_message - ) - } + receiver_dispatcher::dispatch_receive( + &state_signer, message.receiver, any2aptos_message + ) }; } @@ -909,7 +896,7 @@ module ccip_offramp::offramp { account::create_signer_with_capability(&state.state_signer_cap); let (fa, local_amount) = - token_admin_dispatcher::dispatch_release_or_mint_v2( + token_admin_dispatcher::dispatch_release_or_mint( &state_signer, token_pool_address, sender, diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 013e6ee3..68321e44 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -4,9 +4,10 @@ module ccip_offramp::mock_ccip_receiver { use std::account; use std::event; - use std::object::{Self}; + use std::object::{Self, Object}; use std::string::{Self, String}; - use std::fungible_asset::{Metadata}; + use std::fungible_asset::{Self, Metadata}; + use std::option::{Self, Option}; use std::primary_fungible_store; use std::from_bcs; use std::signer; @@ -71,10 +72,30 @@ module ccip_offramp::mock_ccip_receiver { } ); + // Default to V2 registration receiver_registry::register_receiver_v2( publisher, MODULE_NAME, - |message| ccip_receive(message), + |message| ccip_receive_v2(message), + CCIPReceiverProof {} + ); + } + + /// Register this receiver as V1 (dispatchable fungible asset mode) + /// This is used for testing V1 compatibility + public fun register_as_v1(publisher: &signer) { + receiver_registry::register_receiver(publisher, MODULE_NAME, CCIPReceiverProof {}); + } + + /// Migrate from V1 to V2 registration + /// This demonstrates the upgrade path from dispatchable FA to closures + public fun migrate_to_v2(publisher: &signer) { + // V2 registration will coexist with V1 + // The dispatcher will prefer V2 when both exist + receiver_registry::register_receiver_v2( + publisher, + MODULE_NAME, + |message| ccip_receive_v2(message), CCIPReceiverProof {} ); } @@ -88,7 +109,83 @@ module ccip_offramp::mock_ccip_receiver { struct CCIPReceiverProof has drop {} - public fun ccip_receive(message: client::Any2AptosMessage) acquires CCIPReceiverState { + /// This function should only be used with non-dispatchable tokens, + /// as it is currently incompatible with dispatchable tokens. + public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + /* load state and rebuild a signer for the resource account */ + let state = borrow_global_mut(@ccip_offramp); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let message = + receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); + + let data = client::get_data(&message); + + let dest_token_amounts = client::get_dest_token_amounts(&message); + + if (dest_token_amounts.length() != 0 && data.length() != 0) { + let final_recipient = from_bcs::to_address(data); + + for (i in 0..dest_token_amounts.length()) { + let token_amount_ref = &dest_token_amounts[i]; + let token_addr = client::get_token(token_amount_ref); + let amount = client::get_amount(token_amount_ref); + + // Implement the token transfer logic here + + let fa_token = object::address_to_object(token_addr); + let fa_store_sender = + primary_fungible_store::ensure_primary_store_exists( + @ccip_offramp, fa_token + ); + let fa_store_receiver = + primary_fungible_store::ensure_primary_store_exists( + final_recipient, fa_token + ); + + fungible_asset::transfer( + &state_signer, + fa_store_sender, + fa_store_receiver, + amount + ); + }; + + event::emit(ForwardedTokens { final_recipient }); + event::emit_event( + &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + ); + + } else if (data.length() != 0) { + + // Convert the vector to a string + let message = string::utf8(data); + + event::emit(ReceivedMessage { message }); + event::emit_event( + &mut state.received_message_handle, ReceivedMessage { message } + ); + + } else if (dest_token_amounts.length() != 0) { + // Tokens only (no forwarding data) - keep them at receiver + // Emit event to prove receiver was called + let token_count = dest_token_amounts.length(); + event::emit(ReceivedTokensOnly { token_count }); + event::emit_event( + &mut state.received_tokens_only_handle, + ReceivedTokensOnly { token_count } + ); + }; + + // Simple abort condition for testing + if (data == b"abort") { + abort 1 + }; + + option::none() + } + + public fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ let state = borrow_global_mut(@ccip_offramp); let state_signer = account::create_signer_with_capability(&state.signer_cap); @@ -171,6 +268,31 @@ module ccip_offramp::mock_ccip_receiver { init_module(publisher); } + /// Initialize without auto-registering (for testing V1/V2 manually) + public fun test_init_state_only(publisher: &signer) { + // Create a signer capability for the receiver account + let signer_cap = account::create_test_signer_cap(signer::address_of(publisher)); + + // Create a unique handle for each event type + let received_message_handle = + account::new_event_handle(publisher); + let forwarded_tokens_handle = + account::new_event_handle(publisher); + let received_tokens_only_handle = + account::new_event_handle(publisher); + + // Move all state into the single resource struct + move_to( + publisher, + CCIPReceiverState { + signer_cap, + received_message_handle, + forwarded_tokens_handle, + received_tokens_only_handle + } + ); + } + public fun get_received_message_events(): vector acquires CCIPReceiverState { let state = borrow_global(@ccip_offramp); event::emitted_events_by_handle(&state.received_message_handle) diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index 29b751d8..17f35994 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -85,6 +85,8 @@ module burn_mint_token_pool::burn_mint_token_pool { let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); let release_or_mint_closure = |input| release_or_mint_v2(input); + // If the contract has already been deployed with V1 and needs to be upgraded to V2, + // create a new module token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -810,4 +812,61 @@ module burn_mint_token_pool::burn_mint_token_pool { &borrow_global(state).token_pool_state ) } + + #[test_only] + /// Used for registering the pool with V2 closure-based callbacks. + public fun create_callback_proof(): CallbackProof { + CallbackProof {} + } + + #[test_only] + public fun test_init_v1(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @ccip_burn_mint_pool. + assert!( + object::object_exists(@burn_mint_local_token), + error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) + ); + let metadata = object::address_to_object(@burn_mint_local_token); + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@burn_mint_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"burn_mint_token_pool"; + + // Register the entrypoint with mcms + if (@mcms_register_entrypoints == @0x1) { + register_mcms_entrypoint(publisher, token_pool_module_name); + }; + + token_admin_registry::register_pool( + publisher, + token_pool_module_name, + @burn_mint_local_token, + CallbackProof {} + ); + + // create a resource account to be the owner of the primary FungibleStore we will use. + let (store_signer, store_signer_cap) = + account::create_resource_account(publisher, STORE_OBJECT_SEED); + + // make sure this is a valid fungible asset that is primary fungible store enabled, + // ie. created with primary_fungible_store::create_primary_store_enabled_fungible_asset + primary_fungible_store::ensure_primary_store_exists( + signer::address_of(&store_signer), metadata + ); + + move_to( + publisher, + BurnMintTokenPoolDeployment { + store_signer_cap, + ownable_state: ownable::new(&store_signer, @burn_mint_token_pool), + token_pool_state: token_pool::initialize( + &store_signer, @burn_mint_local_token, vector[] + ) + } + ); + } } diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move new file mode 100644 index 00000000..b4b45012 --- /dev/null +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move @@ -0,0 +1,50 @@ +#[test_only] +module burn_mint_token_pool::upgrade_v2 { + use std::account::{Self}; + use std::error; + use std::fungible_asset::{Metadata}; + use std::object::{Self}; + + use burn_mint_token_pool::burn_mint_token_pool; + + use ccip::token_admin_registry::{Self}; + + const E_INVALID_FUNGIBLE_ASSET: u64 = 1; + + fun init_module(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @burn_mint_token_pool. + assert!( + object::object_exists(@burn_mint_local_token), + error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) + ); + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@burn_mint_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"burn_mint_token_pool"; + + let lock_or_burn_closure = + |fa, input| burn_mint_token_pool::lock_or_burn_v2(fa, input); + let release_or_mint_closure = + |input| burn_mint_token_pool::release_or_mint_v2(input); + + // If the contract has already been deployed with V1 and needs to be upgraded to V2, + // create a new module + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + @burn_mint_local_token, + lock_or_burn_closure, + release_or_mint_closure, + burn_mint_token_pool::create_callback_proof() + ); + } + + #[test_only] + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } +} diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index 332f9203..e64e3948 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -968,6 +968,63 @@ module lock_release_token_pool::lock_release_token_pool { init_module(publisher); } + #[test_only] + /// Used for registering the pool with V2 closure-based callbacks. + public fun create_callback_proof(): CallbackProof { + CallbackProof {} + } + + #[test_only] + public fun test_init_v1(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @ccip_lock_release_pool. + assert!( + object::object_exists(@lock_release_local_token), + error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) + ); + let metadata = object::address_to_object(@lock_release_local_token); + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@lock_release_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"lock_release_token_pool"; + + // Register the entrypoint with mcms + if (@mcms_register_entrypoints == @0x1) { + register_mcms_entrypoint(publisher, token_pool_module_name); + }; + + token_admin_registry::register_pool( + publisher, + token_pool_module_name, + @lock_release_local_token, + CallbackProof {} + ); + + // create a resource account to be the owner of the primary FungibleStore we will use. + let (store_signer, store_signer_cap) = + account::create_resource_account(publisher, STORE_OBJECT_SEED); + + // make sure this is a valid fungible asset that is primary fungible store enabled, + // ie. created with primary_fungible_store::create_primary_store_enabled_fungible_asset + primary_fungible_store::ensure_primary_store_exists( + signer::address_of(&store_signer), metadata + ); + + move_to( + publisher, + LockReleaseTokenPoolDeployment { + store_signer_cap, + ownable_state: ownable::new(&store_signer, @lock_release_token_pool), + token_pool_state: token_pool::initialize( + &store_signer, @lock_release_local_token, vector[] + ) + } + ); + } + #[test_only] public fun get_locked_or_burned_events( state: address diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move new file mode 100644 index 00000000..51512a51 --- /dev/null +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move @@ -0,0 +1,50 @@ +#[test_only] +module lock_release_token_pool::upgrade_v2 { + use std::account::{Self}; + use std::error; + use std::fungible_asset::{Metadata}; + use std::object::{Self}; + + use lock_release_token_pool::lock_release_token_pool; + + use ccip::token_admin_registry::{Self}; + + const E_INVALID_FUNGIBLE_ASSET: u64 = 1; + + fun init_module(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @lock_release_token_pool. + assert!( + object::object_exists(@lock_release_local_token), + error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) + ); + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@lock_release_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"lock_release_token_pool"; + + let lock_or_burn_closure = + |fa, input| lock_release_token_pool::lock_or_burn_v2(fa, input); + let release_or_mint_closure = + |input| lock_release_token_pool::release_or_mint_v2(input); + + // If the contract has already been deployed with V1 and needs to be upgraded to V2, + // create a new module + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + @lock_release_local_token, + lock_or_burn_closure, + release_or_mint_closure, + lock_release_token_pool::create_callback_proof() + ); + } + + #[test_only] + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } +} diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index f5214f2d..4b503cd8 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -737,4 +737,62 @@ module managed_token_pool::managed_token_pool { public entry fun test_init_module(owner: &signer) { init_module(owner); } + + #[test_only] + /// Used for registering the pool with V2 closure-based callbacks. + public fun create_callback_proof(): CallbackProof { + CallbackProof {} + } + + #[test_only] + + public fun test_init_v1(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @ccip_managed_pool. + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@managed_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"managed_token_pool"; + + // Register the entrypoint with mcms + if (@mcms_register_entrypoints == @0x1) { + register_mcms_entrypoint(publisher, token_pool_module_name); + }; + + let managed_token_address = managed_token::token_metadata(); + token_admin_registry::register_pool( + publisher, + token_pool_module_name, + managed_token_address, + CallbackProof {} + ); + + // create a resource account to be the owner of the primary FungibleStore we will use. + let (store_signer, store_signer_cap) = + account::create_resource_account(publisher, STORE_OBJECT_SEED); + + let metadata = object::address_to_object(managed_token_address); + + // make sure this is a valid fungible asset that is primary fungible store enabled, + // ie. created with primary_fungible_store::create_primary_store_enabled_fungible_asset + primary_fungible_store::ensure_primary_store_exists( + signer::address_of(&store_signer), metadata + ); + + let store_signer = account::create_signer_with_capability(&store_signer_cap); + + let pool = ManagedTokenPoolState { + ownable_state: ownable::new(&store_signer, @managed_token_pool), + store_signer_address: signer::address_of(&store_signer), + store_signer_cap, + token_pool_state: token_pool::initialize( + &store_signer, managed_token_address, vector[] + ) + }; + + move_to(&store_signer, pool); + } } diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move new file mode 100644 index 00000000..77fe1faf --- /dev/null +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move @@ -0,0 +1,44 @@ +#[test_only] +module managed_token_pool::upgrade_v2 { + use std::account::{Self}; + + use managed_token::managed_token; + use managed_token_pool::managed_token_pool; + + use ccip::token_admin_registry::{Self}; + + fun init_module(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @managed_token_pool. + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@managed_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"managed_token_pool"; + + let managed_token_address = managed_token::token_metadata(); + + let lock_or_burn_closure = + |fa, input| managed_token_pool::lock_or_burn_v2(fa, input); + let release_or_mint_closure = + |input| managed_token_pool::release_or_mint_v2(input); + + // If the contract has already been deployed with V1 and needs to be upgraded to V2, + // create a new module + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + managed_token_address, + lock_or_burn_closure, + release_or_mint_closure, + managed_token_pool::create_callback_proof() + ); + } + + #[test_only] + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } +} diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index b2a285db..309889ef 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -707,4 +707,59 @@ module regulated_token_pool::regulated_token_pool { public entry fun test_init_module(owner: &signer) { init_module(owner); } + + #[test_only] + /// Used for registering the pool with V2 closure-based callbacks. + public fun create_callback_proof(): CallbackProof { + CallbackProof {} + } + + #[test_only] + public fun test_init_v1(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @regulated_token_pool. + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@regulated_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"regulated_token_pool"; + + // Register the entrypoint with mcms + if (@mcms_register_entrypoints == @0x1) { + register_mcms_entrypoint(publisher, token_pool_module_name); + }; + + let regulated_token_address = regulated_token::token_address(); + token_admin_registry::register_pool( + publisher, + token_pool_module_name, + regulated_token_address, + CallbackProof {} + ); + + // create a resource account to be the owner of the primary FungibleStore we will use. + let (store_signer, store_signer_cap) = + account::create_resource_account(publisher, STORE_OBJECT_SEED); + + let metadata = object::address_to_object(regulated_token_address); + + // make sure this is a valid fungible asset that is primary fungible store enabled, + // ie. created with primary_fungible_store::create_primary_store_enabled_fungible_asset + primary_fungible_store::ensure_primary_store_exists( + signer::address_of(&store_signer), metadata + ); + + let pool = RegulatedTokenPoolState { + ownable_state: ownable::new(&store_signer, @regulated_token_pool), + store_signer_address: signer::address_of(&store_signer), + store_signer_cap, + token_pool_state: token_pool::initialize( + &store_signer, regulated_token_address, vector[] + ) + }; + + move_to(&store_signer, pool); + } } diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move new file mode 100644 index 00000000..92a55cc9 --- /dev/null +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move @@ -0,0 +1,44 @@ +#[test_only] +module regulated_token_pool::upgrade_v2 { + use std::account::{Self}; + + use regulated_token::regulated_token::{Self}; + use regulated_token_pool::regulated_token_pool; + + use ccip::token_admin_registry::{Self}; + + fun init_module(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @regulated_token_pool. + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@regulated_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"regulated_token_pool"; + + let regulated_token_address = regulated_token::token_address(); + + let lock_or_burn_closure = + |fa, input| regulated_token_pool::lock_or_burn_v2(fa, input); + let release_or_mint_closure = + |input| regulated_token_pool::release_or_mint_v2(input); + + // If the contract has already been deployed with V1 and needs to be upgraded to V2, + // create a new module + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + regulated_token_address, + lock_or_burn_closure, + release_or_mint_closure, + regulated_token_pool::create_callback_proof() + ); + } + + #[test_only] + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } +} diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index c5846d31..f0b0a561 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -1045,4 +1045,10 @@ module usdc_token_pool::usdc_token_pool { public fun test_init_module(publisher: &signer) { init_module(publisher); } + + #[test_only] + /// Used for registering the pool with V2 closure-based callbacks. + public fun create_callback_proof(): CallbackProof { + CallbackProof {} + } } diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move new file mode 100644 index 00000000..c1fc4424 --- /dev/null +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move @@ -0,0 +1,50 @@ +#[test_only] +module usdc_token_pool::upgrade_v2 { + use std::account::{Self}; + use std::error; + use std::fungible_asset::{Metadata}; + use std::object::{Self}; + + use usdc_token_pool::usdc_token_pool; + + use ccip::token_admin_registry::{Self}; + + const E_INVALID_FUNGIBLE_ASSET: u64 = 1; + + fun init_module(publisher: &signer) { + // register the pool on deployment, because in the case of object code deployment, + // this is the only time we have a signer ref to @usdc_token_pool. + assert!( + object::object_exists(@local_token), + error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) + ); + + // create an Account on the object for event handles. + account::create_account_if_does_not_exist(@usdc_token_pool); + + // the name of this module. if incorrect, callbacks will fail to be registered and + // register_pool will revert. + let token_pool_module_name = b"usdc_token_pool"; + + let lock_or_burn_closure = |fa, input| usdc_token_pool::lock_or_burn_v2( + fa, input + ); + let release_or_mint_closure = |input| usdc_token_pool::release_or_mint_v2(input); + + // If the contract has already been deployed with V1 and needs to be upgraded to V2, + // create a new module + token_admin_registry::register_pool_v2( + publisher, + token_pool_module_name, + @local_token, + lock_or_burn_closure, + release_or_mint_closure, + usdc_token_pool::create_callback_proof() + ); + } + + #[test_only] + public fun test_init_module(publisher: &signer) { + init_module(publisher); + } +} From 51229cf391d819f1fb7daf5fb72eebd262d16f12 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Fri, 28 Nov 2025 13:40:07 -0500 Subject: [PATCH 07/24] Update tests and pool modules to handle v1 and v2 ccip receive callback upgrade --- .../offramp_burn_mint_receiver_test.move | 18 +++-- .../offramp_lock_release_receiver_test.move | 18 +++-- .../tests/offramp_managed_receiver_test.move | 18 +++-- .../offramp_regulated_receiver_test.move | 9 ++- .../ccip/ccip_offramp/tests/offramp_test.move | 66 +++++++++++++------ 5 files changed, 89 insertions(+), 40 deletions(-) diff --git a/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move index d96b0a70..c3127672 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move @@ -144,7 +144,8 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false // token is non-dispatchable + false, // token is non-dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -220,7 +221,8 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false // token is non-dispatchable + false, // token is non-dispatchable + false // use_v1_init ); setup_mock_ccip_receiver(owner, ccip_offramp); @@ -287,7 +289,8 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false // token is non-dispatchable + false, // token is non-dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -374,7 +377,8 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - true // token is dispatchable + true, // token is dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -450,7 +454,8 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - true // token is dispatchable + true, // token is dispatchable + false // use_v1_init ); setup_mock_ccip_receiver(owner, ccip_offramp); @@ -517,7 +522,8 @@ module ccip_offramp::offramp_burn_mint_receiver_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - true // token is dispatchable + true, // token is dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); diff --git a/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move index 0438d265..564ec8e4 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move @@ -144,7 +144,8 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -220,7 +221,8 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - false // token is non-dispatchable + false, // token is non-dispatchable + false // use_v1_init ); setup_mock_ccip_receiver(owner, ccip_offramp); @@ -287,7 +289,8 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -374,7 +377,8 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -450,7 +454,8 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); setup_mock_ccip_receiver(owner, ccip_offramp); @@ -517,7 +522,8 @@ module ccip_offramp::offramp_lock_release_receiver_test { regulated_token, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - true // token is dispatchable + true, // token is dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); diff --git a/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move index 58bf1305..43a54d94 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move @@ -149,7 +149,8 @@ module ccip_offramp::offramp_managed_receiver_test { regulated_token, MANAGED_TOKEN_POOL, MANAGED_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -242,7 +243,8 @@ module ccip_offramp::offramp_managed_receiver_test { regulated_token, MANAGED_TOKEN_POOL, MANAGED_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); setup_mock_ccip_receiver(owner, ccip_offramp); @@ -318,7 +320,8 @@ module ccip_offramp::offramp_managed_receiver_test { regulated_token, MANAGED_TOKEN_POOL, MANAGED_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -414,7 +417,8 @@ module ccip_offramp::offramp_managed_receiver_test { regulated_token, MANAGED_TOKEN_POOL, MANAGED_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -508,7 +512,8 @@ module ccip_offramp::offramp_managed_receiver_test { regulated_token, MANAGED_TOKEN_POOL, MANAGED_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); setup_mock_ccip_receiver(owner, ccip_offramp); @@ -575,7 +580,8 @@ module ccip_offramp::offramp_managed_receiver_test { regulated_token, MANAGED_TOKEN_POOL, MANAGED_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); diff --git a/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move index 6f6f4fa7..f9bdb9f6 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move @@ -150,7 +150,8 @@ module ccip_offramp::offramp_regulated_receiver_test { regulated_token, REGULATED_TOKEN_POOL, REGULATED_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -234,7 +235,8 @@ module ccip_offramp::offramp_regulated_receiver_test { regulated_token, REGULATED_TOKEN_POOL, REGULATED_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); setup_mock_ccip_receiver(owner, ccip_offramp); @@ -301,7 +303,8 @@ module ccip_offramp::offramp_regulated_receiver_test { regulated_token, REGULATED_TOKEN_POOL, REGULATED_TOKEN_SEED, - true + true, // is_dispatchable + false // use_v1_init ); let token_addr = object::object_address(&token_obj); diff --git a/contracts/ccip/ccip_offramp/tests/offramp_test.move b/contracts/ccip/ccip_offramp/tests/offramp_test.move index a51c14ad..cbf5b7ff 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_test.move @@ -70,6 +70,8 @@ module ccip_offramp::offramp_test { timestamp::update_global_time_for_test_secs(timestamp_seconds); } + /// use_v1_init: if true, uses test_init_v1 for token pools (V1 compatibility mode) + /// if false, uses test_init_module for token pools (V2 mode, default) public fun setup( aptos_framework: &signer, ccip: &signer, @@ -83,7 +85,8 @@ module ccip_offramp::offramp_test { regulated_token: &signer, pool_type: u8, seed: vector, - is_dispatchable: bool + is_dispatchable: bool, + use_v1_init: bool ): (address, Object) { let owner_addr = signer::address_of(owner); account::create_account_for_test(signer::address_of(burn_mint_token_pool)); @@ -147,7 +150,8 @@ module ccip_offramp::offramp_test { regulated_token, pool_type, seed, - is_dispatchable + is_dispatchable, + use_v1_init ); // Initialize fee quoter @@ -182,7 +186,8 @@ module ccip_offramp::offramp_test { regulated_token: &signer, pool_type: u8, seed: vector, - is_dispatchable: bool + is_dispatchable: bool, + use_v1_init: bool ): (Object, address) { let constructor_ref = object::create_named_object(owner, seed); @@ -214,7 +219,11 @@ module ccip_offramp::offramp_test { let token_addr = object::object_address(&metadata); if (pool_type == BURN_MINT_TOKEN_POOL) { - burn_mint_token_pool::test_init_module(burn_mint_token_pool); + if (use_v1_init) { + burn_mint_token_pool::test_init_v1(burn_mint_token_pool); + } else { + burn_mint_token_pool::test_init_module(burn_mint_token_pool); + }; burn_mint_token_pool::initialize(owner, burn_ref, mint_ref); burn_mint_token_pool::apply_chain_updates( owner, @@ -244,7 +253,11 @@ module ccip_offramp::offramp_test { signer::address_of(burn_mint_token_pool) ); } else if (pool_type == LOCK_RELEASE_TOKEN_POOL) { - lock_release_token_pool::test_init_module(lock_release_token_pool); + if (use_v1_init) { + lock_release_token_pool::test_init_v1(lock_release_token_pool); + } else { + lock_release_token_pool::test_init_module(lock_release_token_pool); + }; lock_release_token_pool::initialize( owner, option::some(transfer_ref), @@ -366,7 +379,11 @@ module ccip_offramp::offramp_test { string::utf8(b"https://regulatedtoken.com") ); - regulated_token_pool::test_init_module(regulated_token_pool); + if (use_v1_init) { + regulated_token_pool::test_init_v1(regulated_token_pool); + } else { + regulated_token_pool::test_init_module(regulated_token_pool); + }; regulated_token_pool::apply_chain_updates( owner, vector[], @@ -426,7 +443,7 @@ module ccip_offramp::offramp_test { (metadata, token_addr) } - fun initialize_offramp(owner: &signer): address { + public fun initialize_offramp(owner: &signer): address { offramp::initialize( owner, DEST_CHAIN_SELECTOR, @@ -440,7 +457,7 @@ module ccip_offramp::offramp_test { offramp::get_state_address() } - fun setup_fee_quoter( + public fun setup_fee_quoter( owner: &signer, ccip_offramp: &signer, token_addr: address ) { fee_quoter::apply_fee_token_updates(owner, vector[], vector[token_addr]); @@ -547,7 +564,8 @@ module ccip_offramp::offramp_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); // Verify initialization was successful @@ -968,7 +986,8 @@ module ccip_offramp::offramp_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let config_digest = x"000aed76a87f048dab766bc14ecdbb966f4253e309d742585062a75abfc16c38"; @@ -1162,7 +1181,8 @@ module ccip_offramp::offramp_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let merkle_root = @@ -1219,7 +1239,8 @@ module ccip_offramp::offramp_test { receiver, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ) } @@ -1265,7 +1286,8 @@ module ccip_offramp::offramp_test { receiver, LOCK_RELEASE_TOKEN_POOL, LOCK_RELEASE_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ) } @@ -1285,7 +1307,8 @@ module ccip_offramp::offramp_test { receiver: &signer, pool_type: u8, token_seed: vector, - is_dispatchable: bool + is_dispatchable: bool, + use_v1_init: bool ) { let (_owner_addr, token_obj) = setup( @@ -1301,7 +1324,8 @@ module ccip_offramp::offramp_test { regulated_token, pool_type, token_seed, - is_dispatchable + is_dispatchable, + use_v1_init ); let token_addr = object::object_address(&token_obj); @@ -1435,7 +1459,8 @@ module ccip_offramp::offramp_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let new_owner = signer::address_of(aptos_framework); account::create_account_for_test(new_owner); @@ -1488,7 +1513,8 @@ module ccip_offramp::offramp_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); let latest_price_sequence_number = offramp::get_latest_price_sequence_number(); @@ -1542,7 +1568,8 @@ module ccip_offramp::offramp_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); // E_UNKNOWN_SOURCE_CHAIN_SELECTOR @@ -1589,7 +1616,8 @@ module ccip_offramp::offramp_test { regulated_token, BURN_MINT_TOKEN_POOL, BURN_MINT_TOKEN_SEED, - false + false, // is_dispatchable + false // use_v1_init ); // E_INVALID_ROOT From 8f247b3d484e13e97fdfcbf14255307d1b4faed2 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Fri, 28 Nov 2025 13:40:56 -0500 Subject: [PATCH 08/24] Refactor lock_or_burn_v2 return values --- .../sources/burn_mint_token_pool.move | 19 ++--- .../sources/lock_release_token_pool.move | 8 +-- .../sources/managed_token_pool.move | 71 ++----------------- 3 files changed, 15 insertions(+), 83 deletions(-) diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index 17f35994..ef9bfcd5 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -7,9 +7,9 @@ module burn_mint_token_pool::burn_mint_token_pool { use std::option::{Self, Option}; use std::signer; use std::string::{Self, String}; - use aptos_framework::fungible_asset::{BurnRef, MintRef}; + use std::fungible_asset::{BurnRef, MintRef}; - use ccip::token_admin_registry::{Self, ReleaseOrMintInputV1}; + use ccip::token_admin_registry::{Self, ReleaseOrMintInputV1, LockOrBurnInputV1}; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -86,7 +86,7 @@ module burn_mint_token_pool::burn_mint_token_pool { let release_or_mint_closure = |input| release_or_mint_v2(input); // If the contract has already been deployed with V1 and needs to be upgraded to V2, - // create a new module + // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -380,12 +380,11 @@ module burn_mint_token_pool::burn_mint_token_pool { } public fun lock_or_burn_v2( - fa: FungibleAsset, input: token_admin_registry::LockOrBurnInputV1 - ): token_admin_registry::LockOrBurnOutputV1 acquires BurnMintTokenPoolState { + fa: FungibleAsset, input: LockOrBurnInputV1 + ): (vector, vector) acquires BurnMintTokenPoolState { let pool = borrow_pool_mut(); let fa_amount = fungible_asset::amount(&fa); - // Validate the operation (same as V1) let dest_token_address = token_pool::validate_lock_or_burn( &mut pool.token_pool_state, @@ -406,14 +405,9 @@ module burn_mint_token_pool::burn_mint_token_pool { &mut pool.token_pool_state, fa_amount, remote_chain_selector ); - // Return output directly (no need to set in registry!) - token_admin_registry::new_lock_or_burn_output_v1( - dest_token_address, - b"" // empty dest_pool_data for burn/mint pools - ) + (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } - /// V2 release_or_mint callback - receives input directly as parameter public fun release_or_mint_v2( input: ReleaseOrMintInputV1 ): (FungibleAsset, u64) acquires BurnMintTokenPoolState { @@ -870,3 +864,4 @@ module burn_mint_token_pool::burn_mint_token_pool { ); } } + diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index e64e3948..fbc99899 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -447,7 +447,7 @@ module lock_release_token_pool::lock_release_token_pool { public fun lock_or_burn_v2( fa: FungibleAsset, input: token_admin_registry::LockOrBurnInputV1 - ): token_admin_registry::LockOrBurnOutputV1 acquires LockReleaseTokenPoolState { + ): (vector, vector) acquires LockReleaseTokenPoolState { let pool = borrow_pool_mut(); let fa_amount = fungible_asset::amount(&fa); @@ -469,10 +469,7 @@ module lock_release_token_pool::lock_release_token_pool { &mut pool.token_pool_state, fa_amount, remote_chain_selector ); - token_admin_registry::new_lock_or_burn_output_v1( - dest_token_address, - token_pool::encode_local_decimals(&pool.token_pool_state) - ) + (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } public fun release_or_mint_v2( @@ -1043,3 +1040,4 @@ module lock_release_token_pool::lock_release_token_pool { ) } } + diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index 4b503cd8..d5230200 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -10,12 +10,7 @@ module managed_token_pool::managed_token_pool { use managed_token::managed_token; - use ccip::token_admin_registry::{ - Self, - LockOrBurnInputV1, - LockOrBurnOutputV1, - ReleaseOrMintInputV1 - }; + use ccip::token_admin_registry::{Self, LockOrBurnInputV1, ReleaseOrMintInputV1}; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -349,7 +344,7 @@ module managed_token_pool::managed_token_pool { public fun lock_or_burn_v2( fa: FungibleAsset, input: LockOrBurnInputV1 - ): LockOrBurnOutputV1 { + ): (vector, vector) { let pool = borrow_pool_mut(); let fa_amount = fungible_asset::amount(&fa); @@ -363,9 +358,6 @@ module managed_token_pool::managed_token_pool { fa_amount ); - // Construct lock_or_burn output before we lose access to fa - let dest_pool_data = token_pool::encode_local_decimals(&pool.token_pool_state); - // Burn the funds let store = primary_fungible_store::ensure_primary_store_exists( @@ -382,10 +374,7 @@ module managed_token_pool::managed_token_pool { &mut pool.token_pool_state, fa_amount, remote_chain_selector ); - token_admin_registry::new_lock_or_burn_output_v1( - dest_token_address, - token_pool::encode_local_decimals(&pool.token_pool_state) - ) + (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } public fun release_or_mint_v2(input: ReleaseOrMintInputV1): (FungibleAsset, u64) { @@ -407,6 +396,7 @@ module managed_token_pool::managed_token_pool { let signer = &account::create_signer_with_capability(&pool.store_signer_cap); managed_token::mint(signer, pool.store_signer_address, local_amount); + // Calling into `fungible_asset::withdraw` works as managed token is not dispatchable let fa = fungible_asset::withdraw(signer, store, local_amount); let recipient = token_admin_registry::get_release_or_mint_receiver(&input); let remote_chain_selector = @@ -743,56 +733,5 @@ module managed_token_pool::managed_token_pool { public fun create_callback_proof(): CallbackProof { CallbackProof {} } - - #[test_only] - - public fun test_init_v1(publisher: &signer) { - // register the pool on deployment, because in the case of object code deployment, - // this is the only time we have a signer ref to @ccip_managed_pool. - - // create an Account on the object for event handles. - account::create_account_if_does_not_exist(@managed_token_pool); - - // the name of this module. if incorrect, callbacks will fail to be registered and - // register_pool will revert. - let token_pool_module_name = b"managed_token_pool"; - - // Register the entrypoint with mcms - if (@mcms_register_entrypoints == @0x1) { - register_mcms_entrypoint(publisher, token_pool_module_name); - }; - - let managed_token_address = managed_token::token_metadata(); - token_admin_registry::register_pool( - publisher, - token_pool_module_name, - managed_token_address, - CallbackProof {} - ); - - // create a resource account to be the owner of the primary FungibleStore we will use. - let (store_signer, store_signer_cap) = - account::create_resource_account(publisher, STORE_OBJECT_SEED); - - let metadata = object::address_to_object(managed_token_address); - - // make sure this is a valid fungible asset that is primary fungible store enabled, - // ie. created with primary_fungible_store::create_primary_store_enabled_fungible_asset - primary_fungible_store::ensure_primary_store_exists( - signer::address_of(&store_signer), metadata - ); - - let store_signer = account::create_signer_with_capability(&store_signer_cap); - - let pool = ManagedTokenPoolState { - ownable_state: ownable::new(&store_signer, @managed_token_pool), - store_signer_address: signer::address_of(&store_signer), - store_signer_cap, - token_pool_state: token_pool::initialize( - &store_signer, managed_token_address, vector[] - ) - }; - - move_to(&store_signer, pool); - } } + From 55d730f7c717e568f298533e1b7ffb254bd28ff6 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Fri, 28 Nov 2025 13:42:22 -0500 Subject: [PATCH 09/24] Add V1 V2 Compatibility tests using function closures --- .../token_admin_registry.go | 13 +- .../ccip/sources/token_admin_registry.move | 32 +- .../tests/mock/mock_ccip_receiver.move | 54 +- .../ccip_offramp/tests/mock/mock_token.move | 7 +- .../offramp_v1_v2_compatibility_test.move | 562 +++++++++++++++++ .../tests/{ => mock}/mock_token.move | 12 +- .../tests/onramp_migration_test.move | 3 +- .../ccip/ccip_onramp/tests/onramp_test.move | 74 ++- .../onramp_v1_v2_pool_compatibility_test.move | 595 ++++++++++++++++++ .../tests/upgrade_v2.move | 3 +- .../tests/upgrade_v2.move | 3 +- .../managed_token_pool/tests/upgrade_v2.move | 3 +- .../sources/regulated_token_pool.move | 8 +- .../tests/upgrade_v2.move | 3 +- .../sources/usdc_token_pool.move | 14 +- .../usdc_token_pool/tests/upgrade_v2.move | 3 +- 16 files changed, 1287 insertions(+), 102 deletions(-) create mode 100644 contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move rename contracts/ccip/ccip_onramp/tests/{ => mock}/mock_token.move (77%) create mode 100644 contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move diff --git a/bindings/ccip/token_admin_registry/token_admin_registry.go b/bindings/ccip/token_admin_registry/token_admin_registry.go index dad08031..ea18548a 100644 --- a/bindings/ccip/token_admin_registry/token_admin_registry.go +++ b/bindings/ccip/token_admin_registry/token_admin_registry.go @@ -57,7 +57,6 @@ type TokenAdminRegistryEncoder interface { ProposeAdministrator(localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) TransferAdminRole(localToken aptos.AccountAddress, newAdmin aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptAdminRole(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - NewLockOrBurnOutputV1(destTokenAddress []byte, destPoolData []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StartLockOrBurn(tokenPoolAddress aptos.AccountAddress, sender aptos.AccountAddress, remoteChainSelector uint64, receiver []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) FinishLockOrBurn(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) FinishReleaseOrMint(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -65,7 +64,7 @@ type TokenAdminRegistryEncoder interface { RegisterMCMSEntrypoint() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"ccip","module":"token_admin_registry","name":"accept_admin_role","parameters":[{"name":"local_token","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_release_or_mint","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"new_lock_or_burn_output_v1","parameters":[{"name":"dest_token_address","type":"vector\u003cu8\u003e"},{"name":"dest_pool_data","type":"vector\u003cu8\u003e"}]},{"package":"ccip","module":"token_admin_registry","name":"propose_administrator","parameters":[{"name":"local_token","type":"address"},{"name":"administrator","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"register_mcms_entrypoint","parameters":null},{"package":"ccip","module":"token_admin_registry","name":"set_pool","parameters":[{"name":"local_token","type":"address"},{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"start_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"},{"name":"sender","type":"address"},{"name":"remote_chain_selector","type":"u64"},{"name":"receiver","type":"vector\u003cu8\u003e"}]},{"package":"ccip","module":"token_admin_registry","name":"transfer_admin_role","parameters":[{"name":"local_token","type":"address"},{"name":"new_admin","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"unregister_pool","parameters":[{"name":"local_token","type":"address"}]}]` +const FunctionInfo = `[{"package":"ccip","module":"token_admin_registry","name":"accept_admin_role","parameters":[{"name":"local_token","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"finish_release_or_mint","parameters":[{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"propose_administrator","parameters":[{"name":"local_token","type":"address"},{"name":"administrator","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"register_mcms_entrypoint","parameters":null},{"package":"ccip","module":"token_admin_registry","name":"set_pool","parameters":[{"name":"local_token","type":"address"},{"name":"token_pool_address","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"start_lock_or_burn","parameters":[{"name":"token_pool_address","type":"address"},{"name":"sender","type":"address"},{"name":"remote_chain_selector","type":"u64"},{"name":"receiver","type":"vector\u003cu8\u003e"}]},{"package":"ccip","module":"token_admin_registry","name":"transfer_admin_role","parameters":[{"name":"local_token","type":"address"},{"name":"new_admin","type":"address"}]},{"package":"ccip","module":"token_admin_registry","name":"unregister_pool","parameters":[{"name":"local_token","type":"address"}]}]` func NewTokenAdminRegistry(address aptos.AccountAddress, client aptos.AptosRpcClient) TokenAdminRegistryInterface { contract := bind.NewBoundContract(address, "ccip", "token_admin_registry", client) @@ -565,16 +564,6 @@ func (c tokenAdminRegistryEncoder) AcceptAdminRole(localToken aptos.AccountAddre }) } -func (c tokenAdminRegistryEncoder) NewLockOrBurnOutputV1(destTokenAddress []byte, destPoolData []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("new_lock_or_burn_output_v1", nil, []string{ - "vector", - "vector", - }, []any{ - destTokenAddress, - destPoolData, - }) -} - func (c tokenAdminRegistryEncoder) StartLockOrBurn(tokenPoolAddress aptos.AccountAddress, sender aptos.AccountAddress, remoteChainSelector uint64, receiver []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("start_lock_or_burn", nil, []string{ "address", diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index a7ec5063..8b644215 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -4,7 +4,7 @@ module ccip::token_admin_registry { use std::error; use std::event::{Self, EventHandle}; use std::function_info::{Self, FunctionInfo}; - use std::fungible_asset::{Self, Metadata, FungibleStore}; + use std::fungible_asset::{Self, Metadata, FungibleStore, FungibleAsset}; use std::object::{Self, Object, ExtendRef, TransferRef}; use std::option::{Self, Option}; use std::signer; @@ -87,19 +87,10 @@ module ccip::token_admin_registry { destination_amount: u64 } - public fun new_lock_or_burn_output_v1( - dest_token_address: vector, dest_pool_data: vector - ): LockOrBurnOutputV1 { - LockOrBurnOutputV1 { dest_token_address, dest_pool_data } - } - struct TokenPoolCallbacks has drop, copy, store { - lock_or_burn: | - fungible_asset::FungibleAsset, - LockOrBurnInputV1 - | LockOrBurnOutputV1 has drop + copy + store, - release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop - + copy + store + lock_or_burn: |FungibleAsset, LockOrBurnInputV1| (vector, vector) has drop + + copy + store, + release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) has drop + copy + store } struct TokenPoolConfig has key { @@ -432,12 +423,9 @@ module ccip::token_admin_registry { token_pool_account: &signer, token_pool_module_name: vector, local_token: address, - lock_or_burn: | - fungible_asset::FungibleAsset, - LockOrBurnInputV1 - | LockOrBurnOutputV1 has drop + copy + store, - release_or_mint: |ReleaseOrMintInputV1| (fungible_asset::FungibleAsset, u64) has drop + lock_or_burn: |FungibleAsset, LockOrBurnInputV1| (vector, vector) has drop + copy + store, + release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) has drop + copy + store, _proof: ProofType ) { let token_pool_address = signer::address_of(token_pool_account); @@ -1090,9 +1078,8 @@ module ccip::token_admin_registry { let pool_config = &TokenPoolConfig[token_pool_address]; let input = LockOrBurnInputV1 { sender, remote_chain_selector, receiver }; - let output = (pool_config.callbacks.lock_or_burn) - (fa, input); - (output.dest_token_address, output.dest_pool_data) + (pool_config.callbacks.lock_or_burn) + (fa, input) } public(friend) fun release_or_mint_v2( @@ -1106,7 +1093,7 @@ module ccip::token_admin_registry { source_pool_address: vector, source_pool_data: vector, offchain_token_data: vector - ): (fungible_asset::FungibleAsset, u64) acquires TokenPoolConfig { + ): (FungibleAsset, u64) acquires TokenPoolConfig { auth::assert_is_allowed_offramp(signer::address_of(caller)); let pool_config = &TokenPoolConfig[token_pool_address]; @@ -1351,3 +1338,4 @@ module ccip::token_admin_registry { assert!(has_more); } } + diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 68321e44..512f14d7 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -109,16 +109,11 @@ module ccip_offramp::mock_ccip_receiver { struct CCIPReceiverProof has drop {} - /// This function should only be used with non-dispatchable tokens, - /// as it is currently incompatible with dispatchable tokens. - public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { + public fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ let state = borrow_global_mut(@ccip_offramp); let state_signer = account::create_signer_with_capability(&state.signer_cap); - let message = - receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); - let data = client::get_data(&message); let dest_token_amounts = client::get_dest_token_amounts(&message); @@ -134,19 +129,12 @@ module ccip_offramp::mock_ccip_receiver { // Implement the token transfer logic here let fa_token = object::address_to_object(token_addr); - let fa_store_sender = - primary_fungible_store::ensure_primary_store_exists( - @ccip_offramp, fa_token - ); - let fa_store_receiver = - primary_fungible_store::ensure_primary_store_exists( - final_recipient, fa_token - ); - fungible_asset::transfer( + // Must use primary_fungible_store::transfer as token may be dispatchable + primary_fungible_store::transfer( &state_signer, - fa_store_sender, - fa_store_receiver, + fa_token, + final_recipient, amount ); }; @@ -155,9 +143,7 @@ module ccip_offramp::mock_ccip_receiver { event::emit_event( &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } ); - } else if (data.length() != 0) { - // Convert the vector to a string let message = string::utf8(data); @@ -181,15 +167,19 @@ module ccip_offramp::mock_ccip_receiver { if (data == b"abort") { abort 1 }; - - option::none() } - public fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { + #[deprecated] + /// Legacy V1 receive function, use ccip_receive_v2 as this supports dispatchable tokens + /// Only switch to v2 once TokenPools are migrated to V2 + public fun ccip_receive(_metadata: Object): Option acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ let state = borrow_global_mut(@ccip_offramp); let state_signer = account::create_signer_with_capability(&state.signer_cap); + let message = + receiver_registry::get_receiver_input(@ccip_offramp, CCIPReceiverProof {}); + let data = client::get_data(&message); let dest_token_amounts = client::get_dest_token_amounts(&message); @@ -205,12 +195,19 @@ module ccip_offramp::mock_ccip_receiver { // Implement the token transfer logic here let fa_token = object::address_to_object(token_addr); + let fa_store_sender = + primary_fungible_store::ensure_primary_store_exists( + @ccip_offramp, fa_token + ); + let fa_store_receiver = + primary_fungible_store::ensure_primary_store_exists( + final_recipient, fa_token + ); - // Must use primary_fungible_store::transfer as token may be dispatchable - primary_fungible_store::transfer( + fungible_asset::transfer( &state_signer, - fa_token, - final_recipient, + fa_store_sender, + fa_store_receiver, amount ); }; @@ -219,7 +216,9 @@ module ccip_offramp::mock_ccip_receiver { event::emit_event( &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } ); + } else if (data.length() != 0) { + // Convert the vector to a string let message = string::utf8(data); @@ -243,6 +242,8 @@ module ccip_offramp::mock_ccip_receiver { if (data == b"abort") { abort 1 }; + + option::none() } public entry fun withdraw_token( @@ -314,3 +315,4 @@ module ccip_offramp::mock_ccip_receiver { event.message } } + diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_token.move b/contracts/ccip/ccip_offramp/tests/mock/mock_token.move index 4c6d292c..08293318 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_token.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_token.move @@ -33,17 +33,12 @@ module ccip_offramp::mock_token { public fun deposit( store: Object, fa: FungibleAsset, transfer_ref: &TransferRef ) { - std::debug::print(&std::string::utf8(b"custom lock_or_burn called")); fungible_asset::deposit_with_ref(transfer_ref, store, fa); - std::debug::print(&std::string::utf8(b"custom lock_or_burn done")); } public fun withdraw( store: Object, amount: u64, transfer_ref: &TransferRef ): FungibleAsset { - std::debug::print(&std::string::utf8(b"custom release_or_mint called")); - let fa = fungible_asset::withdraw_with_ref(transfer_ref, store, amount); - std::debug::print(&std::string::utf8(b"custom release_or_mint done")); - fa + fungible_asset::withdraw_with_ref(transfer_ref, store, amount) } } diff --git a/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move new file mode 100644 index 00000000..ddba6e79 --- /dev/null +++ b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move @@ -0,0 +1,562 @@ +#[test_only] +/// Verifies V1 → V2 migration path and that both can coexist +module ccip_offramp::offramp_v1_v2_compatibility_test { + use std::signer; + use std::object; + use std::primary_fungible_store; + use std::timestamp; + + use ccip_offramp::offramp; + use ccip_offramp::offramp_test; + use ccip_offramp::mock_ccip_receiver; + use ccip::receiver_registry; + use ccip::token_admin_registry; + use ccip::merkle_proof; + + use burn_mint_token_pool::upgrade_v2; + + const BURN_MINT_TOKEN_POOL: u8 = 0; + const BURN_MINT_TOKEN_SEED: vector = b"TestToken"; + const EVM_SOURCE_CHAIN_SELECTOR: u64 = 909606746561742123; + const DEST_CHAIN_SELECTOR: u64 = 743186221051783445; + const MOCK_EVM_ADDRESS_VECTOR: vector = x"4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"; + const ONRAMP_ADDRESS: vector = x"47a1f0a819457f01153f35c6b6b0d42e2e16e91e"; + + // ============================================ + // Test Helper Functions + // ============================================ + + fun create_and_execute_message( + message_id: vector, + sequence_number: u64, + receiver: address, + data: vector, + token_transfers: vector, + owner: &signer + ) { + // Configure source chain if first message + if (sequence_number == 0) { + offramp::apply_source_chain_config_updates( + owner, + vector[EVM_SOURCE_CHAIN_SELECTOR], + vector[true], // is_enabled + vector[true], // is_rmn_verification_disabled + vector[ONRAMP_ADDRESS] + ); + }; + + let nonce: u64 = 0; + let sender = x"d87929a32cf0cbdc9e2d07ffc7c33344079de727"; + let gas_limit: u256 = 100000; + + let header = + offramp::test_create_ramp_message_header( + message_id, + EVM_SOURCE_CHAIN_SELECTOR, + DEST_CHAIN_SELECTOR, + sequence_number, + nonce + ); + + let message = + offramp::test_create_any2aptos_ramp_message( + header, + sender, + data, + receiver, + gas_limit, + token_transfers + ); + + let metadata_hash = + offramp::test_calculate_metadata_hash( + EVM_SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, ONRAMP_ADDRESS + ); + + let hashed_leaf = offramp::test_calculate_message_hash(&message, metadata_hash); + let proofs = vector[]; + let root = merkle_proof::merkle_root(hashed_leaf, proofs); + + // Commit root (with timestamp in the past to allow execution) + offramp::test_add_root(root, timestamp::now_seconds() - 3700); + + // Create execution report + let offchain_token_data: vector> = vector[vector[]]; + let execution_report = + offramp::test_create_execution_report( + EVM_SOURCE_CHAIN_SELECTOR, + message, + offchain_token_data, + vector[] + ); + + offramp::test_execute_single_report(execution_report); + + // Verify execution state is SUCCESS (2) + let execution_state = + offramp::get_execution_state(EVM_SOURCE_CHAIN_SELECTOR, sequence_number); + assert!(execution_state == 2); + } + + // ============================================ + // Test 1: V1 Receiver Works (Baseline) + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_v1_receiver_works( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + // Setup with V1 pool (use_v1_init = true) + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + // Setup receiver (need receiver_registry initialized) + receiver_registry::init_module_for_testing(owner); + mock_ccip_receiver::test_init_state_only(ccip_offramp); + + // Register as V1 (dispatchable FA mode) + mock_ccip_receiver::register_as_v1(ccip_offramp); + + // Verify V1 receiver registered (not V2) + assert!( + !receiver_registry::is_registered_receiver_v2( + signer::address_of(ccip_offramp) + ) + ); + assert!( + receiver_registry::is_registered_receiver(signer::address_of(ccip_offramp)) + ); + + // Pool is V1-only (test_init_v1 was called in setup) + // No public function to verify V1 pool registration, but successful execution proves it works + assert!( + !token_admin_registry::has_token_pool_config( + signer::address_of(burn_mint_token_pool) + ) + ); + + let token_addr = object::object_address(&token_obj); + let token_amount = 1000; + + // Create token transfer + let token_transfer = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, // source_pool_address + token_addr, // dest_token_address + 1000000, // dest_gas_amount + vector[], // extra_data + (token_amount as u256) // amount + ); + + // Execute message with tokens + create_and_execute_message( + x"0001", + 0, + signer::address_of(ccip_offramp), + vector[], // no data, just tokens + vector[token_transfer], + owner + ); + + // Verify tokens received by V1 receiver + let receiver_balance = + primary_fungible_store::balance(signer::address_of(ccip_offramp), token_obj); + assert!(receiver_balance == token_amount); + + // Verify V1 receiver callback was invoked via dispatchable FA + let events = mock_ccip_receiver::get_received_tokens_only_events(); + assert!(events.length() == 1); + } + + // ============================================ + // Test 2: V1 → V2 Migration Works + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_v1_to_v2_migration( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + // Setup with V1 pool (use_v1_init = true) + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + // Setup receiver (need receiver_registry initialized) + receiver_registry::init_module_for_testing(owner); + mock_ccip_receiver::test_init_state_only(ccip_offramp); + + // STEP 1: Register as V1 + mock_ccip_receiver::register_as_v1(ccip_offramp); + assert!( + !receiver_registry::is_registered_receiver_v2( + signer::address_of(ccip_offramp) + ) + ); + assert!( + receiver_registry::is_registered_receiver(signer::address_of(ccip_offramp)) + ); + + let token_addr = object::object_address(&token_obj); + let token_amount = 1000; + + // Execute message with V1 registration + let token_transfer_v1 = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + (token_amount as u256) + ); + + create_and_execute_message( + x"0002", + 0, + signer::address_of(ccip_offramp), + vector[], + vector[token_transfer_v1], + owner + ); + + // Verify V1 worked + let balance_after_v1 = + primary_fungible_store::balance(signer::address_of(ccip_offramp), token_obj); + assert!(balance_after_v1 == token_amount); + + // STEP 2: Upgrade pool to V2 (realistic upgrade pattern) + upgrade_v2::test_init_module(burn_mint_token_pool); + + // STEP 3: Migrate receiver to V2 + mock_ccip_receiver::migrate_to_v2(ccip_offramp); + + // Verify V2 is now active (V2 registration exists) + assert!( + receiver_registry::is_registered_receiver_v2(signer::address_of(ccip_offramp)) + ); + + // Execute message with V2 registration (dispatcher should prefer V2) + let token_transfer_v2 = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + (token_amount as u256) + ); + + create_and_execute_message( + x"0003", + 1, + signer::address_of(ccip_offramp), + vector[], + vector[token_transfer_v2], + owner + ); + + // Verify V2 worked - should now have 2x token_amount + let balance_after_v2 = + primary_fungible_store::balance(signer::address_of(ccip_offramp), token_obj); + assert!(balance_after_v2 == token_amount * 2); + + // Verify both V1 and V2 callbacks were invoked + let events = mock_ccip_receiver::get_received_tokens_only_events(); + assert!(events.length() == 2); // 1 from V1 execution, 1 from V2 execution + } + + // ============================================ + // Test 3: Direct V2 Registration Works + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_v2_receiver_direct( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + // Setup with V1 pool initially (use_v1_init = true) + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + // Upgrade pool to V2 immediately (realistic new deployment with V2) + upgrade_v2::test_init_module(burn_mint_token_pool); + + // Setup V2 receiver directly (default behavior) + receiver_registry::init_module_for_testing(owner); + mock_ccip_receiver::test_init_module(ccip_offramp); + + // Verify V2 receiver registered + assert!( + receiver_registry::is_registered_receiver_v2(signer::address_of(ccip_offramp)) + ); + + // Verify V2 pool registered + assert!( + token_admin_registry::has_token_pool_config( + signer::address_of(burn_mint_token_pool) + ) + ); + + let token_addr = object::object_address(&token_obj); + let token_amount = 1000; + + // Create token transfer + let token_transfer = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + (token_amount as u256) + ); + + // Execute message with tokens + create_and_execute_message( + x"0004", + 0, + signer::address_of(ccip_offramp), + vector[], + vector[token_transfer], + owner + ); + + // Verify tokens received by V2 receiver + let receiver_balance = + primary_fungible_store::balance(signer::address_of(ccip_offramp), token_obj); + assert!(receiver_balance == token_amount); + + // Verify V2 receiver callback was invoked + let events = mock_ccip_receiver::get_received_tokens_only_events(); + assert!(events.length() == 1); + } + + // ============================================ + // Test 4: Dispatcher Routes Correctly + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_dispatcher_routing( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + // Setup with V1 pool initially (use_v1_init = true) + let (_owner_addr, token_obj) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + // Upgrade pool to V2 before testing (mixed V1 receiver + V2 pool scenario) + upgrade_v2::test_init_module(burn_mint_token_pool); + + // Setup receiver (need receiver_registry initialized) + receiver_registry::init_module_for_testing(owner); + mock_ccip_receiver::test_init_state_only(ccip_offramp); + + let token_addr = object::object_address(&token_obj); + let token_amount = 500; + + // Phase 1: Register V1, verify dispatcher uses V1 path + mock_ccip_receiver::register_as_v1(ccip_offramp); + assert!( + !receiver_registry::is_registered_receiver_v2( + signer::address_of(ccip_offramp) + ) + ); + + let token_transfer_1 = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + (token_amount as u256) + ); + + create_and_execute_message( + x"0005", + 0, + signer::address_of(ccip_offramp), + vector[], + vector[token_transfer_1], + owner + ); + + let balance_1 = + primary_fungible_store::balance(signer::address_of(ccip_offramp), token_obj); + assert!(balance_1 == token_amount); + + // Phase 2: Add V2 registration, verify dispatcher now uses V2 path + mock_ccip_receiver::migrate_to_v2(ccip_offramp); + assert!( + receiver_registry::is_registered_receiver_v2(signer::address_of(ccip_offramp)) + ); + + let token_transfer_2 = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, + token_addr, + 1000000, + vector[], + (token_amount as u256) + ); + + create_and_execute_message( + x"0006", + 1, + signer::address_of(ccip_offramp), + vector[], + vector[token_transfer_2], + owner + ); + + // Should have received both transfers + let balance_2 = + primary_fungible_store::balance(signer::address_of(ccip_offramp), token_obj); + assert!(balance_2 == token_amount * 2); + + // Both callbacks should have been invoked + let events = mock_ccip_receiver::get_received_tokens_only_events(); + assert!(events.length() == 2); + } +} diff --git a/contracts/ccip/ccip_onramp/tests/mock_token.move b/contracts/ccip/ccip_onramp/tests/mock/mock_token.move similarity index 77% rename from contracts/ccip/ccip_onramp/tests/mock_token.move rename to contracts/ccip/ccip_onramp/tests/mock/mock_token.move index eded7cfc..5c60c113 100644 --- a/contracts/ccip/ccip_onramp/tests/mock_token.move +++ b/contracts/ccip/ccip_onramp/tests/mock/mock_token.move @@ -1,10 +1,9 @@ #[test_only] module ccip_onramp::mock_token { use std::fungible_asset::{Self, FungibleAsset, TransferRef}; - use std::object::{Self, Object, ConstructorRef}; + use std::object::{Object, ConstructorRef}; use std::string::{Self}; use std::option::{Self}; - use std::primary_fungible_store; public fun add_dynamic_dispatch_function( ccip_onramp_signer: &signer, constructor_ref: &ConstructorRef @@ -30,16 +29,15 @@ module ccip_onramp::mock_token { } public fun lock_or_burn( - store: Object, fa: FungibleAsset, _transfer_ref: &TransferRef + store: Object, fa: FungibleAsset, transfer_ref: &TransferRef ) { - fungible_asset::deposit(store, fa); + fungible_asset::deposit_with_ref(transfer_ref, store, fa); } public fun release_or_mint( store: Object, amount: u64, transfer_ref: &TransferRef ): FungibleAsset { - primary_fungible_store::withdraw_with_ref( - transfer_ref, object::owner(store), amount - ) + fungible_asset::withdraw_with_ref(transfer_ref, store, amount) } } + diff --git a/contracts/ccip/ccip_onramp/tests/onramp_migration_test.move b/contracts/ccip/ccip_onramp/tests/onramp_migration_test.move index f5a63fd3..cad9841b 100644 --- a/contracts/ccip/ccip_onramp/tests/onramp_migration_test.move +++ b/contracts/ccip/ccip_onramp/tests/onramp_migration_test.move @@ -844,7 +844,8 @@ module ccip_onramp::onramp_migration_test { lock_release_token_pool, pool_type, seed, - is_dispatchable + is_dispatchable, + false // use_v1_init ); let one_e_18 = 1_000_000_000_000_000_000; diff --git a/contracts/ccip/ccip_onramp/tests/onramp_test.move b/contracts/ccip/ccip_onramp/tests/onramp_test.move index c11abb70..19e98d2f 100644 --- a/contracts/ccip/ccip_onramp/tests/onramp_test.move +++ b/contracts/ccip/ccip_onramp/tests/onramp_test.move @@ -66,6 +66,17 @@ module ccip_onramp::onramp_test { transfer_ref: TransferRef } + public fun mint_test_tokens( + token_addr: address, recipient: address, amount: u64 + ) acquires TestToken { + let token = borrow_global(token_addr); + let recipient_store = + primary_fungible_store::ensure_primary_store_exists( + recipient, token.metadata + ); + fungible_asset::mint_to(&token.mint_ref, recipient_store, amount); + } + fun init_timestamp(aptos_framework: &signer, timestamp_seconds: u64) { timestamp::set_time_has_started_for_testing(aptos_framework); timestamp::update_global_time_for_test_secs(timestamp_seconds); @@ -81,7 +92,8 @@ module ccip_onramp::onramp_test { lock_release_token_pool: &signer, pool_type: u8, // 0 for burn_mint, 1 for lock_release seed: vector, - is_dispatchable: bool + is_dispatchable: bool, + use_v1_init: bool ): (address, Object) { let owner_addr = signer::address_of(owner); account::create_account_for_test(signer::address_of(burn_mint_token_pool)); @@ -138,7 +150,8 @@ module ccip_onramp::onramp_test { lock_release_token_pool, pool_type, seed, - is_dispatchable + is_dispatchable, + use_v1_init ); let one_e_18 = 1_000_000_000_000_000_000; @@ -185,12 +198,26 @@ module ccip_onramp::onramp_test { vector[900_000_000_000_000_000] // premium_multiplier_wei_per_eth ); + // Configure token transfer fees (needed for token transfers) + fee_quoter::apply_token_transfer_fee_config_updates( + owner, + DEST_CHAIN_SELECTOR, + vector[token_addr], + vector[50], // min_fee_usd_cents + vector[500], // max_fee_usd_cents + vector[10], // deci_bps + vector[5000], // dest_gas_overhead + vector[64], // dest_bytes_overhead + vector[true], // is_enabled + vector[] + ); + // To be able to call token_admin_dispatcher::dispatch_lock_or_burn - // Need to register onramp signer as an allowed onramp + // Need to register onramp state address as an allowed onramp auth::apply_allowed_onramp_updates( owner, vector[], // onramps_to_remove - vector[signer::address_of(ccip_onramp)] // onramps_to_add + vector[onramp::get_state_address()] // onramps_to_add ); // To be able to call fee_quoter::update_prices, need to register as an allowed offramp @@ -218,7 +245,8 @@ module ccip_onramp::onramp_test { lock_release_token_pool: &signer, pool_type: u8, // 0 for burn_mint, 1 for lock_release seed: vector, - is_dispatchable: bool + is_dispatchable: bool, + use_v1_init: bool ): (Object, address) { let constructor_ref = object::create_named_object(owner, seed); @@ -252,7 +280,11 @@ module ccip_onramp::onramp_test { eth_abi::encode_address(&mut remote_token_address, MOCK_EVM_ADDRESS); if (pool_type == BURN_MINT_TOKEN_POOL) { - burn_mint_token_pool::test_init_module(burn_mint_token_pool); + if (use_v1_init) { + burn_mint_token_pool::test_init_v1(burn_mint_token_pool); + } else { + burn_mint_token_pool::test_init_module(burn_mint_token_pool); + }; burn_mint_token_pool::initialize(owner, burn_ref, mint_ref); burn_mint_token_pool::apply_chain_updates( owner, @@ -282,7 +314,11 @@ module ccip_onramp::onramp_test { signer::address_of(burn_mint_token_pool) ); } else { - lock_release_token_pool::test_init_module(lock_release_token_pool); + if (use_v1_init) { + lock_release_token_pool::test_init_v1(lock_release_token_pool); + } else { + lock_release_token_pool::test_init_module(lock_release_token_pool); + }; lock_release_token_pool::initialize( owner, transfer_ref, @@ -333,7 +369,7 @@ module ccip_onramp::onramp_test { (metadata, token_addr) } - fun initialize_onramp(owner: &signer, router: &signer): address { + public fun initialize_onramp(owner: &signer, router: &signer): address { onramp::initialize( owner, SOURCE_CHAIN_SELECTOR, @@ -387,6 +423,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -443,6 +480,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -498,6 +536,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -535,6 +574,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -615,6 +655,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -703,6 +744,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -823,6 +865,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, LOCK_RELEASE_TOKEN_POOL, b"LockReleaseToken", + false, false ); @@ -947,6 +990,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); initialize_onramp(owner, router); @@ -987,6 +1031,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1024,6 +1069,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1063,6 +1109,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1123,6 +1170,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1172,6 +1220,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1211,6 +1260,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1277,6 +1327,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1334,6 +1385,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1385,6 +1437,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); @@ -1464,6 +1517,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); setup_mcms(mcms); @@ -1531,6 +1585,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); setup_mcms(mcms); @@ -1606,6 +1661,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); setup_mcms(mcms); @@ -1689,6 +1745,7 @@ module ccip_onramp::onramp_test { lock_release_token_pool, BURN_MINT_TOKEN_POOL, b"TestToken", + false, false ); setup_mcms(mcms); @@ -1840,3 +1897,4 @@ module ccip_onramp::onramp_test { extra_args } } + diff --git a/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move new file mode 100644 index 00000000..8ba4ca70 --- /dev/null +++ b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move @@ -0,0 +1,595 @@ +#[test_only] +/// Verifies V1 → V2 migration path and that both can coexist +module ccip_onramp::onramp_v1_v2_pool_compatibility_test { + use std::signer; + use std::object; + use std::primary_fungible_store; + + use ccip::client; + use ccip::token_admin_registry; + use ccip::eth_abi; + use ccip_onramp::onramp; + + use burn_mint_token_pool::burn_mint_token_pool; + use burn_mint_token_pool::upgrade_v2 as burn_mint_upgrade_v2; + use lock_release_token_pool::lock_release_token_pool; + use lock_release_token_pool::upgrade_v2 as lock_release_upgrade_v2; + + use ccip_onramp::onramp_test; + + const DEST_CHAIN_SELECTOR: u64 = 5678; + const TOKEN_AMOUNT: u64 = 5000; + + const SENDER: address = @0x500; + + const BURN_MINT_TOKEN_POOL: u8 = 0; + const LOCK_RELEASE_TOKEN_POOL: u8 = 1; + + const BURN_MINT_TOKEN_SEED: vector = b"TestToken"; + const LOCK_RELEASE_TOKEN_SEED: vector = b"LockReleaseToken"; + + const MOCK_EVM_ADDRESS: address = @0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97; + + const GAS_LIMIT: u64 = 5000000; + const ALLOW_OUT_OF_ORDER_EXECUTION: bool = true; + + fun create_extra_args_v2(): vector { + client::encode_generic_extra_args_v2( + GAS_LIMIT as u256, ALLOW_OUT_OF_ORDER_EXECUTION + ) + } + + fun encode_receiver(): vector { + let receiver = vector[]; + eth_abi::encode_address(&mut receiver, MOCK_EVM_ADDRESS); + receiver + } + + /// Helper to calculate fee and mint enough tokens for sender + fun mint_tokens_for_transfer( + token_addr: address, num_transfers: u64 + ) { + let receiver = encode_receiver(); + let extra_args = create_extra_args_v2(); + + // Calculate fee for one transfer + let fee_amount = + onramp::get_fee( + DEST_CHAIN_SELECTOR, + receiver, + vector[], // data + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + extra_args + ); + + // Mint enough for transfers + fees + let total_needed = (TOKEN_AMOUNT + fee_amount) * num_transfers; + onramp_test::mint_test_tokens(token_addr, SENDER, total_needed); + } + + // ============================================ + // Test 1: V1 Burn/Mint Pool Baseline + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + router = @0x200, + ccip = @ccip, + ccip_onramp = @ccip_onramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + sender = @0x500 + ) + ] + fun test_v1_burn_mint_pool_baseline( + aptos_framework: &signer, + router: &signer, + ccip: &signer, + ccip_onramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + sender: &signer + ) { + let (_owner_addr, token_obj) = + onramp_test::setup( + aptos_framework, + router, + ccip, + ccip_onramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + let token_addr = object::object_address(&token_obj); + + // Fund sender with enough tokens for transfer + fees + mint_tokens_for_transfer(token_addr, 1); + + // Verify V1 pool registered (not V2) + assert!( + !token_admin_registry::has_token_pool_config( + signer::address_of(burn_mint_token_pool) + ) + ); + + // Send tokens via onramp + let sender_balance_before = primary_fungible_store::balance(SENDER, token_obj); + + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], // data + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], // token_store_addresses - use primary store + token_addr, // fee_token + @0x0, // fee_token_store - use primary store + create_extra_args_v2() + ); + + // Verify tokens were burned from sender + let sender_balance_after = primary_fungible_store::balance(SENDER, token_obj); + assert!( + sender_balance_before - sender_balance_after >= TOKEN_AMOUNT + ); + + // Verify V1 callback worked - check events + let events = + burn_mint_token_pool::get_locked_or_burned_events( + burn_mint_token_pool::get_store_address() + ); + assert!(events.length() >= 1); + } + + // ============================================ + // Test 2: V1 → V2 Burn/Mint Migration + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + router = @0x200, + ccip = @ccip, + ccip_onramp = @ccip_onramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + sender = @0x500 + ) + ] + fun test_v1_to_v2_burn_mint_migration( + aptos_framework: &signer, + router: &signer, + ccip: &signer, + ccip_onramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + sender: &signer + ) { + let (_owner_addr, token_obj) = + onramp_test::setup( + aptos_framework, + router, + ccip, + ccip_onramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + let token_addr = object::object_address(&token_obj); + + // Fund sender with enough tokens for 2 transfers + fees + mint_tokens_for_transfer(token_addr, 2); + + // STEP 1: Send with V1 pool + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + create_extra_args_v2() + ); + + // Verify V1 callback worked + let events_before = + burn_mint_token_pool::get_locked_or_burned_events( + burn_mint_token_pool::get_store_address() + ); + assert!(events_before.length() == 1); + + // STEP 2: Upgrade to V2 + burn_mint_upgrade_v2::test_init_module(burn_mint_token_pool); + + // Verify V2 config now exists + assert!( + token_admin_registry::has_token_pool_config( + signer::address_of(burn_mint_token_pool) + ) + ); + + // STEP 3: Send with V2 pool + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + create_extra_args_v2() + ); + + // Verify V2 callback worked + let events_after = + burn_mint_token_pool::get_locked_or_burned_events( + burn_mint_token_pool::get_store_address() + ); + assert!(events_after.length() == 2); + } + + // ============================================ + // Test 3: V2 Burn/Mint Direct (no migration) + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + router = @0x200, + ccip = @ccip, + ccip_onramp = @ccip_onramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + sender = @0x500 + ) + ] + fun test_v2_burn_mint_direct( + aptos_framework: &signer, + router: &signer, + ccip: &signer, + ccip_onramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + sender: &signer + ) { + let (_owner_addr, token_obj) = + onramp_test::setup( + aptos_framework, + router, + ccip, + ccip_onramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + false // use_v2_init (V2) + ); + + let token_addr = object::object_address(&token_obj); + + // Fund sender with enough tokens for transfer + fees + mint_tokens_for_transfer(token_addr, 1); + + // Verify V2 config registered (already done by setup) + assert!( + token_admin_registry::has_token_pool_config( + signer::address_of(burn_mint_token_pool) + ) + ); + + // Send message using V2 pool + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + create_extra_args_v2() + ); + + // Verify V2 callback worked + let events = + burn_mint_token_pool::get_locked_or_burned_events( + burn_mint_token_pool::get_store_address() + ); + assert!(events.length() == 1); + } + + // ============================================ + // Test 4: V1 Lock/Release Pool Baseline + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + router = @0x200, + ccip = @ccip, + ccip_onramp = @ccip_onramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + sender = @0x500 + ) + ] + fun test_v1_lock_release_pool_baseline( + aptos_framework: &signer, + router: &signer, + ccip: &signer, + ccip_onramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + sender: &signer + ) { + let (_owner_addr, token_obj) = + onramp_test::setup( + aptos_framework, + router, + ccip, + ccip_onramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + let token_addr = object::object_address(&token_obj); + + // Fund sender with enough tokens for transfer + fees + mint_tokens_for_transfer(token_addr, 1); + + // Verify V1 pool registered (not V2) + assert!( + !token_admin_registry::has_token_pool_config( + signer::address_of(lock_release_token_pool) + ) + ); + + // Send tokens via onramp + let sender_balance_before = primary_fungible_store::balance(SENDER, token_obj); + + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + create_extra_args_v2() + ); + + // Verify tokens were locked from sender + let sender_balance_after = primary_fungible_store::balance(SENDER, token_obj); + assert!( + sender_balance_before - sender_balance_after >= TOKEN_AMOUNT + ); + + // Verify V1 callback worked - check events + let events = + lock_release_token_pool::get_locked_or_burned_events( + lock_release_token_pool::get_store_address() + ); + assert!(events.length() >= 1); + } + + // ============================================ + // Test 5: V1 → V2 Lock/Release Migration + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + router = @0x200, + ccip = @ccip, + ccip_onramp = @ccip_onramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + sender = @0x500 + ) + ] + fun test_v1_to_v2_lock_release_migration( + aptos_framework: &signer, + router: &signer, + ccip: &signer, + ccip_onramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + sender: &signer + ) { + let (_owner_addr, token_obj) = + onramp_test::setup( + aptos_framework, + router, + ccip, + ccip_onramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + false, // is_dispatchable + true // use_v1_init + ); + + let token_addr = object::object_address(&token_obj); + + // Fund sender with enough tokens for 2 transfers + fees + mint_tokens_for_transfer(token_addr, 2); + + // STEP 1: Send with V1 + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + create_extra_args_v2() + ); + + // Verify V1 callback worked + let events_before = + lock_release_token_pool::get_locked_or_burned_events( + lock_release_token_pool::get_store_address() + ); + assert!(events_before.length() == 1); + + // STEP 2: Upgrade to V2 + lock_release_upgrade_v2::test_init_module(lock_release_token_pool); + + // Verify V2 config now exists + assert!( + token_admin_registry::has_token_pool_config( + signer::address_of(lock_release_token_pool) + ) + ); + + // STEP 3: Send with V2 pool + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + create_extra_args_v2() + ); + + // Verify V2 callback worked + let events_after = + lock_release_token_pool::get_locked_or_burned_events( + lock_release_token_pool::get_store_address() + ); + assert!(events_after.length() == 2); + } + + // ============================================ + // Test 6: V2 Lock/Release Direct (no migration) + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + router = @0x200, + ccip = @ccip, + ccip_onramp = @ccip_onramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + sender = @0x500 + ) + ] + fun test_v2_lock_release_direct( + aptos_framework: &signer, + router: &signer, + ccip: &signer, + ccip_onramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + sender: &signer + ) { + let (_owner_addr, token_obj) = + onramp_test::setup( + aptos_framework, + router, + ccip, + ccip_onramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + LOCK_RELEASE_TOKEN_POOL, + LOCK_RELEASE_TOKEN_SEED, + false, // is_dispatchable + false // use_v2_init (V2) + ); + + let token_addr = object::object_address(&token_obj); + + // Fund sender with enough tokens for transfer + fees + mint_tokens_for_transfer(token_addr, 1); + + assert!( + token_admin_registry::has_token_pool_config( + signer::address_of(lock_release_token_pool) + ) + ); + + // Send message using V2 pool + onramp::ccip_send( + router, + sender, + DEST_CHAIN_SELECTOR, + encode_receiver(), + vector[], + vector[token_addr], + vector[TOKEN_AMOUNT], + vector[@0x0], + token_addr, + @0x0, + create_extra_args_v2() + ); + + // Verify V2 callback worked + let events = + lock_release_token_pool::get_locked_or_burned_events( + lock_release_token_pool::get_store_address() + ); + assert!(events.length() == 1); + } +} + diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move index b4b45012..7a8082e2 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move @@ -32,7 +32,7 @@ module burn_mint_token_pool::upgrade_v2 { |input| burn_mint_token_pool::release_or_mint_v2(input); // If the contract has already been deployed with V1 and needs to be upgraded to V2, - // create a new module + // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -48,3 +48,4 @@ module burn_mint_token_pool::upgrade_v2 { init_module(publisher); } } + diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move index 51512a51..64f9aaed 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move @@ -32,7 +32,7 @@ module lock_release_token_pool::upgrade_v2 { |input| lock_release_token_pool::release_or_mint_v2(input); // If the contract has already been deployed with V1 and needs to be upgraded to V2, - // create a new module + // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -48,3 +48,4 @@ module lock_release_token_pool::upgrade_v2 { init_module(publisher); } } + diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move index 77fe1faf..005d912e 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move @@ -26,7 +26,7 @@ module managed_token_pool::upgrade_v2 { |input| managed_token_pool::release_or_mint_v2(input); // If the contract has already been deployed with V1 and needs to be upgraded to V2, - // create a new module + // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -42,3 +42,4 @@ module managed_token_pool::upgrade_v2 { init_module(publisher); } } + diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index 309889ef..21970e6c 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -334,7 +334,7 @@ module regulated_token_pool::regulated_token_pool { public fun lock_or_burn_v2( fa: FungibleAsset, input: LockOrBurnInputV1 - ): token_admin_registry::LockOrBurnOutputV1 acquires RegulatedTokenPoolState { + ): (vector, vector) acquires RegulatedTokenPoolState { let pool = borrow_pool_mut(); let fa_amount = fungible_asset::amount(&fa); @@ -357,10 +357,7 @@ module regulated_token_pool::regulated_token_pool { &mut pool.token_pool_state, fa_amount, remote_chain_selector ); - token_admin_registry::new_lock_or_burn_output_v1( - dest_token_address, - token_pool::encode_local_decimals(&pool.token_pool_state) - ) + (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } public fun release_or_mint_v2( @@ -763,3 +760,4 @@ module regulated_token_pool::regulated_token_pool { move_to(&store_signer, pool); } } + diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move index 92a55cc9..91001ca3 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move @@ -26,7 +26,7 @@ module regulated_token_pool::upgrade_v2 { |input| regulated_token_pool::release_or_mint_v2(input); // If the contract has already been deployed with V1 and needs to be upgraded to V2, - // create a new module + // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -42,3 +42,4 @@ module regulated_token_pool::upgrade_v2 { init_module(publisher); } } + diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index f0b0a561..5b718704 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -13,12 +13,7 @@ module usdc_token_pool::usdc_token_pool { use ccip::address; use ccip::eth_abi; - use ccip::token_admin_registry::{ - Self, - LockOrBurnInputV1, - ReleaseOrMintInputV1, - LockOrBurnOutputV1 - }; + use ccip::token_admin_registry::{Self, LockOrBurnInputV1, ReleaseOrMintInputV1}; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -516,7 +511,7 @@ module usdc_token_pool::usdc_token_pool { public fun lock_or_burn_v2( fa: FungibleAsset, input: LockOrBurnInputV1 - ): LockOrBurnOutputV1 acquires USDCTokenPoolState { + ): (vector, vector) acquires USDCTokenPoolState { let pool = borrow_pool_mut(); let fa_amount = fungible_asset::amount(&fa); @@ -562,9 +557,7 @@ module usdc_token_pool::usdc_token_pool { &mut pool.token_pool_state, fa_amount, remote_chain_selector ); - token_admin_registry::new_lock_or_burn_output_v1( - dest_token_address, dest_pool_data - ) + (dest_token_address, dest_pool_data) } public fun release_or_mint_v2( @@ -1052,3 +1045,4 @@ module usdc_token_pool::usdc_token_pool { CallbackProof {} } } + diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move index c1fc4424..0f7c55d7 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move @@ -32,7 +32,7 @@ module usdc_token_pool::upgrade_v2 { let release_or_mint_closure = |input| usdc_token_pool::release_or_mint_v2(input); // If the contract has already been deployed with V1 and needs to be upgraded to V2, - // create a new module + // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -48,3 +48,4 @@ module usdc_token_pool::upgrade_v2 { init_module(publisher); } } + From 8792318e4f2f4d4ea69d34fcd2470d02f8f8c954 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Fri, 28 Nov 2025 13:44:12 -0500 Subject: [PATCH 10/24] Formatting move files --- contracts/ccip/ccip/sources/token_admin_registry.move | 1 - contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move | 1 - contracts/ccip/ccip_onramp/tests/mock/mock_token.move | 1 - contracts/ccip/ccip_onramp/tests/onramp_test.move | 1 - .../ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move | 1 - .../burn_mint_token_pool/sources/burn_mint_token_pool.move | 1 - .../ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move | 1 - .../lock_release_token_pool/sources/lock_release_token_pool.move | 1 - .../lock_release_token_pool/tests/upgrade_v2.move | 1 - .../managed_token_pool/sources/managed_token_pool.move | 1 - .../ccip_token_pools/managed_token_pool/tests/upgrade_v2.move | 1 - .../regulated_token_pool/sources/regulated_token_pool.move | 1 - .../ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move | 1 - .../usdc_token_pool/sources/usdc_token_pool.move | 1 - .../ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move | 1 - 15 files changed, 15 deletions(-) diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index 8b644215..33a85f95 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -1338,4 +1338,3 @@ module ccip::token_admin_registry { assert!(has_more); } } - diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 512f14d7..0b3a3a53 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -315,4 +315,3 @@ module ccip_offramp::mock_ccip_receiver { event.message } } - diff --git a/contracts/ccip/ccip_onramp/tests/mock/mock_token.move b/contracts/ccip/ccip_onramp/tests/mock/mock_token.move index 5c60c113..d22f1566 100644 --- a/contracts/ccip/ccip_onramp/tests/mock/mock_token.move +++ b/contracts/ccip/ccip_onramp/tests/mock/mock_token.move @@ -40,4 +40,3 @@ module ccip_onramp::mock_token { fungible_asset::withdraw_with_ref(transfer_ref, store, amount) } } - diff --git a/contracts/ccip/ccip_onramp/tests/onramp_test.move b/contracts/ccip/ccip_onramp/tests/onramp_test.move index 19e98d2f..d4fdb33b 100644 --- a/contracts/ccip/ccip_onramp/tests/onramp_test.move +++ b/contracts/ccip/ccip_onramp/tests/onramp_test.move @@ -1897,4 +1897,3 @@ module ccip_onramp::onramp_test { extra_args } } - diff --git a/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move index 8ba4ca70..3c3bae6c 100644 --- a/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move +++ b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move @@ -592,4 +592,3 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { assert!(events.length() == 1); } } - diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index ef9bfcd5..f4f9f5e7 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -864,4 +864,3 @@ module burn_mint_token_pool::burn_mint_token_pool { ); } } - diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move index 7a8082e2..6d838345 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move @@ -48,4 +48,3 @@ module burn_mint_token_pool::upgrade_v2 { init_module(publisher); } } - diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index fbc99899..4ff04c5d 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -1040,4 +1040,3 @@ module lock_release_token_pool::lock_release_token_pool { ) } } - diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move index 64f9aaed..7d42c801 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move @@ -48,4 +48,3 @@ module lock_release_token_pool::upgrade_v2 { init_module(publisher); } } - diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index d5230200..c1ad8e00 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -734,4 +734,3 @@ module managed_token_pool::managed_token_pool { CallbackProof {} } } - diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move index 005d912e..e2be9476 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move @@ -42,4 +42,3 @@ module managed_token_pool::upgrade_v2 { init_module(publisher); } } - diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index 21970e6c..aec3dab0 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -760,4 +760,3 @@ module regulated_token_pool::regulated_token_pool { move_to(&store_signer, pool); } } - diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move index 91001ca3..9cd54956 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move @@ -42,4 +42,3 @@ module regulated_token_pool::upgrade_v2 { init_module(publisher); } } - diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index 5b718704..5c47a4a2 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -1045,4 +1045,3 @@ module usdc_token_pool::usdc_token_pool { CallbackProof {} } } - diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move index 0f7c55d7..62ecd44d 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move @@ -48,4 +48,3 @@ module usdc_token_pool::upgrade_v2 { init_module(publisher); } } - From 78b6d0013a3de3bc678c1dbe5620bc4d53fd8847 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Fri, 28 Nov 2025 14:49:18 -0500 Subject: [PATCH 11/24] Multiple token transfer test --- .../offramp_v1_v2_compatibility_test.move | 130 +++++++++++++++++- 1 file changed, 128 insertions(+), 2 deletions(-) diff --git a/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move index ddba6e79..bb46ace5 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move @@ -16,10 +16,13 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { use burn_mint_token_pool::upgrade_v2; const BURN_MINT_TOKEN_POOL: u8 = 0; + const LOCK_RELEASE_TOKEN_POOL: u8 = 1; const BURN_MINT_TOKEN_SEED: vector = b"TestToken"; + const LOCK_RELEASE_TOKEN_SEED: vector = b"LockReleaseToken"; const EVM_SOURCE_CHAIN_SELECTOR: u64 = 909606746561742123; const DEST_CHAIN_SELECTOR: u64 = 743186221051783445; const MOCK_EVM_ADDRESS_VECTOR: vector = x"4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97"; + const MOCK_EVM_ADDRESS_VECTOR_2: vector = x"1234567890abcdef1234567890abcdef12345678"; const ONRAMP_ADDRESS: vector = x"47a1f0a819457f01153f35c6b6b0d42e2e16e91e"; // ============================================ @@ -58,6 +61,15 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { nonce ); + // Create offchain_token_data: one empty vector per token transfer + let num_tokens = token_transfers.length(); + let offchain_token_data: vector> = vector[]; + let i = 0; + while (i < num_tokens) { + offchain_token_data.push_back(vector[]); + i = i + 1; + }; + let message = offramp::test_create_any2aptos_ramp_message( header, @@ -80,8 +92,6 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // Commit root (with timestamp in the past to allow execution) offramp::test_add_root(root, timestamp::now_seconds() - 3700); - // Create execution report - let offchain_token_data: vector> = vector[vector[]]; let execution_report = offramp::test_create_execution_report( EVM_SOURCE_CHAIN_SELECTOR, @@ -559,4 +569,120 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { let events = mock_ccip_receiver::get_received_tokens_only_events(); assert!(events.length() == 2); } + + // ============================================ + // Test 5: Multi-Transfer Message with V2 Receiver + // Tests V2 receiver handling multiple token transfers in a single message + // ============================================ + + #[ + test( + aptos_framework = @aptos_framework, + ccip = @ccip, + ccip_offramp = @ccip_offramp, + owner = @0x100, + burn_mint_token_pool = @burn_mint_token_pool, + lock_release_token_pool = @lock_release_token_pool, + managed_token_pool = @managed_token_pool, + managed_token = @managed_token, + regulated_token_pool = @regulated_token_pool, + regulated_token = @regulated_token + ) + ] + fun test_multi_token_v2_receiver( + aptos_framework: &signer, + ccip: &signer, + ccip_offramp: &signer, + owner: &signer, + burn_mint_token_pool: &signer, + lock_release_token_pool: &signer, + managed_token_pool: &signer, + managed_token: &signer, + regulated_token_pool: &signer, + regulated_token: &signer + ) { + // Setup first pool: burn_mint with V2 + let (_owner_addr, token_obj_1) = + offramp_test::setup( + aptos_framework, + ccip, + ccip_offramp, + owner, + burn_mint_token_pool, + lock_release_token_pool, + managed_token_pool, + managed_token, + regulated_token_pool, + regulated_token, + BURN_MINT_TOKEN_POOL, + BURN_MINT_TOKEN_SEED, + false, // is_dispatchable + false // use_v1_init = false (V2 from start) + ); + + let token_addr_1 = object::object_address(&token_obj_1); + + receiver_registry::init_module_for_testing(owner); + mock_ccip_receiver::test_init_module(ccip_offramp); + + assert!( + receiver_registry::is_registered_receiver_v2(signer::address_of(ccip_offramp)) + ); + + // Verify pool has V2 config + assert!( + token_admin_registry::has_token_pool_config( + signer::address_of(burn_mint_token_pool) + ) + ); + + // Create 2 token transfers of the same token + // This tests that V2 receiver can handle multiple transfers in one message + // and that pool closures can be invoked multiple times sequentially + let token_amount_1 = 1000; + let token_amount_2 = 2000; + + let token_transfer_1 = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, // source_pool_address + token_addr_1, // dest_token_address + 1000000, // dest_gas_amount + vector[], // extra_data + (token_amount_1 as u256) // amount + ); + + let token_transfer_2 = + offramp::test_create_any2aptos_token_transfer( + MOCK_EVM_ADDRESS_VECTOR, // same source_pool_address + token_addr_1, // dest_token_address (same token) + 1000000, // dest_gas_amount + vector[], // extra_data + (token_amount_2 as u256) // amount + ); + + // Execute message with 2 transfers + create_and_execute_message( + x"0007", // unique message_id + 0, // sequence_number + signer::address_of(ccip_offramp), // receiver + vector[], // no data, just tokens + vector[token_transfer_1, token_transfer_2], // 2 token transfers + owner + ); + + // Verify BOTH 2 transfers were received (total amount = amount_1 + amount_2) + let total_balance = + primary_fungible_store::balance( + signer::address_of(ccip_offramp), token_obj_1 + ); + assert!( + total_balance == token_amount_1 + token_amount_2 + ); + + // Verify V2 receiver callback was invoked once with multiple tokens + // The mock receiver's ccip_receive_v2 handles multiple tokens in a loop + // and emits a single ReceivedTokensOnly event + let events = mock_ccip_receiver::get_received_tokens_only_events(); + assert!(events.length() == 1); + } } From 6dfbe5665bf0c1f82876712a28c5009c22eb4a32 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Sat, 29 Nov 2025 13:10:35 -0500 Subject: [PATCH 12/24] Remove duplicate onramp call check, slight refactor --- .../burn_mint_token_pool.go | 1 - .../lock_release_token_pool.go | 1 - .../managed_token_pool/managed_token_pool.go | 1 - .../regulated_token_pool.go | 1 - .../ccip/sources/token_admin_dispatcher.move | 4 --- .../ccip/sources/token_admin_registry.move | 27 ++++++++----------- .../sources/burn_mint_token_pool.move | 2 -- .../sources/lock_release_token_pool.move | 1 - .../sources/managed_token_pool.move | 1 - .../sources/regulated_token_pool.move | 1 - 10 files changed, 11 insertions(+), 29 deletions(-) diff --git a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go index 6f6986f9..ee8f84a2 100644 --- a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go +++ b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go @@ -114,7 +114,6 @@ const ( E_UNKNOWN_FUNCTION uint64 = 6 E_MINT_REF_NOT_SET uint64 = 7 E_BURN_REF_NOT_SET uint64 = 8 - E_NOT_EXECUTING_RECEIVER uint64 = 9 ) // Structs diff --git a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go index 70504e03..413b73b8 100644 --- a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go +++ b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go @@ -130,7 +130,6 @@ const ( E_UNAUTHORIZED uint64 = 8 E_INSUFFICIENT_LIQUIDITY uint64 = 9 E_TRANSFER_REF_NOT_SET uint64 = 10 - E_NOT_EXECUTING_RECEIVER uint64 = 11 ) // Structs diff --git a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go index 389c17cf..585473a2 100644 --- a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go +++ b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go @@ -111,7 +111,6 @@ const ( E_LOCAL_TOKEN_MISMATCH uint64 = 4 E_INVALID_ARGUMENTS uint64 = 5 E_UNKNOWN_FUNCTION uint64 = 6 - E_NOT_EXECUTING_RECEIVER uint64 = 9 ) // Structs diff --git a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go index 64494076..e34fad23 100644 --- a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go +++ b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go @@ -112,7 +112,6 @@ const ( E_INVALID_ARGUMENTS uint64 = 5 E_UNKNOWN_FUNCTION uint64 = 6 E_NOT_REGISTERED_RECEIVER uint64 = 7 - E_NOT_EXECUTING_RECEIVER uint64 = 9 ) // Structs diff --git a/contracts/ccip/ccip/sources/token_admin_dispatcher.move b/contracts/ccip/ccip/sources/token_admin_dispatcher.move index bc0028bf..603b1fb3 100644 --- a/contracts/ccip/ccip/sources/token_admin_dispatcher.move +++ b/contracts/ccip/ccip/sources/token_admin_dispatcher.move @@ -18,7 +18,6 @@ module ccip::token_admin_dispatcher { if (token_admin_registry::has_token_pool_config(token_pool_address)) { token_admin_registry::lock_or_burn_v2( - caller, token_pool_address, fa, sender, @@ -52,11 +51,8 @@ module ccip::token_admin_dispatcher { source_pool_data: vector, offchain_token_data: vector ): (FungibleAsset, u64) { - auth::assert_is_allowed_offramp(signer::address_of(caller)); - if (token_admin_registry::has_token_pool_config(token_pool_address)) { token_admin_registry::release_or_mint_v2( - caller, token_pool_address, sender, receiver, diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index 33a85f95..7d2dde78 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -1066,15 +1066,12 @@ module ccip::token_admin_registry { } public(friend) fun lock_or_burn_v2( - caller: &signer, token_pool_address: address, fa: fungible_asset::FungibleAsset, sender: address, remote_chain_selector: u64, receiver: vector ): (vector, vector) acquires TokenPoolConfig { - auth::assert_is_allowed_onramp(signer::address_of(caller)); - let pool_config = &TokenPoolConfig[token_pool_address]; let input = LockOrBurnInputV1 { sender, remote_chain_selector, receiver }; @@ -1083,7 +1080,6 @@ module ccip::token_admin_registry { } public(friend) fun release_or_mint_v2( - caller: &signer, token_pool_address: address, sender: vector, receiver: address, @@ -1094,19 +1090,18 @@ module ccip::token_admin_registry { source_pool_data: vector, offchain_token_data: vector ): (FungibleAsset, u64) acquires TokenPoolConfig { - auth::assert_is_allowed_offramp(signer::address_of(caller)); - let pool_config = &TokenPoolConfig[token_pool_address]; - let input = ReleaseOrMintInputV1 { - sender, - receiver, - source_amount, - local_token, - remote_chain_selector, - source_pool_address, - source_pool_data, - offchain_token_data - }; + let input = + ReleaseOrMintInputV1 { + sender, + receiver, + source_amount, + local_token, + remote_chain_selector, + source_pool_address, + source_pool_data, + offchain_token_data + }; (pool_config.callbacks.release_or_mint) (input) diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index f4f9f5e7..702956bc 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -42,7 +42,6 @@ module burn_mint_token_pool::burn_mint_token_pool { const E_UNKNOWN_FUNCTION: u64 = 6; const E_MINT_REF_NOT_SET: u64 = 7; const E_BURN_REF_NOT_SET: u64 = 8; - const E_NOT_EXECUTING_RECEIVER: u64 = 9; // ================================================================ // | Init | @@ -415,7 +414,6 @@ module burn_mint_token_pool::burn_mint_token_pool { let local_amount = token_pool::calculate_release_or_mint_amount(&pool.token_pool_state, &input); - // Validate the operation (same as V1) token_pool::validate_release_or_mint( &mut pool.token_pool_state, &input, local_amount ); diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index 4ff04c5d..c8be7f04 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -44,7 +44,6 @@ module lock_release_token_pool::lock_release_token_pool { const E_UNAUTHORIZED: u64 = 8; const E_INSUFFICIENT_LIQUIDITY: u64 = 9; const E_TRANSFER_REF_NOT_SET: u64 = 10; - const E_NOT_EXECUTING_RECEIVER: u64 = 11; // ================================================================ // | Init | diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index c1ad8e00..f41c0e93 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -33,7 +33,6 @@ module managed_token_pool::managed_token_pool { const E_LOCAL_TOKEN_MISMATCH: u64 = 4; const E_INVALID_ARGUMENTS: u64 = 5; const E_UNKNOWN_FUNCTION: u64 = 6; - const E_NOT_EXECUTING_RECEIVER: u64 = 9; // ================================================================ // | Init | diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index aec3dab0..ebda6763 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -34,7 +34,6 @@ module regulated_token_pool::regulated_token_pool { const E_INVALID_ARGUMENTS: u64 = 5; const E_UNKNOWN_FUNCTION: u64 = 6; const E_NOT_REGISTERED_RECEIVER: u64 = 7; - const E_NOT_EXECUTING_RECEIVER: u64 = 9; // ================================================================ // | Init | From c25af36e12c9a5d3f666ec36018e05992635d603 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Tue, 9 Dec 2025 20:30:51 -0500 Subject: [PATCH 13/24] Clean up register pool, refactor --- .../regulated_token_pool/regulated_token_pool.go | 13 ++++++------- .../ccip/ccip/sources/token_admin_dispatcher.move | 2 ++ .../ccip/ccip/sources/token_admin_registry.move | 15 +++++++++++---- .../sources/burn_mint_token_pool.move | 11 +---------- .../sources/lock_release_token_pool.move | 15 ++++----------- .../sources/managed_token_pool.move | 9 +-------- .../sources/regulated_token_pool.move | 10 +--------- .../tests/regulated_token_pool_ccip_test.move | 4 ++-- .../usdc_token_pool/sources/usdc_token_pool.move | 11 +---------- 9 files changed, 29 insertions(+), 61 deletions(-) diff --git a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go index e34fad23..854def7f 100644 --- a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go +++ b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go @@ -105,13 +105,12 @@ func NewRegulatedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcCl // Constants const ( - E_NOT_PUBLISHER uint64 = 1 - E_ALREADY_INITIALIZED uint64 = 2 - E_INVALID_FUNGIBLE_ASSET uint64 = 3 - E_LOCAL_TOKEN_MISMATCH uint64 = 4 - E_INVALID_ARGUMENTS uint64 = 5 - E_UNKNOWN_FUNCTION uint64 = 6 - E_NOT_REGISTERED_RECEIVER uint64 = 7 + E_NOT_PUBLISHER uint64 = 1 + E_ALREADY_INITIALIZED uint64 = 2 + E_INVALID_FUNGIBLE_ASSET uint64 = 3 + E_LOCAL_TOKEN_MISMATCH uint64 = 4 + E_INVALID_ARGUMENTS uint64 = 5 + E_UNKNOWN_FUNCTION uint64 = 6 ) // Structs diff --git a/contracts/ccip/ccip/sources/token_admin_dispatcher.move b/contracts/ccip/ccip/sources/token_admin_dispatcher.move index 603b1fb3..7c9665bd 100644 --- a/contracts/ccip/ccip/sources/token_admin_dispatcher.move +++ b/contracts/ccip/ccip/sources/token_admin_dispatcher.move @@ -51,6 +51,8 @@ module ccip::token_admin_dispatcher { source_pool_data: vector, offchain_token_data: vector ): (FungibleAsset, u64) { + auth::assert_is_allowed_offramp(signer::address_of(caller)); + if (token_admin_registry::has_token_pool_config(token_pool_address)) { token_admin_registry::release_or_mint_v2( token_pool_address, diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index 7d2dde78..28ab1779 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -88,9 +88,8 @@ module ccip::token_admin_registry { } struct TokenPoolCallbacks has drop, copy, store { - lock_or_burn: |FungibleAsset, LockOrBurnInputV1| (vector, vector) has drop - + copy + store, - release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) has drop + copy + store + lock_or_burn: |FungibleAsset, LockOrBurnInputV1| (vector, vector), + release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) } struct TokenPoolConfig has key { @@ -318,6 +317,9 @@ module ccip::token_admin_registry { // | Register Pool | // ================================================================ + #[deprecated] + /// @deprecated: Use `register_pool_v2()` instead. + /// /// Registers pool with `TokenPoolRegistration` and sets up dynamic dispatch for a token pool /// Registry token config mapping must be done separately via `set_pool()` /// by token owner or ccip owner. @@ -459,7 +461,7 @@ module ccip::token_admin_registry { public entry fun unregister_pool( caller: &signer, local_token: address - ) acquires TokenAdminRegistryState, TokenPoolRegistration { + ) acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolConfig { let state = borrow_state_mut(); assert!( state.token_configs.contains(&local_token), @@ -492,6 +494,11 @@ module ccip::token_admin_registry { } = move_from(previous_pool_address); }; + if (exists(previous_pool_address)) { + let TokenPoolConfig { callbacks: _, local_token: _ } = + move_from(previous_pool_address); + }; + event::emit_event( &mut state.token_unregistered_events, TokenUnregistered { diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index 702956bc..70e0481c 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -73,19 +73,10 @@ module burn_mint_token_pool::burn_mint_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - // Register V1 pool (for backward compatibility) - token_admin_registry::register_pool( - publisher, - token_pool_module_name, - @burn_mint_local_token, - CallbackProof {} - ); - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); let release_or_mint_closure = |input| release_or_mint_v2(input); - // If the contract has already been deployed with V1 and needs to be upgraded to V2, - // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` + // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, token_pool_module_name, diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index c8be7f04..a2e800fb 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -9,7 +9,7 @@ module lock_release_token_pool::lock_release_token_pool { use std::signer; use std::string::{Self, String}; - use ccip::token_admin_registry; + use ccip::token_admin_registry::{Self, LockOrBurnInputV1, ReleaseOrMintInputV1}; use ccip_token_pool::ownable; use ccip_token_pool::rate_limiter; use ccip_token_pool::token_pool; @@ -75,17 +75,10 @@ module lock_release_token_pool::lock_release_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - // Register V1 pool (for backward compatibility) - token_admin_registry::register_pool( - publisher, - token_pool_module_name, - @lock_release_local_token, - CallbackProof {} - ); - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); let release_or_mint_closure = |input| release_or_mint_v2(input); + // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -445,7 +438,7 @@ module lock_release_token_pool::lock_release_token_pool { } public fun lock_or_burn_v2( - fa: FungibleAsset, input: token_admin_registry::LockOrBurnInputV1 + fa: FungibleAsset, input: LockOrBurnInputV1 ): (vector, vector) acquires LockReleaseTokenPoolState { let pool = borrow_pool_mut(); let fa_amount = fungible_asset::amount(&fa); @@ -472,7 +465,7 @@ module lock_release_token_pool::lock_release_token_pool { } public fun release_or_mint_v2( - input: token_admin_registry::ReleaseOrMintInputV1 + input: ReleaseOrMintInputV1 ): (FungibleAsset, u64) acquires LockReleaseTokenPoolState { let pool = borrow_pool_mut(); let local_amount = diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index f41c0e93..524bb7a0 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -61,17 +61,10 @@ module managed_token_pool::managed_token_pool { let managed_token_address = managed_token::token_metadata(); - // Register V1 pool (for backward compatibility) - token_admin_registry::register_pool( - publisher, - token_pool_module_name, - managed_token_address, - CallbackProof {} - ); - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); let release_or_mint_closure = |input| release_or_mint_v2(input); + // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, token_pool_module_name, diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index ebda6763..dc1dd769 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -33,7 +33,6 @@ module regulated_token_pool::regulated_token_pool { const E_LOCAL_TOKEN_MISMATCH: u64 = 4; const E_INVALID_ARGUMENTS: u64 = 5; const E_UNKNOWN_FUNCTION: u64 = 6; - const E_NOT_REGISTERED_RECEIVER: u64 = 7; // ================================================================ // | Init | @@ -62,17 +61,10 @@ module regulated_token_pool::regulated_token_pool { let regulated_token_address = regulated_token::token_address(); - // Register V1 pool (for backward compatibility) - token_admin_registry::register_pool( - publisher, - token_pool_module_name, - regulated_token_address, - CallbackProof {} - ); - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); let release_or_mint_closure = |input| release_or_mint_v2(input); + // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, token_pool_module_name, diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_ccip_test.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_ccip_test.move index da256a25..51f2a4f1 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_ccip_test.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/regulated_token_pool_ccip_test.move @@ -399,9 +399,9 @@ module regulated_token_pool::regulated_token_pool_ccip_test { assert!(administrator != @0x0); assert!(pending_admin == @0x0); - // Verify pool local token matches + // Verify pool local token matches (using V2 since pools now only register with V2) let local_token = - token_admin_registry::get_pool_local_token(@regulated_token_pool); + token_admin_registry::get_pool_local_token_v2(@regulated_token_pool); assert!(local_token == regulated_token_address); // Test the basic registry functions work diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index 5c47a4a2..4b4c1d9f 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -113,16 +113,10 @@ module usdc_token_pool::usdc_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - token_admin_registry::register_pool( - publisher, - token_pool_module_name, - @local_token, - CallbackProof {} - ); - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); let release_or_mint_closure = |input| release_or_mint_v2(input); + // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, token_pool_module_name, @@ -377,9 +371,6 @@ module usdc_token_pool::usdc_token_pool { dest_pool_data ); - let remote_chain_selector = - token_admin_registry::get_lock_or_burn_remote_chain_selector(&input); - token_pool::emit_locked_or_burned( &mut pool.token_pool_state, fa_amount, remote_chain_selector ); From 694e30ab4f62a9fe0667a792c99c5d1a57b95f26 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Wed, 10 Dec 2025 13:23:11 -0500 Subject: [PATCH 14/24] Add PTT CCIP Receiver --- .../ccip_dummy_receiver.go | 46 ++++- .../ptt_dummy_receiver/ptt_dummy_receiver.go | 165 +++++++++++++++++ contracts/ccip/ccip_dummy_receiver/Move.toml | 2 + .../sources/ptt_dummy_receiver.move | 167 ++++++++++++++++++ gen.go | 1 + 5 files changed, 378 insertions(+), 3 deletions(-) create mode 100644 bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go create mode 100644 contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move diff --git a/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go b/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go index 58647a55..37418a7a 100644 --- a/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go +++ b/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go @@ -6,6 +6,7 @@ import ( "github.com/smartcontractkit/chainlink-aptos/bindings/bind" module_dummy_receiver "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_dummy_receiver/dummy_receiver" + module_ptt_dummy_receiver "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_dummy_receiver/ptt_dummy_receiver" "github.com/smartcontractkit/chainlink-aptos/bindings/compile" "github.com/smartcontractkit/chainlink-aptos/contracts" ) @@ -14,6 +15,7 @@ type CCIPDummyReceiver interface { Address() aptos.AccountAddress DummyReceiver() module_dummy_receiver.DummyReceiverInterface + PTTDummyReceiver() module_ptt_dummy_receiver.PttDummyReceiverInterface } var _ CCIPDummyReceiver = CCIPDummyReceiverContract{} @@ -21,7 +23,8 @@ var _ CCIPDummyReceiver = CCIPDummyReceiverContract{} type CCIPDummyReceiverContract struct { address aptos.AccountAddress - dummyReceiver module_dummy_receiver.DummyReceiverInterface + dummyReceiver module_dummy_receiver.DummyReceiverInterface + pttDummyReceiver module_ptt_dummy_receiver.PttDummyReceiverInterface } func (C CCIPDummyReceiverContract) Address() aptos.AccountAddress { @@ -32,8 +35,13 @@ func (C CCIPDummyReceiverContract) DummyReceiver() module_dummy_receiver.DummyRe return C.dummyReceiver } +func (C CCIPDummyReceiverContract) PTTDummyReceiver() module_ptt_dummy_receiver.PttDummyReceiverInterface { + return C.pttDummyReceiver +} + var FunctionInfo = bind.MustParseFunctionInfo( module_dummy_receiver.FunctionInfo, + module_ptt_dummy_receiver.FunctionInfo, ) func Compile(address aptos.AccountAddress, ccipAddress aptos.AccountAddress, mcmsAddress aptos.AccountAddress) (compile.CompiledPackage, error) { @@ -49,11 +57,16 @@ func Compile(address aptos.AccountAddress, ccipAddress aptos.AccountAddress, mcm func Bind(address aptos.AccountAddress, client aptos.AptosRpcClient) CCIPDummyReceiver { return CCIPDummyReceiverContract{ - address: address, - dummyReceiver: module_dummy_receiver.NewDummyReceiver(address, client), + address: address, + dummyReceiver: module_dummy_receiver.NewDummyReceiver(address, client), + pttDummyReceiver: module_ptt_dummy_receiver.NewPttDummyReceiver(address, client), } } +const ( + DefaultSeed = "chainlink_ccip_dummy_receiver" +) + // DeployToObject deploys the dummmy receiver contract to a new named object. // The resulting address will be calculated using the deployer's account address and the next sequence number func DeployToObject( @@ -73,3 +86,30 @@ func DeployToObject( } return address, tx, Bind(address, client), nil } + +// DeployToResourceAccount deploys the dummy receiver contract to a new resource account. +// The address of that resource account is determined by the deployer account + an optional seed. +// If no seed is provided, the default seed DefaultSeed is used. +func DeployToResourceAccount( + auth aptos.TransactionSigner, + client aptos.AptosRpcClient, + ccipAddress, + mcmsAddress aptos.AccountAddress, + seed ...string, +) (aptos.AccountAddress, *api.PendingTransaction, CCIPDummyReceiver, error) { + dummyReceiverSeed := DefaultSeed + if len(seed) > 0 { + dummyReceiverSeed = seed[0] + } + namedAddresses := map[string]aptos.AccountAddress{ + "ccip": ccipAddress, + "mcms": mcmsAddress, + "mcms_register_entrypoints": aptos.AccountZero, + "deployer": auth.AccountAddress(), // Origin account where Container is stored + } + address, tx, err := bind.DeployPackageToResourceAccount(auth, client, contracts.CCIPDummyReceiver, dummyReceiverSeed, namedAddresses) + if err != nil { + return aptos.AccountAddress{}, nil, nil, err + } + return address, tx, Bind(address, client), nil +} diff --git a/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go new file mode 100644 index 00000000..dcc824d6 --- /dev/null +++ b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go @@ -0,0 +1,165 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package module_ptt_dummy_receiver + +import ( + "math/big" + + "github.com/aptos-labs/aptos-go-sdk" + "github.com/aptos-labs/aptos-go-sdk/api" + + "github.com/smartcontractkit/chainlink-aptos/bindings/bind" + "github.com/smartcontractkit/chainlink-aptos/relayer/codec" +) + +var ( + _ = aptos.AccountAddress{} + _ = api.PendingTransaction{} + _ = big.NewInt + _ = bind.NewBoundContract + _ = codec.DecodeAptosJsonValue +) + +type PttDummyReceiverInterface interface { + TypeAndVersion(opts *bind.CallOpts) (string, error) + GetStateAddress(opts *bind.CallOpts) (aptos.AccountAddress, error) + + WithdrawToken(opts *bind.TransactOpts, recipient aptos.AccountAddress, tokenAddress aptos.AccountAddress) (*api.PendingTransaction, error) + + // Encoder returns the encoder implementation of this module. + Encoder() PttDummyReceiverEncoder +} + +type PttDummyReceiverEncoder interface { + TypeAndVersion() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + GetStateAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + WithdrawToken(recipient aptos.AccountAddress, tokenAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) +} + +const FunctionInfo = `[{"package":"ccip_dummy_receiver","module":"ptt_dummy_receiver","name":"withdraw_token","parameters":[{"name":"recipient","type":"address"},{"name":"token_address","type":"address"}]}]` + +func NewPttDummyReceiver(address aptos.AccountAddress, client aptos.AptosRpcClient) PttDummyReceiverInterface { + contract := bind.NewBoundContract(address, "ccip_dummy_receiver", "ptt_dummy_receiver", client) + return PttDummyReceiverContract{ + BoundContract: contract, + pttDummyReceiverEncoder: pttDummyReceiverEncoder{BoundContract: contract}, + } +} + +// Constants +const ( + E_RESOURCE_NOT_FOUND_ON_ACCOUNT uint64 = 1 + E_UNAUTHORIZED uint64 = 2 + E_INVALID_TOKEN_ADDRESS uint64 = 3 + E_NO_TOKENS_AVAILABLE_TO_WITHDRAW uint64 = 4 +) + +// Structs + +type ReceivedMessage struct { + Message string `move:"0x1::string::String"` +} + +type ForwardedTokens struct { + FinalRecipient aptos.AccountAddress `move:"address"` +} + +type ReceivedTokensOnly struct { + TokenCount uint64 `move:"u64"` +} + +type CCIPReceiverState struct { +} + +type CCIPReceiverProof struct { +} + +type PttDummyReceiverContract struct { + *bind.BoundContract + pttDummyReceiverEncoder +} + +var _ PttDummyReceiverInterface = PttDummyReceiverContract{} + +func (c PttDummyReceiverContract) Encoder() PttDummyReceiverEncoder { + return c.pttDummyReceiverEncoder +} + +// View Functions + +func (c PttDummyReceiverContract) TypeAndVersion(opts *bind.CallOpts) (string, error) { + module, function, typeTags, args, err := c.pttDummyReceiverEncoder.TypeAndVersion() + if err != nil { + return *new(string), err + } + + callData, err := c.Call(opts, module, function, typeTags, args) + if err != nil { + return *new(string), err + } + + var ( + r0 string + ) + + if err := codec.DecodeAptosJsonArray(callData, &r0); err != nil { + return *new(string), err + } + return r0, nil +} + +func (c PttDummyReceiverContract) GetStateAddress(opts *bind.CallOpts) (aptos.AccountAddress, error) { + module, function, typeTags, args, err := c.pttDummyReceiverEncoder.GetStateAddress() + if err != nil { + return *new(aptos.AccountAddress), err + } + + callData, err := c.Call(opts, module, function, typeTags, args) + if err != nil { + return *new(aptos.AccountAddress), err + } + + var ( + r0 aptos.AccountAddress + ) + + if err := codec.DecodeAptosJsonArray(callData, &r0); err != nil { + return *new(aptos.AccountAddress), err + } + return r0, nil +} + +// Entry Functions + +func (c PttDummyReceiverContract) WithdrawToken(opts *bind.TransactOpts, recipient aptos.AccountAddress, tokenAddress aptos.AccountAddress) (*api.PendingTransaction, error) { + module, function, typeTags, args, err := c.pttDummyReceiverEncoder.WithdrawToken(recipient, tokenAddress) + if err != nil { + return nil, err + } + + return c.BoundContract.Transact(opts, module, function, typeTags, args) +} + +// Encoder +type pttDummyReceiverEncoder struct { + *bind.BoundContract +} + +func (c pttDummyReceiverEncoder) TypeAndVersion() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("type_and_version", nil, []string{}, []any{}) +} + +func (c pttDummyReceiverEncoder) GetStateAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("get_state_address", nil, []string{}, []any{}) +} + +func (c pttDummyReceiverEncoder) WithdrawToken(recipient aptos.AccountAddress, tokenAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("withdraw_token", nil, []string{ + "address", + "address", + }, []any{ + recipient, + tokenAddress, + }) +} diff --git a/contracts/ccip/ccip_dummy_receiver/Move.toml b/contracts/ccip/ccip_dummy_receiver/Move.toml index 560a2054..5ccbe1fa 100644 --- a/contracts/ccip/ccip_dummy_receiver/Move.toml +++ b/contracts/ccip/ccip_dummy_receiver/Move.toml @@ -8,12 +8,14 @@ ccip = "_" ccip_dummy_receiver = "_" mcms = "_" mcms_register_entrypoints = "_" +deployer = "_" [dev-addresses] ccip = "0x85d5520ea6a8b1501502651040c6f61238b281142ccbafdc205d40258f0bec10" ccip_dummy_receiver = "0x3010" mcms = "0x4000" mcms_register_entrypoints = "0x4001" +deployer = "0x9910" [dependencies] AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", rev = "16beac69835f3a71564c96164a606a23f259099a", subdir = "aptos-move/framework/aptos-framework" } diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move new file mode 100644 index 00000000..df62dd41 --- /dev/null +++ b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move @@ -0,0 +1,167 @@ +module ccip_dummy_receiver::ptt_dummy_receiver { + use std::account; + use std::event; + use std::object::{Self}; + use std::string::{Self, String}; + use std::fungible_asset::{Metadata}; + use std::resource_account; + use std::primary_fungible_store; + use std::from_bcs; + use std::signer; + + use ccip::client; + use ccip::receiver_registry; + + #[event] + struct ReceivedMessage has store, drop { + message: String + } + + #[event] + struct ForwardedTokens has store, drop { + final_recipient: address + } + + #[event] + struct ReceivedTokensOnly has store, drop { + token_count: u64 + } + + struct CCIPReceiverState has key { + signer_cap: account::SignerCapability, + received_message_handle: event::EventHandle, + forwarded_tokens_handle: event::EventHandle, + received_tokens_only_handle: event::EventHandle + } + + const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; + const E_UNAUTHORIZED: u64 = 2; + const E_INVALID_TOKEN_ADDRESS: u64 = 3; + const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + + #[view] + public fun type_and_version(): String { + string::utf8(b"PTTDummyReceiver 1.6.0") + } + + const MODULE_NAME: vector = b"ptt_dummy_receiver"; + + fun init_module(publisher: &signer) { + let signer_cap = + resource_account::retrieve_resource_account_cap(publisher, @deployer); + + let received_message_handle = + account::new_event_handle(publisher); + let forwarded_tokens_handle = + account::new_event_handle(publisher); + let received_tokens_only_handle = + account::new_event_handle(publisher); + + move_to( + publisher, + CCIPReceiverState { + signer_cap, + received_message_handle, + forwarded_tokens_handle, + received_tokens_only_handle + } + ); + + // Default to V2 registration + receiver_registry::register_receiver_v2( + publisher, + MODULE_NAME, + |message| ccip_receive_v2(message), + CCIPReceiverProof {} + ); + } + + #[view] + public fun get_state_address(): address acquires CCIPReceiverState { + let state = borrow_global(@ccip_dummy_receiver); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + signer::address_of(&state_signer) + } + + struct CCIPReceiverProof has drop {} + + public fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { + /* load state and rebuild a signer for the resource account */ + let state = borrow_global_mut(@ccip_dummy_receiver); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let data = client::get_data(&message); + + let dest_token_amounts = client::get_dest_token_amounts(&message); + + if (dest_token_amounts.length() != 0 && data.length() != 0) { + let final_recipient = from_bcs::to_address(data); + + for (i in 0..dest_token_amounts.length()) { + let token_amount_ref = &dest_token_amounts[i]; + let token_addr = client::get_token(token_amount_ref); + let amount = client::get_amount(token_amount_ref); + + // Implement the token transfer logic here + + let fa_token = object::address_to_object(token_addr); + + // Must use primary_fungible_store::transfer as token may be dispatchable + primary_fungible_store::transfer( + &state_signer, + fa_token, + final_recipient, + amount + ); + }; + + event::emit(ForwardedTokens { final_recipient }); + event::emit_event( + &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + ); + } else if (data.length() != 0) { + // Convert the vector to a string + let message = string::utf8(data); + + event::emit(ReceivedMessage { message }); + event::emit_event( + &mut state.received_message_handle, ReceivedMessage { message } + ); + + } else if (dest_token_amounts.length() != 0) { + // Tokens only (no forwarding data) - keep them at receiver + // Emit event to prove receiver was called + let token_count = dest_token_amounts.length(); + event::emit(ReceivedTokensOnly { token_count }); + event::emit_event( + &mut state.received_tokens_only_handle, + ReceivedTokensOnly { token_count } + ); + }; + + // Simple abort condition for testing + if (data == b"abort") { + abort 1 + }; + } + + public entry fun withdraw_token( + sender: &signer, recipient: address, token_address: address + ) acquires CCIPReceiverState { + assert!( + exists(@ccip_dummy_receiver), + E_RESOURCE_NOT_FOUND_ON_ACCOUNT + ); + assert!(signer::address_of(sender) == @ccip_dummy_receiver, E_UNAUTHORIZED); + + let state = borrow_global_mut(@ccip_dummy_receiver); + let state_signer = account::create_signer_with_capability(&state.signer_cap); + + let fa_token = object::address_to_object(token_address); + let balance = primary_fungible_store::balance(@ccip_dummy_receiver, fa_token); + + assert!(balance > 0, E_NO_TOKENS_AVAILABLE_TO_WITHDRAW); + + primary_fungible_store::transfer(&state_signer, fa_token, recipient, balance); + } +} diff --git a/gen.go b/gen.go index 843884c7..05bd3dde 100644 --- a/gen.go +++ b/gen.go @@ -21,6 +21,7 @@ package aptos //go:generate go run ./cmd/bindgen --input ./contracts/ccip/ccip_router/sources/router.move --output ./bindings/ccip_router/router //go:generate go run ./cmd/bindgen --input ./contracts/ccip/ccip_dummy_receiver/sources/dummy_receiver.move --output ./bindings/ccip_dummy_receiver/dummy_receiver +//go:generate go run ./cmd/bindgen --input ./contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move --output ./bindings/ccip_dummy_receiver/ptt_dummy_receiver //go:generate go run ./cmd/bindgen --input ./contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move --output ./bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool --externalStructs ccip_token_pool::rate_limiter::TokenBucket=github.com/smartcontractkit/chainlink-aptos/bindings/ccip_token_pools/token_pool/rate_limiter //go:generate go run ./cmd/bindgen --input ./contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move --output ./bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool --externalStructs ccip_token_pool::rate_limiter::TokenBucket=github.com/smartcontractkit/chainlink-aptos/bindings/ccip_token_pools/token_pool/rate_limiter From a103894dd54346b3bedfec0787ac936a2707aad9 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Wed, 10 Dec 2025 18:16:20 -0500 Subject: [PATCH 15/24] Remove `_proof` in V2 CCIP Receiver registry --- .../ptt_dummy_receiver/ptt_dummy_receiver.go | 3 --- .../ccip/ccip/sources/receiver_registry.move | 20 ++++--------------- .../sources/ptt_dummy_receiver.move | 5 +---- .../tests/mock/mock_ccip_receiver.move | 6 ++---- 4 files changed, 7 insertions(+), 27 deletions(-) diff --git a/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go index dcc824d6..363444c6 100644 --- a/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go +++ b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go @@ -72,9 +72,6 @@ type ReceivedTokensOnly struct { type CCIPReceiverState struct { } -type CCIPReceiverProof struct { -} - type PttDummyReceiverContract struct { *bind.BoundContract pttDummyReceiverEncoder diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index 7860c2e0..1c21e2e9 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -33,8 +33,7 @@ module ccip::receiver_registry { } struct CCIPReceiverRegistrationV2 has key { - callback: |client::Any2AptosMessage| has drop + copy + store, - proof_typeinfo: TypeInfo + callback: |client::Any2AptosMessage| has drop + copy + store } #[event] @@ -144,11 +143,10 @@ module ccip::receiver_registry { ); } - public fun register_receiver_v2( + public fun register_receiver_v2( receiver_account: &signer, receiver_module_name: vector, - callback: |client::Any2AptosMessage| has drop + copy + store, - _proof: ProofType + callback: |client::Any2AptosMessage| has drop + copy + store ) acquires ReceiverRegistryState { let receiver_address = signer::address_of(receiver_account); assert!( @@ -156,19 +154,9 @@ module ccip::receiver_registry { error::invalid_argument(E_ALREADY_REGISTERED) ); - let proof_typeinfo = type_info::type_of(); - assert!( - proof_typeinfo.account_address() == receiver_address, - E_PROOF_TYPE_ACCOUNT_MISMATCH - ); - assert!( - proof_typeinfo.module_name() == receiver_module_name, - E_PROOF_TYPE_MODULE_MISMATCH - ); - move_to( receiver_account, - CCIPReceiverRegistrationV2 { callback, proof_typeinfo } + CCIPReceiverRegistrationV2 { callback } ); let state = borrow_state_mut(); diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move index df62dd41..1bed3bef 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move @@ -71,8 +71,7 @@ module ccip_dummy_receiver::ptt_dummy_receiver { receiver_registry::register_receiver_v2( publisher, MODULE_NAME, - |message| ccip_receive_v2(message), - CCIPReceiverProof {} + |message| ccip_receive_v2(message) ); } @@ -83,8 +82,6 @@ module ccip_dummy_receiver::ptt_dummy_receiver { signer::address_of(&state_signer) } - struct CCIPReceiverProof has drop {} - public fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ let state = borrow_global_mut(@ccip_dummy_receiver); diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 0b3a3a53..641660c6 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -76,8 +76,7 @@ module ccip_offramp::mock_ccip_receiver { receiver_registry::register_receiver_v2( publisher, MODULE_NAME, - |message| ccip_receive_v2(message), - CCIPReceiverProof {} + |message| ccip_receive_v2(message) ); } @@ -95,8 +94,7 @@ module ccip_offramp::mock_ccip_receiver { receiver_registry::register_receiver_v2( publisher, MODULE_NAME, - |message| ccip_receive_v2(message), - CCIPReceiverProof {} + |message| ccip_receive_v2(message) ); } From 6573a4c00ea5259fc2fbd8e1dc95c4355da6294f Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Wed, 10 Dec 2025 18:18:23 -0500 Subject: [PATCH 16/24] Add missing deployer address in ccip dummy receiver bindings --- bindings/ccip_dummy_receiver/ccip_dummy_receiver.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go b/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go index 37418a7a..ee9b3701 100644 --- a/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go +++ b/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go @@ -69,6 +69,9 @@ const ( // DeployToObject deploys the dummmy receiver contract to a new named object. // The resulting address will be calculated using the deployer's account address and the next sequence number +// +// NOTE: This deployment method will NOT work with ptt_dummy_receiver module as it requires resource account. +// Use DeployToResourceAccount if you need PTT functionality. func DeployToObject( auth aptos.TransactionSigner, client aptos.AptosRpcClient, @@ -79,6 +82,7 @@ func DeployToObject( "ccip": ccipAddress, "mcms": mcmsAddress, "mcms_register_entrypoints": aptos.AccountZero, + "deployer": auth.AccountAddress(), // Required for compilation, but ptt_dummy_receiver won't work with object deployment } address, tx, err := bind.DeployPackageToObject(auth, client, contracts.CCIPDummyReceiver, namedAddresses) if err != nil { From 3b00f7628f019cd19c766cee8eb222a4b594d50c Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Wed, 10 Dec 2025 22:07:40 -0500 Subject: [PATCH 17/24] PTT receiver to be consistent with dummy receiver --- bindings/ccip_dummy_receiver/ccip_dummy_receiver.go | 3 ++- bindings/ccip_dummy_receiver/ccip_dummy_receiver_test.go | 2 +- .../ptt_dummy_receiver/ptt_dummy_receiver.go | 2 +- .../ccip_dummy_receiver/sources/ptt_dummy_receiver.move | 9 +++------ 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go b/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go index ee9b3701..8cb21f00 100644 --- a/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go +++ b/bindings/ccip_dummy_receiver/ccip_dummy_receiver.go @@ -44,12 +44,13 @@ var FunctionInfo = bind.MustParseFunctionInfo( module_ptt_dummy_receiver.FunctionInfo, ) -func Compile(address aptos.AccountAddress, ccipAddress aptos.AccountAddress, mcmsAddress aptos.AccountAddress) (compile.CompiledPackage, error) { +func Compile(address aptos.AccountAddress, ccipAddress aptos.AccountAddress, mcmsAddress aptos.AccountAddress, deployer aptos.AccountAddress) (compile.CompiledPackage, error) { namedAddresses := map[string]aptos.AccountAddress{ "ccip_dummy_receiver": address, "ccip": ccipAddress, "mcms": mcmsAddress, "mcms_register_entrypoints": aptos.AccountZero, + "deployer": deployer, } // Compile using CLI return compile.CompilePackage(contracts.CCIPDummyReceiver, namedAddresses) diff --git a/bindings/ccip_dummy_receiver/ccip_dummy_receiver_test.go b/bindings/ccip_dummy_receiver/ccip_dummy_receiver_test.go index 1e3cd326..f07e3b28 100644 --- a/bindings/ccip_dummy_receiver/ccip_dummy_receiver_test.go +++ b/bindings/ccip_dummy_receiver/ccip_dummy_receiver_test.go @@ -9,7 +9,7 @@ import ( func TestCompile(t *testing.T) { t.Parallel() - output, err := Compile(aptos.AccountOne, aptos.AccountOne, aptos.AccountThree) + output, err := Compile(aptos.AccountOne, aptos.AccountOne, aptos.AccountThree, aptos.AccountFour) require.NoError(t, err) require.NotZero(t, output.Metadata, "Compilation resulted in no metadata") require.NotZero(t, output.Bytecode, "Compilation resulted in no bytecode") diff --git a/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go index 363444c6..612f8fee 100644 --- a/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go +++ b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go @@ -58,7 +58,7 @@ const ( // Structs type ReceivedMessage struct { - Message string `move:"0x1::string::String"` + Data []byte `move:"vector"` } type ForwardedTokens struct { diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move index 1bed3bef..04a39614 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move @@ -14,7 +14,7 @@ module ccip_dummy_receiver::ptt_dummy_receiver { #[event] struct ReceivedMessage has store, drop { - message: String + data: vector } #[event] @@ -117,12 +117,9 @@ module ccip_dummy_receiver::ptt_dummy_receiver { &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } ); } else if (data.length() != 0) { - // Convert the vector to a string - let message = string::utf8(data); - - event::emit(ReceivedMessage { message }); + event::emit(ReceivedMessage { data }); event::emit_event( - &mut state.received_message_handle, ReceivedMessage { message } + &mut state.received_message_handle, ReceivedMessage { data } ); } else if (dest_token_amounts.length() != 0) { From 139193fb68ee62d3597baf12c26e77ae2b13f2f0 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Thu, 11 Dec 2025 14:50:56 -0500 Subject: [PATCH 18/24] Remove proof from pool registration. --- .../receiver_registry/receiver_registry.go | 7 ++++ .../ccip/ccip/sources/receiver_registry.move | 38 +++++++++++++++---- .../ccip/sources/token_admin_registry.move | 22 +++-------- .../sources/ptt_dummy_receiver.move | 6 +-- .../tests/mock/mock_ccip_receiver.move | 8 +--- .../sources/burn_mint_token_pool.move | 4 +- .../tests/upgrade_v2.move | 8 +--- .../sources/lock_release_token_pool.move | 4 +- .../tests/upgrade_v2.move | 8 +--- .../sources/managed_token_pool.move | 4 +- .../managed_token_pool/tests/upgrade_v2.move | 8 +--- .../sources/regulated_token_pool.move | 4 +- .../tests/upgrade_v2.move | 8 +--- .../sources/usdc_token_pool.move | 4 +- .../usdc_token_pool/tests/upgrade_v2.move | 8 +--- 15 files changed, 56 insertions(+), 85 deletions(-) diff --git a/bindings/ccip/receiver_registry/receiver_registry.go b/bindings/ccip/receiver_registry/receiver_registry.go index fc7ee891..f0b0d87d 100644 --- a/bindings/ccip/receiver_registry/receiver_registry.go +++ b/bindings/ccip/receiver_registry/receiver_registry.go @@ -64,6 +64,9 @@ const ( type ReceiverRegistryState struct { } +type ReceiverRegistryEventsV2 struct { +} + type CCIPReceiverRegistration struct { DispatchMetadata bind.StdObject `move:"aptos_framework::object::Object"` } @@ -76,6 +79,10 @@ type ReceiverRegistered struct { ReceiverModuleName []byte `move:"vector"` } +type ReceiverRegisteredV2 struct { + ReceiverAddress aptos.AccountAddress `move:"address"` +} + type ReceiverRegistryContract struct { *bind.BoundContract receiverRegistryEncoder diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index 1c21e2e9..c8547e0a 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -23,6 +23,10 @@ module ccip::receiver_registry { receiver_registered_events: EventHandle } + struct ReceiverRegistryEventsV2 has key { + receiver_registered: EventHandle + } + struct CCIPReceiverRegistration has key { ccip_receive_function: FunctionInfo, proof_typeinfo: TypeInfo, @@ -33,7 +37,7 @@ module ccip::receiver_registry { } struct CCIPReceiverRegistrationV2 has key { - callback: |client::Any2AptosMessage| has drop + copy + store + callback: |client::Any2AptosMessage| has copy + drop + store } #[event] @@ -42,6 +46,12 @@ module ccip::receiver_registry { receiver_module_name: vector } + #[event] + struct ReceiverRegisteredV2 has drop, store { + receiver_address: address, + callback: |client::Any2AptosMessage| has copy + drop + store + } + const E_ALREADY_REGISTERED: u64 = 1; const E_UNKNOWN_RECEIVER: u64 = 2; const E_UNKNOWN_PROOF_TYPE: u64 = 3; @@ -145,9 +155,8 @@ module ccip::receiver_registry { public fun register_receiver_v2( receiver_account: &signer, - receiver_module_name: vector, - callback: |client::Any2AptosMessage| has drop + copy + store - ) acquires ReceiverRegistryState { + callback: |client::Any2AptosMessage| has copy + drop + store + ) { let receiver_address = signer::address_of(receiver_account); assert!( !exists(receiver_address), @@ -159,10 +168,9 @@ module ccip::receiver_registry { CCIPReceiverRegistrationV2 { callback } ); - let state = borrow_state_mut(); event::emit_event( - &mut state.receiver_registered_events, - ReceiverRegistered { receiver_address, receiver_module_name } + &mut borrow_events_v2_mut().receiver_registered, + ReceiverRegisteredV2 { receiver_address, callback } ); } @@ -248,6 +256,22 @@ module ccip::receiver_registry { borrow_global_mut(receiver_address) } + inline fun borrow_events_v2_mut(): &mut ReceiverRegistryEventsV2 { + let state_signer = &state_object::object_signer(); + let state_address = state_object::object_address(); + + if (!exists(state_address)) { + move_to( + state_signer, + ReceiverRegistryEventsV2 { + receiver_registered: account::new_event_handle(state_signer) + } + ); + }; + + borrow_global_mut(state_address) + } + #[test_only] public fun init_module_for_testing(publisher: &signer) { init_module(publisher); diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index 28ab1779..31b49d2b 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -87,7 +87,7 @@ module ccip::token_admin_registry { destination_amount: u64 } - struct TokenPoolCallbacks has drop, copy, store { + struct TokenPoolCallbacks has copy, drop, store { lock_or_burn: |FungibleAsset, LockOrBurnInputV1| (vector, vector), release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) } @@ -421,14 +421,12 @@ module ccip::token_admin_registry { ); } - public fun register_pool_v2( + public fun register_pool_v2( token_pool_account: &signer, - token_pool_module_name: vector, local_token: address, - lock_or_burn: |FungibleAsset, LockOrBurnInputV1| (vector, vector) has drop - + copy + store, - release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) has drop + copy + store, - _proof: ProofType + lock_or_burn: |FungibleAsset, LockOrBurnInputV1| (vector, vector) has copy + + drop + store, + release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) has copy + drop + store ) { let token_pool_address = signer::address_of(token_pool_account); assert!( @@ -440,16 +438,6 @@ module ccip::token_admin_registry { error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) ); - let proof_typeinfo = type_info::type_of(); - assert!( - proof_typeinfo.account_address() == token_pool_address, - error::invalid_argument(E_PROOF_NOT_AT_TOKEN_POOL_ADDRESS) - ); - assert!( - proof_typeinfo.module_name() == token_pool_module_name, - error::invalid_argument(E_PROOF_NOT_IN_TOKEN_POOL_MODULE) - ); - move_to( token_pool_account, TokenPoolConfig { diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move index 04a39614..79f35e4f 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move @@ -44,8 +44,6 @@ module ccip_dummy_receiver::ptt_dummy_receiver { string::utf8(b"PTTDummyReceiver 1.6.0") } - const MODULE_NAME: vector = b"ptt_dummy_receiver"; - fun init_module(publisher: &signer) { let signer_cap = resource_account::retrieve_resource_account_cap(publisher, @deployer); @@ -69,9 +67,7 @@ module ccip_dummy_receiver::ptt_dummy_receiver { // Default to V2 registration receiver_registry::register_receiver_v2( - publisher, - MODULE_NAME, - |message| ccip_receive_v2(message) + publisher, |message| ccip_receive_v2(message) ); } diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 641660c6..269c6962 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -74,9 +74,7 @@ module ccip_offramp::mock_ccip_receiver { // Default to V2 registration receiver_registry::register_receiver_v2( - publisher, - MODULE_NAME, - |message| ccip_receive_v2(message) + publisher, |message| ccip_receive_v2(message) ); } @@ -92,9 +90,7 @@ module ccip_offramp::mock_ccip_receiver { // V2 registration will coexist with V1 // The dispatcher will prefer V2 when both exist receiver_registry::register_receiver_v2( - publisher, - MODULE_NAME, - |message| ccip_receive_v2(message) + publisher, |message| ccip_receive_v2(message) ); } diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index 70e0481c..d6925689 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -79,11 +79,9 @@ module burn_mint_token_pool::burn_mint_token_pool { // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, @burn_mint_local_token, lock_or_burn_closure, - release_or_mint_closure, - CallbackProof {} + release_or_mint_closure ); // create a resource account to be the owner of the primary FungibleStore we will use. diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move index 6d838345..d9dcf35c 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move @@ -22,10 +22,6 @@ module burn_mint_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@burn_mint_token_pool); - // the name of this module. if incorrect, callbacks will fail to be registered and - // register_pool will revert. - let token_pool_module_name = b"burn_mint_token_pool"; - let lock_or_burn_closure = |fa, input| burn_mint_token_pool::lock_or_burn_v2(fa, input); let release_or_mint_closure = @@ -35,11 +31,9 @@ module burn_mint_token_pool::upgrade_v2 { // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, @burn_mint_local_token, lock_or_burn_closure, - release_or_mint_closure, - burn_mint_token_pool::create_callback_proof() + release_or_mint_closure ); } diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index a2e800fb..4d99b12e 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -81,11 +81,9 @@ module lock_release_token_pool::lock_release_token_pool { // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, @lock_release_local_token, lock_or_burn_closure, - release_or_mint_closure, - CallbackProof {} + release_or_mint_closure ); // create a resource account to be the owner of the primary FungibleStore we will use. diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move index 7d42c801..117e32d1 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move @@ -22,10 +22,6 @@ module lock_release_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@lock_release_token_pool); - // the name of this module. if incorrect, callbacks will fail to be registered and - // register_pool will revert. - let token_pool_module_name = b"lock_release_token_pool"; - let lock_or_burn_closure = |fa, input| lock_release_token_pool::lock_or_burn_v2(fa, input); let release_or_mint_closure = @@ -35,11 +31,9 @@ module lock_release_token_pool::upgrade_v2 { // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, @lock_release_local_token, lock_or_burn_closure, - release_or_mint_closure, - lock_release_token_pool::create_callback_proof() + release_or_mint_closure ); } diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index 524bb7a0..b93bfd7a 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -67,11 +67,9 @@ module managed_token_pool::managed_token_pool { // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, managed_token_address, lock_or_burn_closure, - release_or_mint_closure, - CallbackProof {} + release_or_mint_closure ); // create a resource account to be the owner of the primary FungibleStore we will use. diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move index e2be9476..3820765f 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move @@ -14,10 +14,6 @@ module managed_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@managed_token_pool); - // the name of this module. if incorrect, callbacks will fail to be registered and - // register_pool will revert. - let token_pool_module_name = b"managed_token_pool"; - let managed_token_address = managed_token::token_metadata(); let lock_or_burn_closure = @@ -29,11 +25,9 @@ module managed_token_pool::upgrade_v2 { // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, managed_token_address, lock_or_burn_closure, - release_or_mint_closure, - managed_token_pool::create_callback_proof() + release_or_mint_closure ); } diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index dc1dd769..b63a19ad 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -67,11 +67,9 @@ module regulated_token_pool::regulated_token_pool { // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, regulated_token_address, lock_or_burn_closure, - release_or_mint_closure, - CallbackProof {} + release_or_mint_closure ); // create a resource account to be the owner of the primary FungibleStore we will use. diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move index 9cd54956..caf89caf 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move @@ -14,10 +14,6 @@ module regulated_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@regulated_token_pool); - // the name of this module. if incorrect, callbacks will fail to be registered and - // register_pool will revert. - let token_pool_module_name = b"regulated_token_pool"; - let regulated_token_address = regulated_token::token_address(); let lock_or_burn_closure = @@ -29,11 +25,9 @@ module regulated_token_pool::upgrade_v2 { // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, regulated_token_address, lock_or_burn_closure, - release_or_mint_closure, - regulated_token_pool::create_callback_proof() + release_or_mint_closure ); } diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index 4b4c1d9f..7ec6d72f 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -119,11 +119,9 @@ module usdc_token_pool::usdc_token_pool { // Register V2 pool with closure-based callbacks token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, @local_token, lock_or_burn_closure, - release_or_mint_closure, - CallbackProof {} + release_or_mint_closure ); // create a resource account to be the owner of the primary FungibleStore we will use. diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move index 62ecd44d..ad23bd34 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move @@ -22,10 +22,6 @@ module usdc_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@usdc_token_pool); - // the name of this module. if incorrect, callbacks will fail to be registered and - // register_pool will revert. - let token_pool_module_name = b"usdc_token_pool"; - let lock_or_burn_closure = |fa, input| usdc_token_pool::lock_or_burn_v2( fa, input ); @@ -35,11 +31,9 @@ module usdc_token_pool::upgrade_v2 { // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` token_admin_registry::register_pool_v2( publisher, - token_pool_module_name, @local_token, lock_or_burn_closure, - release_or_mint_closure, - usdc_token_pool::create_callback_proof() + release_or_mint_closure ); } From 0c21ac597f67501e3b34de3733845e82a1ef3211 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Thu, 11 Dec 2025 19:27:31 -0500 Subject: [PATCH 19/24] receiver_registered_v2_events rename --- contracts/ccip/ccip/sources/receiver_registry.move | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index c8547e0a..90b87064 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -24,7 +24,7 @@ module ccip::receiver_registry { } struct ReceiverRegistryEventsV2 has key { - receiver_registered: EventHandle + receiver_registered_v2_events: EventHandle } struct CCIPReceiverRegistration has key { @@ -169,7 +169,7 @@ module ccip::receiver_registry { ); event::emit_event( - &mut borrow_events_v2_mut().receiver_registered, + &mut borrow_events_v2_mut().receiver_registered_v2_events, ReceiverRegisteredV2 { receiver_address, callback } ); } @@ -264,7 +264,7 @@ module ccip::receiver_registry { move_to( state_signer, ReceiverRegistryEventsV2 { - receiver_registered: account::new_event_handle(state_signer) + receiver_registered_v2_events: account::new_event_handle(state_signer) } ); }; From 0c8c4c8a8506aaba3f34b3d79881c377187ed8f1 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Thu, 29 Jan 2026 00:53:24 -0500 Subject: [PATCH 20/24] Add persistent callbacks --- .../burn_mint_token_pool.go | 7 +++- .../lock_release_token_pool.go | 7 +++- .../managed_token_pool/managed_token_pool.go | 7 +++- .../regulated_token_pool.go | 7 +++- .../usdc_token_pool/usdc_token_pool.go | 7 +++- .../sources/ptt_dummy_receiver.move | 3 +- .../tests/mock/mock_ccip_receiver.move | 3 +- .../sources/burn_mint_token_pool.move | 28 +++++++++------ .../tests/upgrade_v2.move | 14 +------- .../sources/lock_release_token_pool.move | 28 +++++++++------ .../tests/upgrade_v2.move | 14 +------- .../sources/managed_token_pool.move | 36 +++++++++++-------- .../managed_token_pool/tests/upgrade_v2.move | 17 +-------- .../sources/regulated_token_pool.move | 33 ++++++++++------- .../tests/upgrade_v2.move | 17 +-------- .../sources/usdc_token_pool.move | 28 +++++++++------ .../usdc_token_pool/tests/upgrade_v2.move | 14 +------- 17 files changed, 131 insertions(+), 139 deletions(-) diff --git a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go index ee8f84a2..c2401fdb 100644 --- a/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go +++ b/bindings/ccip_token_pools/burn_mint_token_pool/burn_mint_token_pool/burn_mint_token_pool.go @@ -88,13 +88,14 @@ type BurnMintTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertCanInitialize(callerAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"accept_ownership","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"store_address","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"accept_ownership","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"register_v2_callbacks","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"store_address","parameters":null},{"package":"burn_mint_token_pool","module":"burn_mint_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewBurnMintTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) BurnMintTokenPoolInterface { contract := bind.NewBoundContract(address, "burn_mint_token_pool", "burn_mint_token_pool", client) @@ -854,6 +855,10 @@ func (c burnMintTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddre }) } +func (c burnMintTokenPoolEncoder) RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("register_v2_callbacks", nil, []string{}, []any{}) +} + func (c burnMintTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go index 413b73b8..daebaede 100644 --- a/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go +++ b/bindings/ccip_token_pools/lock_release_token_pool/lock_release_token_pool/lock_release_token_pool.go @@ -102,13 +102,14 @@ type LockReleaseTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AssertCanInitialize(callerAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"accept_ownership","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"provide_liquidity","parameters":[{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_rebalancer","parameters":[{"name":"rebalancer","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"store_address","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"withdraw_liquidity","parameters":[{"name":"amount","type":"u64"}]}]` +const FunctionInfo = `[{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"accept_ownership","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"provide_liquidity","parameters":[{"name":"amount","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"register_v2_callbacks","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"set_rebalancer","parameters":[{"name":"rebalancer","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"store_address","parameters":null},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]},{"package":"lock_release_token_pool","module":"lock_release_token_pool","name":"withdraw_liquidity","parameters":[{"name":"amount","type":"u64"}]}]` func NewLockReleaseTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) LockReleaseTokenPoolInterface { contract := bind.NewBoundContract(address, "lock_release_token_pool", "lock_release_token_pool", client) @@ -1022,6 +1023,10 @@ func (c lockReleaseTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAd }) } +func (c lockReleaseTokenPoolEncoder) RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("register_v2_callbacks", nil, []string{}, []any{}) +} + func (c lockReleaseTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go index 585473a2..f1ceea5d 100644 --- a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go +++ b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go @@ -88,12 +88,13 @@ type ManagedTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"managed_token_pool","module":"managed_token_pool","name":"accept_ownership","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"store_address","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"managed_token_pool","module":"managed_token_pool","name":"accept_ownership","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"register_v2_callbacks","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"managed_token_pool","module":"managed_token_pool","name":"store_address","parameters":null},{"package":"managed_token_pool","module":"managed_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewManagedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) ManagedTokenPoolInterface { contract := bind.NewBoundContract(address, "managed_token_pool", "managed_token_pool", client) @@ -848,6 +849,10 @@ func (c managedTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddres }) } +func (c managedTokenPoolEncoder) RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("register_v2_callbacks", nil, []string{}, []any{}) +} + func (c managedTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go index 854def7f..30427c91 100644 --- a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go +++ b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go @@ -88,12 +88,13 @@ type RegulatedTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) MCMSEntrypoint(Metadata aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"regulated_token_pool","module":"regulated_token_pool","name":"accept_ownership","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"store_address","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"regulated_token_pool","module":"regulated_token_pool","name":"accept_ownership","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"register_v2_callbacks","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"store_address","parameters":null},{"package":"regulated_token_pool","module":"regulated_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewRegulatedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) RegulatedTokenPoolInterface { contract := bind.NewBoundContract(address, "regulated_token_pool", "regulated_token_pool", client) @@ -848,6 +849,10 @@ func (c regulatedTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddr }) } +func (c regulatedTokenPoolEncoder) RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("register_v2_callbacks", nil, []string{}, []any{}) +} + func (c regulatedTokenPoolEncoder) StoreAddress() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("store_address", nil, []string{}, []any{}) } diff --git a/bindings/ccip_token_pools/usdc_token_pool/usdc_token_pool/usdc_token_pool.go b/bindings/ccip_token_pools/usdc_token_pool/usdc_token_pool/usdc_token_pool.go index 609e0f98..fa3c9762 100644 --- a/bindings/ccip_token_pools/usdc_token_pool/usdc_token_pool/usdc_token_pool.go +++ b/bindings/ccip_token_pools/usdc_token_pool/usdc_token_pool/usdc_token_pool.go @@ -90,6 +90,7 @@ type USDCTokenPoolEncoder interface { TransferOwnership(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) AcceptOwnership() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ExecuteOwnershipTransfer(to aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) Initialize() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) ParseMessageAndAttestation(payload []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) EncodeDestPoolData(localDomainIdentifier uint32, nonce uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -101,7 +102,7 @@ type USDCTokenPoolEncoder interface { RegisterMCMSEntrypoint(moduleName []byte) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) } -const FunctionInfo = `[{"package":"usdc_token_pool","module":"usdc_token_pool","name":"accept_ownership","parameters":null},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"decode_dest_pool_data","parameters":[{"name":"dest_pool_data","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"encode_dest_pool_data","parameters":[{"name":"local_domain_identifier","type":"u32"},{"name":"nonce","type":"u64"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"initialize","parameters":null},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"parse_message_and_attestation","parameters":[{"name":"payload","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_domains","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"remote_domain_identifiers","type":"vector\u003cu32\u003e"},{"name":"allowed_remote_callers","type":"vector\u003cvector\u003cu8\u003e\u003e"},{"name":"enableds","type":"vector\u003cbool\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"store_address","parameters":null},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` +const FunctionInfo = `[{"package":"usdc_token_pool","module":"usdc_token_pool","name":"accept_ownership","parameters":null},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"add_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"apply_allowlist_updates","parameters":[{"name":"removes","type":"vector\u003caddress\u003e"},{"name":"adds","type":"vector\u003caddress\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"apply_chain_updates","parameters":[{"name":"remote_chain_selectors_to_remove","type":"vector\u003cu64\u003e"},{"name":"remote_chain_selectors_to_add","type":"vector\u003cu64\u003e"},{"name":"remote_pool_addresses_to_add","type":"vector\u003cvector\u003cvector\u003cu8\u003e\u003e\u003e"},{"name":"remote_token_addresses_to_add","type":"vector\u003cvector\u003cu8\u003e\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"assert_can_initialize","parameters":[{"name":"caller_address","type":"address"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"decode_dest_pool_data","parameters":[{"name":"dest_pool_data","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"encode_dest_pool_data","parameters":[{"name":"local_domain_identifier","type":"u32"},{"name":"nonce","type":"u64"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"execute_ownership_transfer","parameters":[{"name":"to","type":"address"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"initialize","parameters":null},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"mcms_entrypoint","parameters":[{"name":"_metadata","type":"address"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"parse_message_and_attestation","parameters":[{"name":"payload","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"register_mcms_entrypoint","parameters":[{"name":"module_name","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"register_v2_callbacks","parameters":null},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"remove_remote_pool","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"remote_pool_address","type":"vector\u003cu8\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_allowlist_enabled","parameters":[{"name":"enabled","type":"bool"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_chain_rate_limiter_config","parameters":[{"name":"remote_chain_selector","type":"u64"},{"name":"outbound_is_enabled","type":"bool"},{"name":"outbound_capacity","type":"u64"},{"name":"outbound_rate","type":"u64"},{"name":"inbound_is_enabled","type":"bool"},{"name":"inbound_capacity","type":"u64"},{"name":"inbound_rate","type":"u64"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_chain_rate_limiter_configs","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"outbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"outbound_capacities","type":"vector\u003cu64\u003e"},{"name":"outbound_rates","type":"vector\u003cu64\u003e"},{"name":"inbound_is_enableds","type":"vector\u003cbool\u003e"},{"name":"inbound_capacities","type":"vector\u003cu64\u003e"},{"name":"inbound_rates","type":"vector\u003cu64\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"set_domains","parameters":[{"name":"remote_chain_selectors","type":"vector\u003cu64\u003e"},{"name":"remote_domain_identifiers","type":"vector\u003cu32\u003e"},{"name":"allowed_remote_callers","type":"vector\u003cvector\u003cu8\u003e\u003e"},{"name":"enableds","type":"vector\u003cbool\u003e"}]},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"store_address","parameters":null},{"package":"usdc_token_pool","module":"usdc_token_pool","name":"transfer_ownership","parameters":[{"name":"to","type":"address"}]}]` func NewUSDCTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClient) USDCTokenPoolInterface { contract := bind.NewBoundContract(address, "usdc_token_pool", "usdc_token_pool", client) @@ -912,6 +913,10 @@ func (c usdcTokenPoolEncoder) ExecuteOwnershipTransfer(to aptos.AccountAddress) }) } +func (c usdcTokenPoolEncoder) RegisterV2Callbacks() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("register_v2_callbacks", nil, []string{}, []any{}) +} + func (c usdcTokenPoolEncoder) Initialize() (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { return c.BoundContract.Encode("initialize", nil, []string{}, []any{}) } diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move index 79f35e4f..da3b6882 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move @@ -78,7 +78,8 @@ module ccip_dummy_receiver::ptt_dummy_receiver { signer::address_of(&state_signer) } - public fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { + #[persistent] + fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ let state = borrow_global_mut(@ccip_dummy_receiver); let state_signer = account::create_signer_with_capability(&state.signer_cap); diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 269c6962..171ca5c0 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -103,7 +103,8 @@ module ccip_offramp::mock_ccip_receiver { struct CCIPReceiverProof has drop {} - public fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { + #[persistent] + fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ let state = borrow_global_mut(@ccip_offramp); let state_signer = account::create_signer_with_capability(&state.signer_cap); diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index d6925689..e86af3ba 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -73,16 +73,8 @@ module burn_mint_token_pool::burn_mint_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - // Register V2 pool with closure-based callbacks - token_admin_registry::register_pool_v2( - publisher, - @burn_mint_local_token, - lock_or_burn_closure, - release_or_mint_closure - ); + register_v2_callbacks(publisher); // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = @@ -145,6 +137,18 @@ module burn_mint_token_pool::burn_mint_token_pool { move_to(&store_signer, pool); } + public fun register_v2_callbacks(publisher: &signer) { + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + @burn_mint_local_token, + lock_or_burn_closure, + release_or_mint_closure + ); + } + // ================================================================ // | Exposing token_pool functions | // ================================================================ @@ -367,7 +371,8 @@ module burn_mint_token_pool::burn_mint_token_pool { fa } - public fun lock_or_burn_v2( + #[persistent] + fun lock_or_burn_v2( fa: FungibleAsset, input: LockOrBurnInputV1 ): (vector, vector) acquires BurnMintTokenPoolState { let pool = borrow_pool_mut(); @@ -396,7 +401,8 @@ module burn_mint_token_pool::burn_mint_token_pool { (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } - public fun release_or_mint_v2( + #[persistent] + fun release_or_mint_v2( input: ReleaseOrMintInputV1 ): (FungibleAsset, u64) acquires BurnMintTokenPoolState { let pool = borrow_pool_mut(); diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move index d9dcf35c..6f442a05 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/tests/upgrade_v2.move @@ -7,8 +7,6 @@ module burn_mint_token_pool::upgrade_v2 { use burn_mint_token_pool::burn_mint_token_pool; - use ccip::token_admin_registry::{Self}; - const E_INVALID_FUNGIBLE_ASSET: u64 = 1; fun init_module(publisher: &signer) { @@ -22,19 +20,9 @@ module burn_mint_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@burn_mint_token_pool); - let lock_or_burn_closure = - |fa, input| burn_mint_token_pool::lock_or_burn_v2(fa, input); - let release_or_mint_closure = - |input| burn_mint_token_pool::release_or_mint_v2(input); - // If the contract has already been deployed with V1 and needs to be upgraded to V2, // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` - token_admin_registry::register_pool_v2( - publisher, - @burn_mint_local_token, - lock_or_burn_closure, - release_or_mint_closure - ); + burn_mint_token_pool::register_v2_callbacks(publisher); } #[test_only] diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index 4d99b12e..ebe8e73c 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -75,16 +75,8 @@ module lock_release_token_pool::lock_release_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - // Register V2 pool with closure-based callbacks - token_admin_registry::register_pool_v2( - publisher, - @lock_release_local_token, - lock_or_burn_closure, - release_or_mint_closure - ); + register_v2_callbacks(publisher); // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = @@ -162,6 +154,18 @@ module lock_release_token_pool::lock_release_token_pool { move_to(&store_signer, pool); } + public fun register_v2_callbacks(publisher: &signer) { + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + @lock_release_local_token, + lock_or_burn_closure, + release_or_mint_closure + ); + } + // ================================================================ // | Exposing token_pool functions | // ================================================================ @@ -435,7 +439,8 @@ module lock_release_token_pool::lock_release_token_pool { fa } - public fun lock_or_burn_v2( + #[persistent] + fun lock_or_burn_v2( fa: FungibleAsset, input: LockOrBurnInputV1 ): (vector, vector) acquires LockReleaseTokenPoolState { let pool = borrow_pool_mut(); @@ -462,7 +467,8 @@ module lock_release_token_pool::lock_release_token_pool { (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } - public fun release_or_mint_v2( + #[persistent] + fun release_or_mint_v2( input: ReleaseOrMintInputV1 ): (FungibleAsset, u64) acquires LockReleaseTokenPoolState { let pool = borrow_pool_mut(); diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move index 117e32d1..0fbd1d1f 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/tests/upgrade_v2.move @@ -7,8 +7,6 @@ module lock_release_token_pool::upgrade_v2 { use lock_release_token_pool::lock_release_token_pool; - use ccip::token_admin_registry::{Self}; - const E_INVALID_FUNGIBLE_ASSET: u64 = 1; fun init_module(publisher: &signer) { @@ -22,19 +20,9 @@ module lock_release_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@lock_release_token_pool); - let lock_or_burn_closure = - |fa, input| lock_release_token_pool::lock_or_burn_v2(fa, input); - let release_or_mint_closure = - |input| lock_release_token_pool::release_or_mint_v2(input); - // If the contract has already been deployed with V1 and needs to be upgraded to V2, // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` - token_admin_registry::register_pool_v2( - publisher, - @lock_release_local_token, - lock_or_burn_closure, - release_or_mint_closure - ); + lock_release_token_pool::register_v2_callbacks(publisher); } #[test_only] diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index b93bfd7a..18e542af 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -59,23 +59,14 @@ module managed_token_pool::managed_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - let managed_token_address = managed_token::token_metadata(); - - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - // Register V2 pool with closure-based callbacks - token_admin_registry::register_pool_v2( - publisher, - managed_token_address, - lock_or_burn_closure, - release_or_mint_closure - ); + register_v2_callbacks(publisher); // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = account::create_resource_account(publisher, STORE_OBJECT_SEED); + let managed_token_address = managed_token::token_metadata(); let metadata = object::address_to_object(managed_token_address); // make sure this is a valid fungible asset that is primary fungible store enabled, @@ -98,6 +89,20 @@ module managed_token_pool::managed_token_pool { move_to(&store_signer, pool); } + public fun register_v2_callbacks(publisher: &signer) { + let managed_token_address = managed_token::token_metadata(); + + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + managed_token_address, + lock_or_burn_closure, + release_or_mint_closure + ); + } + // ================================================================ // | Exposing token_pool functions | // ================================================================ @@ -332,9 +337,9 @@ module managed_token_pool::managed_token_pool { fa } - public fun lock_or_burn_v2( - fa: FungibleAsset, input: LockOrBurnInputV1 - ): (vector, vector) { + #[persistent] + fun lock_or_burn_v2(fa: FungibleAsset, input: LockOrBurnInputV1) + : (vector, vector) { let pool = borrow_pool_mut(); let fa_amount = fungible_asset::amount(&fa); @@ -367,7 +372,8 @@ module managed_token_pool::managed_token_pool { (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } - public fun release_or_mint_v2(input: ReleaseOrMintInputV1): (FungibleAsset, u64) { + #[persistent] + fun release_or_mint_v2(input: ReleaseOrMintInputV1): (FungibleAsset, u64) { let pool = borrow_pool_mut(); let local_amount = token_pool::calculate_release_or_mint_amount(&pool.token_pool_state, &input); diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move index 3820765f..9e8c413d 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/tests/upgrade_v2.move @@ -2,11 +2,8 @@ module managed_token_pool::upgrade_v2 { use std::account::{Self}; - use managed_token::managed_token; use managed_token_pool::managed_token_pool; - use ccip::token_admin_registry::{Self}; - fun init_module(publisher: &signer) { // register the pool on deployment, because in the case of object code deployment, // this is the only time we have a signer ref to @managed_token_pool. @@ -14,21 +11,9 @@ module managed_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@managed_token_pool); - let managed_token_address = managed_token::token_metadata(); - - let lock_or_burn_closure = - |fa, input| managed_token_pool::lock_or_burn_v2(fa, input); - let release_or_mint_closure = - |input| managed_token_pool::release_or_mint_v2(input); - // If the contract has already been deployed with V1 and needs to be upgraded to V2, // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` - token_admin_registry::register_pool_v2( - publisher, - managed_token_address, - lock_or_burn_closure, - release_or_mint_closure - ); + managed_token_pool::register_v2_callbacks(publisher); } #[test_only] diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index b63a19ad..13e17aba 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -59,23 +59,14 @@ module regulated_token_pool::regulated_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - let regulated_token_address = regulated_token::token_address(); - - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - // Register V2 pool with closure-based callbacks - token_admin_registry::register_pool_v2( - publisher, - regulated_token_address, - lock_or_burn_closure, - release_or_mint_closure - ); + register_v2_callbacks(publisher); // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = account::create_resource_account(publisher, STORE_OBJECT_SEED); + let regulated_token_address = regulated_token::token_address(); let metadata = object::address_to_object(regulated_token_address); // make sure this is a valid fungible asset that is primary fungible store enabled, @@ -96,6 +87,20 @@ module regulated_token_pool::regulated_token_pool { move_to(&store_signer, pool); } + public fun register_v2_callbacks(publisher: &signer) { + let regulated_token_address = regulated_token::token_address(); + + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + regulated_token_address, + lock_or_burn_closure, + release_or_mint_closure + ); + } + // ================================================================ // | Exposing token_pool functions | // ================================================================ @@ -321,7 +326,8 @@ module regulated_token_pool::regulated_token_pool { fa } - public fun lock_or_burn_v2( + #[persistent] + fun lock_or_burn_v2( fa: FungibleAsset, input: LockOrBurnInputV1 ): (vector, vector) acquires RegulatedTokenPoolState { let pool = borrow_pool_mut(); @@ -349,7 +355,8 @@ module regulated_token_pool::regulated_token_pool { (dest_token_address, token_pool::encode_local_decimals(&pool.token_pool_state)) } - public fun release_or_mint_v2( + #[persistent] + fun release_or_mint_v2( input: ReleaseOrMintInputV1 ): (FungibleAsset, u64) acquires RegulatedTokenPoolState { let pool = borrow_pool_mut(); diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move index caf89caf..220edb7b 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/tests/upgrade_v2.move @@ -2,11 +2,8 @@ module regulated_token_pool::upgrade_v2 { use std::account::{Self}; - use regulated_token::regulated_token::{Self}; use regulated_token_pool::regulated_token_pool; - use ccip::token_admin_registry::{Self}; - fun init_module(publisher: &signer) { // register the pool on deployment, because in the case of object code deployment, // this is the only time we have a signer ref to @regulated_token_pool. @@ -14,21 +11,9 @@ module regulated_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@regulated_token_pool); - let regulated_token_address = regulated_token::token_address(); - - let lock_or_burn_closure = - |fa, input| regulated_token_pool::lock_or_burn_v2(fa, input); - let release_or_mint_closure = - |input| regulated_token_pool::release_or_mint_v2(input); - // If the contract has already been deployed with V1 and needs to be upgraded to V2, // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` - token_admin_registry::register_pool_v2( - publisher, - regulated_token_address, - lock_or_burn_closure, - release_or_mint_closure - ); + regulated_token_pool::register_v2_callbacks(publisher); } #[test_only] diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index 7ec6d72f..c9af961c 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -113,16 +113,8 @@ module usdc_token_pool::usdc_token_pool { register_mcms_entrypoint(publisher, token_pool_module_name); }; - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - // Register V2 pool with closure-based callbacks - token_admin_registry::register_pool_v2( - publisher, - @local_token, - lock_or_burn_closure, - release_or_mint_closure - ); + register_v2_callbacks(publisher); // create a resource account to be the owner of the primary FungibleStore we will use. let (store_signer, store_signer_cap) = @@ -147,6 +139,18 @@ module usdc_token_pool::usdc_token_pool { ); } + public fun register_v2_callbacks(publisher: &signer) { + let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); + let release_or_mint_closure = |input| release_or_mint_v2(input); + + token_admin_registry::register_pool_v2( + publisher, + @local_token, + lock_or_burn_closure, + release_or_mint_closure + ); + } + public fun initialize(caller: &signer) acquires USDCTokenPoolDeployment { assert_can_initialize(signer::address_of(caller)); @@ -498,7 +502,8 @@ module usdc_token_pool::usdc_token_pool { ); } - public fun lock_or_burn_v2( + #[persistent] + fun lock_or_burn_v2( fa: FungibleAsset, input: LockOrBurnInputV1 ): (vector, vector) acquires USDCTokenPoolState { let pool = borrow_pool_mut(); @@ -549,7 +554,8 @@ module usdc_token_pool::usdc_token_pool { (dest_token_address, dest_pool_data) } - public fun release_or_mint_v2( + #[persistent] + fun release_or_mint_v2( input: ReleaseOrMintInputV1 ): (FungibleAsset, u64) acquires USDCTokenPoolState { let pool = borrow_pool_mut(); diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move index ad23bd34..296c1dce 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/tests/upgrade_v2.move @@ -7,8 +7,6 @@ module usdc_token_pool::upgrade_v2 { use usdc_token_pool::usdc_token_pool; - use ccip::token_admin_registry::{Self}; - const E_INVALID_FUNGIBLE_ASSET: u64 = 1; fun init_module(publisher: &signer) { @@ -22,19 +20,9 @@ module usdc_token_pool::upgrade_v2 { // create an Account on the object for event handles. account::create_account_if_does_not_exist(@usdc_token_pool); - let lock_or_burn_closure = |fa, input| usdc_token_pool::lock_or_burn_v2( - fa, input - ); - let release_or_mint_closure = |input| usdc_token_pool::release_or_mint_v2(input); - // If the contract has already been deployed with V1 and needs to be upgraded to V2, // create a new module and pass in `publisher` from `fun init_module(publisher: &signer)` - token_admin_registry::register_pool_v2( - publisher, - @local_token, - lock_or_burn_closure, - release_or_mint_closure - ); + usdc_token_pool::register_v2_callbacks(publisher); } #[test_only] From 61aa64c91edd244659fb94e9ae7185bb83dd8891 Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Sat, 7 Feb 2026 14:55:12 -0500 Subject: [PATCH 21/24] Add documentation, refactor on chain code --- .../token_admin_registry.go | 15 +++-- .../ptt_dummy_receiver/ptt_dummy_receiver.go | 4 +- .../managed_token_pool/managed_token_pool.go | 8 +-- .../regulated_token_pool.go | 8 +-- .../ccip/ccip/sources/receiver_registry.move | 25 ++++++- .../ccip/sources/token_admin_dispatcher.move | 4 +- .../ccip/sources/token_admin_registry.move | 66 ++++++++++++------- .../sources/ptt_dummy_receiver.move | 11 +++- .../ccip/ccip_offramp/sources/offramp.move | 5 +- .../tests/mock/mock_ccip_receiver.move | 5 ++ .../offramp_v1_v2_compatibility_test.move | 6 +- .../onramp_v1_v2_pool_compatibility_test.move | 12 ++-- .../sources/burn_mint_token_pool.move | 7 +- .../sources/lock_release_token_pool.move | 7 +- .../sources/managed_token_pool.move | 16 ++--- .../sources/regulated_token_pool.move | 16 ++--- .../sources/usdc_token_pool.move | 7 +- 17 files changed, 122 insertions(+), 100 deletions(-) diff --git a/bindings/ccip/token_admin_registry/token_admin_registry.go b/bindings/ccip/token_admin_registry/token_admin_registry.go index ea18548a..caaef27d 100644 --- a/bindings/ccip/token_admin_registry/token_admin_registry.go +++ b/bindings/ccip/token_admin_registry/token_admin_registry.go @@ -27,7 +27,7 @@ type TokenAdminRegistryInterface interface { GetPool(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, error) GetPoolLocalToken(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (aptos.AccountAddress, error) GetPoolLocalTokenV2(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (aptos.AccountAddress, error) - HasTokenPoolConfig(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (bool, error) + HasTokenPoolRegistrationV2(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (bool, error) GetTokenConfig(opts *bind.CallOpts, localToken aptos.AccountAddress) (aptos.AccountAddress, aptos.AccountAddress, aptos.AccountAddress, error) GetAllConfiguredTokens(opts *bind.CallOpts, startKey aptos.AccountAddress, maxCount uint64) ([]aptos.AccountAddress, aptos.AccountAddress, bool, error) IsAdministrator(opts *bind.CallOpts, localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bool, error) @@ -48,7 +48,7 @@ type TokenAdminRegistryEncoder interface { GetPool(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetPoolLocalToken(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetPoolLocalTokenV2(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) - HasTokenPoolConfig(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) + HasTokenPoolRegistrationV2(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetTokenConfig(localToken aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) GetAllConfiguredTokens(startKey aptos.AccountAddress, maxCount uint64) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) IsAdministrator(localToken aptos.AccountAddress, administrator aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) @@ -106,6 +106,7 @@ const ( E_ADMIN_ALREADY_SET_FOR_TOKEN uint64 = 28 E_ZERO_ADDRESS uint64 = 29 E_POOL_NOT_REGISTERED uint64 = 30 + E_TOKEN_MISMATCH uint64 = 31 ) // Structs @@ -158,7 +159,7 @@ type ReleaseOrMintOutputV1 struct { type TokenPoolCallbacks struct { } -type TokenPoolConfig struct { +type TokenPoolRegistrationV2 struct { Callbacks TokenPoolCallbacks `move:"TokenPoolCallbacks"` LocalToken aptos.AccountAddress `move:"address"` } @@ -306,8 +307,8 @@ func (c TokenAdminRegistryContract) GetPoolLocalTokenV2(opts *bind.CallOpts, tok return r0, nil } -func (c TokenAdminRegistryContract) HasTokenPoolConfig(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (bool, error) { - module, function, typeTags, args, err := c.tokenAdminRegistryEncoder.HasTokenPoolConfig(tokenPoolAddress) +func (c TokenAdminRegistryContract) HasTokenPoolRegistrationV2(opts *bind.CallOpts, tokenPoolAddress aptos.AccountAddress) (bool, error) { + module, function, typeTags, args, err := c.tokenAdminRegistryEncoder.HasTokenPoolRegistrationV2(tokenPoolAddress) if err != nil { return *new(bool), err } @@ -482,8 +483,8 @@ func (c tokenAdminRegistryEncoder) GetPoolLocalTokenV2(tokenPoolAddress aptos.Ac }) } -func (c tokenAdminRegistryEncoder) HasTokenPoolConfig(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { - return c.BoundContract.Encode("has_token_pool_config", nil, []string{ +func (c tokenAdminRegistryEncoder) HasTokenPoolRegistrationV2(tokenPoolAddress aptos.AccountAddress) (bind.ModuleInformation, string, []aptos.TypeTag, [][]byte, error) { + return c.BoundContract.Encode("has_token_pool_registration_v2", nil, []string{ "address", }, []any{ tokenPoolAddress, diff --git a/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go index 612f8fee..be352bee 100644 --- a/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go +++ b/bindings/ccip_dummy_receiver/ptt_dummy_receiver/ptt_dummy_receiver.go @@ -51,8 +51,8 @@ func NewPttDummyReceiver(address aptos.AccountAddress, client aptos.AptosRpcClie const ( E_RESOURCE_NOT_FOUND_ON_ACCOUNT uint64 = 1 E_UNAUTHORIZED uint64 = 2 - E_INVALID_TOKEN_ADDRESS uint64 = 3 - E_NO_TOKENS_AVAILABLE_TO_WITHDRAW uint64 = 4 + E_NO_TOKENS_AVAILABLE_TO_WITHDRAW uint64 = 3 + E_TEST_ABORT uint64 = 4 ) // Structs diff --git a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go index f1ceea5d..1ecae699 100644 --- a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go +++ b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go @@ -106,12 +106,8 @@ func NewManagedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClie // Constants const ( - E_NOT_PUBLISHER uint64 = 1 - E_ALREADY_INITIALIZED uint64 = 2 - E_INVALID_FUNGIBLE_ASSET uint64 = 3 - E_LOCAL_TOKEN_MISMATCH uint64 = 4 - E_INVALID_ARGUMENTS uint64 = 5 - E_UNKNOWN_FUNCTION uint64 = 6 + E_INVALID_ARGUMENTS uint64 = 1 + E_UNKNOWN_FUNCTION uint64 = 2 ) // Structs diff --git a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go index 30427c91..06409b4e 100644 --- a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go +++ b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go @@ -106,12 +106,8 @@ func NewRegulatedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcCl // Constants const ( - E_NOT_PUBLISHER uint64 = 1 - E_ALREADY_INITIALIZED uint64 = 2 - E_INVALID_FUNGIBLE_ASSET uint64 = 3 - E_LOCAL_TOKEN_MISMATCH uint64 = 4 - E_INVALID_ARGUMENTS uint64 = 5 - E_UNKNOWN_FUNCTION uint64 = 6 + E_INVALID_ARGUMENTS uint64 = 1 + E_UNKNOWN_FUNCTION uint64 = 2 ) // Structs diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index 90b87064..8ebcde33 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -87,7 +87,8 @@ module ccip::receiver_registry { ) acquires ReceiverRegistryState { let receiver_address = signer::address_of(receiver_account); assert!( - !exists(receiver_address), + !exists(receiver_address) + && !exists(receiver_address), error::invalid_argument(E_ALREADY_REGISTERED) ); @@ -153,6 +154,28 @@ module ccip::receiver_registry { ); } + /// Registers a V2 CCIP receiver using a function-value callback (closure). + /// + /// Upgrade path: existing legacy receivers can upgrade to V2 by calling this function, + /// which supersedes the legacy registration without requiring unregistration. + /// New receivers should use V2 directly. Once V2 is registered, legacy registration + /// via `register_receiver()` is rejected. + /// + /// SECURITY: The callback MUST wrap a private `#[persistent]` function. Exposing the + /// receive function as `public fun` allows any caller to construct an `Any2AptosMessage` + /// and invoke the receiver directly, + /// + /// Correct pattern: + /// ``` + /// #[persistent] + /// fun ccip_receive_v2(message: client::Any2AptosMessage) { ... } + /// + /// fun init_module(publisher: &signer) { + /// receiver_registry::register_receiver_v2( + /// publisher, |message| ccip_receive_v2(message) + /// ); + /// } + /// ``` public fun register_receiver_v2( receiver_account: &signer, callback: |client::Any2AptosMessage| has copy + drop + store diff --git a/contracts/ccip/ccip/sources/token_admin_dispatcher.move b/contracts/ccip/ccip/sources/token_admin_dispatcher.move index 7c9665bd..c3e17f8c 100644 --- a/contracts/ccip/ccip/sources/token_admin_dispatcher.move +++ b/contracts/ccip/ccip/sources/token_admin_dispatcher.move @@ -16,7 +16,7 @@ module ccip::token_admin_dispatcher { ): (vector, vector) { auth::assert_is_allowed_onramp(signer::address_of(caller)); - if (token_admin_registry::has_token_pool_config(token_pool_address)) { + if (token_admin_registry::has_token_pool_registration_v2(token_pool_address)) { token_admin_registry::lock_or_burn_v2( token_pool_address, fa, @@ -53,7 +53,7 @@ module ccip::token_admin_dispatcher { ): (FungibleAsset, u64) { auth::assert_is_allowed_offramp(signer::address_of(caller)); - if (token_admin_registry::has_token_pool_config(token_pool_address)) { + if (token_admin_registry::has_token_pool_registration_v2(token_pool_address)) { token_admin_registry::release_or_mint_v2( token_pool_address, sender, diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index 31b49d2b..b07231c9 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -92,7 +92,7 @@ module ccip::token_admin_registry { release_or_mint: |ReleaseOrMintInputV1| (FungibleAsset, u64) } - struct TokenPoolConfig has key { + struct TokenPoolRegistrationV2 has key { callbacks: TokenPoolCallbacks, local_token: address } @@ -153,6 +153,7 @@ module ccip::token_admin_registry { const E_ADMIN_ALREADY_SET_FOR_TOKEN: u64 = 28; const E_ZERO_ADDRESS: u64 = 29; const E_POOL_NOT_REGISTERED: u64 = 30; + const E_TOKEN_MISMATCH: u64 = 31; #[view] public fun type_and_version(): String { @@ -225,25 +226,31 @@ module ccip::token_admin_registry { } #[view] - /// Returns the local token address for the token pool. + /// Returns the local token address for the token pool (supports both V1 and V2). public fun get_pool_local_token( token_pool_address: address - ): address acquires TokenPoolRegistration { - get_registration(token_pool_address).local_token + ): address acquires TokenPoolRegistration, TokenPoolRegistrationV2 { + if (exists(token_pool_address)) { + TokenPoolRegistrationV2[token_pool_address].local_token + } else if (exists(token_pool_address)) { + get_registration(token_pool_address).local_token + } else { + abort error::invalid_argument(E_POOL_NOT_REGISTERED) + } } #[view] /// Returns the local token address for the token pool. public fun get_pool_local_token_v2( token_pool_address: address - ): address acquires TokenPoolConfig { - TokenPoolConfig[token_pool_address].local_token + ): address acquires TokenPoolRegistrationV2 { + TokenPoolRegistrationV2[token_pool_address].local_token } #[view] - /// Returns true if token pool has TokenPoolConfig resource - public fun has_token_pool_config(token_pool_address: address): bool { - exists(token_pool_address) + /// Returns true if token pool has TokenPoolRegistrationV2 resource + public fun has_token_pool_registration_v2(token_pool_address: address): bool { + exists(token_pool_address) } #[view] @@ -331,7 +338,8 @@ module ccip::token_admin_registry { ) acquires TokenAdminRegistryState { let token_pool_address = signer::address_of(token_pool_account); assert!( - !exists(token_pool_address), + !exists(token_pool_address) + && !exists(token_pool_address), error::invalid_argument(E_ALREADY_REGISTERED) ); assert!( @@ -421,6 +429,12 @@ module ccip::token_admin_registry { ); } + /// Registers a V2 token pool using function-value callbacks (closures). + /// + /// Upgrade path: existing legacy pools can upgrade to V2 by calling this function, + /// which supersedes the legacy registration without requiring `unregister_pool()`. + /// New pools should use V2 directly. Once V2 is registered, legacy registration + /// via `register_pool()` is rejected. public fun register_pool_v2( token_pool_account: &signer, local_token: address, @@ -430,17 +444,23 @@ module ccip::token_admin_registry { ) { let token_pool_address = signer::address_of(token_pool_account); assert!( - !exists(token_pool_address), + !exists(token_pool_address), error::invalid_argument(E_ALREADY_REGISTERED) ); assert!( object::object_exists(local_token), error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) ); + if (exists(token_pool_address)) { + assert!( + get_registration(token_pool_address).local_token == local_token, + error::invalid_argument(E_TOKEN_MISMATCH) + ); + }; move_to( token_pool_account, - TokenPoolConfig { + TokenPoolRegistrationV2 { callbacks: TokenPoolCallbacks { lock_or_burn, release_or_mint }, local_token } @@ -449,7 +469,7 @@ module ccip::token_admin_registry { public entry fun unregister_pool( caller: &signer, local_token: address - ) acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolConfig { + ) acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolRegistrationV2 { let state = borrow_state_mut(); assert!( state.token_configs.contains(&local_token), @@ -482,9 +502,9 @@ module ccip::token_admin_registry { } = move_from(previous_pool_address); }; - if (exists(previous_pool_address)) { - let TokenPoolConfig { callbacks: _, local_token: _ } = - move_from(previous_pool_address); + if (exists(previous_pool_address)) { + let TokenPoolRegistrationV2 { callbacks: _, local_token: _ } = + move_from(previous_pool_address); }; event::emit_event( @@ -498,7 +518,7 @@ module ccip::token_admin_registry { public entry fun set_pool( caller: &signer, local_token: address, token_pool_address: address - ) acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolConfig { + ) acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolRegistrationV2 { assert!( object::object_exists(local_token), error::invalid_argument(E_INVALID_FUNGIBLE_ASSET) @@ -507,7 +527,7 @@ module ccip::token_admin_registry { let caller_addr = signer::address_of(caller); let pool_local_token = - if (exists(token_pool_address)) { + if (exists(token_pool_address)) { get_pool_local_token_v2(token_pool_address) } else if (exists(token_pool_address)) { get_registration(token_pool_address).local_token @@ -1066,8 +1086,8 @@ module ccip::token_admin_registry { sender: address, remote_chain_selector: u64, receiver: vector - ): (vector, vector) acquires TokenPoolConfig { - let pool_config = &TokenPoolConfig[token_pool_address]; + ): (vector, vector) acquires TokenPoolRegistrationV2 { + let pool_config = &TokenPoolRegistrationV2[token_pool_address]; let input = LockOrBurnInputV1 { sender, remote_chain_selector, receiver }; (pool_config.callbacks.lock_or_burn) @@ -1084,8 +1104,8 @@ module ccip::token_admin_registry { source_pool_address: vector, source_pool_data: vector, offchain_token_data: vector - ): (FungibleAsset, u64) acquires TokenPoolConfig { - let pool_config = &TokenPoolConfig[token_pool_address]; + ): (FungibleAsset, u64) acquires TokenPoolRegistrationV2 { + let pool_config = &TokenPoolRegistrationV2[token_pool_address]; let input = ReleaseOrMintInputV1 { sender, @@ -1131,7 +1151,7 @@ module ccip::token_admin_registry { public fun mcms_entrypoint( _metadata: Object - ): option::Option acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolConfig { + ): option::Option acquires TokenAdminRegistryState, TokenPoolRegistration, TokenPoolRegistrationV2 { let (caller, function, data) = mcms_registry::get_callback_params(@ccip, McmsCallback {}); diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move index da3b6882..eb362c1f 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move @@ -36,8 +36,8 @@ module ccip_dummy_receiver::ptt_dummy_receiver { const E_RESOURCE_NOT_FOUND_ON_ACCOUNT: u64 = 1; const E_UNAUTHORIZED: u64 = 2; - const E_INVALID_TOKEN_ADDRESS: u64 = 3; - const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 3; + const E_TEST_ABORT: u64 = 4; #[view] public fun type_and_version(): String { @@ -78,6 +78,11 @@ module ccip_dummy_receiver::ptt_dummy_receiver { signer::address_of(&state_signer) } + /// This function MUST remain private (not `public fun`). The `#[persistent]` + /// attribute allows it to be stored as a closure without exposing it to external callers. + /// Only the authorized offramp can invoke this via the closure registered with + /// `receiver_registry::register_receiver_v2()`. Making this public would allow anyone to + /// construct an `Any2AptosMessage` and execute arbitrary token transfers. #[persistent] fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ @@ -132,7 +137,7 @@ module ccip_dummy_receiver::ptt_dummy_receiver { // Simple abort condition for testing if (data == b"abort") { - abort 1 + abort E_TEST_ABORT }; } diff --git a/contracts/ccip/ccip_offramp/sources/offramp.move b/contracts/ccip/ccip_offramp/sources/offramp.move index f0edd5de..101e8da3 100644 --- a/contracts/ccip/ccip_offramp/sources/offramp.move +++ b/contracts/ccip/ccip_offramp/sources/offramp.move @@ -396,8 +396,9 @@ module ccip_offramp::offramp { ); let source_chain_execution_states = state.execution_states.borrow(source_chain_selector); - let execution_state = source_chain_execution_states.borrow(sequence_number); - *execution_state + *source_chain_execution_states.borrow_with_default( + sequence_number, &EXECUTION_STATE_UNTOUCHED + ) } fun execute_single_report( diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 171ca5c0..a1a3fc2f 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -103,6 +103,11 @@ module ccip_offramp::mock_ccip_receiver { struct CCIPReceiverProof has drop {} + /// This function MUST remain private (not `public fun`). The `#[persistent]` + /// attribute allows it to be stored as a closure without exposing it to external callers. + /// Only the authorized offramp can invoke this via the closure registered with + /// `receiver_registry::register_receiver_v2()`. Making this public would allow anyone to + /// construct an `Any2AptosMessage` and execute arbitrary token transfers. #[persistent] fun ccip_receive_v2(message: client::Any2AptosMessage) acquires CCIPReceiverState { /* load state and rebuild a signer for the resource account */ diff --git a/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move index bb46ace5..198feaef 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move @@ -177,7 +177,7 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // Pool is V1-only (test_init_v1 was called in setup) // No public function to verify V1 pool registration, but successful execution proves it works assert!( - !token_admin_registry::has_token_pool_config( + !token_admin_registry::has_token_pool_registration_v2( signer::address_of(burn_mint_token_pool) ) ); @@ -409,7 +409,7 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // Verify V2 pool registered assert!( - token_admin_registry::has_token_pool_config( + token_admin_registry::has_token_pool_registration_v2( signer::address_of(burn_mint_token_pool) ) ); @@ -631,7 +631,7 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // Verify pool has V2 config assert!( - token_admin_registry::has_token_pool_config( + token_admin_registry::has_token_pool_registration_v2( signer::address_of(burn_mint_token_pool) ) ); diff --git a/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move index 3c3bae6c..e2c26076 100644 --- a/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move +++ b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move @@ -119,7 +119,7 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // Verify V1 pool registered (not V2) assert!( - !token_admin_registry::has_token_pool_config( + !token_admin_registry::has_token_pool_registration_v2( signer::address_of(burn_mint_token_pool) ) ); @@ -228,7 +228,7 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // Verify V2 config now exists assert!( - token_admin_registry::has_token_pool_config( + token_admin_registry::has_token_pool_registration_v2( signer::address_of(burn_mint_token_pool) ) ); @@ -304,7 +304,7 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // Verify V2 config registered (already done by setup) assert!( - token_admin_registry::has_token_pool_config( + token_admin_registry::has_token_pool_registration_v2( signer::address_of(burn_mint_token_pool) ) ); @@ -380,7 +380,7 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // Verify V1 pool registered (not V2) assert!( - !token_admin_registry::has_token_pool_config( + !token_admin_registry::has_token_pool_registration_v2( signer::address_of(lock_release_token_pool) ) ); @@ -489,7 +489,7 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // Verify V2 config now exists assert!( - token_admin_registry::has_token_pool_config( + token_admin_registry::has_token_pool_registration_v2( signer::address_of(lock_release_token_pool) ) ); @@ -564,7 +564,7 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { mint_tokens_for_transfer(token_addr, 1); assert!( - token_admin_registry::has_token_pool_config( + token_admin_registry::has_token_pool_registration_v2( signer::address_of(lock_release_token_pool) ) ); diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index e86af3ba..58d08f6f 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -138,14 +138,11 @@ module burn_mint_token_pool::burn_mint_token_pool { } public fun register_v2_callbacks(publisher: &signer) { - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - token_admin_registry::register_pool_v2( publisher, @burn_mint_local_token, - lock_or_burn_closure, - release_or_mint_closure + lock_or_burn_v2, + release_or_mint_v2 ); } diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index ebe8e73c..18fed44f 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -155,14 +155,11 @@ module lock_release_token_pool::lock_release_token_pool { } public fun register_v2_callbacks(publisher: &signer) { - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - token_admin_registry::register_pool_v2( publisher, @lock_release_local_token, - lock_or_burn_closure, - release_or_mint_closure + lock_or_burn_v2, + release_or_mint_v2 ); } diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index 18e542af..6b1f0c53 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -27,12 +27,8 @@ module managed_token_pool::managed_token_pool { store_signer_address: address } - const E_NOT_PUBLISHER: u64 = 1; - const E_ALREADY_INITIALIZED: u64 = 2; - const E_INVALID_FUNGIBLE_ASSET: u64 = 3; - const E_LOCAL_TOKEN_MISMATCH: u64 = 4; - const E_INVALID_ARGUMENTS: u64 = 5; - const E_UNKNOWN_FUNCTION: u64 = 6; + const E_INVALID_ARGUMENTS: u64 = 1; + const E_UNKNOWN_FUNCTION: u64 = 2; // ================================================================ // | Init | @@ -91,15 +87,11 @@ module managed_token_pool::managed_token_pool { public fun register_v2_callbacks(publisher: &signer) { let managed_token_address = managed_token::token_metadata(); - - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - token_admin_registry::register_pool_v2( publisher, managed_token_address, - lock_or_burn_closure, - release_or_mint_closure + lock_or_burn_v2, + release_or_mint_v2 ); } diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index 13e17aba..19b018d6 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -27,12 +27,8 @@ module regulated_token_pool::regulated_token_pool { store_signer_address: address } - const E_NOT_PUBLISHER: u64 = 1; - const E_ALREADY_INITIALIZED: u64 = 2; - const E_INVALID_FUNGIBLE_ASSET: u64 = 3; - const E_LOCAL_TOKEN_MISMATCH: u64 = 4; - const E_INVALID_ARGUMENTS: u64 = 5; - const E_UNKNOWN_FUNCTION: u64 = 6; + const E_INVALID_ARGUMENTS: u64 = 1; + const E_UNKNOWN_FUNCTION: u64 = 2; // ================================================================ // | Init | @@ -89,15 +85,11 @@ module regulated_token_pool::regulated_token_pool { public fun register_v2_callbacks(publisher: &signer) { let regulated_token_address = regulated_token::token_address(); - - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - token_admin_registry::register_pool_v2( publisher, regulated_token_address, - lock_or_burn_closure, - release_or_mint_closure + lock_or_burn_v2, + release_or_mint_v2 ); } diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index c9af961c..493245b1 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -140,14 +140,11 @@ module usdc_token_pool::usdc_token_pool { } public fun register_v2_callbacks(publisher: &signer) { - let lock_or_burn_closure = |fa, input| lock_or_burn_v2(fa, input); - let release_or_mint_closure = |input| release_or_mint_v2(input); - token_admin_registry::register_pool_v2( publisher, @local_token, - lock_or_burn_closure, - release_or_mint_closure + lock_or_burn_v2, + release_or_mint_v2 ); } From 0be6807e8a17f2c33594ee5b3bef1bed67e6c6aa Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Sat, 7 Feb 2026 15:21:15 -0500 Subject: [PATCH 22/24] move fmt --- .../ccip/ccip/sources/receiver_registry.move | 8 +--- .../ccip/sources/token_admin_registry.move | 5 ++- .../sources/ptt_dummy_receiver.move | 7 ++- .../tests/mock/mock_ccip_receiver.move | 17 ++++--- .../offramp_burn_mint_receiver_test.move | 4 +- .../offramp_lock_release_receiver_test.move | 4 +- .../tests/offramp_managed_receiver_test.move | 5 +-- .../offramp_regulated_receiver_test.move | 5 +-- .../ccip/ccip_offramp/tests/offramp_test.move | 44 +++++++------------ .../offramp_v1_v2_compatibility_test.move | 6 --- .../onramp_v1_v2_pool_compatibility_test.move | 10 +---- .../sources/usdc_token_pool.move | 5 +-- 12 files changed, 38 insertions(+), 82 deletions(-) diff --git a/contracts/ccip/ccip/sources/receiver_registry.move b/contracts/ccip/ccip/sources/receiver_registry.move index 8ebcde33..93af3d1e 100644 --- a/contracts/ccip/ccip/sources/receiver_registry.move +++ b/contracts/ccip/ccip/sources/receiver_registry.move @@ -177,8 +177,7 @@ module ccip::receiver_registry { /// } /// ``` public fun register_receiver_v2( - receiver_account: &signer, - callback: |client::Any2AptosMessage| has copy + drop + store + receiver_account: &signer, callback: |client::Any2AptosMessage| has copy + drop + store ) { let receiver_address = signer::address_of(receiver_account); assert!( @@ -186,10 +185,7 @@ module ccip::receiver_registry { error::invalid_argument(E_ALREADY_REGISTERED) ); - move_to( - receiver_account, - CCIPReceiverRegistrationV2 { callback } - ); + move_to(receiver_account, CCIPReceiverRegistrationV2 { callback }); event::emit_event( &mut borrow_events_v2_mut().receiver_registered_v2_events, diff --git a/contracts/ccip/ccip/sources/token_admin_registry.move b/contracts/ccip/ccip/sources/token_admin_registry.move index 746ec3f3..8b290396 100644 --- a/contracts/ccip/ccip/sources/token_admin_registry.move +++ b/contracts/ccip/ccip/sources/token_admin_registry.move @@ -249,7 +249,9 @@ module ccip::token_admin_registry { #[view] /// Returns true if token pool has TokenPoolRegistrationV2 resource - public fun has_token_pool_registration_v2(token_pool_address: address): bool { + public fun has_token_pool_registration_v2( + token_pool_address: address + ): bool { exists(token_pool_address) } @@ -323,7 +325,6 @@ module ccip::token_admin_registry { // ================================================================ // | Register Pool | // ================================================================ - #[deprecated] /// @deprecated: Use `register_pool_v2()` instead. /// diff --git a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move index eb362c1f..87022892 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/ptt_dummy_receiver.move @@ -116,13 +116,12 @@ module ccip_dummy_receiver::ptt_dummy_receiver { event::emit(ForwardedTokens { final_recipient }); event::emit_event( - &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + &mut state.forwarded_tokens_handle, + ForwardedTokens { final_recipient } ); } else if (data.length() != 0) { event::emit(ReceivedMessage { data }); - event::emit_event( - &mut state.received_message_handle, ReceivedMessage { data } - ); + event::emit_event(&mut state.received_message_handle, ReceivedMessage { data }); } else if (dest_token_amounts.length() != 0) { // Tokens only (no forwarding data) - keep them at receiver diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index a1a3fc2f..080e62bd 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -141,7 +141,8 @@ module ccip_offramp::mock_ccip_receiver { event::emit(ForwardedTokens { final_recipient }); event::emit_event( - &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + &mut state.forwarded_tokens_handle, + ForwardedTokens { final_recipient } ); } else if (data.length() != 0) { // Convert the vector to a string @@ -164,9 +165,7 @@ module ccip_offramp::mock_ccip_receiver { }; // Simple abort condition for testing - if (data == b"abort") { - abort 1 - }; + if (data == b"abort") { abort 1 }; } #[deprecated] @@ -214,7 +213,8 @@ module ccip_offramp::mock_ccip_receiver { event::emit(ForwardedTokens { final_recipient }); event::emit_event( - &mut state.forwarded_tokens_handle, ForwardedTokens { final_recipient } + &mut state.forwarded_tokens_handle, + ForwardedTokens { final_recipient } ); } else if (data.length() != 0) { @@ -239,9 +239,7 @@ module ccip_offramp::mock_ccip_receiver { }; // Simple abort condition for testing - if (data == b"abort") { - abort 1 - }; + if (data == b"abort") { abort 1 }; option::none() } @@ -250,7 +248,8 @@ module ccip_offramp::mock_ccip_receiver { sender: &signer, recipient: address, token_address: address ) acquires CCIPReceiverState { assert!( - exists(@ccip_offramp), E_RESOURCE_NOT_FOUND_ON_ACCOUNT + exists(@ccip_offramp), + E_RESOURCE_NOT_FOUND_ON_ACCOUNT ); assert!(signer::address_of(sender) == @ccip_offramp, E_UNAUTHORIZED); diff --git a/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move index c3127672..d6e0e698 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_burn_mint_receiver_test.move @@ -68,9 +68,7 @@ module ccip_offramp::offramp_burn_mint_receiver_test { let metadata_hash = offramp::test_calculate_metadata_hash( - EVM_SOURCE_CHAIN_SELECTOR, - dest_chain_selector, - on_ramp + EVM_SOURCE_CHAIN_SELECTOR, dest_chain_selector, on_ramp ); let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); diff --git a/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move index 564ec8e4..1f6edb0e 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_lock_release_receiver_test.move @@ -68,9 +68,7 @@ module ccip_offramp::offramp_lock_release_receiver_test { let metadata_hash = offramp::test_calculate_metadata_hash( - EVM_SOURCE_CHAIN_SELECTOR, - dest_chain_selector, - on_ramp + EVM_SOURCE_CHAIN_SELECTOR, dest_chain_selector, on_ramp ); let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); diff --git a/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move index 43a54d94..c3560712 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_managed_receiver_test.move @@ -71,9 +71,7 @@ module ccip_offramp::offramp_managed_receiver_test { let metadata_hash = offramp::test_calculate_metadata_hash( - EVM_SOURCE_CHAIN_SELECTOR, - dest_chain_selector, - on_ramp + EVM_SOURCE_CHAIN_SELECTOR, dest_chain_selector, on_ramp ); let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); @@ -108,7 +106,6 @@ module ccip_offramp::offramp_managed_receiver_test { } // ======================== NON DISPATCHABLE TESTS ======================== - #[ test( aptos_framework = @aptos_framework, diff --git a/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move index f9bdb9f6..9fee9c21 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_regulated_receiver_test.move @@ -70,9 +70,7 @@ module ccip_offramp::offramp_regulated_receiver_test { let metadata_hash = offramp::test_calculate_metadata_hash( - EVM_SOURCE_CHAIN_SELECTOR, - dest_chain_selector, - on_ramp + EVM_SOURCE_CHAIN_SELECTOR, dest_chain_selector, on_ramp ); let message_hash = offramp::test_calculate_message_hash(&message, metadata_hash); @@ -109,7 +107,6 @@ module ccip_offramp::offramp_regulated_receiver_test { // ======================== DISPATCHABLE TESTS ======================== // // Regulated token is always dispatchable, therefore we test the dispatchable token transfer only - #[ test( aptos_framework = @aptos_framework, diff --git a/contracts/ccip/ccip_offramp/tests/offramp_test.move b/contracts/ccip/ccip_offramp/tests/offramp_test.move index cbf5b7ff..8a22cb1b 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_test.move @@ -115,8 +115,7 @@ module ccip_offramp::offramp_test { // Create token pool object let constructor_ref = object::create_named_object( - burn_mint_token_pool_obj_signer, - b"ccip_token_pool" + burn_mint_token_pool_obj_signer, b"ccip_token_pool" ); let ccip_token_pool_obj = object::object_from_constructor_ref(&constructor_ref); @@ -248,9 +247,7 @@ module ccip_offramp::offramp_test { ); token_admin_registry::accept_admin_role(owner, token_addr); token_admin_registry::set_pool( - owner, - token_addr, - signer::address_of(burn_mint_token_pool) + owner, token_addr, signer::address_of(burn_mint_token_pool) ); } else if (pool_type == LOCK_RELEASE_TOKEN_POOL) { if (use_v1_init) { @@ -259,9 +256,7 @@ module ccip_offramp::offramp_test { lock_release_token_pool::test_init_module(lock_release_token_pool); }; lock_release_token_pool::initialize( - owner, - option::some(transfer_ref), - signer::address_of(owner) + owner, option::some(transfer_ref), signer::address_of(owner) ); lock_release_token_pool::apply_chain_updates( owner, @@ -286,9 +281,7 @@ module ccip_offramp::offramp_test { ); token_admin_registry::accept_admin_role(owner, token_addr); token_admin_registry::set_pool( - owner, - token_addr, - signer::address_of(lock_release_token_pool) + owner, token_addr, signer::address_of(lock_release_token_pool) ); } else if (pool_type == MANAGED_TOKEN_POOL) { let seed = b"MT"; @@ -335,15 +328,11 @@ module ccip_offramp::offramp_test { ); token_admin_registry::accept_admin_role(owner, token_addr); token_admin_registry::set_pool( - owner, - token_addr, - signer::address_of(managed_token_pool) + owner, token_addr, signer::address_of(managed_token_pool) ); // Fund managed token pool primary_fungible_store::mint( - &mint_ref, - managed_token_pool::get_store_address(), - 1000 + &mint_ref, managed_token_pool::get_store_address(), 1000 ); } else if (pool_type == REGULATED_TOKEN_POOL) { account::create_account_for_test(signer::address_of(owner)); @@ -411,16 +400,12 @@ module ccip_offramp::offramp_test { ); token_admin_registry::accept_admin_role(owner, token_addr); token_admin_registry::set_pool( - owner, - token_addr, - signer::address_of(regulated_token_pool) + owner, token_addr, signer::address_of(regulated_token_pool) ); // Fund regulated token pool primary_fungible_store::mint( - &mint_ref, - regulated_token_pool::get_store_address(), - 1000 + &mint_ref, regulated_token_pool::get_store_address(), 1000 ); }; @@ -437,7 +422,13 @@ module ccip_offramp::offramp_test { move_to( &obj_signer, - TestToken { metadata, extend_ref, mint_ref, burn_ref, transfer_ref } + TestToken { + metadata, + extend_ref, + mint_ref, + burn_ref, + transfer_ref + } ); (metadata, token_addr) @@ -1386,9 +1377,7 @@ module ccip_offramp::offramp_test { ); let metadata_hash = offramp::test_calculate_metadata_hash( - EVM_SOURCE_CHAIN_SELECTOR, - dest_chain_selector, - onramp_address + EVM_SOURCE_CHAIN_SELECTOR, dest_chain_selector, onramp_address ); let hashed_leaf = offramp::test_calculate_message_hash(&message, metadata_hash); @@ -1527,7 +1516,6 @@ module ccip_offramp::offramp_test { } // =============== Error handling tests =============== - #[ test( aptos_framework = @aptos_framework, diff --git a/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move index 198feaef..f143c69d 100644 --- a/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move +++ b/contracts/ccip/ccip_offramp/tests/offramp_v1_v2_compatibility_test.move @@ -28,7 +28,6 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // ============================================ // Test Helper Functions // ============================================ - fun create_and_execute_message( message_id: vector, sequence_number: u64, @@ -111,7 +110,6 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // ============================================ // Test 1: V1 Receiver Works (Baseline) // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -218,7 +216,6 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // ============================================ // Test 2: V1 → V2 Migration Works // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -349,7 +346,6 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // ============================================ // Test 3: Direct V2 Registration Works // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -450,7 +446,6 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // ============================================ // Test 4: Dispatcher Routes Correctly // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -574,7 +569,6 @@ module ccip_offramp::offramp_v1_v2_compatibility_test { // Test 5: Multi-Transfer Message with V2 Receiver // Tests V2 receiver handling multiple token transfers in a single message // ============================================ - #[ test( aptos_framework = @aptos_framework, diff --git a/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move index e2c26076..e543f137 100644 --- a/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move +++ b/contracts/ccip/ccip_onramp/tests/onramp_v1_v2_pool_compatibility_test.move @@ -46,9 +46,7 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { } /// Helper to calculate fee and mint enough tokens for sender - fun mint_tokens_for_transfer( - token_addr: address, num_transfers: u64 - ) { + fun mint_tokens_for_transfer(token_addr: address, num_transfers: u64) { let receiver = encode_receiver(); let extra_args = create_extra_args_v2(); @@ -74,7 +72,6 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // ============================================ // Test 1: V1 Burn/Mint Pool Baseline // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -158,7 +155,6 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // ============================================ // Test 2: V1 → V2 Burn/Mint Migration // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -259,7 +255,6 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // ============================================ // Test 3: V2 Burn/Mint Direct (no migration) // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -335,7 +330,6 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // ============================================ // Test 4: V1 Lock/Release Pool Baseline // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -419,7 +413,6 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // ============================================ // Test 5: V1 → V2 Lock/Release Migration // ============================================ - #[ test( aptos_framework = @aptos_framework, @@ -520,7 +513,6 @@ module ccip_onramp::onramp_v1_v2_pool_compatibility_test { // ============================================ // Test 6: V2 Lock/Release Direct (no migration) // ============================================ - #[ test( aptos_framework = @aptos_framework, diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index 03ae8ec0..8243b640 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -521,10 +521,7 @@ module usdc_token_pool::usdc_token_pool { let remote_domain_info = pool.chain_to_domain.borrow(remote_chain_selector); - assert!( - remote_domain_info.enabled, - error::invalid_argument(E_DOMAIN_DISABLED) - ); + assert!(remote_domain_info.enabled, error::invalid_argument(E_DOMAIN_DISABLED)); let mint_recipient_bytes = token_admin_registry::get_lock_or_burn_receiver(&input); From 4ae06942d4004f9b5ded1e6d56ba70b30f30e0cd Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Tue, 10 Feb 2026 13:19:24 -0500 Subject: [PATCH 23/24] Add publisher check register_v2_callbacks in token pools --- .../managed_token_pool/managed_token_pool.go | 1 + .../regulated_token_pool/regulated_token_pool.go | 1 + .../burn_mint_token_pool/sources/burn_mint_token_pool.move | 4 ++++ .../sources/lock_release_token_pool.move | 4 ++++ .../managed_token_pool/sources/managed_token_pool.move | 5 +++++ .../regulated_token_pool/sources/regulated_token_pool.move | 5 +++++ .../usdc_token_pool/sources/usdc_token_pool.move | 4 ++++ 7 files changed, 24 insertions(+) diff --git a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go index 1ecae699..ddb9fded 100644 --- a/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go +++ b/bindings/ccip_token_pools/managed_token_pool/managed_token_pool/managed_token_pool.go @@ -108,6 +108,7 @@ func NewManagedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcClie const ( E_INVALID_ARGUMENTS uint64 = 1 E_UNKNOWN_FUNCTION uint64 = 2 + E_NOT_PUBLISHER uint64 = 3 ) // Structs diff --git a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go index 06409b4e..59afd2e1 100644 --- a/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go +++ b/bindings/ccip_token_pools/regulated_token_pool/regulated_token_pool/regulated_token_pool.go @@ -108,6 +108,7 @@ func NewRegulatedTokenPool(address aptos.AccountAddress, client aptos.AptosRpcCl const ( E_INVALID_ARGUMENTS uint64 = 1 E_UNKNOWN_FUNCTION uint64 = 2 + E_NOT_PUBLISHER uint64 = 3 ) // Structs diff --git a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move index f142f8b7..8a21728b 100644 --- a/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move +++ b/contracts/ccip/ccip_token_pools/burn_mint_token_pool/sources/burn_mint_token_pool.move @@ -137,6 +137,10 @@ module burn_mint_token_pool::burn_mint_token_pool { } public fun register_v2_callbacks(publisher: &signer) { + assert!( + signer::address_of(publisher) == @burn_mint_token_pool, + error::permission_denied(E_NOT_PUBLISHER) + ); token_admin_registry::register_pool_v2( publisher, @burn_mint_local_token, diff --git a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move index 76a6c0a1..5ceea6cf 100644 --- a/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move +++ b/contracts/ccip/ccip_token_pools/lock_release_token_pool/sources/lock_release_token_pool.move @@ -160,6 +160,10 @@ module lock_release_token_pool::lock_release_token_pool { } public fun register_v2_callbacks(publisher: &signer) { + assert!( + signer::address_of(publisher) == @lock_release_token_pool, + error::permission_denied(E_NOT_PUBLISHER) + ); token_admin_registry::register_pool_v2( publisher, @lock_release_local_token, diff --git a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move index 340b9d29..4b2193fa 100644 --- a/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move +++ b/contracts/ccip/ccip_token_pools/managed_token_pool/sources/managed_token_pool.move @@ -29,6 +29,7 @@ module managed_token_pool::managed_token_pool { const E_INVALID_ARGUMENTS: u64 = 1; const E_UNKNOWN_FUNCTION: u64 = 2; + const E_NOT_PUBLISHER: u64 = 3; // ================================================================ // | Init | @@ -85,6 +86,10 @@ module managed_token_pool::managed_token_pool { } public fun register_v2_callbacks(publisher: &signer) { + assert!( + signer::address_of(publisher) == @managed_token_pool, + error::permission_denied(E_NOT_PUBLISHER) + ); let managed_token_address = managed_token::token_metadata(); token_admin_registry::register_pool_v2( publisher, diff --git a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move index 443eee6d..4d41d4de 100644 --- a/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move +++ b/contracts/ccip/ccip_token_pools/regulated_token_pool/sources/regulated_token_pool.move @@ -29,6 +29,7 @@ module regulated_token_pool::regulated_token_pool { const E_INVALID_ARGUMENTS: u64 = 1; const E_UNKNOWN_FUNCTION: u64 = 2; + const E_NOT_PUBLISHER: u64 = 3; // ================================================================ // | Init | @@ -83,6 +84,10 @@ module regulated_token_pool::regulated_token_pool { } public fun register_v2_callbacks(publisher: &signer) { + assert!( + signer::address_of(publisher) == @regulated_token_pool, + error::permission_denied(E_NOT_PUBLISHER) + ); let regulated_token_address = regulated_token::token_address(); token_admin_registry::register_pool_v2( publisher, diff --git a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move index 8243b640..15dc7e5c 100644 --- a/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move +++ b/contracts/ccip/ccip_token_pools/usdc_token_pool/sources/usdc_token_pool.move @@ -139,6 +139,10 @@ module usdc_token_pool::usdc_token_pool { } public fun register_v2_callbacks(publisher: &signer) { + assert!( + signer::address_of(publisher) == @usdc_token_pool, + error::permission_denied(E_NOT_PUBLISHER) + ); token_admin_registry::register_pool_v2( publisher, @local_token, From c82eba51f3ddcae0b02b9ce9a2c683a32a957dff Mon Sep 17 00:00:00 2001 From: JohnChangUK Date: Tue, 10 Feb 2026 19:40:04 -0500 Subject: [PATCH 24/24] Change numbers to constants - test receiver --- .../dummy_receiver/dummy_receiver.go | 5 +++++ .../ccip_dummy_receiver/sources/dummy_receiver.move | 6 +++++- .../ccip_offramp/tests/mock/mock_ccip_receiver.move | 10 ++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/bindings/ccip_dummy_receiver/dummy_receiver/dummy_receiver.go b/bindings/ccip_dummy_receiver/dummy_receiver/dummy_receiver.go index 65c0d3c2..0989c083 100644 --- a/bindings/ccip_dummy_receiver/dummy_receiver/dummy_receiver.go +++ b/bindings/ccip_dummy_receiver/dummy_receiver/dummy_receiver.go @@ -43,6 +43,11 @@ func NewDummyReceiver(address aptos.AccountAddress, client aptos.AptosRpcClient) } } +// Constants +const ( + E_TEST_ABORT uint64 = 1 +) + // Structs type ReceivedMessage struct { diff --git a/contracts/ccip/ccip_dummy_receiver/sources/dummy_receiver.move b/contracts/ccip/ccip_dummy_receiver/sources/dummy_receiver.move index 51dca322..b3a111ea 100644 --- a/contracts/ccip/ccip_dummy_receiver/sources/dummy_receiver.move +++ b/contracts/ccip/ccip_dummy_receiver/sources/dummy_receiver.move @@ -9,6 +9,8 @@ module ccip_dummy_receiver::dummy_receiver { use ccip::client; use ccip::receiver_registry; + const E_TEST_ABORT: u64 = 1; + #[event] struct ReceivedMessage has store, drop { data: vector @@ -46,7 +48,9 @@ module ccip_dummy_receiver::dummy_receiver { @ccip_dummy_receiver, DummyReceiverProof {} ); let data = client::get_data(&message); - if (data == b"abort") { abort 1 }; + if (data == b"abort") { + abort E_TEST_ABORT + }; let state = borrow_state_mut(); diff --git a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move index 080e62bd..920acbf9 100644 --- a/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move +++ b/contracts/ccip/ccip_offramp/tests/mock/mock_ccip_receiver.move @@ -41,6 +41,8 @@ module ccip_offramp::mock_ccip_receiver { const E_UNAUTHORIZED: u64 = 2; const E_INVALID_TOKEN_ADDRESS: u64 = 3; const E_NO_TOKENS_AVAILABLE_TO_WITHDRAW: u64 = 4; + /// Test-only abort triggered when message data equals "abort". + const E_TEST_ABORT: u64 = 5; #[view] public fun type_and_version(): String { @@ -165,7 +167,9 @@ module ccip_offramp::mock_ccip_receiver { }; // Simple abort condition for testing - if (data == b"abort") { abort 1 }; + if (data == b"abort") { + abort E_TEST_ABORT + }; } #[deprecated] @@ -239,7 +243,9 @@ module ccip_offramp::mock_ccip_receiver { }; // Simple abort condition for testing - if (data == b"abort") { abort 1 }; + if (data == b"abort") { + abort E_TEST_ABORT + }; option::none() }