Skip to content

feat(scout_access): optional cross-contract player validation on pay_to_contact#1

Merged
gracious01-tech merged 1 commit into
mainfrom
feat/cross-contract-player-validation
May 31, 2026
Merged

feat(scout_access): optional cross-contract player validation on pay_to_contact#1
gracious01-tech merged 1 commit into
mainfrom
feat/cross-contract-player-validation

Conversation

@gracious01-tech
Copy link
Copy Markdown
Owner

Summary

Adds an optional cross-contract player existence check to pay_to_contact. When the registration contract address is configured via the new set_registration_contract admin function, the scout access contract validates that the target player_id exists before collecting any fee or creating a contact record. When the address is not set the existing behaviour is fully preserved.

Changes

contracts/scout_access/src/errors.rs

  • Added PlayerNotFound = 13 to ScoutAccessError

contracts/scout_access/src/types.rs

  • Added DataKey::RegistrationContract variant

contracts/scout_access/src/lib.rs

  • Added PERSISTENT_TTL_MIN / PERSISTENT_TTL_MAX constants (were referenced but never declared — pre-existing bug fixed)
  • Added mod progress_contract { contractimport!(...) } (same pre-existing missing declaration fixed)
  • Added mod registration_contract { contractimport!(...) } for the new cross-contract client
  • Added set_registration_contract(env, addr) admin function — stores the registration contract address in DataKey::RegistrationContract (admin auth required)
  • In pay_to_contact: after the duplicate-contact guard, optionally calls registration_contract::Client::try_get_player(&player_id); returns PlayerNotFound and aborts before any XLM transfer if the lookup fails; skips the check entirely when no address is stored
  • Added two unit tests:
    • test_pay_to_contact_without_registration_contract_skips_validation — no registration contract set; contact with a non-existent player_id succeeds
    • test_pay_to_contact_with_registration_contract_rejects_unknown_player — registration contract wired; contact with a non-existent player_id panics with PlayerNotFound

contracts/scout_access/Cargo.toml

  • Added scoutchain-registration = { path = "../registration" } as a dev-dependency so tests can register the contract directly via env.register_contract

.github/workflows/contract-ci.yml

  • Moved the WASM build step before cargo testcontractimport! reads the WASM at compile time so tests cannot compile without the artefacts present

Validation logic

pay_to_contact(scout, player_id)
  ├── require_not_paused
  ├── scout.require_auth
  ├── require_active_subscription
  ├── guard: AlreadyContacted
  ├── [if RegistrationContract set]
  │     └── try_get_player(player_id) → Err → return PlayerNotFound (no fee collected)
  ├── transfer contact_fee_stroops XLM
  ├── accumulate_fee
  ├── write ContactRecord
  └── emit player_contacted event

Testing

Test Registration contract set Expected result
test_pay_to_contact_without_registration_contract_skips_validation No Contact succeeds for any player_id
test_pay_to_contact_with_registration_contract_rejects_unknown_player Yes (empty registry) Panics with PlayerNotFound

All existing tests are unaffected — no production logic outside pay_to_contact was changed.

…to_contact

- Add ScoutAccessError::PlayerNotFound = 13
- Add DataKey::RegistrationContract to types
- Add set_registration_contract(env, addr) admin function that stores the
  registration contract address in DataKey::RegistrationContract
- In pay_to_contact: when RegistrationContract is set, call
  registration_contract::Client::try_get_player before collecting any fee;
  return PlayerNotFound and abort if the lookup fails; skip validation
  entirely when the address is not configured (preserves existing behaviour)
- Add mod registration_contract { contractimport!(...) } for the cross-
  contract client (mirrors the existing progress_contract pattern)
- Add missing PERSISTENT_TTL_MIN / PERSISTENT_TTL_MAX constants and
  mod progress_contract { contractimport!(...) } that were referenced but
  never declared in the original file
- Add scoutchain-registration as a dev-dependency so tests can register
  the contract directly with env.register_contract
- Add two unit tests:
    test_pay_to_contact_without_registration_contract_skips_validation
    test_pay_to_contact_with_registration_contract_rejects_unknown_player
- Fix CI: move WASM build step before cargo test because contractimport!
  reads the WASM at compile time
@gracious01-tech gracious01-tech merged commit 7f556f7 into main May 31, 2026
0 of 2 checks passed
@gracious01-tech gracious01-tech deleted the feat/cross-contract-player-validation branch May 31, 2026 11:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant