diff --git a/contract/src/lib.rs b/contract/src/lib.rs index 602210d..af2b317 100644 --- a/contract/src/lib.rs +++ b/contract/src/lib.rs @@ -162,6 +162,11 @@ impl FlowPay { assert!(amount > 0, "amount must be positive"); assert!(interval > 0, "interval must be positive"); + use soroban_sdk::xdr::ToXdr; + if token.clone().to_xdr(&env).get(7) == Some(0) { + env.panic_with_error(ContractError::InvalidTokenAddress); + } + let token_client = token::Client::new(&env, &token); let allowance = token_client.allowance(&user, &env.current_contract_address()); assert!(allowance >= amount, "insufficient allowance"); @@ -716,3 +721,4 @@ fn is_contract_paused(env: &Env) -> bool { fn ensure_contract_not_paused(env: &Env) { assert!(!is_contract_paused(env), "contract is paused"); } + diff --git a/contract/src/test.rs b/contract/src/test.rs index 767ca57..c452487 100644 --- a/contract/src/test.rs +++ b/contract/src/test.rs @@ -1194,6 +1194,8 @@ fn test_custom_sac_token_end_to_end_flow() { // Verify subscription is still active after pay_per_use let sub_final = client.get_subscription(&user).unwrap(); assert!(sub_final.active, "subscription should remain active after pay_per_use"); +} + // ───────────────────────────────────────────────────────────── // Issue #237: get_token() read function tests // ───────────────────────────────────────────────────────────── @@ -1285,3 +1287,22 @@ fn test_set_grace_period_emits_event() { assert_eq!(topic_symbol, Symbol::new(&env, "grace_period_updated")); assert_eq!(emitted_seconds, 7200u64); } + +// ───────────────────────────────────────────── +// Issue #243: Token address validation +// ───────────────────────────────────────────── + +#[test] +#[should_panic(expected = "Error(Contract, #11)")] +fn test_subscribe_non_contract_address() { + let (env, contract_id, _token_addr, user, merchant) = setup(); + let client = FlowPayClient::new(&env, &contract_id); + + // Provide a non-contract address (just an account) + use soroban_sdk::xdr::{ScAddress, AccountId, PublicKey, Uint256}; + use soroban_sdk::TryFromVal; + let account_id = AccountId(PublicKey::PublicKeyTypeEd25519(Uint256([0; 32]))); + let non_contract_token = Address::try_from_val(&env, &ScAddress::Account(account_id)).unwrap(); + + client.subscribe(&user, &merchant, &1_0000000, &86400, &non_contract_token, &None, &None); +}