Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: update mock auth macro to support non root auth #134

Merged
merged 15 commits into from
Jan 17, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use soroban_sdk::token::{self, StellarAssetClient};
use soroban_sdk::{Address, Bytes, IntoVal, String, Symbol};
use soroban_token_sdk::metadata::TokenMetadata;
use stellar_axelar_std::address::AddressExt;
use stellar_axelar_std::{auth_invocation, events};
use stellar_axelar_std::{auth_invocation, events, mock_auth};
use stellar_interchain_token_service::event::InterchainTokenDeploymentStartedEvent;
use stellar_interchain_token_service::types::{
DeployInterchainToken, HubMessage, Message, TokenManagerType,
Expand All @@ -14,7 +14,7 @@ use utils::{setup_env, setup_gas_token};

#[test]
fn deploy_remote_canonical_token_succeeds() {
let (env, client, _, gas_service, _) = setup_env();
let (env, client, gateway, gas_service, _) = setup_env();
let spender = Address::generate(&env);
let gas_token = setup_gas_token(&env, &spender);
let asset = &env.register_stellar_asset_contract_v2(Address::generate(&env));
Expand Down Expand Up @@ -63,8 +63,35 @@ fn deploy_remote_canonical_token_succeeds() {
}
.abi_encode(&env);

let transfer_token_auth = mock_auth!(
ahramy marked this conversation as resolved.
Show resolved Hide resolved
env,
spender,
gas_token.transfer(spender, gas_service.address, gas_token.amount)
);

let pay_gas_auth = mock_auth!(
env,
spender,
gas_service.pay_gas(
client.address,
its_hub_chain,
its_hub_address,
payload,
spender,
gas_token,
Bytes::new(&env)
),
&[(transfer_token_auth.invoke).clone()]
ahramy marked this conversation as resolved.
Show resolved Hide resolved
ahramy marked this conversation as resolved.
Show resolved Hide resolved
);

let call_contract_auth = mock_auth!(
env,
spender,
gateway.call_contract(client.address, its_hub_chain, its_hub_address, payload)
);

let deployed_token_id = client
.mock_all_auths_allowing_non_root_auth()
.mock_auths(&[pay_gas_auth, call_contract_auth])
.deploy_remote_canonical_token(&token_address, &destination_chain, &spender, &gas_token);
assert_eq!(expected_id, deployed_token_id);

Expand Down
86 changes: 21 additions & 65 deletions contracts/upgrader/tests/atomic_upgrades.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
mod utils;

use soroban_sdk::testutils::{Address as _, MockAuth, MockAuthInvoke};
use soroban_sdk::testutils::Address as _;
use soroban_sdk::{Address, BytesN, Env, String};
use stellar_axelar_std::mock_auth;
use stellar_upgrader::{Upgrader, UpgraderClient};
use utils::{DataKey, DummyContract, DummyContractClient};

Expand All @@ -23,22 +24,12 @@ fn upgrade_and_migrate_are_atomic() {
let original_version: String = dummy_client.version();
assert_eq!(original_version, String::from_str(&env, "0.1.0"));

let (upgrade_auth, migrate_auth) =
build_invocation_auths(&env, &contract_address, &hash_after_upgrade, &expected_data);

// add the owner to the set of authenticated addresses
env.mock_auths(&[
MockAuth {
address: &owner,
invoke: &upgrade_auth,
},
MockAuth {
address: &owner,
invoke: &migrate_auth,
},
]);
let upgrader = UpgraderClient::new(&env, &upgrader_address);

UpgraderClient::new(&env, &upgrader_address).upgrade(
let upgrade_auth = mock_auth!(env, owner, dummy_client.upgrade(hash_after_upgrade));
let migrate_auth = mock_auth!(env, owner, dummy_client.migrate(expected_data));

upgrader.mock_auths(&[upgrade_auth, migrate_auth]).upgrade(
&contract_address,
&expected_version,
&hash_after_upgrade,
Expand Down Expand Up @@ -69,24 +60,17 @@ fn upgrade_fails_if_caller_is_authenticated_but_not_owner() {
..
} = setup_contracts_and_call_args();

let (upgrade_auth, migrate_auth) =
build_invocation_auths(&env, &contract_address, &hash_after_upgrade, &expected_data);
let dummy_client = DummyContractClient::new(&env, &contract_address);
let upgrader = UpgraderClient::new(&env, &upgrader_address);

// add the caller to the set of authenticated addresses
let caller = Address::generate(&env);
env.mock_auths(&[
MockAuth {
address: &caller,
invoke: &upgrade_auth,
},
MockAuth {
address: &caller,
invoke: &migrate_auth,
},
]);

let upgrade_auth = mock_auth!(env, caller, dummy_client.upgrade(hash_after_upgrade));
let migrate_auth = mock_auth!(env, caller, dummy_client.migrate(expected_data));

// should panic: caller is authenticated, but not the owner
UpgraderClient::new(&env, &upgrader_address).upgrade(
upgrader.mock_auths(&[upgrade_auth, migrate_auth]).upgrade(
&contract_address,
&expected_version,
&hash_after_upgrade,
Expand All @@ -106,24 +90,17 @@ fn upgrade_fails_if_correct_owner_is_not_authenticated_for_full_invocation_tree(
expected_data,
expected_version,
} = setup_contracts_and_call_args();
let dummy_client = DummyContractClient::new(&env, &contract_address);
let upgrader = UpgraderClient::new(&env, &upgrader_address);

let (upgrade_auth, migrate_auth) =
build_invocation_auths(&env, &contract_address, &hash_after_upgrade, &expected_data);

// only add the owner to the set of authenticated addresses for the upgrade function, and the caller for the migrate function
// add the caller to the set of authenticated addresses
let caller = Address::generate(&env);
env.mock_auths(&[
MockAuth {
address: &owner,
invoke: &upgrade_auth,
},
MockAuth {
address: &caller,
invoke: &migrate_auth,
},
]);

UpgraderClient::new(&env, &upgrader_address).upgrade(
let upgrade_auth = mock_auth!(env, owner, dummy_client.upgrade(hash_after_upgrade));
let migrate_auth = mock_auth!(env, caller, dummy_client.migrate(expected_data));

// only add the owner to the set of authenticated addresses for the upgrade function, and the caller for the migrate function
upgrader.mock_auths(&[upgrade_auth, migrate_auth]).upgrade(
&contract_address,
&expected_version,
&hash_after_upgrade,
Expand Down Expand Up @@ -184,24 +161,3 @@ fn setup_contracts_and_call_args() -> TestFixture {
expected_version,
}
}

fn build_invocation_auths<'a>(
env: &Env,
contract_address: &'a Address,
hash_after_upgrade: &'a BytesN<32>,
expected_data: &'a String,
) -> (MockAuthInvoke<'a>, MockAuthInvoke<'a>) {
let upgrade = MockAuthInvoke {
contract: contract_address,
fn_name: "upgrade",
args: soroban_sdk::vec![&env, hash_after_upgrade.to_val()],
sub_invokes: &[],
};
let migrate = MockAuthInvoke {
contract: contract_address,
fn_name: "migrate",
args: soroban_sdk::vec![&env, expected_data.to_val()],
sub_invokes: &[],
};
(upgrade, migrate)
}
54 changes: 38 additions & 16 deletions packages/axelar-std/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,15 @@ macro_rules! assert_some {
#[macro_export]
macro_rules! assert_auth {
($caller:expr, $client:ident . $method:ident ( $($arg:expr),* $(,)? )) => {{
use soroban_sdk::IntoVal;

// Paste is used to concatenate the method name with the `try_` prefix
paste::paste! {
let call_result = $client
.mock_auths($crate::mock_auth!($caller, $client, $method, $($arg),*))
.mock_auths(&[$crate::mock_auth!(
$client.env,
$caller,
$client.$method($($arg),*),
&[]
)])
.[<try_ $method>]($($arg),*);
}

Expand All @@ -132,11 +135,16 @@ macro_rules! assert_auth {
#[macro_export]
macro_rules! assert_auth_err {
($caller:expr, $client:ident . $method:ident ( $($arg:expr),* $(,)? )) => {{
use soroban_sdk::{IntoVal, xdr::{ScError, ScErrorCode, ScVal}};
use soroban_sdk::xdr::{ScError, ScErrorCode, ScVal};

paste::paste! {
let call_result = $client
.mock_auths($crate::mock_auth!($caller, $client, $method, $($arg),*))
.mock_auths(&[$crate::mock_auth!(
$client.env,
$caller,
$client.$method($($arg),*),
&[]
)])
.[<try_ $method>]($($arg),*);
}
match call_result {
Expand All @@ -154,15 +162,29 @@ macro_rules! assert_auth_err {

#[macro_export]
macro_rules! mock_auth {
($caller:expr, $client:ident, $method:ident, $($arg:expr),*) => {
&[soroban_sdk::testutils::MockAuth {
address: &$caller,
invoke: &soroban_sdk::testutils::MockAuthInvoke {
contract: &$client.address,
fn_name: &stringify!($method),
args: ($($arg.clone(),)*).into_val(&$client.env),
sub_invokes: &[],
},
}]
};
(
$env:expr,
$caller:expr,
$client:ident . $method:ident ( $($arg:expr),* $(,)? ),
$sub_invokes:expr
) => {{
use soroban_sdk::IntoVal;

soroban_sdk::testutils::MockAuth {
address: &$caller,
invoke: &soroban_sdk::testutils::MockAuthInvoke {
contract: &$client.address,
fn_name: &stringify!($method).replace("try_", ""),
args: ($($arg.clone(),)*).into_val(&$env),
sub_invokes: $sub_invokes,
},
}
}};
(
$env:expr,
$caller:expr,
$client:ident . $method:ident ( $($arg:expr),* $(,)? )
) => {{
mock_auth!($env, $caller, $client.$method($($arg),*), &[])
}};
}
Loading