Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions contracts/ccip/ccip/Move.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,30 @@
version = 4

[pinned.testnet.MoveStdlib]
source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/move-stdlib", rev = "384b1c7ff289b32ed2664f29dc47dbc879fa43ee" }
source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/move-stdlib", rev = "718ae563a42fb4ba0d055588f81c704dcef58c25" }
use_environment = "testnet"
manifest_digest = "C4FE4C91DE74CBF223B2E380AE40F592177D21870DC2D7EB6227D2D694E05363"
deps = {}

[pinned.testnet.Sui]
source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "384b1c7ff289b32ed2664f29dc47dbc879fa43ee" }
source = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "718ae563a42fb4ba0d055588f81c704dcef58c25" }
use_environment = "testnet"
manifest_digest = "7AFB66695545775FBFBB2D3078ADFD084244D5002392E837FDE21D9EA1C6D01C"
deps = { MoveStdlib = "MoveStdlib" }

[pinned.testnet.ccip]
source = { root = true }
use_environment = "testnet"
manifest_digest = "B41543A1928002B1ABE6F16D69A3C1BE6BCA4D7A4DB7D2F9048274EFE11ED724"
deps = { mcms = "mcms", std = "MoveStdlib", sui = "Sui" }
manifest_digest = "E5912E2FA12F49E878734EC73B1CAC461C88F1562C6C02B940082B986AE865FE"
deps = { fast_mcms = "mcms", mcms = "mcms_1", std = "MoveStdlib", sui = "Sui" }

[pinned.testnet.mcms]
source = { local = "../../mcms/fast_mcms" }
use_environment = "testnet"
manifest_digest = "5745706258F61D6CE210904B3E6AE87A73CE9D31A6F93BE4718C442529332A87"
deps = { std = "MoveStdlib", sui = "Sui" }

[pinned.testnet.mcms_1]
source = { local = "../../mcms/mcms" }
use_environment = "testnet"
manifest_digest = "5745706258F61D6CE210904B3E6AE87A73CE9D31A6F93BE4718C442529332A87"
Expand Down
34 changes: 34 additions & 0 deletions contracts/ccip/ccip/sources/receiver_registry.move
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use ccip::ownable::OwnerCap;
use ccip::publisher_wrapper::{Self, PublisherWrapper};
use ccip::state_object::{Self, CCIPObjectRef};
use ccip::upgrade_registry::verify_function_allowed;
use mcms::bcs_stream;
use mcms::mcms_registry::{Self, Registry, ExecutingCallbackParams};
use std::ascii;
use std::string::{Self, String};
use std::type_name;
Expand Down Expand Up @@ -35,6 +37,7 @@ const EAlreadyRegistered: u64 = 1;
const EAlreadyInitialized: u64 = 2;
const EUnknownReceiver: u64 = 3;
const EInvalidOwnerCap: u64 = 4;
const EInvalidFunction: u64 = 5;

const VERSION: u8 = 1;

Expand Down Expand Up @@ -156,3 +159,34 @@ public fun get_receiver_info(

(string::utf8(b""), ascii::string(b""))
}

// ================================================================
// | MCMS Functions |
// ================================================================

