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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions contracts/smart-account/src/tests/auth_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use crate::{
},
error::Error,
tests::test_utils::{
get_token_auth_context, get_update_signer_auth_context, setup, Ed25519TestSigner,
TestSignerTrait as _,
budget_snapshot, get_token_auth_context, get_update_signer_auth_context,
print_budget_delta, setup, Ed25519TestSigner, TestSignerTrait as _,
},
};

Expand All @@ -31,13 +31,16 @@ fn test_auth_ed25519_happy_case() {
let payload = BytesN::random(&env);
let (signer_key, proof) = test_signer.sign(&env, &payload);
let auth_payloads = SignatureProofs(map![&env, (signer_key.clone(), proof.clone())]);
let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&contract_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("check_auth", &b, &a);
}

#[test]
Expand Down Expand Up @@ -89,13 +92,16 @@ fn test_auth_ed25519_wrong_signature() {
panic!("Invalid proof type");
};
let auth_payloads = SignatureProofs(map![&env, (signer_key.clone(), wrong_proof.clone())]);
let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&contract_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("check_auth", &b, &a);
}

#[test]
Expand Down Expand Up @@ -170,13 +176,16 @@ fn test_auth_multi_signature_admin_and_standard() {
(standard_key.clone(), standard_proof.clone())
]);

let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&contract_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("check_auth", &b, &a);
}

#[test]
Expand All @@ -202,13 +211,16 @@ fn test_auth_multi_signature_only_admin_needed() {

let auth_payloads = SignatureProofs(map![&env, (admin_key.clone(), admin_proof.clone())]);

let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&contract_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("check_auth", &b, &a);
}

#[test]
Expand All @@ -234,13 +246,16 @@ fn test_auth_multi_signature_only_standard_needed() {

let auth_payloads = SignatureProofs(map![&env, (standard_key.clone(), standard_proof.clone())]);

let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&contract_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("check_auth", &b, &a);
}

// ============================================================================
Expand Down Expand Up @@ -352,13 +367,16 @@ fn test_auth_time_based_policy_within_window() {
(restricted_key.clone(), restricted_proof.clone())
]);

let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&contract_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("check_auth", &b, &a);
}

#[test]
Expand Down Expand Up @@ -518,13 +536,16 @@ fn test_auth_idempotency() {
)
.unwrap();

let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&contract_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("check_auth", &b, &a);
}

#[test]
Expand Down
17 changes: 16 additions & 1 deletion contracts/smart-account/src/tests/plugin_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use crate::{
auth::{permissions::SignerRole, proof::SignatureProofs},
error::Error,
interface::SmartAccountInterface,
tests::test_utils::{get_token_auth_context, setup, Ed25519TestSigner, TestSignerTrait as _},
tests::test_utils::{
budget_snapshot, get_token_auth_context, print_budget_delta, setup, Ed25519TestSigner,
TestSignerTrait as _,
},
};

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -67,10 +70,13 @@ fn test_uninstall_plugin_persists_removal() {
let plugin_id = env.register(DummyPlugin, ());

// Install plugin
let b = budget_snapshot(&env);
env.as_contract(&smart_account_id, || {
SmartAccount::install_plugin(&env, plugin_id.clone())
})
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("install_plugin", &b, &a);

// Verify plugin is installed by triggering on_auth
let payload = BytesN::random(&env);
Expand All @@ -80,13 +86,16 @@ fn test_uninstall_plugin_persists_removal() {
(admin_key.clone(), admin_proof.clone())
]);

let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&smart_account_id,
&payload,
auth_payloads.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("__check_auth:plugin_on_auth", &b, &a);

