Skip to content
Merged
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
14 changes: 14 additions & 0 deletions contracts/escrow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ const DEFAULT_MATCH_TIMEOUT_LEDGERS: u32 = MATCH_TTL_LEDGERS;
/// Both formats fit well within this limit.
const MAX_GAME_ID_LEN: u32 = 64;

/// Extend instance storage TTL on every invocation so Admin, Oracle, Paused, and other
/// instance keys never expire.
fn extend_instance_ttl(env: &Env) {
env.storage()
.instance()
.extend_ttl(MATCH_TTL_LEDGERS / 2, MATCH_TTL_LEDGERS);
}

#[contract]
pub struct EscrowContract;

Expand All @@ -40,6 +48,7 @@ impl EscrowContract {

/// Pause the contract — admin only. Blocks create_match, deposit, and submit_result.
pub fn pause(env: Env) -> Result<(), Error> {
extend_instance_ttl(&env);
let admin: Address = env
.storage()
.instance()
Expand All @@ -54,6 +63,7 @@ impl EscrowContract {

/// Unpause the contract — admin only.
pub fn unpause(env: Env) -> Result<(), Error> {
extend_instance_ttl(&env);
let admin: Address = env
.storage()
.instance()
Expand Down Expand Up @@ -143,6 +153,7 @@ impl EscrowContract {
game_id: String,
platform: Platform,
) -> Result<u64, Error> {
extend_instance_ttl(&env);
player1.require_auth();

if env
Expand Down Expand Up @@ -257,6 +268,7 @@ impl EscrowContract {

/// Player deposits their stake into escrow.
pub fn deposit(env: Env, match_id: u64, player: Address) -> Result<(), Error> {
extend_instance_ttl(&env);
player.require_auth();

if env
Expand Down Expand Up @@ -430,6 +442,7 @@ impl EscrowContract {
/// Cancel a pending match and refund any deposits.
/// Either player can cancel a pending match.
pub fn cancel_match(env: Env, match_id: u64, caller: Address) -> Result<(), Error> {
extend_instance_ttl(&env);
let mut m: Match = env
.storage()
.persistent()
Expand Down Expand Up @@ -481,6 +494,7 @@ impl EscrowContract {
/// Expire a pending match that has not been fully funded within MATCH_TIMEOUT_LEDGERS.
/// Anyone can call this; funds are returned to whoever deposited.
pub fn expire_match(env: Env, match_id: u64) -> Result<(), Error> {
extend_instance_ttl(&env);
let mut m: Match = env
.storage()
.persistent()
Expand Down
62 changes: 62 additions & 0 deletions contracts/escrow/src/tests/ttl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,65 @@ fn test_player_match_index_ttl_refreshes_on_read() {
});
assert_eq!(ttl, crate::MATCH_TTL_LEDGERS);
}

#[test]
fn test_get_player_matches_ttl_returns_correct_value() {
let (env, contract_id, _oracle, player1, player2, token, _admin) = setup();
let client = EscrowContractClient::new(&env, &contract_id);

// Before any matches, TTL should be 0
let ttl_before = client.get_player_matches_ttl(&player1);
assert_eq!(ttl_before, 0);

// Create a match
client.create_match(
&player1,
&player2,
&100,
&token,
&String::from_str(&env, "ttl_getter_test"),
&Platform::Lichess,
);

// After creating a match, TTL should be set to MATCH_TTL_LEDGERS
let ttl_after = client.get_player_matches_ttl(&player1);
assert_eq!(ttl_after, crate::MATCH_TTL_LEDGERS);

// Advance ledger by 1000
env.ledger().set(soroban_sdk::testutils::LedgerInfo {
sequence_number: env.ledger().sequence() + 1000,
timestamp: env.ledger().timestamp() + 5000,
protocol_version: 22,
network_id: Default::default(),
base_reserve: 10,
min_temp_entry_ttl: 1,
min_persistent_entry_ttl: 1,
max_entry_ttl: crate::MATCH_TTL_LEDGERS + 2000,
});

// TTL should have decreased by approximately 1000 ledgers
let ttl_decreased = client.get_player_matches_ttl(&player1);
assert!(
ttl_decreased < ttl_after,
"TTL should decrease after ledger advancement"
);
assert!(
ttl_decreased >= ttl_after - 1000,
"TTL should be approximately 1000 less"
);

// Reading player matches should refresh TTL back to MATCH_TTL_LEDGERS
client.get_player_matches(&player1);
let ttl_refreshed = client.get_player_matches_ttl(&player1);
assert_eq!(ttl_refreshed, crate::MATCH_TTL_LEDGERS);
}

#[test]
fn test_get_player_matches_ttl_for_nonexistent_player() {
let (env, contract_id, _oracle, _player1, _player2, _token, _admin) = setup();
let client = EscrowContractClient::new(&env, &contract_id);

let random_player = Address::generate(&env);
let ttl = client.get_player_matches_ttl(&random_player);
assert_eq!(ttl, 0, "TTL should be 0 for player with no match history");
}
Loading