From cf69c11b97e37a42138ab23c4921844bc1d7ea1a Mon Sep 17 00:00:00 2001 From: Christian Gorenflo Date: Wed, 4 Dec 2024 17:18:47 +0100 Subject: [PATCH 1/7] refactor: move shared interfaces in preparation of ownership trait extraction --- contracts/axelar-gas-service/src/contract.rs | 14 ++++----- contracts/axelar-gateway/src/contract.rs | 15 ++++----- contracts/axelar-gateway/src/interface.rs | 2 +- contracts/axelar-operators/src/contract.rs | 17 +++++----- .../interchain-token-service/src/contract.rs | 16 +++++----- contracts/interchain-token/src/contract.rs | 16 +++++----- contracts/upgrader/src/contract.rs | 2 +- .../upgrader/tests/utils/dummy_contract.rs | 8 ++--- .../utils/dummy_contract_after_upgrade.rs | 8 ++--- .../src/contract_traits/mod.rs | 5 +++ .../testdata/contract.rs | 11 ++++--- .../testdata/contract.wasm | Bin ...henticated_and_called_after_upgrade.golden | 0 .../src/{ => contract_traits}/testdata/mod.rs | 0 .../upgradable.rs} | 29 +++++++++--------- packages/axelar-soroban-std/src/lib.rs | 5 +-- 16 files changed, 77 insertions(+), 71 deletions(-) create mode 100644 packages/axelar-soroban-std/src/contract_traits/mod.rs rename packages/axelar-soroban-std/src/{ => contract_traits}/testdata/contract.rs (79%) rename packages/axelar-soroban-std/src/{ => contract_traits}/testdata/contract.wasm (100%) rename packages/axelar-soroban-std/src/{ => contract_traits}/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden (100%) rename packages/axelar-soroban-std/src/{ => contract_traits}/testdata/mod.rs (100%) rename packages/axelar-soroban-std/src/{shared_interfaces.rs => contract_traits/upgradable.rs} (93%) diff --git a/contracts/axelar-gas-service/src/contract.rs b/contracts/axelar-gas-service/src/contract.rs index efe88339..9f5eb8e9 100644 --- a/contracts/axelar-gas-service/src/contract.rs +++ b/contracts/axelar-gas-service/src/contract.rs @@ -4,10 +4,10 @@ use crate::error::ContractError; use crate::event; use crate::interface::AxelarGasServiceInterface; use crate::storage_types::DataKey; -use axelar_soroban_std::shared_interfaces::{ - migrate, MigratableInterface, OwnableInterface, UpgradableInterface, +use axelar_soroban_std::contract_traits::{ + MigratableInterface, OwnableInterface, UpgradableInterface, }; -use axelar_soroban_std::{ensure, shared_interfaces, types::Token}; +use axelar_soroban_std::{contract_traits, ensure, types::Token}; #[contract] pub struct AxelarGasService; @@ -16,7 +16,7 @@ pub struct AxelarGasService; impl AxelarGasService { /// Initialize the gas service contract with a gas_collector address. pub fn __constructor(env: Env, owner: Address, gas_collector: Address) { - shared_interfaces::set_owner(&env, &owner); + contract_traits::set_owner(&env, &owner); env.storage() .instance() .set(&DataKey::GasCollector, &gas_collector); @@ -34,7 +34,7 @@ impl MigratableInterface for AxelarGasService { type Error = ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), ContractError> { - migrate::(env, || Self::run_migration(env, migration_data)) + contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| ContractError::MigrationNotAllowed) } } @@ -46,7 +46,7 @@ impl UpgradableInterface for AxelarGasService { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - shared_interfaces::upgrade::(env, new_wasm_hash); + contract_traits::upgrade::(env, new_wasm_hash); } } @@ -54,7 +54,7 @@ impl UpgradableInterface for AxelarGasService { impl OwnableInterface for AxelarGasService { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + contract_traits::owner(env) } } diff --git a/contracts/axelar-gateway/src/contract.rs b/contracts/axelar-gateway/src/contract.rs index 52878d11..a04311c9 100644 --- a/contracts/axelar-gateway/src/contract.rs +++ b/contracts/axelar-gateway/src/contract.rs @@ -4,10 +4,11 @@ use crate::messaging_interface::AxelarGatewayMessagingInterface; use crate::storage_types::{DataKey, MessageApprovalKey, MessageApprovalValue}; use crate::types::{CommandType, Message, Proof, WeightedSigners}; use crate::{auth, event}; -use axelar_soroban_std::shared_interfaces::{migrate, UpgradableInterface}; -use axelar_soroban_std::shared_interfaces::{MigratableInterface, OwnableInterface}; +use axelar_soroban_std::contract_traits::{ + migrate, MigratableInterface, OwnableInterface, UpgradableInterface, +}; use axelar_soroban_std::ttl::{INSTANCE_TTL_EXTEND_TO, INSTANCE_TTL_THRESHOLD}; -use axelar_soroban_std::{ensure, shared_interfaces}; +use axelar_soroban_std::{contract_traits, ensure}; use soroban_sdk::xdr::ToXdr; use soroban_sdk::{contract, contractimpl, Address, Bytes, BytesN, Env, String, Vec}; @@ -35,7 +36,7 @@ impl UpgradableInterface for AxelarGateway { // boilerplate necessary for the contractimpl macro to include function in the generated client fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - shared_interfaces::upgrade::(env, new_wasm_hash); + contract_traits::upgrade::(env, new_wasm_hash); } } @@ -43,7 +44,7 @@ impl UpgradableInterface for AxelarGateway { impl OwnableInterface for AxelarGateway { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + contract_traits::owner(env) } } @@ -59,7 +60,7 @@ impl AxelarGateway { previous_signers_retention: u64, initial_signers: Vec, ) -> Result<(), ContractError> { - shared_interfaces::set_owner(&env, &owner); + contract_traits::set_owner(&env, &owner); env.storage().instance().set(&DataKey::Operator, &operator); auth::initialize_auth( @@ -254,7 +255,7 @@ impl AxelarGatewayInterface for AxelarGateway { let owner: Address = Self::owner(&env); owner.require_auth(); - shared_interfaces::set_owner(&env, &new_owner); + contract_traits::set_owner(&env, &new_owner); event::transfer_ownership(&env, owner, new_owner); } diff --git a/contracts/axelar-gateway/src/interface.rs b/contracts/axelar-gateway/src/interface.rs index 079c3193..c0e966af 100644 --- a/contracts/axelar-gateway/src/interface.rs +++ b/contracts/axelar-gateway/src/interface.rs @@ -3,7 +3,7 @@ use crate::{ types::{Message, Proof, WeightedSigners}, AxelarGatewayMessagingInterface, }; -use axelar_soroban_std::shared_interfaces::UpgradableInterface; +use axelar_soroban_std::contract_traits::UpgradableInterface; use soroban_sdk::{contractclient, Address, BytesN, Env, Vec}; #[contractclient(name = "AxelarGatewayClient")] diff --git a/contracts/axelar-operators/src/contract.rs b/contracts/axelar-operators/src/contract.rs index c483bf80..68801d14 100644 --- a/contracts/axelar-operators/src/contract.rs +++ b/contracts/axelar-operators/src/contract.rs @@ -1,9 +1,10 @@ use crate::error::ContractError; use crate::event; use crate::storage_types::DataKey; -use axelar_soroban_std::shared_interfaces::{migrate, UpgradableInterface}; -use axelar_soroban_std::shared_interfaces::{MigratableInterface, OwnableInterface}; -use axelar_soroban_std::{ensure, shared_interfaces}; +use axelar_soroban_std::contract_traits::{ + MigratableInterface, OwnableInterface, UpgradableInterface, +}; +use axelar_soroban_std::{contract_traits, ensure}; use soroban_sdk::{contract, contractimpl, Address, BytesN, Env, String, Symbol, Val, Vec}; #[contract] @@ -12,7 +13,7 @@ pub struct AxelarOperators; #[contractimpl] impl AxelarOperators { pub fn __constructor(env: Env, owner: Address) { - shared_interfaces::set_owner(&env, &owner); + contract_traits::set_owner(&env, &owner); } pub fn transfer_ownership(env: Env, new_owner: Address) -> Result<(), ContractError> { @@ -20,7 +21,7 @@ impl AxelarOperators { owner.require_auth(); - shared_interfaces::set_owner(&env, &new_owner); + contract_traits::set_owner(&env, &new_owner); event::transfer_ownership(&env, owner, new_owner); @@ -106,7 +107,7 @@ impl MigratableInterface for AxelarOperators { type Error = ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), ContractError> { - migrate::(env, || Self::run_migration(env, migration_data)) + contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| ContractError::MigrationNotAllowed) } } @@ -118,7 +119,7 @@ impl UpgradableInterface for AxelarOperators { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - shared_interfaces::upgrade::(env, new_wasm_hash); + contract_traits::upgrade::(env, new_wasm_hash); } } @@ -126,6 +127,6 @@ impl UpgradableInterface for AxelarOperators { impl OwnableInterface for AxelarOperators { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + contract_traits::owner(env) } } diff --git a/contracts/interchain-token-service/src/contract.rs b/contracts/interchain-token-service/src/contract.rs index 7cc4ea4a..1b51298c 100644 --- a/contracts/interchain-token-service/src/contract.rs +++ b/contracts/interchain-token-service/src/contract.rs @@ -1,5 +1,5 @@ use axelar_soroban_std::types::Token; -use axelar_soroban_std::{ensure, shared_interfaces}; +use axelar_soroban_std::{contract_traits, ensure}; use soroban_sdk::{bytes, contract, contractimpl, Address, Bytes, BytesN, Env, FromVal, String}; use crate::error::ContractError; @@ -12,8 +12,8 @@ use axelar_gas_service::AxelarGasServiceClient; use axelar_gateway::AxelarGatewayMessagingClient; use axelar_gateway::executable::AxelarExecutableInterface; -use axelar_soroban_std::shared_interfaces::{ - migrate, MigratableInterface, OwnableInterface, UpgradableInterface, +use axelar_soroban_std::contract_traits::{ + MigratableInterface, OwnableInterface, UpgradableInterface, }; #[contract] @@ -22,7 +22,7 @@ pub struct InterchainTokenService; #[contractimpl] impl InterchainTokenService { pub fn __constructor(env: Env, owner: Address, gateway: Address, gas_service: Address) { - shared_interfaces::set_owner(&env, &owner); + contract_traits::set_owner(&env, &owner); env.storage().instance().set(&DataKey::Gateway, &gateway); env.storage() .instance() @@ -101,7 +101,7 @@ impl InterchainTokenServiceInterface for InterchainTokenService { let owner = Self::owner(env); owner.require_auth(); - shared_interfaces::set_owner(env, &new_owner); + contract_traits::set_owner(env, &new_owner); event::transfer_ownership(env, owner, new_owner); } @@ -246,7 +246,7 @@ impl MigratableInterface for InterchainTokenService { type Error = axelar_gateway::error::ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), axelar_gateway::error::ContractError> { - migrate::(env, || Self::run_migration(env, migration_data)) + contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| axelar_gateway::error::ContractError::MigrationNotAllowed) } } @@ -258,7 +258,7 @@ impl UpgradableInterface for InterchainTokenService { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - shared_interfaces::upgrade::(env, new_wasm_hash); + contract_traits::upgrade::(env, new_wasm_hash); } } @@ -266,6 +266,6 @@ impl UpgradableInterface for InterchainTokenService { impl OwnableInterface for InterchainTokenService { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + contract_traits::owner(env) } } diff --git a/contracts/interchain-token/src/contract.rs b/contracts/interchain-token/src/contract.rs index ffe6c502..1c42ed53 100644 --- a/contracts/interchain-token/src/contract.rs +++ b/contracts/interchain-token/src/contract.rs @@ -10,10 +10,10 @@ use crate::storage_types::DataKey; use crate::interface::InterchainTokenInterface; use crate::storage_types::{AllowanceDataKey, AllowanceValue}; -use axelar_soroban_std::shared_interfaces::{ - migrate, MigratableInterface, OwnableInterface, UpgradableInterface, +use axelar_soroban_std::contract_traits::{ + MigratableInterface, OwnableInterface, UpgradableInterface, }; -use axelar_soroban_std::{ensure, shared_interfaces}; +use axelar_soroban_std::{contract_traits, ensure}; use soroban_sdk::token::TokenInterface; use soroban_sdk::{assert_with_error, contract, contractimpl, token, Address, BytesN, Env, String}; @@ -31,7 +31,7 @@ impl InterchainToken { token_id: BytesN<32>, token_meta_data: TokenMetadata, ) -> Result<(), ContractError> { - shared_interfaces::set_owner(&env, &owner); + contract_traits::set_owner(&env, &owner); Self::validate_token_metadata(token_meta_data.clone())?; @@ -114,7 +114,7 @@ impl InterchainTokenInterface for InterchainToken { owner.require_auth(); - shared_interfaces::set_owner(&env, &new_owner); + contract_traits::set_owner(&env, &new_owner); TokenUtils::new(&env) .events() @@ -366,7 +366,7 @@ impl MigratableInterface for InterchainToken { type Error = ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), ContractError> { - migrate::(env, || Self::run_migration(env, migration_data)) + contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| ContractError::MigrationNotAllowed) } } @@ -378,7 +378,7 @@ impl UpgradableInterface for InterchainToken { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - shared_interfaces::upgrade::(env, new_wasm_hash); + contract_traits::upgrade::(env, new_wasm_hash); } } @@ -386,6 +386,6 @@ impl UpgradableInterface for InterchainToken { impl OwnableInterface for InterchainToken { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + contract_traits::owner(env) } } diff --git a/contracts/upgrader/src/contract.rs b/contracts/upgrader/src/contract.rs index 6a4bc94f..29a5e66b 100644 --- a/contracts/upgrader/src/contract.rs +++ b/contracts/upgrader/src/contract.rs @@ -1,6 +1,6 @@ use crate::error::ContractError; +use axelar_soroban_std::contract_traits::UpgradableClient; use axelar_soroban_std::ensure; -use axelar_soroban_std::shared_interfaces::UpgradableClient; use soroban_sdk::{ contract, contractimpl, symbol_short, Address, BytesN, Env, String, Symbol, Val, }; diff --git a/contracts/upgrader/tests/utils/dummy_contract.rs b/contracts/upgrader/tests/utils/dummy_contract.rs index 99466be6..79038bb9 100644 --- a/contracts/upgrader/tests/utils/dummy_contract.rs +++ b/contracts/upgrader/tests/utils/dummy_contract.rs @@ -1,7 +1,7 @@ //! Dummy contract to test the [crate::Upgrader] -use axelar_soroban_std::shared_interfaces; -use axelar_soroban_std::shared_interfaces::{OwnableInterface, UpgradableInterface}; +use axelar_soroban_std::contract_traits; +use axelar_soroban_std::contract_traits::{OwnableInterface, UpgradableInterface}; use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, BytesN, Env}; #[contract] @@ -23,14 +23,14 @@ impl UpgradableInterface for DummyContract { #[contractimpl] impl OwnableInterface for DummyContract { fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + contract_traits::owner(env) } } #[contractimpl] impl DummyContract { pub fn __constructor(env: Env, owner: Address) { - shared_interfaces::set_owner(&env, &owner); + contract_traits::set_owner(&env, &owner); } } diff --git a/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs b/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs index d1b067e0..13868140 100644 --- a/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs +++ b/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs @@ -1,7 +1,7 @@ //! Base for the dummy.wasm file. This is the dummy contract after upgrade. -use axelar_soroban_std::shared_interfaces; -use axelar_soroban_std::shared_interfaces::{OwnableInterface, UpgradableInterface}; +use axelar_soroban_std::contract_traits; +use axelar_soroban_std::contract_traits::{OwnableInterface, UpgradableInterface}; use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, BytesN, Env}; #[contract] @@ -23,14 +23,14 @@ impl UpgradableInterface for DummyContract { #[contractimpl] impl OwnableInterface for DummyContract { fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + contract_traits::owner(env) } } #[contractimpl] impl DummyContract { pub fn __constructor(env: Env, owner: Address) { - shared_interfaces::set_owner(&env, &owner); + contract_traits::set_owner(&env, &owner); } pub fn migrate(env: Env, migration_data: soroban_sdk::String) -> Result<(), ContractError> { diff --git a/packages/axelar-soroban-std/src/contract_traits/mod.rs b/packages/axelar-soroban-std/src/contract_traits/mod.rs new file mode 100644 index 00000000..3565fc27 --- /dev/null +++ b/packages/axelar-soroban-std/src/contract_traits/mod.rs @@ -0,0 +1,5 @@ +#[cfg(test)] +mod testdata; +mod upgradable; + +pub use upgradable::*; diff --git a/packages/axelar-soroban-std/src/testdata/contract.rs b/packages/axelar-soroban-std/src/contract_traits/testdata/contract.rs similarity index 79% rename from packages/axelar-soroban-std/src/testdata/contract.rs rename to packages/axelar-soroban-std/src/contract_traits/testdata/contract.rs index 9490a2e6..040ec03a 100644 --- a/packages/axelar-soroban-std/src/testdata/contract.rs +++ b/packages/axelar-soroban-std/src/contract_traits/testdata/contract.rs @@ -1,5 +1,6 @@ -use crate::shared_interfaces; -use crate::shared_interfaces::{MigratableInterface, OwnableInterface, UpgradableInterface}; +use crate::contract_traits::{ + upgradable, MigratableInterface, OwnableInterface, UpgradableInterface, +}; use soroban_sdk::testutils::arbitrary::std; use soroban_sdk::{ contract, contracterror, contractimpl, contracttype, Address, BytesN, Env, String, @@ -29,7 +30,7 @@ impl MigratableInterface for Contract { type Error = ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), ContractError> { - shared_interfaces::migrate::(env, || Self::run_migration(env, migration_data)) + upgradable::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| ContractError::SomeFailure) } } @@ -37,7 +38,7 @@ impl MigratableInterface for Contract { #[contractimpl] impl OwnableInterface for Contract { fn owner(env: &Env) -> Address { - shared_interfaces::owner(env) + upgradable::owner(env) } } @@ -48,7 +49,7 @@ impl UpgradableInterface for Contract { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - shared_interfaces::upgrade::(env, new_wasm_hash); + upgradable::upgrade::(env, new_wasm_hash); } } diff --git a/packages/axelar-soroban-std/src/testdata/contract.wasm b/packages/axelar-soroban-std/src/contract_traits/testdata/contract.wasm similarity index 100% rename from packages/axelar-soroban-std/src/testdata/contract.wasm rename to packages/axelar-soroban-std/src/contract_traits/testdata/contract.wasm diff --git a/packages/axelar-soroban-std/src/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden b/packages/axelar-soroban-std/src/contract_traits/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden similarity index 100% rename from packages/axelar-soroban-std/src/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden rename to packages/axelar-soroban-std/src/contract_traits/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden diff --git a/packages/axelar-soroban-std/src/testdata/mod.rs b/packages/axelar-soroban-std/src/contract_traits/testdata/mod.rs similarity index 100% rename from packages/axelar-soroban-std/src/testdata/mod.rs rename to packages/axelar-soroban-std/src/contract_traits/testdata/mod.rs diff --git a/packages/axelar-soroban-std/src/shared_interfaces.rs b/packages/axelar-soroban-std/src/contract_traits/upgradable.rs similarity index 93% rename from packages/axelar-soroban-std/src/shared_interfaces.rs rename to packages/axelar-soroban-std/src/contract_traits/upgradable.rs index c1ae9f54..0cb9141f 100644 --- a/packages/axelar-soroban-std/src/shared_interfaces.rs +++ b/packages/axelar-soroban-std/src/contract_traits/upgradable.rs @@ -159,11 +159,12 @@ pub enum MigrationError { #[cfg(test)] mod test { - use crate::shared_interfaces::{OwnershipClient, UpgradableClient, UpgradedEvent}; - use crate::{assert_invoke_auth_err, assert_invoke_auth_ok, shared_interfaces, testdata}; + use crate::contract_traits::upgradable::{OwnershipClient, UpgradableClient, UpgradedEvent}; + use crate::{assert_invoke_auth_err, assert_invoke_auth_ok}; use std::format; - use crate::testdata::contract::ContractClient; + use crate::contract_traits::testdata::contract::ContractClient; + use crate::contract_traits::{testdata, upgradable}; use soroban_sdk::testutils::{Address as _, Events, MockAuth, MockAuthInvoke}; use soroban_sdk::{contracttype, Address, Env, String, TryFromVal}; @@ -210,7 +211,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); assert_eq!(OwnershipClient::new(&env, &contract_id).owner(), owner); @@ -235,7 +236,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); assert!(UpgradableClient::new(&env, &contract_id) @@ -251,7 +252,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); let client = UpgradableClient::new(&env, &contract_id); @@ -266,7 +267,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); let client = UpgradableClient::new(&env, &contract_id); @@ -281,7 +282,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); let upgrade_client = UpgradableClient::new(&env, &contract_id); @@ -299,7 +300,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); let upgrade_client = UpgradableClient::new(&env, &contract_id); @@ -316,7 +317,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); let client = ContractClient::new(&env, &contract_id); @@ -331,7 +332,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); let upgradable_client = UpgradableClient::new(&env, &contract_id); @@ -364,8 +365,8 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); - shared_interfaces::start_migration(&env); + upgradable::set_owner(&env, &owner); + upgradable::start_migration(&env); }); let client = ContractClient::new(&env, &contract_id); @@ -380,7 +381,7 @@ mod test { let owner = Address::generate(&env); env.as_contract(&contract_id, || { - shared_interfaces::set_owner(&env, &owner); + upgradable::set_owner(&env, &owner); }); let upgradable_client = UpgradableClient::new(&env, &contract_id); diff --git a/packages/axelar-soroban-std/src/lib.rs b/packages/axelar-soroban-std/src/lib.rs index f55e07de..4f948d9b 100644 --- a/packages/axelar-soroban-std/src/lib.rs +++ b/packages/axelar-soroban-std/src/lib.rs @@ -15,9 +15,6 @@ pub mod types; pub mod error; -pub mod shared_interfaces; - pub mod ttl; -#[cfg(test)] -mod testdata; +pub mod contract_traits; From c60efb92e8bebafd3c696b2838c9862832186d4f Mon Sep 17 00:00:00 2001 From: Christian Gorenflo Date: Wed, 4 Dec 2024 21:46:28 +0100 Subject: [PATCH 2/7] rename to interfaces --- contracts/axelar-gas-service/src/contract.rs | 14 ++++++-------- contracts/axelar-gateway/src/contract.rs | 12 ++++++------ contracts/axelar-gateway/src/interface.rs | 2 +- contracts/axelar-operators/src/contract.rs | 16 +++++++--------- .../interchain-token-service/src/contract.rs | 16 +++++++--------- contracts/interchain-token/src/contract.rs | 16 +++++++--------- contracts/upgrader/src/contract.rs | 2 +- .../upgrader/tests/utils/dummy_contract.rs | 8 ++++---- .../tests/utils/dummy_contract_after_upgrade.rs | 8 ++++---- ...uthenticated_and_called_after_upgrade.golden | 3 --- .../src/{contract_traits => interfaces}/mod.rs | 0 .../testdata/contract.rs | 4 +--- .../testdata/contract.wasm | Bin ...uthenticated_and_called_after_upgrade.golden | 1 + .../testdata/mod.rs | 0 .../upgradable.rs | 15 +++++++-------- packages/axelar-soroban-std/src/lib.rs | 2 +- 17 files changed, 53 insertions(+), 66 deletions(-) delete mode 100644 packages/axelar-soroban-std/src/contract_traits/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden rename packages/axelar-soroban-std/src/{contract_traits => interfaces}/mod.rs (100%) rename packages/axelar-soroban-std/src/{contract_traits => interfaces}/testdata/contract.rs (92%) rename packages/axelar-soroban-std/src/{contract_traits => interfaces}/testdata/contract.wasm (100%) create mode 100644 packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden rename packages/axelar-soroban-std/src/{contract_traits => interfaces}/testdata/mod.rs (100%) rename packages/axelar-soroban-std/src/{contract_traits => interfaces}/upgradable.rs (96%) diff --git a/contracts/axelar-gas-service/src/contract.rs b/contracts/axelar-gas-service/src/contract.rs index 9f5eb8e9..9108ba60 100644 --- a/contracts/axelar-gas-service/src/contract.rs +++ b/contracts/axelar-gas-service/src/contract.rs @@ -4,10 +4,8 @@ use crate::error::ContractError; use crate::event; use crate::interface::AxelarGasServiceInterface; use crate::storage_types::DataKey; -use axelar_soroban_std::contract_traits::{ - MigratableInterface, OwnableInterface, UpgradableInterface, -}; -use axelar_soroban_std::{contract_traits, ensure, types::Token}; +use axelar_soroban_std::interfaces::{MigratableInterface, OwnableInterface, UpgradableInterface}; +use axelar_soroban_std::{ensure, interfaces, types::Token}; #[contract] pub struct AxelarGasService; @@ -16,7 +14,7 @@ pub struct AxelarGasService; impl AxelarGasService { /// Initialize the gas service contract with a gas_collector address. pub fn __constructor(env: Env, owner: Address, gas_collector: Address) { - contract_traits::set_owner(&env, &owner); + interfaces::set_owner(&env, &owner); env.storage() .instance() .set(&DataKey::GasCollector, &gas_collector); @@ -34,7 +32,7 @@ impl MigratableInterface for AxelarGasService { type Error = ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), ContractError> { - contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) + interfaces::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| ContractError::MigrationNotAllowed) } } @@ -46,7 +44,7 @@ impl UpgradableInterface for AxelarGasService { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - contract_traits::upgrade::(env, new_wasm_hash); + interfaces::upgrade::(env, new_wasm_hash); } } @@ -54,7 +52,7 @@ impl UpgradableInterface for AxelarGasService { impl OwnableInterface for AxelarGasService { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - contract_traits::owner(env) + interfaces::owner(env) } } diff --git a/contracts/axelar-gateway/src/contract.rs b/contracts/axelar-gateway/src/contract.rs index a04311c9..6a9f1d0c 100644 --- a/contracts/axelar-gateway/src/contract.rs +++ b/contracts/axelar-gateway/src/contract.rs @@ -4,11 +4,11 @@ use crate::messaging_interface::AxelarGatewayMessagingInterface; use crate::storage_types::{DataKey, MessageApprovalKey, MessageApprovalValue}; use crate::types::{CommandType, Message, Proof, WeightedSigners}; use crate::{auth, event}; -use axelar_soroban_std::contract_traits::{ +use axelar_soroban_std::interfaces::{ migrate, MigratableInterface, OwnableInterface, UpgradableInterface, }; use axelar_soroban_std::ttl::{INSTANCE_TTL_EXTEND_TO, INSTANCE_TTL_THRESHOLD}; -use axelar_soroban_std::{contract_traits, ensure}; +use axelar_soroban_std::{ensure, interfaces}; use soroban_sdk::xdr::ToXdr; use soroban_sdk::{contract, contractimpl, Address, Bytes, BytesN, Env, String, Vec}; @@ -36,7 +36,7 @@ impl UpgradableInterface for AxelarGateway { // boilerplate necessary for the contractimpl macro to include function in the generated client fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - contract_traits::upgrade::(env, new_wasm_hash); + interfaces::upgrade::(env, new_wasm_hash); } } @@ -44,7 +44,7 @@ impl UpgradableInterface for AxelarGateway { impl OwnableInterface for AxelarGateway { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - contract_traits::owner(env) + interfaces::owner(env) } } @@ -60,7 +60,7 @@ impl AxelarGateway { previous_signers_retention: u64, initial_signers: Vec, ) -> Result<(), ContractError> { - contract_traits::set_owner(&env, &owner); + interfaces::set_owner(&env, &owner); env.storage().instance().set(&DataKey::Operator, &operator); auth::initialize_auth( @@ -255,7 +255,7 @@ impl AxelarGatewayInterface for AxelarGateway { let owner: Address = Self::owner(&env); owner.require_auth(); - contract_traits::set_owner(&env, &new_owner); + interfaces::set_owner(&env, &new_owner); event::transfer_ownership(&env, owner, new_owner); } diff --git a/contracts/axelar-gateway/src/interface.rs b/contracts/axelar-gateway/src/interface.rs index c0e966af..9c2081ea 100644 --- a/contracts/axelar-gateway/src/interface.rs +++ b/contracts/axelar-gateway/src/interface.rs @@ -3,7 +3,7 @@ use crate::{ types::{Message, Proof, WeightedSigners}, AxelarGatewayMessagingInterface, }; -use axelar_soroban_std::contract_traits::UpgradableInterface; +use axelar_soroban_std::interfaces::UpgradableInterface; use soroban_sdk::{contractclient, Address, BytesN, Env, Vec}; #[contractclient(name = "AxelarGatewayClient")] diff --git a/contracts/axelar-operators/src/contract.rs b/contracts/axelar-operators/src/contract.rs index 68801d14..c33e7b40 100644 --- a/contracts/axelar-operators/src/contract.rs +++ b/contracts/axelar-operators/src/contract.rs @@ -1,10 +1,8 @@ use crate::error::ContractError; use crate::event; use crate::storage_types::DataKey; -use axelar_soroban_std::contract_traits::{ - MigratableInterface, OwnableInterface, UpgradableInterface, -}; -use axelar_soroban_std::{contract_traits, ensure}; +use axelar_soroban_std::interfaces::{MigratableInterface, OwnableInterface, UpgradableInterface}; +use axelar_soroban_std::{ensure, interfaces}; use soroban_sdk::{contract, contractimpl, Address, BytesN, Env, String, Symbol, Val, Vec}; #[contract] @@ -13,7 +11,7 @@ pub struct AxelarOperators; #[contractimpl] impl AxelarOperators { pub fn __constructor(env: Env, owner: Address) { - contract_traits::set_owner(&env, &owner); + interfaces::set_owner(&env, &owner); } pub fn transfer_ownership(env: Env, new_owner: Address) -> Result<(), ContractError> { @@ -21,7 +19,7 @@ impl AxelarOperators { owner.require_auth(); - contract_traits::set_owner(&env, &new_owner); + interfaces::set_owner(&env, &new_owner); event::transfer_ownership(&env, owner, new_owner); @@ -107,7 +105,7 @@ impl MigratableInterface for AxelarOperators { type Error = ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), ContractError> { - contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) + interfaces::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| ContractError::MigrationNotAllowed) } } @@ -119,7 +117,7 @@ impl UpgradableInterface for AxelarOperators { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - contract_traits::upgrade::(env, new_wasm_hash); + interfaces::upgrade::(env, new_wasm_hash); } } @@ -127,6 +125,6 @@ impl UpgradableInterface for AxelarOperators { impl OwnableInterface for AxelarOperators { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - contract_traits::owner(env) + interfaces::owner(env) } } diff --git a/contracts/interchain-token-service/src/contract.rs b/contracts/interchain-token-service/src/contract.rs index 1b51298c..9e5a4958 100644 --- a/contracts/interchain-token-service/src/contract.rs +++ b/contracts/interchain-token-service/src/contract.rs @@ -1,5 +1,5 @@ use axelar_soroban_std::types::Token; -use axelar_soroban_std::{contract_traits, ensure}; +use axelar_soroban_std::{ensure, interfaces}; use soroban_sdk::{bytes, contract, contractimpl, Address, Bytes, BytesN, Env, FromVal, String}; use crate::error::ContractError; @@ -12,9 +12,7 @@ use axelar_gas_service::AxelarGasServiceClient; use axelar_gateway::AxelarGatewayMessagingClient; use axelar_gateway::executable::AxelarExecutableInterface; -use axelar_soroban_std::contract_traits::{ - MigratableInterface, OwnableInterface, UpgradableInterface, -}; +use axelar_soroban_std::interfaces::{MigratableInterface, OwnableInterface, UpgradableInterface}; #[contract] pub struct InterchainTokenService; @@ -22,7 +20,7 @@ pub struct InterchainTokenService; #[contractimpl] impl InterchainTokenService { pub fn __constructor(env: Env, owner: Address, gateway: Address, gas_service: Address) { - contract_traits::set_owner(&env, &owner); + interfaces::set_owner(&env, &owner); env.storage().instance().set(&DataKey::Gateway, &gateway); env.storage() .instance() @@ -101,7 +99,7 @@ impl InterchainTokenServiceInterface for InterchainTokenService { let owner = Self::owner(env); owner.require_auth(); - contract_traits::set_owner(env, &new_owner); + interfaces::set_owner(env, &new_owner); event::transfer_ownership(env, owner, new_owner); } @@ -246,7 +244,7 @@ impl MigratableInterface for InterchainTokenService { type Error = axelar_gateway::error::ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), axelar_gateway::error::ContractError> { - contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) + interfaces::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| axelar_gateway::error::ContractError::MigrationNotAllowed) } } @@ -258,7 +256,7 @@ impl UpgradableInterface for InterchainTokenService { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - contract_traits::upgrade::(env, new_wasm_hash); + interfaces::upgrade::(env, new_wasm_hash); } } @@ -266,6 +264,6 @@ impl UpgradableInterface for InterchainTokenService { impl OwnableInterface for InterchainTokenService { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - contract_traits::owner(env) + interfaces::owner(env) } } diff --git a/contracts/interchain-token/src/contract.rs b/contracts/interchain-token/src/contract.rs index 1c42ed53..e7c2f752 100644 --- a/contracts/interchain-token/src/contract.rs +++ b/contracts/interchain-token/src/contract.rs @@ -10,10 +10,8 @@ use crate::storage_types::DataKey; use crate::interface::InterchainTokenInterface; use crate::storage_types::{AllowanceDataKey, AllowanceValue}; -use axelar_soroban_std::contract_traits::{ - MigratableInterface, OwnableInterface, UpgradableInterface, -}; -use axelar_soroban_std::{contract_traits, ensure}; +use axelar_soroban_std::interfaces::{MigratableInterface, OwnableInterface, UpgradableInterface}; +use axelar_soroban_std::{ensure, interfaces}; use soroban_sdk::token::TokenInterface; use soroban_sdk::{assert_with_error, contract, contractimpl, token, Address, BytesN, Env, String}; @@ -31,7 +29,7 @@ impl InterchainToken { token_id: BytesN<32>, token_meta_data: TokenMetadata, ) -> Result<(), ContractError> { - contract_traits::set_owner(&env, &owner); + interfaces::set_owner(&env, &owner); Self::validate_token_metadata(token_meta_data.clone())?; @@ -114,7 +112,7 @@ impl InterchainTokenInterface for InterchainToken { owner.require_auth(); - contract_traits::set_owner(&env, &new_owner); + interfaces::set_owner(&env, &new_owner); TokenUtils::new(&env) .events() @@ -366,7 +364,7 @@ impl MigratableInterface for InterchainToken { type Error = ContractError; fn migrate(env: &Env, migration_data: ()) -> Result<(), ContractError> { - contract_traits::migrate::(env, || Self::run_migration(env, migration_data)) + interfaces::migrate::(env, || Self::run_migration(env, migration_data)) .map_err(|_| ContractError::MigrationNotAllowed) } } @@ -378,7 +376,7 @@ impl UpgradableInterface for InterchainToken { } fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { - contract_traits::upgrade::(env, new_wasm_hash); + interfaces::upgrade::(env, new_wasm_hash); } } @@ -386,6 +384,6 @@ impl UpgradableInterface for InterchainToken { impl OwnableInterface for InterchainToken { // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { - contract_traits::owner(env) + interfaces::owner(env) } } diff --git a/contracts/upgrader/src/contract.rs b/contracts/upgrader/src/contract.rs index 29a5e66b..a7ab428f 100644 --- a/contracts/upgrader/src/contract.rs +++ b/contracts/upgrader/src/contract.rs @@ -1,6 +1,6 @@ use crate::error::ContractError; -use axelar_soroban_std::contract_traits::UpgradableClient; use axelar_soroban_std::ensure; +use axelar_soroban_std::interfaces::UpgradableClient; use soroban_sdk::{ contract, contractimpl, symbol_short, Address, BytesN, Env, String, Symbol, Val, }; diff --git a/contracts/upgrader/tests/utils/dummy_contract.rs b/contracts/upgrader/tests/utils/dummy_contract.rs index 79038bb9..69509d4d 100644 --- a/contracts/upgrader/tests/utils/dummy_contract.rs +++ b/contracts/upgrader/tests/utils/dummy_contract.rs @@ -1,7 +1,7 @@ //! Dummy contract to test the [crate::Upgrader] -use axelar_soroban_std::contract_traits; -use axelar_soroban_std::contract_traits::{OwnableInterface, UpgradableInterface}; +use axelar_soroban_std::interfaces; +use axelar_soroban_std::interfaces::{OwnableInterface, UpgradableInterface}; use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, BytesN, Env}; #[contract] @@ -23,14 +23,14 @@ impl UpgradableInterface for DummyContract { #[contractimpl] impl OwnableInterface for DummyContract { fn owner(env: &Env) -> Address { - contract_traits::owner(env) + interfaces::owner(env) } } #[contractimpl] impl DummyContract { pub fn __constructor(env: Env, owner: Address) { - contract_traits::set_owner(&env, &owner); + interfaces::set_owner(&env, &owner); } } diff --git a/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs b/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs index 13868140..1df4ccd3 100644 --- a/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs +++ b/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs @@ -1,7 +1,7 @@ //! Base for the dummy.wasm file. This is the dummy contract after upgrade. -use axelar_soroban_std::contract_traits; -use axelar_soroban_std::contract_traits::{OwnableInterface, UpgradableInterface}; +use axelar_soroban_std::interfaces; +use axelar_soroban_std::interfaces::{OwnableInterface, UpgradableInterface}; use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, BytesN, Env}; #[contract] @@ -23,14 +23,14 @@ impl UpgradableInterface for DummyContract { #[contractimpl] impl OwnableInterface for DummyContract { fn owner(env: &Env) -> Address { - contract_traits::owner(env) + interfaces::owner(env) } } #[contractimpl] impl DummyContract { pub fn __constructor(env: Env, owner: Address) { - contract_traits::set_owner(&env, &owner); + interfaces::set_owner(&env, &owner); } pub fn migrate(env: Env, migration_data: soroban_sdk::String) -> Result<(), ContractError> { diff --git a/packages/axelar-soroban-std/src/contract_traits/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden b/packages/axelar-soroban-std/src/contract_traits/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden deleted file mode 100644 index f71caf31..00000000 --- a/packages/axelar-soroban-std/src/contract_traits/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden +++ /dev/null @@ -1,3 +0,0 @@ -contract: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM) -topics: (Symbol(upgraded)) -data: (String(0.1.0)) \ No newline at end of file diff --git a/packages/axelar-soroban-std/src/contract_traits/mod.rs b/packages/axelar-soroban-std/src/interfaces/mod.rs similarity index 100% rename from packages/axelar-soroban-std/src/contract_traits/mod.rs rename to packages/axelar-soroban-std/src/interfaces/mod.rs diff --git a/packages/axelar-soroban-std/src/contract_traits/testdata/contract.rs b/packages/axelar-soroban-std/src/interfaces/testdata/contract.rs similarity index 92% rename from packages/axelar-soroban-std/src/contract_traits/testdata/contract.rs rename to packages/axelar-soroban-std/src/interfaces/testdata/contract.rs index 040ec03a..499e36c0 100644 --- a/packages/axelar-soroban-std/src/contract_traits/testdata/contract.rs +++ b/packages/axelar-soroban-std/src/interfaces/testdata/contract.rs @@ -1,6 +1,4 @@ -use crate::contract_traits::{ - upgradable, MigratableInterface, OwnableInterface, UpgradableInterface, -}; +use crate::interfaces::{upgradable, MigratableInterface, OwnableInterface, UpgradableInterface}; use soroban_sdk::testutils::arbitrary::std; use soroban_sdk::{ contract, contracterror, contractimpl, contracttype, Address, BytesN, Env, String, diff --git a/packages/axelar-soroban-std/src/contract_traits/testdata/contract.wasm b/packages/axelar-soroban-std/src/interfaces/testdata/contract.wasm similarity index 100% rename from packages/axelar-soroban-std/src/contract_traits/testdata/contract.wasm rename to packages/axelar-soroban-std/src/interfaces/testdata/contract.wasm diff --git a/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden b/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden new file mode 100644 index 00000000..284157b4 --- /dev/null +++ b/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden @@ -0,0 +1 @@ +Some(UpgradedEvent { version: String(0.1.0) }) \ No newline at end of file diff --git a/packages/axelar-soroban-std/src/contract_traits/testdata/mod.rs b/packages/axelar-soroban-std/src/interfaces/testdata/mod.rs similarity index 100% rename from packages/axelar-soroban-std/src/contract_traits/testdata/mod.rs rename to packages/axelar-soroban-std/src/interfaces/testdata/mod.rs diff --git a/packages/axelar-soroban-std/src/contract_traits/upgradable.rs b/packages/axelar-soroban-std/src/interfaces/upgradable.rs similarity index 96% rename from packages/axelar-soroban-std/src/contract_traits/upgradable.rs rename to packages/axelar-soroban-std/src/interfaces/upgradable.rs index 1c549f8c..e503e0b0 100644 --- a/packages/axelar-soroban-std/src/contract_traits/upgradable.rs +++ b/packages/axelar-soroban-std/src/interfaces/upgradable.rs @@ -144,14 +144,13 @@ pub enum MigrationError { #[cfg(test)] mod test { - use crate::contract_traits::upgradable::{OwnershipClient, UpgradableClient, UpgradedEvent}; - use crate::{assert_invoke_auth_err, assert_invoke_auth_ok}; - use std::format; - - use crate::contract_traits::testdata::contract::ContractClient; - use crate::contract_traits::{testdata, upgradable}; - use soroban_sdk::testutils::{Address as _, Events, MockAuth, MockAuthInvoke}; - use soroban_sdk::{contracttype, Address, Env, String, TryFromVal}; + use crate::interfaces::upgradable::{OwnershipClient, UpgradableClient, UpgradedEvent}; + use crate::{assert_invoke_auth_err, assert_invoke_auth_ok, events}; + + use crate::interfaces::testdata::contract::ContractClient; + use crate::interfaces::{testdata, upgradable}; + use soroban_sdk::testutils::{Address as _, MockAuth, MockAuthInvoke}; + use soroban_sdk::{contracttype, Address, Env, String}; const WASM: &[u8] = include_bytes!("testdata/contract.wasm"); diff --git a/packages/axelar-soroban-std/src/lib.rs b/packages/axelar-soroban-std/src/lib.rs index 61732391..1b9bd3e7 100644 --- a/packages/axelar-soroban-std/src/lib.rs +++ b/packages/axelar-soroban-std/src/lib.rs @@ -20,4 +20,4 @@ pub mod ttl; pub mod events; -pub mod contract_traits; +pub mod interfaces; From acdf17c78c112900473374d7fd163590a2610451 Mon Sep 17 00:00:00 2001 From: Christian Gorenflo Date: Wed, 4 Dec 2024 21:49:48 +0100 Subject: [PATCH 3/7] fix tests --- packages/axelar-soroban-std/src/events.rs | 2 +- ..._if_owner_is_authenticated_and_called_after_upgrade.golden | 4 +++- .../src/testdata/format_last_emitted_event.golden | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 packages/axelar-soroban-std/src/testdata/format_last_emitted_event.golden diff --git a/packages/axelar-soroban-std/src/events.rs b/packages/axelar-soroban-std/src/events.rs index 62e931ce..d25ec41e 100644 --- a/packages/axelar-soroban-std/src/events.rs +++ b/packages/axelar-soroban-std/src/events.rs @@ -128,7 +128,7 @@ mod test { struct Contract; #[test] - fn test_format_last_emitted_event() { + fn format_last_emitted_event() { let env = Env::default(); let expected = TestEvent { topic1: Symbol::new(&env, "topic1"), diff --git a/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden b/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden index 284157b4..f71caf31 100644 --- a/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden +++ b/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden @@ -1 +1,3 @@ -Some(UpgradedEvent { version: String(0.1.0) }) \ No newline at end of file +contract: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM) +topics: (Symbol(upgraded)) +data: (String(0.1.0)) \ No newline at end of file diff --git a/packages/axelar-soroban-std/src/testdata/format_last_emitted_event.golden b/packages/axelar-soroban-std/src/testdata/format_last_emitted_event.golden new file mode 100644 index 00000000..6ed8dd01 --- /dev/null +++ b/packages/axelar-soroban-std/src/testdata/format_last_emitted_event.golden @@ -0,0 +1,3 @@ +contract: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM) +topics: (Symbol(topic1), String(topic2), 10) +data: (String(data1), BytesN<32>(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3)) \ No newline at end of file From dccfe1a52bfc9deef28705638ee42f7cda3debde Mon Sep 17 00:00:00 2001 From: Christian Gorenflo Date: Fri, 6 Dec 2024 00:16:20 +0100 Subject: [PATCH 4/7] finalize ownable interface --- contracts/axelar-gas-service/src/contract.rs | 5 +- contracts/axelar-gas-service/tests/test.rs | 1 - contracts/axelar-gateway/src/contract.rs | 14 +- contracts/axelar-gateway/src/event.rs | 9 - contracts/axelar-gateway/src/interface.rs | 3 - contracts/axelar-gateway/src/lib.rs | 2 +- contracts/axelar-gateway/tests/test.rs | 25 +-- contracts/axelar-operators/src/contract.rs | 17 +- contracts/axelar-operators/src/event.rs | 9 - contracts/axelar-operators/tests/test.rs | 37 +--- .../interchain-token-service/src/contract.rs | 14 +- .../interchain-token-service/src/event.rs | 11 +- .../interchain-token-service/src/interface.rs | 2 - .../interchain-token-service/tests/test.rs | 25 --- contracts/interchain-token/src/contract.rs | 24 +-- contracts/interchain-token/src/event.rs | 9 - contracts/interchain-token/src/interface.rs | 2 - contracts/interchain-token/tests/test.rs | 1 - contracts/upgrader/tests/testdata/dummy.wasm | Bin 13588 -> 2458 bytes .../upgrader/tests/utils/dummy_contract.rs | 4 + .../utils/dummy_contract_after_upgrade.rs | 4 + .../test_format_last_emitted_event.golden | 3 - packages/axelar-soroban-std/src/error.rs | 4 +- packages/axelar-soroban-std/src/events.rs | 18 +- .../axelar-soroban-std/src/interfaces/mod.rs | 2 + .../src/interfaces/ownable.rs | 140 ++++++++++++++ .../src/interfaces/testdata/contract.rs | 16 +- .../src/interfaces/testdata/contract.wasm | Bin 15198 -> 2938 bytes ...henticated_and_called_after_upgrade.golden | 2 +- .../src/interfaces/upgradable.rs | 179 ++++-------------- 30 files changed, 246 insertions(+), 336 deletions(-) delete mode 100644 packages/axelar-soroban-std/src/contract_traits/testdata/test_format_last_emitted_event.golden create mode 100644 packages/axelar-soroban-std/src/interfaces/ownable.rs diff --git a/contracts/axelar-gas-service/src/contract.rs b/contracts/axelar-gas-service/src/contract.rs index 9108ba60..a5b43922 100644 --- a/contracts/axelar-gas-service/src/contract.rs +++ b/contracts/axelar-gas-service/src/contract.rs @@ -50,10 +50,13 @@ impl UpgradableInterface for AxelarGasService { #[contractimpl] impl OwnableInterface for AxelarGasService { - // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { interfaces::owner(env) } + + fn transfer_ownership(env: &Env, new_owner: Address) { + interfaces::transfer_ownership::(env, new_owner); + } } #[contractimpl] diff --git a/contracts/axelar-gas-service/tests/test.rs b/contracts/axelar-gas-service/tests/test.rs index ca38941d..8f748f0b 100644 --- a/contracts/axelar-gas-service/tests/test.rs +++ b/contracts/axelar-gas-service/tests/test.rs @@ -8,7 +8,6 @@ use axelar_gas_service::error::ContractError; use axelar_soroban_std::{ assert_contract_err, assert_invoke_auth_err, assert_last_emitted_event, types::Token, }; -use soroban_sdk::testutils::{MockAuth, MockAuthInvoke}; use soroban_sdk::Bytes; use soroban_sdk::{ bytes, diff --git a/contracts/axelar-gateway/src/contract.rs b/contracts/axelar-gateway/src/contract.rs index 6a9f1d0c..6560fc17 100644 --- a/contracts/axelar-gateway/src/contract.rs +++ b/contracts/axelar-gateway/src/contract.rs @@ -42,10 +42,13 @@ impl UpgradableInterface for AxelarGateway { #[contractimpl] impl OwnableInterface for AxelarGateway { - // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { interfaces::owner(env) } + + fn transfer_ownership(env: &Env, new_owner: Address) { + interfaces::transfer_ownership::(env, new_owner); + } } #[contractimpl] @@ -251,15 +254,6 @@ impl AxelarGatewayInterface for AxelarGateway { auth::epoch(env) } - fn transfer_ownership(env: Env, new_owner: Address) { - let owner: Address = Self::owner(&env); - owner.require_auth(); - - interfaces::set_owner(&env, &new_owner); - - event::transfer_ownership(&env, owner, new_owner); - } - fn epoch_by_signers_hash(env: &Env, signers_hash: BytesN<32>) -> Result { auth::epoch_by_signers_hash(env, signers_hash) } diff --git a/contracts/axelar-gateway/src/event.rs b/contracts/axelar-gateway/src/event.rs index 3173f818..a28b6301 100644 --- a/contracts/axelar-gateway/src/event.rs +++ b/contracts/axelar-gateway/src/event.rs @@ -42,12 +42,3 @@ pub fn transfer_operatorship(env: &Env, previous_operator: Address, new_operator ); env.events().publish(topics, ()); } - -pub fn transfer_ownership(env: &Env, previous_owner: Address, new_owner: Address) { - let topics = ( - Symbol::new(env, "ownership_transferred"), - previous_owner, - new_owner, - ); - env.events().publish(topics, ()); -} diff --git a/contracts/axelar-gateway/src/interface.rs b/contracts/axelar-gateway/src/interface.rs index 9c2081ea..8686b2d5 100644 --- a/contracts/axelar-gateway/src/interface.rs +++ b/contracts/axelar-gateway/src/interface.rs @@ -32,9 +32,6 @@ pub trait AxelarGatewayInterface: AxelarGatewayMessagingInterface + UpgradableIn /// Returns the epoch of the gateway. fn epoch(env: &Env) -> u64; - /// Transfers ownership of the gateway to a new address. - fn transfer_ownership(env: Env, new_owner: Address); - /// Returns the epoch by signers hash. fn epoch_by_signers_hash(env: &Env, signers_hash: BytesN<32>) -> Result; diff --git a/contracts/axelar-gateway/src/lib.rs b/contracts/axelar-gateway/src/lib.rs index cf07afd5..0af6885d 100644 --- a/contracts/axelar-gateway/src/lib.rs +++ b/contracts/axelar-gateway/src/lib.rs @@ -16,7 +16,7 @@ mod interface; #[cfg(all(target_family = "wasm", feature = "testutils"))] compile_error!("'testutils' feature is not supported on 'wasm' target"); -#[cfg(feature = "testutils")] +#[cfg(any(test, feature = "testutils"))] pub mod testutils; cfg_if::cfg_if! { diff --git a/contracts/axelar-gateway/tests/test.rs b/contracts/axelar-gateway/tests/test.rs index eb4414b4..bcfc5284 100644 --- a/contracts/axelar-gateway/tests/test.rs +++ b/contracts/axelar-gateway/tests/test.rs @@ -1,4 +1,5 @@ use axelar_gateway::error::ContractError; +#[cfg(any(test, feature = "testutils"))] use axelar_gateway::testutils::{ generate_proof, generate_signers_set, generate_test_message, get_approve_hash, randint, setup_gateway, TestSignerSet, @@ -12,7 +13,7 @@ use axelar_soroban_std::{ use soroban_sdk::Symbol; use soroban_sdk::{ bytes, - testutils::{Address as _, Events, MockAuth, MockAuthInvoke}, + testutils::{Address as _, Events}, vec, Address, BytesN, Env, String, }; @@ -366,28 +367,6 @@ fn transfer_operatorship_unauthorized() { ); } -#[test] -fn transfer_ownership() { - let (env, _signers, client) = setup_env(1, randint(1, 10)); - - let owner = client.owner(); - let new_owner = Address::generate(&env); - - assert_invoke_auth_ok!(owner, client.try_transfer_ownership(&new_owner)); - assert_last_emitted_event( - &env, - &client.address, - ( - Symbol::new(&env, "ownership_transferred"), - owner, - new_owner.clone(), - ), - (), - ); - - assert_eq!(client.owner(), new_owner); -} - #[test] fn transfer_ownership_unauthorized() { let (env, _, client) = setup_env(1, randint(1, 10)); diff --git a/contracts/axelar-operators/src/contract.rs b/contracts/axelar-operators/src/contract.rs index c33e7b40..0f4a19d0 100644 --- a/contracts/axelar-operators/src/contract.rs +++ b/contracts/axelar-operators/src/contract.rs @@ -14,18 +14,6 @@ impl AxelarOperators { interfaces::set_owner(&env, &owner); } - pub fn transfer_ownership(env: Env, new_owner: Address) -> Result<(), ContractError> { - let owner: Address = Self::owner(&env); - - owner.require_auth(); - - interfaces::set_owner(&env, &new_owner); - - event::transfer_ownership(&env, owner, new_owner); - - Ok(()) - } - /// Return true if the account is an operator. pub fn is_operator(env: Env, account: Address) -> bool { let key = DataKey::Operators(account); @@ -123,8 +111,11 @@ impl UpgradableInterface for AxelarOperators { #[contractimpl] impl OwnableInterface for AxelarOperators { - // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { interfaces::owner(env) } + + fn transfer_ownership(env: &Env, new_owner: Address) { + interfaces::transfer_ownership::(env, new_owner); + } } diff --git a/contracts/axelar-operators/src/event.rs b/contracts/axelar-operators/src/event.rs index 2173bcc3..9e030e32 100644 --- a/contracts/axelar-operators/src/event.rs +++ b/contracts/axelar-operators/src/event.rs @@ -1,14 +1,5 @@ use soroban_sdk::{Address, Env, Symbol}; -pub fn transfer_ownership(env: &Env, previous_owner: Address, new_owner: Address) { - let topics = ( - Symbol::new(env, "ownership_transferred"), - previous_owner, - new_owner, - ); - env.events().publish(topics, ()); -} - pub fn add_operator(env: &Env, operator: Address) { let topics = (Symbol::new(env, "operator_added"), operator); env.events().publish(topics, ()); diff --git a/contracts/axelar-operators/tests/test.rs b/contracts/axelar-operators/tests/test.rs index 6857b540..c661a98b 100644 --- a/contracts/axelar-operators/tests/test.rs +++ b/contracts/axelar-operators/tests/test.rs @@ -9,9 +9,7 @@ use axelar_soroban_std::{ use axelar_operators::contract::{AxelarOperators, AxelarOperatorsClient}; use soroban_sdk::{ - contract, contractimpl, symbol_short, - testutils::{Address as _, MockAuth, MockAuthInvoke}, - Address, Env, Symbol, Val, Vec, + contract, contractimpl, symbol_short, testutils::Address as _, Address, Env, Symbol, Val, Vec, }; #[contract] @@ -51,39 +49,6 @@ fn register_operators() { assert_eq!(client.owner(), user); } -#[test] -fn transfer_owner() { - let (env, client, _) = setup_env(); - - let initial_owner = client.owner(); - let new_owner = Address::generate(&env); - - // transfer ownership to the new owner - client.transfer_ownership(&new_owner); - - assert_invocation( - &env, - &initial_owner, - &client.address, - "transfer_ownership", - (new_owner.clone(),), - ); - - assert_last_emitted_event( - &env, - &client.address, - ( - Symbol::new(&env, "ownership_transferred"), - initial_owner, - new_owner.clone(), - ), - (), - ); - - let retrieved_owner = client.owner(); - assert_eq!(retrieved_owner, new_owner); -} - #[test] fn add_operator() { let (env, client, _) = setup_env(); diff --git a/contracts/interchain-token-service/src/contract.rs b/contracts/interchain-token-service/src/contract.rs index 9e5a4958..50985d8a 100644 --- a/contracts/interchain-token-service/src/contract.rs +++ b/contracts/interchain-token-service/src/contract.rs @@ -95,15 +95,6 @@ impl InterchainTokenService { #[contractimpl] impl InterchainTokenServiceInterface for InterchainTokenService { - fn transfer_ownership(env: &Env, new_owner: Address) { - let owner = Self::owner(env); - owner.require_auth(); - - interfaces::set_owner(env, &new_owner); - - event::transfer_ownership(env, owner, new_owner); - } - fn trusted_address(env: &Env, chain: String) -> Option { env.storage() .persistent() @@ -262,8 +253,11 @@ impl UpgradableInterface for InterchainTokenService { #[contractimpl] impl OwnableInterface for InterchainTokenService { - // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { interfaces::owner(env) } + + fn transfer_ownership(env: &Env, new_owner: Address) { + interfaces::transfer_ownership::(env, new_owner); + } } diff --git a/contracts/interchain-token-service/src/event.rs b/contracts/interchain-token-service/src/event.rs index 3926ec0a..5631203b 100644 --- a/contracts/interchain-token-service/src/event.rs +++ b/contracts/interchain-token-service/src/event.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{Address, Bytes, Env, String, Symbol}; +use soroban_sdk::{Bytes, Env, String, Symbol}; pub fn set_trusted_address(env: &Env, chain: String, trusted_address: String) { let topics = ( @@ -18,15 +18,6 @@ pub fn remove_trusted_address(env: &Env, chain: String, trusted_address: String) env.events().publish(topics, ()); } -pub fn transfer_ownership(env: &Env, previous_owner: Address, new_owner: Address) { - let topics = ( - Symbol::new(env, "ownership_transferred"), - previous_owner, - new_owner, - ); - env.events().publish(topics, ()); -} - pub fn executed( env: &Env, source_chain: String, diff --git a/contracts/interchain-token-service/src/interface.rs b/contracts/interchain-token-service/src/interface.rs index d5486f56..b86875c8 100644 --- a/contracts/interchain-token-service/src/interface.rs +++ b/contracts/interchain-token-service/src/interface.rs @@ -6,8 +6,6 @@ use crate::error::ContractError; #[contractclient(name = "InterchainTokenServiceClient")] pub trait InterchainTokenServiceInterface: AxelarExecutableInterface { - fn transfer_ownership(env: &Env, new_owner: Address); - fn trusted_address(env: &Env, chain: String) -> Option; fn set_trusted_address(env: &Env, chain: String, address: String) -> Result<(), ContractError>; diff --git a/contracts/interchain-token-service/tests/test.rs b/contracts/interchain-token-service/tests/test.rs index c219068b..dc52571e 100644 --- a/contracts/interchain-token-service/tests/test.rs +++ b/contracts/interchain-token-service/tests/test.rs @@ -5,7 +5,6 @@ use interchain_token_service::contract::{InterchainTokenService, InterchainToken use interchain_token_service::error::ContractError; use axelar_soroban_std::{assert_contract_err, assert_invoke_auth_err, assert_last_emitted_event}; -use soroban_sdk::testutils::{MockAuth, MockAuthInvoke}; use soroban_sdk::{testutils::Address as _, Address, Env, String, Symbol}; @@ -151,27 +150,3 @@ fn remove_trusted_address_fails_if_address_not_set() { ContractError::NoTrustedAddressSet ); } - -#[test] -fn transfer_ownership() { - let (env, client) = setup_env(); - env.mock_all_auths(); - - let prev_owner = client.owner(); - let new_owner = Address::generate(&env); - - client.transfer_ownership(&new_owner); - - assert_last_emitted_event( - &env, - &client.address, - ( - Symbol::new(&env, "ownership_transferred"), - prev_owner, - new_owner.clone(), - ), - (), - ); - - assert_eq!(client.owner(), new_owner); -} diff --git a/contracts/interchain-token/src/contract.rs b/contracts/interchain-token/src/contract.rs index e7c2f752..bfb607ea 100644 --- a/contracts/interchain-token/src/contract.rs +++ b/contracts/interchain-token/src/contract.rs @@ -15,6 +15,7 @@ use axelar_soroban_std::{ensure, interfaces}; use soroban_sdk::token::TokenInterface; use soroban_sdk::{assert_with_error, contract, contractimpl, token, Address, BytesN, Env, String}; +use soroban_token_sdk::event::Events as TokenEvents; #[contract] pub struct InterchainToken; @@ -106,22 +107,6 @@ impl InterchainTokenInterface for InterchainToken { event::remove_minter(env, minter); } - - fn transfer_ownership(env: Env, new_owner: Address) -> Result<(), ContractError> { - let owner: Address = Self::owner(&env); - - owner.require_auth(); - - interfaces::set_owner(&env, &new_owner); - - TokenUtils::new(&env) - .events() - .set_admin(owner.clone(), new_owner.clone()); - - event::transfer_ownership(&env, owner, new_owner); - - Ok(()) - } } #[contractimpl] @@ -382,8 +367,13 @@ impl UpgradableInterface for InterchainToken { #[contractimpl] impl OwnableInterface for InterchainToken { - // boilerplate necessary for the contractimpl macro to include function in the generated client fn owner(env: &Env) -> Address { interfaces::owner(env) } + + fn transfer_ownership(env: &Env, new_owner: Address) { + interfaces::transfer_ownership::(env, new_owner.clone()); + // adhere to reference implementation for tokens and emit predefined soroban event + TokenEvents::new(env).set_admin(Self::owner(env), new_owner); + } } diff --git a/contracts/interchain-token/src/event.rs b/contracts/interchain-token/src/event.rs index af74d7b0..4bb3098f 100644 --- a/contracts/interchain-token/src/event.rs +++ b/contracts/interchain-token/src/event.rs @@ -1,14 +1,5 @@ use soroban_sdk::{Address, Env, Symbol}; -pub fn transfer_ownership(env: &Env, previous_owner: Address, new_owner: Address) { - let topics = ( - Symbol::new(env, "ownership_transferred"), - previous_owner, - new_owner, - ); - env.events().publish(topics, ()); -} - pub fn add_minter(env: &Env, minter: Address) { let topics = (Symbol::new(env, "minter_added"), minter); env.events().publish(topics, ()); diff --git a/contracts/interchain-token/src/interface.rs b/contracts/interchain-token/src/interface.rs index 99bd8b75..103fee2a 100644 --- a/contracts/interchain-token/src/interface.rs +++ b/contracts/interchain-token/src/interface.rs @@ -11,6 +11,4 @@ pub trait InterchainTokenInterface: token::Interface { fn mint(env: Env, minter: Address, to: Address, amount: i128) -> Result<(), ContractError>; fn add_minter(env: &Env, minter: Address); fn remove_minter(env: &Env, minter: Address); - - fn transfer_ownership(env: Env, new_owner: Address) -> Result<(), ContractError>; } diff --git a/contracts/interchain-token/tests/test.rs b/contracts/interchain-token/tests/test.rs index 946f2fd1..4277cb89 100644 --- a/contracts/interchain-token/tests/test.rs +++ b/contracts/interchain-token/tests/test.rs @@ -5,7 +5,6 @@ use axelar_soroban_std::{ assert_invoke_auth_err, assert_invoke_auth_ok, assert_last_emitted_event, }; use interchain_token::{contract::InterchainToken, InterchainTokenClient}; -use soroban_sdk::testutils::{MockAuth, MockAuthInvoke}; use soroban_sdk::{ testutils::{Address as _, BytesN as _}, Address, BytesN, Env, IntoVal as _, Symbol, diff --git a/contracts/upgrader/tests/testdata/dummy.wasm b/contracts/upgrader/tests/testdata/dummy.wasm index 1f14cff17b6bbfeb6f0e4e91e0a3a823b6ffd63c..cf894fd7cd8628a464b666d4759933a4ef259367 100755 GIT binary patch literal 2458 zcmdrO%Z}Sr^c*{{iJPh00%}KqZl-LyXp~8ZPP;%F8``QGA)rNUJx+YnI8E$edopyB z1Uen4gak;uR`3C+h&>BfAy`!E7r>eYY+06bt{*df@B>)Nz32V*alnno2mshx+SX<> zoNXf?`b@!~aM;%7bAq(_jKCQk0NN{c?4nPKUAzE@F1G0$;dwgW!!@Fhh{7ksT^!Om z#T$y^fTkZab<}k%mCJ~gs$Q$r$~wZa$|-%0)?)E97;~_`&+Z@it|s-$SdPQ!mIl?S zjAB0wpkCdX+=yIHf>9240~tZ%coMlm+?SD~2=Tz5z;eTJdSMVJ(M~T3BRF0i`=pjg zIDrnFsymM7Caxm`Pe;RX2GX54T{o7xR{ySQJ`Wtx0`A#j-!ARhdyB>50hn|yz_WFwBpcWq!ct3Q68pfUOyuh%>fie#w+o zur>1zLpCatgzjeyc61-e9-I4$iC_pYYLMDCen%bW+6?EXiMIf&eRCCGQeYA1eU38~ zU)2tR`9#UzH-C9=q6p-hF+sf-_XH=W=Y>9dnN1Sm4-sKO<*Ls}!M z-WRND{DKx`t5P{g=X6UJ{Mw!q{!)E!2W)QT+5HfU)AVX+&WnYx<@fhrpd)=B3DT0!P zdDfa;+qakZD7Ac$1ZERueyH+Tq0z}G2ds}2>je%roiT1bsFs_mUo<;CEShaT+3epk zg-1sZtvjmErL@oH=j=z|8ESD>SE{C2bcE+KA1LynrJWK~XC4X=8nxHLw5N( z3F9bbCy@Gmmp!c*mWH%cvKb|lkeLMQ8x@%ONMJyLHBmrePoS{`=GSZsj1m__quJU( z^{#@^YPUMA_G|Q37hAx|7egeyt3e{8zT1P zNVi#V0g4?&H0JTs2;{D_OUu<6xbZ-d^uOs63OqQntyK_M|3rZSJZ+mXJNL81e$vgS zv<~Ys;jzW1WOCiZz8}{s79?rp^2_Pcq`j-wrLx6!Ain-5{r*xEs6L>(@oHAhOHo7% zS3O#Ksk6$h*^;*y$?Y>-VmjZ9WY5!VfPpA6WT8bFcUnn-dg z`+guj;gfA;IOoS?(oKXvo{Z#}ybD*v1DB?nM6w*CdO*FIhV literal 13588 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 t@#0Ci{#d=_l^Xw%q`({{aow5bXc} diff --git a/contracts/upgrader/tests/utils/dummy_contract.rs b/contracts/upgrader/tests/utils/dummy_contract.rs index 69509d4d..4114f58d 100644 --- a/contracts/upgrader/tests/utils/dummy_contract.rs +++ b/contracts/upgrader/tests/utils/dummy_contract.rs @@ -25,6 +25,10 @@ impl OwnableInterface for DummyContract { fn owner(env: &Env) -> Address { interfaces::owner(env) } + + fn transfer_ownership(env: &Env, new_owner: Address) { + interfaces::transfer_ownership::(env, new_owner); + } } #[contractimpl] diff --git a/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs b/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs index 1df4ccd3..60b608db 100644 --- a/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs +++ b/contracts/upgrader/tests/utils/dummy_contract_after_upgrade.rs @@ -25,6 +25,10 @@ impl OwnableInterface for DummyContract { fn owner(env: &Env) -> Address { interfaces::owner(env) } + + fn transfer_ownership(env: &Env, new_owner: Address) { + interfaces::transfer_ownership::(env, new_owner); + } } #[contractimpl] diff --git a/packages/axelar-soroban-std/src/contract_traits/testdata/test_format_last_emitted_event.golden b/packages/axelar-soroban-std/src/contract_traits/testdata/test_format_last_emitted_event.golden deleted file mode 100644 index 6ed8dd01..00000000 --- a/packages/axelar-soroban-std/src/contract_traits/testdata/test_format_last_emitted_event.golden +++ /dev/null @@ -1,3 +0,0 @@ -contract: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM) -topics: (Symbol(topic1), String(topic2), 10) -data: (String(data1), BytesN<32>(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3)) \ No newline at end of file diff --git a/packages/axelar-soroban-std/src/error.rs b/packages/axelar-soroban-std/src/error.rs index 991aa3c1..b3f22cae 100644 --- a/packages/axelar-soroban-std/src/error.rs +++ b/packages/axelar-soroban-std/src/error.rs @@ -146,9 +146,9 @@ macro_rules! assert_invoke_auth_err { #[macro_export] macro_rules! mock_auth { ($caller:expr, $client:ident, $method:ident, $($arg:expr),*) => { - &[MockAuth { + &[soroban_sdk::testutils::MockAuth { address: &$caller, - invoke: &MockAuthInvoke { + invoke: &soroban_sdk::testutils::MockAuthInvoke { contract: &$client.address, fn_name: &stringify!($method).replace("try_", ""), args: ($($arg.clone(),)*).into_val(&$client.env), diff --git a/packages/axelar-soroban-std/src/events.rs b/packages/axelar-soroban-std/src/events.rs index d25ec41e..0a504b8e 100644 --- a/packages/axelar-soroban-std/src/events.rs +++ b/packages/axelar-soroban-std/src/events.rs @@ -5,12 +5,12 @@ use soroban_sdk::{Env, IntoVal, Topics, Val}; pub use testutils::*; pub trait Event: Debug + PartialEq { - fn topics(&self) -> impl Topics + Debug; + fn topics(&self, env: &Env) -> impl Topics + Debug; - fn data(&self) -> impl IntoVal + Debug; + fn data(&self, env: &Env) -> impl IntoVal + Debug; fn emit(&self, env: &Env) { - env.events().publish(self.topics(), self.data()); + env.events().publish(self.topics(env), self.data(env)); } } @@ -56,14 +56,16 @@ mod testutils { fn matches(&self, env: &soroban_sdk::Env, event: &(soroban_sdk::Address, soroban_sdk::Vec, soroban_sdk::Val)) -> bool { use soroban_sdk::IntoVal; - Self::standardized_fmt(env, event) == Self::standardized_fmt(env, &(event.0.clone(), self.topics().into_val(env), self.data().into_val(env))) + Self::standardized_fmt(env, event) == Self::standardized_fmt(env, &(event.0.clone(), self.topics(env).into_val(env), self.data(env).into_val(env))) } #[allow(unused_assignments)] + #[allow(unused_variables)] + #[allow(unused_mut)] fn standardized_fmt(env: &soroban_sdk::Env, (contract_id, topics, data): &(soroban_sdk::Address, soroban_sdk::Vec, soroban_sdk::Val)) -> std::string::String { use soroban_sdk::TryFromVal; - let mut topics_output = std::vec![]; + let mut topics_output: std::vec::Vec = std::vec![]; let mut i = 0; $( @@ -76,7 +78,7 @@ mod testutils { let data = soroban_sdk::Vec::::try_from_val(env, data).expect("data should be defined as a vector-compatible type"); - let mut data_output = std::vec![]; + let mut data_output: std::vec::Vec = std::vec![]; let mut i = 0; $( @@ -113,11 +115,11 @@ mod test { } impl Event for TestEvent { - fn topics(&self) -> impl Topics + Debug { + fn topics(&self, _env: &Env) -> impl Topics + Debug { (self.topic1.clone(), self.topic2.clone(), self.topic3) } - fn data(&self) -> impl IntoVal + Debug { + fn data(&self, _env: &Env) -> impl IntoVal + Debug { (self.data1.clone(), self.data2.clone()) } } diff --git a/packages/axelar-soroban-std/src/interfaces/mod.rs b/packages/axelar-soroban-std/src/interfaces/mod.rs index 3565fc27..4acc8f07 100644 --- a/packages/axelar-soroban-std/src/interfaces/mod.rs +++ b/packages/axelar-soroban-std/src/interfaces/mod.rs @@ -1,5 +1,7 @@ +mod ownable; #[cfg(test)] mod testdata; mod upgradable; +pub use ownable::*; pub use upgradable::*; diff --git a/packages/axelar-soroban-std/src/interfaces/ownable.rs b/packages/axelar-soroban-std/src/interfaces/ownable.rs new file mode 100644 index 00000000..8957832e --- /dev/null +++ b/packages/axelar-soroban-std/src/interfaces/ownable.rs @@ -0,0 +1,140 @@ +use crate::events::Event; +#[cfg(any(test, feature = "testutils"))] +use crate::impl_event_testutils; +use soroban_sdk::{contractclient, Address, Env, IntoVal, Symbol, Topics, Val, Vec}; +use std::fmt::Debug; + +#[contractclient(name = "OwnableClient")] +pub trait OwnableInterface { + /// Returns the address of the contract's owner. + fn owner(env: &Env) -> Address; + + /// Transfers ownership of the contract to a new address. + fn transfer_ownership(env: &Env, new_owner: Address); +} + +/// Default implementation of the [OwnableInterface] trait. +pub fn owner(env: &Env) -> Address { + env.storage() + .instance() + .get(&storage::DataKey::Interfaces_Owner) + .expect("owner must be set during contract construction") +} + +/// Default implementation of the [OwnableInterface] trait. Ensures the current owner is authorized and emits an event after the transfer. +pub fn transfer_ownership(env: &Env, new_owner: Address) { + let previous_owner = T::owner(env); + previous_owner.require_auth(); + + set_owner(env, &new_owner); + + OwnerChangedEvent { + previous_owner, + new_owner, + } + .emit(env); +} + +/// Default implementation accompanying the [OwnableInterface] trait. This should never be part of a contract interface, +/// but allows contracts internally to set the owner. +pub fn set_owner(env: &Env, owner: &Address) { + env.storage() + .instance() + .set(&storage::DataKey::Interfaces_Owner, owner); +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct OwnerChangedEvent { + pub previous_owner: Address, + pub new_owner: Address, +} + +impl Event for OwnerChangedEvent { + fn topics(&self, env: &Env) -> impl Topics + Debug { + ( + Symbol::new(env, "ownership_transferred"), + self.previous_owner.to_val(), + self.new_owner.to_val(), + ) + } + + fn data(&self, env: &Env) -> impl IntoVal + Debug { + Vec::::new(env) + } +} + +#[cfg(any(test, feature = "testutils"))] +impl_event_testutils!(OwnerChangedEvent, (Symbol, Address, Address), ()); + +// submodule to encapsulate the disabled linting +mod storage { + // linting is disabled for the enum variant names on purpose, so we can define names that would otherwise be invalid. + // This way, if a contract that implements a shared interface defines a variant with the same name, the linter will + // complain about it. + #![allow(non_camel_case_types)] + + use soroban_sdk::contracttype; + + #[contracttype] + /// Variants do not follow the naming convention of other variants to let the linter help to avoid + /// collisions with contract types defined in other contracts that implement a shared interface. + pub enum DataKey { + Interfaces_Owner, + } +} + +#[cfg(test)] +mod test { + use crate::interfaces::testdata::contract::Contract; + use crate::interfaces::{OwnableClient, OwnerChangedEvent}; + use crate::{assert_invoke_auth_err, assert_invoke_auth_ok, events}; + use soroban_sdk::testutils::Address as _; + use soroban_sdk::{Address, Env}; + + #[test] + fn owner_fails_if_owner_not_set() { + let env = Env::default(); + let contract_id = env.register(Contract, (None::
,)); + + assert!(OwnableClient::new(&env, &contract_id).try_owner().is_err()); + } + + #[test] + fn owner_returns_correct_owner_when_set() { + let env = Env::default(); + let owner = Address::generate(&env); + let contract_id = env.register(Contract, (owner.clone(),)); + + assert_eq!(OwnableClient::new(&env, &contract_id).owner(), owner); + } + + #[test] + fn transfer_ownership_fails_if_caller_is_not_owner() { + let env = Env::default(); + let owner = Address::generate(&env); + let contract_id = env.register(Contract, (owner.clone(),)); + + let client = OwnableClient::new(&env, &contract_id); + assert_eq!(client.owner(), owner); + + let new_owner = Address::generate(&env); + assert_invoke_auth_err!(new_owner, client.try_transfer_ownership(&new_owner)); + } + + #[test] + fn transfer_ownership_succeeds_if_caller_is_owner() { + let env = Env::default(); + let owner = Address::generate(&env); + let contract_id = env.register(Contract, (owner.clone(),)); + + let client = OwnableClient::new(&env, &contract_id); + assert_eq!(client.owner(), owner); + + let new_owner = Address::generate(&env); + assert_invoke_auth_ok!(owner, client.try_transfer_ownership(&new_owner)); + + goldie::assert!(events::fmt_last_emitted_event::(&env)); + + assert_eq!(client.owner(), new_owner); + } +} diff --git a/packages/axelar-soroban-std/src/interfaces/testdata/contract.rs b/packages/axelar-soroban-std/src/interfaces/testdata/contract.rs index 499e36c0..7af2ddc1 100644 --- a/packages/axelar-soroban-std/src/interfaces/testdata/contract.rs +++ b/packages/axelar-soroban-std/src/interfaces/testdata/contract.rs @@ -1,4 +1,6 @@ -use crate::interfaces::{upgradable, MigratableInterface, OwnableInterface, UpgradableInterface}; +use crate::interfaces::{ + ownable, upgradable, MigratableInterface, OwnableInterface, UpgradableInterface, +}; use soroban_sdk::testutils::arbitrary::std; use soroban_sdk::{ contract, contracterror, contractimpl, contracttype, Address, BytesN, Env, String, @@ -9,7 +11,11 @@ pub struct Contract; #[contractimpl] impl Contract { - pub fn __constructor(_env: Env) {} + pub fn __constructor(_env: Env, owner: Option
) { + if let Some(owner) = owner { + ownable::set_owner(&_env, &owner); + } + } pub fn migration_data(env: &Env) -> Option { env.storage().instance().get(&DataKey::Data) @@ -36,7 +42,11 @@ impl MigratableInterface for Contract { #[contractimpl] impl OwnableInterface for Contract { fn owner(env: &Env) -> Address { - upgradable::owner(env) + ownable::owner(env) + } + + fn transfer_ownership(env: &Env, new_owner: Address) { + ownable::transfer_ownership::(env, new_owner); } } diff --git a/packages/axelar-soroban-std/src/interfaces/testdata/contract.wasm b/packages/axelar-soroban-std/src/interfaces/testdata/contract.wasm index c012bb0f4e763eefd6b231d942e780016ff28ecc..7ab2f41444395cac8e2bf17227d646d9a66fbe21 100755 GIT binary patch literal 2938 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 MygoMFtO3{m0sy*Tga7~l diff --git a/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden b/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden index f71caf31..4a2b86d0 100644 --- a/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden +++ b/packages/axelar-soroban-std/src/interfaces/testdata/migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade.golden @@ -1,3 +1,3 @@ -contract: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM) +contract: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4) topics: (Symbol(upgraded)) data: (String(0.1.0)) \ No newline at end of file diff --git a/packages/axelar-soroban-std/src/interfaces/upgradable.rs b/packages/axelar-soroban-std/src/interfaces/upgradable.rs index e503e0b0..6c04ac79 100644 --- a/packages/axelar-soroban-std/src/interfaces/upgradable.rs +++ b/packages/axelar-soroban-std/src/interfaces/upgradable.rs @@ -2,16 +2,12 @@ use crate::ensure; use crate::events::Event; #[cfg(any(test, feature = "testutils"))] use crate::impl_event_testutils; +use crate::interfaces::OwnableInterface; use core::fmt::Debug; use soroban_sdk::{ - contractclient, symbol_short, Address, BytesN, Env, FromVal, IntoVal, String, Topics, Val, + contractclient, symbol_short, BytesN, Env, FromVal, IntoVal, String, Topics, Val, }; -#[contractclient(name = "OwnershipClient")] -pub trait OwnableInterface { - fn owner(env: &Env) -> Address; -} - #[contractclient(name = "UpgradableClient")] pub trait UpgradableInterface: OwnableInterface { /// Returns the current version of the contract. @@ -31,22 +27,6 @@ pub trait MigratableInterface: UpgradableInterface { fn migrate(env: &Env, migration_data: Self::MigrationData) -> Result<(), Self::Error>; } -/// Default implementation of the [OwnableInterface] trait. -pub fn owner(env: &Env) -> Address { - env.storage() - .instance() - .get(&storage::DataKey::SharedInterfaces_Owner) - .expect("owner must be set during contract construction") -} - -/// Default implementation accompanying the [OwnableInterface] trait. This should never be part of a contract interface, -/// but allows contracts internally to set the owner. -pub fn set_owner(env: &Env, owner: &Address) { - env.storage() - .instance() - .set(&storage::DataKey::SharedInterfaces_Owner, owner); -} - /// This function checks that the caller can authenticate as the owner of the contract, /// then upgrades the contract to a new WASM hash and prepares it for migration. pub fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) { @@ -82,14 +62,14 @@ pub fn migrate( fn start_migration(env: &Env) { env.storage() .instance() - .set(&storage::DataKey::SharedInterfaces_Migrating, &()); + .set(&storage::DataKey::Interfaces_Migrating, &()); } fn ensure_is_migrating(env: &Env) -> Result<(), MigrationError> { ensure!( env.storage() .instance() - .has(&storage::DataKey::SharedInterfaces_Migrating), + .has(&storage::DataKey::Interfaces_Migrating), MigrationError::NotAllowed ); @@ -99,21 +79,21 @@ fn ensure_is_migrating(env: &Env) -> Result<(), MigrationError> { fn complete_migration(env: &Env) { env.storage() .instance() - .remove(&storage::DataKey::SharedInterfaces_Migrating); + .remove(&storage::DataKey::Interfaces_Migrating); } -#[derive(Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct UpgradedEvent { version: String, } impl Event for UpgradedEvent { - fn topics(&self) -> impl Topics + Debug { + fn topics(&self, _env: &Env) -> impl Topics + Debug { (symbol_short!("upgraded"),) } - fn data(&self) -> impl IntoVal + Debug { - (self.version.clone(),) + fn data(&self, _env: &Env) -> impl IntoVal + Debug { + (self.version.to_val(),) } } @@ -133,8 +113,7 @@ mod storage { /// Variants do not follow the naming convention of other variants to let the linter help to avoid /// collisions with contract types defined in other contracts that implement a shared interface. pub enum DataKey { - SharedInterfaces_Migrating, - SharedInterfaces_Owner, + Interfaces_Migrating, } } @@ -144,20 +123,20 @@ pub enum MigrationError { #[cfg(test)] mod test { - use crate::interfaces::upgradable::{OwnershipClient, UpgradableClient, UpgradedEvent}; + use crate::interfaces::upgradable::UpgradedEvent; use crate::{assert_invoke_auth_err, assert_invoke_auth_ok, events}; use crate::interfaces::testdata::contract::ContractClient; use crate::interfaces::{testdata, upgradable}; - use soroban_sdk::testutils::{Address as _, MockAuth, MockAuthInvoke}; - use soroban_sdk::{contracttype, Address, Env, String}; + use soroban_sdk::testutils::Address as _; + use soroban_sdk::{contracttype, Address, BytesN, Env, String}; const WASM: &[u8] = include_bytes!("testdata/contract.wasm"); #[test] fn contracttype_enum_name_is_irrelevant_for_key_collision() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); + let contract_id = env.register(testdata::contract::Contract, (None::
,)); env.as_contract(&contract_id, || { assert!(!env @@ -177,132 +156,66 @@ mod test { assert!(env.storage().instance().has(&DataKey2::Migrating)); }); } - - #[test] - fn owner_fails_if_owner_not_set() { - let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - - assert!(OwnershipClient::new(&env, &contract_id) - .try_owner() - .is_err()); - } - - #[test] - fn owner_returns_correct_owner_when_set() { - let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); - - assert_eq!(OwnershipClient::new(&env, &contract_id).owner(), owner); - } - #[test] fn upgrade_fails_if_owner_not_set() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); + let (client, hash) = prepare_client_and_bytecode(&env, None); - assert!(UpgradableClient::new(&env, &contract_id) - .try_upgrade(&hash) - .is_err()); + assert!(client.try_upgrade(&hash).is_err()); } #[test] fn upgrade_fails_if_caller_not_authenticated() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); + let (client, hash) = prepare_client_and_bytecode(&env, Some(owner)); - assert!(UpgradableClient::new(&env, &contract_id) - .try_upgrade(&hash) - .is_err()); + assert!(client.try_upgrade(&hash).is_err()); } #[test] fn upgrade_fails_if_called_by_non_owner() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); + let (client, hash) = prepare_client_and_bytecode(&env, Some(owner)); - let client = UpgradableClient::new(&env, &contract_id); assert_invoke_auth_err!(Address::generate(&env), client.try_upgrade(&hash)); } #[test] fn upgrade_succeeds_if_owner_is_authenticated() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); + let (client, hash) = prepare_client_and_bytecode(&env, Some(owner.clone())); - let client = UpgradableClient::new(&env, &contract_id); assert_invoke_auth_ok!(owner, client.try_upgrade(&hash)); } #[test] fn migrate_fails_if_caller_not_authenticated() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); + let (client, hash) = prepare_client_and_bytecode(&env, Some(owner.clone())); - let upgrade_client = UpgradableClient::new(&env, &contract_id); - assert_invoke_auth_ok!(owner, upgrade_client.try_upgrade(&hash)); - - let client = ContractClient::new(&env, &contract_id); + assert_invoke_auth_ok!(owner, client.try_upgrade(&hash)); assert!(client.try_migrate(&()).is_err()); } #[test] fn migrate_fails_if_called_by_non_owner() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); - - let upgrade_client = UpgradableClient::new(&env, &contract_id); - assert_invoke_auth_ok!(owner, upgrade_client.try_upgrade(&hash)); + let (client, hash) = prepare_client_and_bytecode(&env, Some(owner.clone())); - let client = ContractClient::new(&env, &contract_id); + assert_invoke_auth_ok!(owner, client.try_upgrade(&hash)); assert_invoke_auth_err!(Address::generate(&env), client.try_migrate(&())); } #[test] fn migrate_fails_if_not_called_after_upgrade() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); + let contract_id = env.register(testdata::contract::Contract, (Some(owner.clone()),)); let client = ContractClient::new(&env, &contract_id); assert_invoke_auth_err!(owner, client.try_migrate(&())); @@ -311,18 +224,11 @@ mod test { #[test] fn migrate_succeeds_if_owner_is_authenticated_and_called_after_upgrade() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); + let (client, hash) = prepare_client_and_bytecode(&env, Some(owner.clone())); - let upgradable_client = UpgradableClient::new(&env, &contract_id); - assert_invoke_auth_ok!(owner, upgradable_client.try_upgrade(&hash)); + assert_invoke_auth_ok!(owner, client.try_upgrade(&hash)); - let client = ContractClient::new(&env, &contract_id); assert!(client.migration_data().is_none()); assert_invoke_auth_ok!(owner, client.try_migrate(&())); @@ -332,8 +238,7 @@ mod test { Some(String::from_str(&env, "migrated")) ); - let event = events::fmt_last_emitted_event::(&env); - goldie::assert!(event) + goldie::assert!(events::fmt_last_emitted_event::(&env)) } // Because migration happens on a contract loaded from WASM, code coverage analysis doesn't recognize @@ -341,11 +246,10 @@ mod test { #[test] fn simulate_migration_for_code_coverage() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let owner = Address::generate(&env); + let contract_id = env.register(testdata::contract::Contract, (Some(owner.clone()),)); + env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); upgradable::start_migration(&env); }); @@ -356,23 +260,24 @@ mod test { #[test] fn migrate_fails_if_called_twice() { let env = Env::default(); - let contract_id = env.register(testdata::contract::Contract, ()); - let hash = env.deployer().upload_contract_wasm(WASM); - let owner = Address::generate(&env); - env.as_contract(&contract_id, || { - upgradable::set_owner(&env, &owner); - }); - - let upgradable_client = UpgradableClient::new(&env, &contract_id); - assert_invoke_auth_ok!(owner, upgradable_client.try_upgrade(&hash)); + let (client, hash) = prepare_client_and_bytecode(&env, Some(owner.clone())); - let client = ContractClient::new(&env, &contract_id); + assert_invoke_auth_ok!(owner, client.try_upgrade(&hash)); assert_invoke_auth_ok!(owner, client.try_migrate(&())); - assert_invoke_auth_err!(owner, client.try_migrate(&())); } + fn prepare_client_and_bytecode( + env: &Env, + owner: Option
, + ) -> (ContractClient, BytesN<32>) { + let contract_id = env.register(testdata::contract::Contract, (owner,)); + let hash = env.deployer().upload_contract_wasm(WASM); + let client = ContractClient::new(env, &contract_id); + (client, hash) + } + #[contracttype] enum DataKey2 { Migrating, From 3bcc6c63c7be1a46a299907b0e87b4f3aee235b5 Mon Sep 17 00:00:00 2001 From: Christian Gorenflo Date: Fri, 6 Dec 2024 00:23:25 +0100 Subject: [PATCH 5/7] update golden file --- packages/axelar-soroban-std/src/interfaces/ownable.rs | 2 +- .../transfer_ownership_succeeds_if_caller_is_owner.golden | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 packages/axelar-soroban-std/src/interfaces/testdata/transfer_ownership_succeeds_if_caller_is_owner.golden diff --git a/packages/axelar-soroban-std/src/interfaces/ownable.rs b/packages/axelar-soroban-std/src/interfaces/ownable.rs index 8957832e..195848d9 100644 --- a/packages/axelar-soroban-std/src/interfaces/ownable.rs +++ b/packages/axelar-soroban-std/src/interfaces/ownable.rs @@ -1,8 +1,8 @@ use crate::events::Event; #[cfg(any(test, feature = "testutils"))] use crate::impl_event_testutils; +use core::fmt::Debug; use soroban_sdk::{contractclient, Address, Env, IntoVal, Symbol, Topics, Val, Vec}; -use std::fmt::Debug; #[contractclient(name = "OwnableClient")] pub trait OwnableInterface { diff --git a/packages/axelar-soroban-std/src/interfaces/testdata/transfer_ownership_succeeds_if_caller_is_owner.golden b/packages/axelar-soroban-std/src/interfaces/testdata/transfer_ownership_succeeds_if_caller_is_owner.golden new file mode 100644 index 00000000..a560927b --- /dev/null +++ b/packages/axelar-soroban-std/src/interfaces/testdata/transfer_ownership_succeeds_if_caller_is_owner.golden @@ -0,0 +1,3 @@ +contract: Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4) +topics: (Symbol(ownership_transferred), Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM), Contract(CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M)) +data: () \ No newline at end of file From 748a5244ab5c599c5a203747a0ba1eec9e621704 Mon Sep 17 00:00:00 2001 From: Christian Gorenflo Date: Fri, 6 Dec 2024 01:15:53 +0100 Subject: [PATCH 6/7] fmt --- contracts/interchain-token-service/tests/test.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/interchain-token-service/tests/test.rs b/contracts/interchain-token-service/tests/test.rs index e28f1a8f..53945085 100644 --- a/contracts/interchain-token-service/tests/test.rs +++ b/contracts/interchain-token-service/tests/test.rs @@ -164,7 +164,6 @@ fn remove_trusted_address_fails_if_address_not_set() { ); } - #[test] fn interchain_token_deploy_salt() { let (env, client) = setup_env(); From b10a553f297024ed764c43e1060a14448fcfdc8f Mon Sep 17 00:00:00 2001 From: Christian Gorenflo Date: Fri, 6 Dec 2024 15:29:53 +0100 Subject: [PATCH 7/7] address comments --- .../src/interfaces/ownable.rs | 20 ++++++++++--------- .../src/interfaces/upgradable.rs | 20 +++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/axelar-soroban-std/src/interfaces/ownable.rs b/packages/axelar-soroban-std/src/interfaces/ownable.rs index 195848d9..aab76ae4 100644 --- a/packages/axelar-soroban-std/src/interfaces/ownable.rs +++ b/packages/axelar-soroban-std/src/interfaces/ownable.rs @@ -23,13 +23,13 @@ pub fn owner(env: &Env) -> Address { /// Default implementation of the [OwnableInterface] trait. Ensures the current owner is authorized and emits an event after the transfer. pub fn transfer_ownership(env: &Env, new_owner: Address) { - let previous_owner = T::owner(env); - previous_owner.require_auth(); + let current_owner = T::owner(env); + current_owner.require_auth(); set_owner(env, &new_owner); - OwnerChangedEvent { - previous_owner, + OwnershipTransferredEvent { + previous_owner: current_owner, new_owner, } .emit(env); @@ -44,12 +44,12 @@ pub fn set_owner(env: &Env, owner: &Address) { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct OwnerChangedEvent { +pub struct OwnershipTransferredEvent { pub previous_owner: Address, pub new_owner: Address, } -impl Event for OwnerChangedEvent { +impl Event for OwnershipTransferredEvent { fn topics(&self, env: &Env) -> impl Topics + Debug { ( Symbol::new(env, "ownership_transferred"), @@ -64,7 +64,7 @@ impl Event for OwnerChangedEvent { } #[cfg(any(test, feature = "testutils"))] -impl_event_testutils!(OwnerChangedEvent, (Symbol, Address, Address), ()); +impl_event_testutils!(OwnershipTransferredEvent, (Symbol, Address, Address), ()); // submodule to encapsulate the disabled linting mod storage { @@ -86,7 +86,7 @@ mod storage { #[cfg(test)] mod test { use crate::interfaces::testdata::contract::Contract; - use crate::interfaces::{OwnableClient, OwnerChangedEvent}; + use crate::interfaces::{OwnableClient, OwnershipTransferredEvent}; use crate::{assert_invoke_auth_err, assert_invoke_auth_ok, events}; use soroban_sdk::testutils::Address as _; use soroban_sdk::{Address, Env}; @@ -133,7 +133,9 @@ mod test { let new_owner = Address::generate(&env); assert_invoke_auth_ok!(owner, client.try_transfer_ownership(&new_owner)); - goldie::assert!(events::fmt_last_emitted_event::(&env)); + goldie::assert!(events::fmt_last_emitted_event::( + &env + )); assert_eq!(client.owner(), new_owner); } diff --git a/packages/axelar-soroban-std/src/interfaces/upgradable.rs b/packages/axelar-soroban-std/src/interfaces/upgradable.rs index 6c04ac79..a8188f77 100644 --- a/packages/axelar-soroban-std/src/interfaces/upgradable.rs +++ b/packages/axelar-soroban-std/src/interfaces/upgradable.rs @@ -133,6 +133,16 @@ mod test { const WASM: &[u8] = include_bytes!("testdata/contract.wasm"); + fn prepare_client_and_bytecode( + env: &Env, + owner: Option
, + ) -> (ContractClient, BytesN<32>) { + let contract_id = env.register(testdata::contract::Contract, (owner,)); + let hash = env.deployer().upload_contract_wasm(WASM); + let client = ContractClient::new(env, &contract_id); + (client, hash) + } + #[test] fn contracttype_enum_name_is_irrelevant_for_key_collision() { let env = Env::default(); @@ -268,16 +278,6 @@ mod test { assert_invoke_auth_err!(owner, client.try_migrate(&())); } - fn prepare_client_and_bytecode( - env: &Env, - owner: Option
, - ) -> (ContractClient, BytesN<32>) { - let contract_id = env.register(testdata::contract::Contract, (owner,)); - let hash = env.deployer().upload_contract_wasm(WASM); - let client = ContractClient::new(env, &contract_id); - (client, hash) - } - #[contracttype] enum DataKey2 { Migrating,