// Verify plugin is installed
assert!(env.as_contract(&smart_account_id, || {
Expand All @@ -101,10 +110,13 @@ fn test_uninstall_plugin_persists_removal() {
);

// Uninstall plugin (FIX: removal now persisted to storage)
let b = budget_snapshot(&env);
env.as_contract(&smart_account_id, || {
SmartAccount::uninstall_plugin(&env, plugin_id.clone())
})
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("uninstall_plugin", &b, &a);

// Verify plugin is uninstalled
assert!(!env.as_contract(&smart_account_id, || {
Expand All @@ -116,13 +128,16 @@ fn test_uninstall_plugin_persists_removal() {
let (admin_key2, admin_proof2) = admin.sign(&env, &payload2);
let auth_payloads2 = SignatureProofs(soroban_sdk::map![&env, (admin_key2, admin_proof2)]);

let b = budget_snapshot(&env);
env.try_invoke_contract_check_auth::<Error>(
&smart_account_id,
&payload2,
auth_payloads2.into_val(&env),
&vec![&env, get_token_auth_context(&env)],
)
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("__check_auth:after_uninstall", &b, &a);

// Verify plugin did NOT receive second on_auth call (count should still be 1)
let count_after_uninstall = env.as_contract(&plugin_id, || DummyPlugin::get_count(&env));
Expand Down
11 changes: 10 additions & 1 deletion contracts/smart-account/src/tests/policy_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::auth::permissions::{SignerPolicy, SignerRole};
use crate::auth::policy::{ExternalPolicy, TimeBasedPolicy};
use crate::auth::signer::{Signer, SignerKey};
use crate::error::Error;
use crate::tests::test_utils::{setup, Ed25519TestSigner};
use crate::tests::test_utils::{budget_snapshot, print_budget_delta, setup, Ed25519TestSigner};

#[contract]
pub struct DummyExternalPolicy;
Expand Down Expand Up @@ -187,6 +187,7 @@ fn test_revoke_signer_with_external_polic_calls_on_revoke() {
),
);
env.mock_all_auths();
let b = budget_snapshot(&env);
env.as_contract(&account_id, || {
if let Signer::Ed25519(signer, _) = test_signer {
let signer_key = SignerKey::Ed25519(signer.public_key);
Expand All @@ -196,6 +197,8 @@ fn test_revoke_signer_with_external_polic_calls_on_revoke() {
}
})
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("revoke_signer:with_external_policy", &b, &a);

ensure_policy_event_is_emmited(&env, policy_id, symbol_short!("ON_REVOKE"));
}
Expand Down Expand Up @@ -232,10 +235,13 @@ fn test_update_signer_with_external_polic_lifecycle() {

ensure_policy_event_is_emmited(&env, policy_id_1.clone(), symbol_short!("ON_ADD"));

let b = budget_snapshot(&env);
env.as_contract(&account_id, || {
SmartAccount::update_signer(&env, test_signer_2)
})
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("update_signer:external_policy_lifecycle", &b, &a);
ensure_policy_event_is_emmited(&env, policy_id_1, symbol_short!("ON_REVOKE"));
ensure_policy_event_is_emmited(&env, policy_id_2, symbol_short!("ON_ADD"));
} else {
Expand Down Expand Up @@ -266,9 +272,12 @@ fn test_update_signer_with_external_polic_lifecycle_with_same_policy() {

ensure_policy_event_is_emmited(&env, policy_id_1.clone(), symbol_short!("ON_ADD"));

let b = budget_snapshot(&env);
env.as_contract(&account_id, || {
SmartAccount::update_signer(&env, test_signer_1)
})
.unwrap();
let a = budget_snapshot(&env);
print_budget_delta("update_signer:same_policy", &b, &a);
ensure_policy_event_is_not_emmited(&env, policy_id_1.clone(), symbol_short!("ON_REVOKE"));
}
22 changes: 21 additions & 1 deletion contracts/smart-account/src/tests/signer_management_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::{
auth::{permissions::SignerRole, proof::SignatureProofs, signer::SignerKey},
error::Error,
interface::SmartAccountInterface,
tests::test_utils::{setup, Ed25519TestSigner, TestSignerTrait as _},
tests::test_utils::{
budget_snapshot, print_budget_delta, setup, Ed25519TestSigner, TestSignerTrait as _,
},
};

extern crate std;
Expand Down Expand Up @@ -37,9 +39,12 @@ fn test_revoke_admin_signer_prevented() {
let admin_signer_key = SignerKey::Ed25519(admin_signer.public_key(&env));

env.mock_all_auths();
let b = budget_snapshot(&env);
let result = env.as_contract(&contract_id, || {
SmartAccount::revoke_signer(&env, admin_signer_key)
});
let a = budget_snapshot(&env);
print_budget_delta("revoke_signer:admin", &b, &a);

assert_eq!(result.unwrap_err(), Error::CannotRevokeAdminSigner);
}
Expand Down Expand Up @@ -69,9 +74,12 @@ fn test_revoke_standard_signer_allowed() {
let standard_signer_key = SignerKey::Ed25519(standard_signer.public_key(&env));

env.mock_all_auths();
let b = budget_snapshot(&env);
let result = env.as_contract(&contract_id, || {
SmartAccount::revoke_signer(&env, standard_signer_key)
});
let a = budget_snapshot(&env);
print_budget_delta("revoke_signer:standard", &b, &a);

assert!(result.is_ok());
}
Expand All @@ -96,9 +104,12 @@ fn test_add_multiple_admin_signers_success() {

// Call add_signer as contract (auth mocked) to simulate admin operation
env.mock_all_auths();
let b = budget_snapshot(&env);
let result = env.as_contract(&contract_id, || {
SmartAccount::add_signer(&env, admin2_signer.clone())
});
let a = budget_snapshot(&env);
print_budget_delta("add_signer:admin2", &b, &a);

// Should succeed - this tests that the admin count arithmetic works correctly
assert!(result.is_ok(), "Adding second admin should succeed");
Expand All @@ -107,9 +118,12 @@ fn test_add_multiple_admin_signers_success() {
let admin3 = Ed25519TestSigner::generate(SignerRole::Admin);
let admin3_signer = admin3.into_signer(&env);

let b = budget_snapshot(&env);
let result2 = env.as_contract(&contract_id, || {
SmartAccount::add_signer(&env, admin3_signer)
});
let a = budget_snapshot(&env);
print_budget_delta("add_signer:admin3", &b, &a);

assert!(result2.is_ok(), "Adding third admin should also succeed");
}
Expand All @@ -133,9 +147,12 @@ fn test_admin_count_underflow_protection() {
let admin1_standard = Ed25519TestSigner(admin1.0, SignerRole::Standard(vec![&env]));

env.mock_all_auths();
let b = budget_snapshot(&env);
let result = env.as_contract(&contract_id, || {
SmartAccount::update_signer(&env, admin1_standard.into_signer(&env))
});
let a = budget_snapshot(&env);
print_budget_delta("update_signer:admin1_to_standard", &b, &a);

assert!(
result.is_ok(),
Expand All @@ -145,9 +162,12 @@ fn test_admin_count_underflow_protection() {
// Try to downgrade the last admin (should fail)
let admin2_standard = Ed25519TestSigner(admin2.0, SignerRole::Standard(vec![&env]));

let b = budget_snapshot(&env);
let result2 = env.as_contract(&contract_id, || {
SmartAccount::update_signer(&env, admin2_standard.into_signer(&env))
});
let a = budget_snapshot(&env);
print_budget_delta("update_signer:admin2_to_standard", &b, &a);

assert_eq!(
result2.unwrap_err(),
Expand Down
25 changes: 25 additions & 0 deletions contracts/smart-account/src/tests/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![cfg(test)]
extern crate std;

use ed25519_dalek::Keypair;
use ed25519_dalek::Signer as _;
Expand Down Expand Up @@ -77,3 +78,27 @@ impl TestSignerTrait for Ed25519TestSigner {
(signer_key, signature)
}
}

pub struct BudgetSnapshot {
pub cpu: u64,
pub mem: u64,
}

pub fn budget_snapshot(env: &Env) -> BudgetSnapshot {
let budget = env.cost_estimate().budget();
BudgetSnapshot {
cpu: budget.cpu_instruction_cost(),
mem: budget.memory_bytes_cost(),
}
}

pub fn print_budget_delta(label: &str, before: &BudgetSnapshot, after: &BudgetSnapshot) {
let cpu_delta = after.cpu.saturating_sub(before.cpu);
let mem_delta = after.mem.saturating_sub(before.mem);
std::println!(
"[Budget] {} cpu_insns={} mem_bytes={}",
label,
cpu_delta,
mem_delta
);
}