diff --git a/packages/layerzero-v2/initia/contracts/endpoint_v2/sources/admin.move b/packages/layerzero-v2/initia/contracts/endpoint_v2/sources/admin.move index 89972ffe..2e3dc60c 100644 --- a/packages/layerzero-v2/initia/contracts/endpoint_v2/sources/admin.move +++ b/packages/layerzero-v2/initia/contracts/endpoint_v2/sources/admin.move @@ -3,18 +3,19 @@ module endpoint_v2::admin { use std::signer::address_of; use endpoint_v2::msglib_manager; + use endpoint_v2_common::universal_config::assert_layerzero_admin; /// Register new message library /// A library must be registered to be called by this endpoint. Once registered, it cannot be unregistered. The /// library must be connected to the router node before it can be registered public entry fun register_library(account: &signer, lib: address) { - assert_admin(address_of(move account)); + assert_layerzero_admin(address_of(move account)); msglib_manager::register_library(lib); } /// Sets the default sending message library for the given destination EID public entry fun set_default_send_library(account: &signer, dst_eid: u32, lib: address) { - assert_admin(address_of(move account)); + assert_layerzero_admin(address_of(move account)); msglib_manager::set_default_send_library(dst_eid, lib); } @@ -25,7 +26,7 @@ module endpoint_v2::admin { lib: address, grace_period: u64, ) { - assert_admin(address_of(move account)); + assert_layerzero_admin(address_of(move account)); msglib_manager::set_default_receive_library(src_eid, lib, grace_period); } @@ -38,17 +39,12 @@ module endpoint_v2::admin { fallback_lib: address, expiry: u64, ) { - assert_admin(address_of(move account)); + assert_layerzero_admin(address_of(move account)); msglib_manager::set_default_receive_library_timeout(src_eid, fallback_lib, expiry); } // ==================================================== Helpers =================================================== - /// Internal function to assert that the caller is the endpoint admin - inline fun assert_admin(admin: address) { - assert!(admin == @layerzero_admin, EUNAUTHORIZED); - } - #[test_only] /// Test-only function to initialize the endpoint and EID public fun initialize_endpoint_for_test() { diff --git a/packages/layerzero-v2/initia/contracts/endpoint_v2_common/sources/universal_config.move b/packages/layerzero-v2/initia/contracts/endpoint_v2_common/sources/universal_config.move index 43438be4..25fe84d4 100644 --- a/packages/layerzero-v2/initia/contracts/endpoint_v2_common/sources/universal_config.move +++ b/packages/layerzero-v2/initia/contracts/endpoint_v2_common/sources/universal_config.move @@ -1,5 +1,6 @@ -/// This module provides a groud truth for EID and ZRO Metadata address +/// This module provides a ground truth for EID and ZRO Metadata address module endpoint_v2_common::universal_config { + use std::account; use std::event::emit; use std::fungible_asset::{Self, FungibleAsset, Metadata}; use std::object::{Self, Object}; @@ -13,6 +14,8 @@ module endpoint_v2_common::universal_config { friend endpoint_v2_common::universal_config_tests; struct UniversalStore has key { + // The LayerZero admin account + layerzero_admin: address, // The EID for this endpoint eid: u32, // The ZRO metadata if it has been set @@ -23,13 +26,15 @@ module endpoint_v2_common::universal_config { /// Initialize the UniversalStore must be called by endpoint_v2_common public entry fun initialize(admin: &signer, eid: u32) acquires UniversalStore { - assert_admin(address_of(move admin)); + assert_layerzero_admin(address_of(move admin)); assert!(universal_store().eid == 0, EALREADY_INITIALIZED); universal_store_mut().eid = eid; } fun init_module(account: &signer) { move_to(account, UniversalStore { + // The initial admin address is @layerzero_admin, which can be transferred + layerzero_admin: @layerzero_admin, eid: 0, zro_data: option::none(), zro_locked: false, @@ -48,11 +53,20 @@ module endpoint_v2_common::universal_config { universal_store().eid } + /// Transfer the LayerZero admin to a new LayerZero admin address + public entry fun transfer_layerzero_admin(account: &signer, new_admin: address) acquires UniversalStore { + assert_layerzero_admin(address_of(move account)); + assert!(account::exists_at(new_admin), EINVALID_ACCOUNT_ADDRESS); + assert!(new_admin != universal_store().layerzero_admin, ENO_CHANGE); + universal_store_mut().layerzero_admin = new_admin; + emit(LayerZeroAdminTransferred { new_admin }); + } + /// Set the ZRO address /// @param account: The layerzero admin account signer /// @param zro_address: The address of the ZRO metadata (@0x0 to unset) public entry fun set_zro_address(account: &signer, zro_address: address) acquires UniversalStore { - assert_admin(address_of(move account)); + assert_layerzero_admin(address_of(move account)); assert!(!universal_store().zro_locked, EZRO_ADDRESS_LOCKED); if (zro_address == @0x0) { @@ -76,7 +90,7 @@ module endpoint_v2_common::universal_config { /// Lock the ZRO address so it can no longer be set or unset public entry fun lock_zro_address(account: &signer) acquires UniversalStore { - assert_admin(address_of(move account)); + assert_layerzero_admin(address_of(move account)); assert!(!universal_store().zro_locked, ENO_CHANGE); assert!(option::is_some(&universal_store().zro_data), EZRO_ADDRESS_NOT_SET); @@ -123,12 +137,17 @@ module endpoint_v2_common::universal_config { metadata == get_zro_metadata() } - // ==================================================== Helpers =================================================== + #[view] + public fun layerzero_admin(): address acquires UniversalStore { + universal_store().layerzero_admin + } - inline fun assert_admin(admin: address) { - assert!(admin == @layerzero_admin, EUNAUTHORIZED); + public fun assert_layerzero_admin(admin: address) acquires UniversalStore { + assert!(admin == universal_store().layerzero_admin, EUNAUTHORIZED); } + // ==================================================== Helpers =================================================== + inline fun universal_store(): &UniversalStore { borrow_global(@endpoint_v2_common) } inline fun universal_store_mut(): &mut UniversalStore { borrow_global_mut(@endpoint_v2_common) } @@ -138,6 +157,11 @@ module endpoint_v2_common::universal_config { // ==================================================== Events ==================================================== + #[event] + struct LayerZeroAdminTransferred has drop, store { + new_admin: address, + } + #[event] struct ZroMetadataSet has drop, store { zro_address: address, @@ -146,6 +170,11 @@ module endpoint_v2_common::universal_config { #[event] struct ZroMetadataLocked has drop, store {} + #[test_only] + public fun layerzero_admin_transferred_event(new_admin: address): LayerZeroAdminTransferred { + LayerZeroAdminTransferred { new_admin } + } + #[test_only] public fun zro_metadata_set(zro_address: address): ZroMetadataSet { ZroMetadataSet { zro_address } @@ -160,8 +189,9 @@ module endpoint_v2_common::universal_config { const EALREADY_INITIALIZED: u64 = 1; const EUNAUTHORIZED: u64 = 2; - const EINVALID_ZRO_ADDRESS: u64 = 3; - const ENO_CHANGE: u64 = 4; - const EZRO_ADDRESS_NOT_SET: u64 = 5; - const EZRO_ADDRESS_LOCKED: u64 = 6; + const EINVALID_ACCOUNT_ADDRESS: u64 = 3; + const EINVALID_ZRO_ADDRESS: u64 = 4; + const ENO_CHANGE: u64 = 5; + const EZRO_ADDRESS_NOT_SET: u64 = 6; + const EZRO_ADDRESS_LOCKED: u64 = 7; }