public fun mcms_unregister_receiver(
ref: &mut CCIPObjectRef,
registry: &mut Registry,
params: ExecutingCallbackParams,
ctx: &mut TxContext,
) {
let (owner_cap, function, data) = mcms_registry::get_callback_params_with_caps<
state_object::McmsCallback,
OwnerCap,
>(
registry,
state_object::mcms_callback(),
params,
);
assert!(function == string::utf8(b"unregister_receiver"), EInvalidFunction);

let mut stream = bcs_stream::new(data);
bcs_stream::validate_obj_addrs(
vector[object::id_address(ref), object::id_address(owner_cap)],
&mut stream,
);
let receiver_package_id = bcs_stream::deserialize_address(&mut stream);
bcs_stream::assert_is_consumed(&stream);

unregister_receiver(ref, owner_cap, receiver_package_id, ctx);
}
1 change: 1 addition & 0 deletions contracts/ccip/ccip/sources/state_object.move
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ public fun execute_ownership_transfer_to_mcms(
vector[
b"fee_quoter",
b"rmn_remote",
b"receiver_registry",
b"state_object",
b"token_admin_registry",
b"upgrade_registry",
Expand Down
187 changes: 187 additions & 0 deletions contracts/ccip/ccip/tests/receiver_registry_mcms_test.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#[test_only]
#[allow(implicit_const_copy)]
module ccip::receiver_registry_mcms_test;

use ccip::ownable::OwnerCap;
use ccip::publisher_wrapper;
use ccip::receiver_registry;
use ccip::state_object::{Self, CCIPObjectRef};
use ccip::upgrade_registry;
use mcms::mcms_account;
use mcms::mcms_deployer;
use mcms::mcms_registry::{Self, Registry};
use std::string;
use std::type_name;
use sui::address;
use sui::bcs;
use sui::package;
use sui::test_scenario::{Self as ts, Scenario};

const OWNER: address = @0x123;
const RECEIVER_REGISTRY_MODULE_NAME: vector<u8> = b"receiver_registry";

public struct RECEIVER_REGISTRY_MCMS_TEST has drop {}
public struct TestReceiverProof has drop, copy {}

public struct Env {
scenario: Scenario,
ref: CCIPObjectRef,
registry: Registry,
}

fun get_package_id_from_proof<ProofType>(): address {
let proof_tn = type_name::with_defining_ids<ProofType>();
let address_str = type_name::address_string(&proof_tn);
address::from_ascii_bytes(&std::ascii::into_bytes(address_str))
}

fun setup(): Env {
let mut scenario = ts::begin(OWNER);

{
let ctx = scenario.ctx();
mcms_account::test_init(ctx);
mcms_registry::test_init(ctx);
mcms_deployer::test_init(ctx);
state_object::test_init(ctx);
};

scenario.next_tx(OWNER);

let registry = ts::take_shared<Registry>(&scenario);
let mut ref = ts::take_shared<CCIPObjectRef>(&scenario);
let owner_cap = ts::take_from_sender<OwnerCap>(&scenario);

upgrade_registry::initialize(&mut ref, &owner_cap, scenario.ctx());
receiver_registry::initialize(&mut ref, &owner_cap, scenario.ctx());
ts::return_to_address(OWNER, owner_cap);

scenario.next_tx(OWNER);

Env {
scenario,
ref,
registry,
}
}

fun tear_down(env: Env) {
let Env { scenario, ref, registry } = env;
ts::return_shared(ref);
ts::return_shared(registry);
ts::end(scenario);
}

fun register_test_receiver(ref: &mut CCIPObjectRef, ctx: &mut TxContext) {
let proof = TestReceiverProof {};
let publisher = package::test_claim(RECEIVER_REGISTRY_MCMS_TEST {}, ctx);
let publisher_wrapper = publisher_wrapper::create(&publisher, proof);
receiver_registry::register_receiver(ref, publisher_wrapper, proof);
package::burn_publisher(publisher);
}

fun transfer_ownership_to_mcms(env: &mut Env, owner_cap: OwnerCap) {
state_object::transfer_ownership(
&mut env.ref,
&owner_cap,
mcms_registry::get_multisig_address(),
env.scenario.ctx(),
);

env.scenario.next_tx(mcms_registry::get_multisig_address());
state_object::accept_ownership(&mut env.ref, env.scenario.ctx());

state_object::execute_ownership_transfer_to_mcms(
&mut env.ref,
owner_cap,
&mut env.registry,
@mcms,
env.scenario.ctx(),
);

env.scenario.next_tx(OWNER);
}

#[test]
public fun test_mcms_unregister_receiver() {
let mut env = setup();
let package_id = get_package_id_from_proof<TestReceiverProof>();

register_test_receiver(&mut env.ref, env.scenario.ctx());
assert!(receiver_registry::is_registered_receiver(&env.ref, package_id));

let owner_cap = ts::take_from_sender<OwnerCap>(&env.scenario);
transfer_ownership_to_mcms(&mut env, owner_cap);

let owner_cap_address = mcms_registry::test_get_cap_address<OwnerCap>(
&env.registry,
@ccip.to_ascii_string(),
);

let mut data = vector[];
data.append(bcs::to_bytes(&object::id_address(&env.ref)));
data.append(bcs::to_bytes(&owner_cap_address));
data.append(bcs::to_bytes(&package_id));

let params = mcms_registry::test_create_executing_callback_params(
@ccip,
string::utf8(RECEIVER_REGISTRY_MODULE_NAME),
string::utf8(b"unregister_receiver"),
data,
x"0000000000000000000000000000000000000000000000000000000000000001",
0,
1,
);

receiver_registry::mcms_unregister_receiver(
&mut env.ref,
&mut env.registry,
params,
env.scenario.ctx(),
);

assert!(!receiver_registry::is_registered_receiver(&env.ref, package_id));

env.tear_down();
}

#[test]
#[expected_failure(abort_code = receiver_registry::EInvalidFunction)]
public fun test_mcms_unregister_receiver_wrong_function_name() {
let mut env = setup();
let package_id = get_package_id_from_proof<TestReceiverProof>();

register_test_receiver(&mut env.ref, env.scenario.ctx());

let owner_cap = ts::take_from_sender<OwnerCap>(&env.scenario);
transfer_ownership_to_mcms(&mut env, owner_cap);

let owner_cap_address = mcms_registry::test_get_cap_address<OwnerCap>(
&env.registry,
@ccip.to_ascii_string(),
);

let mut data = vector[];
data.append(bcs::to_bytes(&object::id_address(&env.ref)));
data.append(bcs::to_bytes(&owner_cap_address));
data.append(bcs::to_bytes(&package_id));

let params = mcms_registry::test_create_executing_callback_params(
@ccip,
string::utf8(RECEIVER_REGISTRY_MODULE_NAME),
string::utf8(b"register_receiver"),
data,
x"0000000000000000000000000000000000000000000000000000000000000001",
0,
1,
);

receiver_registry::mcms_unregister_receiver(
&mut env.ref,
&mut env.registry,
params,
env.scenario.ctx(),
);

env.tear_down();
}
10 changes: 6 additions & 4 deletions contracts/ccip/ccip/tests/state_object_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,18 @@ fun setup_with_mcms_ownership(): (Scenario, Registry, CCIPObjectRef) {
fun test_mcms_add_allowed_modules_success() {
let (mut scenario, mut registry, ref) = setup_with_mcms_ownership();

// Verify initial allowed modules (should have fee_quoter, rmn_remote, state_object, token_admin_registry)
// Verify initial allowed modules
let initial_modules = mcms_registry::get_allowed_modules(
&registry,
address::to_ascii_string(@ccip),
);
assert!(initial_modules.contains(&b"fee_quoter"), 0);
assert!(initial_modules.contains(&b"rmn_remote"), 1);
assert!(initial_modules.contains(&b"state_object"), 2);
assert!(initial_modules.contains(&b"token_admin_registry"), 3);
assert!(!initial_modules.contains(&b"nonce_manager"), 4); // Should not exist yet
assert!(initial_modules.contains(&b"receiver_registry"), 2);
assert!(initial_modules.contains(&b"state_object"), 3);
assert!(initial_modules.contains(&b"token_admin_registry"), 4);
assert!(initial_modules.contains(&b"upgrade_registry"), 5);
assert!(!initial_modules.contains(&b"nonce_manager"), 6); // Should not exist yet

// Prepare data for mcms_add_allowed_modules
// Data format: [registry_address][vector<vector<u8>> of module names]
Expand Down
Loading