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/atomic-swap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ pub struct CrossChainTxInfo {

const DEFAULT_TIMEOUT_LEDGERS_MAX: u32 = 6 * 60 * 24 * 7; // ~7 days at 10s/ledger, sanity cap

/// TTL extension (in ledgers) for persistent storage entries — ~5.8 days at
/// ~5s/ledger. Applied on every active interaction that writes a persistent key
/// so the entry remains observable until settlement completes.
const TTL_EXTEND: u32 = 100_000;

/// Cross-chain reorg protection: finality depth per EVM chain
/// These are chain_id -> k_confirmations mappings
const ETHEREUM_MAINNET_FINALITY: u32 = 64; // ~15 minutes
Expand Down Expand Up @@ -233,6 +238,9 @@ impl AtomicSwapContract {
state.timeout_ledger = old_timeout.saturating_add(MAX_REORG_WINDOW_LEDGERS);

env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);
env.events().publish(
(Symbol::new(&env, "timelock_extended"), trade_id),
(old_timeout, state.timeout_ledger),
Expand Down Expand Up @@ -362,6 +370,9 @@ impl Htlc for AtomicSwapContract {
// CEI pattern: update state before external calls
state.status = TradeStatus::Released;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

let token_addr: Address = env.storage().instance().get(&DataKey::Token).unwrap();
let client = token::Client::new(&env, &token_addr);
Expand Down Expand Up @@ -396,6 +407,9 @@ impl Htlc for AtomicSwapContract {
// CEI pattern: update state before external calls
state.status = TradeStatus::Refunded;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

let token_addr: Address = env.storage().instance().get(&DataKey::Token).unwrap();
let client = token::Client::new(&env, &token_addr);
Expand Down
45 changes: 45 additions & 0 deletions contracts/escrow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ enum DataKey {
/// (~50s at Stellar's ~5s ledger close time).
pub const PAUSE_DELAY_LEDGERS: u32 = 10;

/// Default TTL extension (in ledgers) for persistent storage entries during
/// active interactions. ~5.8 days at ~5s/ledger. Long enough for clients,
/// relayers, and reputation-scanners to observe terminal trade states, but
/// short enough that archived entries are eventually reclaimed.
const TTL_EXTEND: u32 = 100_000;

#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Error {
Expand Down Expand Up @@ -770,13 +776,19 @@ impl EscrowContract {

state.status = TradeStatus::Disputed;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

let info = DisputeInfo {
start_ledger: env.ledger().sequence(),
};
env.storage()
.persistent()
.set(&DataKey::Dispute(id.clone()), &info);
env.storage()
.persistent()
.extend_ttl(&DataKey::Dispute(id.clone()), TTL_EXTEND, TTL_EXTEND);

// Snapshot arbitrator-pool eligibility now, before anyone can react
// to this dispute existing. `resolve_dispute()` and
Expand Down Expand Up @@ -940,6 +952,9 @@ impl EscrowContract {

state.status = TradeStatus::Resolved;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);
env.storage()
.persistent()
.remove(&DataKey::Dispute(id.clone()));
Expand Down Expand Up @@ -1019,6 +1034,9 @@ impl EscrowContract {

state.status = TradeStatus::Refunded;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);
env.storage()
.persistent()
.remove(&DataKey::Dispute(id.clone()));
Expand Down Expand Up @@ -1242,6 +1260,9 @@ impl EscrowContract {
// CEI pattern, same as release(): update state before external calls.
state.status = TradeStatus::Released;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

client.transfer(&env.current_contract_address(), &state.seller, &payout);
if fee > 0 {
Expand Down Expand Up @@ -1348,6 +1369,9 @@ impl EscrowContract {
// property this function exists to provide.
release_state.status = TradeStatus::Released;
env.storage().persistent().set(&release_key, &release_state);
env.storage()
.persistent()
.extend_ttl(&release_key, TTL_EXTEND, TTL_EXTEND);

let new_timeout_ledger = env.ledger().sequence() + new_timeout_ledgers;

Expand Down Expand Up @@ -1454,6 +1478,9 @@ impl EscrowContract {
// CEI pattern: update state before external calls.
state.status = TradeStatus::Released;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

client.transfer(&env.current_contract_address(), &state.seller, &payout);
if fee > 0 {
Expand Down Expand Up @@ -1738,6 +1765,9 @@ impl EscrowContract {
}

env.storage().persistent().set(&nonce_key, &true);
env.storage()
.persistent()
.extend_ttl(&nonce_key, TTL_EXTEND, TTL_EXTEND);

let key = DataKey::Trade(escrow_id.clone());
let mut state: TradeState = env.storage().persistent().get(&key).ok_or(Error::TradeNotFound)?;
Expand All @@ -1758,6 +1788,9 @@ impl EscrowContract {

state.status = TradeStatus::Released;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

let client = token::Client::new(&env, &token_addr);
client.transfer(&env.current_contract_address(), &recipient_address, &payout);
Expand Down Expand Up @@ -1934,9 +1967,15 @@ impl Htlc for EscrowContract {
env.storage()
.persistent()
.set(&DataKey::TradeCounter, &next_idx);
env.storage()
.persistent()
.extend_ttl(&DataKey::TradeCounter, TTL_EXTEND, TTL_EXTEND);
env.storage()
.persistent()
.set(&DataKey::TradeId(next_idx), &id);
env.storage()
.persistent()
.extend_ttl(&DataKey::TradeId(next_idx), TTL_EXTEND, TTL_EXTEND);

let client = token::Client::new(&env, &token_addr);
client.transfer(&buyer, &env.current_contract_address(), &amount);
Expand Down Expand Up @@ -2134,6 +2173,9 @@ impl Htlc for EscrowContract {

// CEI pattern: update state before external calls
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

let client = token::Client::new(&env, &token_addr);
client.transfer(&env.current_contract_address(), &state.seller, &payout);
Expand Down Expand Up @@ -2256,6 +2298,9 @@ impl Htlc for EscrowContract {
// CEI pattern: update state before external calls
state.status = TradeStatus::Refunded;
env.storage().persistent().set(&key, &state);
env.storage()
.persistent()
.extend_ttl(&key, TTL_EXTEND, TTL_EXTEND);

// Only transfer if there's an unreleased amount to refund
if refund_amount > 0 {
Expand Down
32 changes: 27 additions & 5 deletions contracts/reputation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ use soroban_sdk::{
const LEDGERS_PER_DAY: u32 = 17_280;
const MAX_TRADES: u32 = 200;

/// TTL extension (in ledgers) for persistent storage entries. ~5.8 days at
/// ~5s/ledger. Applied on every active interaction that writes a persistent key.
const TTL_EXTEND: u32 = 100_000;

// Pre-computed exp(-0.01 * n) * 1_000_000 for n = 0..365
const DECAY_TABLE: [u32; 356] = [
1_000_000, 990_049, 980_198, 970_445, 960_789, 951_229, 941_764, 932_393, 923_116, 913_931,
Expand Down Expand Up @@ -110,9 +114,15 @@ impl ReputationContract {
panic!("already initialized");
}
env.storage().persistent().set(&RepDataKey::Admin, &admin);
env.storage()
.persistent()
.extend_ttl(&RepDataKey::Admin, TTL_EXTEND, TTL_EXTEND);
env.storage()
.persistent()
.set(&RepDataKey::EscrowContract, &escrow_contract);
env.storage()
.persistent()
.extend_ttl(&RepDataKey::EscrowContract, TTL_EXTEND, TTL_EXTEND);
}

/// Register a verified identity Merkle root (admin only).
Expand All @@ -129,7 +139,10 @@ impl ReputationContract {

env.storage()
.persistent()
.set(&RepDataKey::VerifiedRoot(root), &true);
.set(&RepDataKey::VerifiedRoot(root.clone()), &true);
env.storage()
.persistent()
.extend_ttl(&RepDataKey::VerifiedRoot(root), TTL_EXTEND, TTL_EXTEND);
Ok(())
}

Expand Down Expand Up @@ -182,6 +195,9 @@ impl ReputationContract {
env.storage()
.persistent()
.set(&RepDataKey::SpentNullifier(nullifier_hash.clone()), &true);
env.storage()
.persistent()
.extend_ttl(&RepDataKey::SpentNullifier(nullifier_hash.clone()), TTL_EXTEND, TTL_EXTEND);

// Emit verification event
env.events().publish(
Expand Down Expand Up @@ -243,9 +259,12 @@ impl ReputationContract {
let count = call_escrow_u32(&env, &escrow, "get_trade_count");
let scan_max = core::cmp::min(count, MAX_TRADES);
if scan_max == 0 {
env.storage()
.persistent()
.set(&RepDataKey::CachedScore(address), &0u32);
env.storage()
.persistent()
.set(&RepDataKey::CachedScore(address.clone()), &0u32);
env.storage()
.persistent()
.extend_ttl(&RepDataKey::CachedScore(address), TTL_EXTEND, TTL_EXTEND);
return 0;
}

Expand Down Expand Up @@ -303,7 +322,10 @@ impl ReputationContract {

env.storage()
.persistent()
.set(&RepDataKey::CachedScore(address), &score);
.set(&RepDataKey::CachedScore(address.clone()), &score);
env.storage()
.persistent()
.extend_ttl(&RepDataKey::CachedScore(address), TTL_EXTEND, TTL_EXTEND);
score
}

Expand Down
16 changes: 16 additions & 0 deletions contracts/zk-credential/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ use soroban_sdk::{
const TREE_DEPTH: u32 = 8;
const MAX_LEAVES: u32 = 256; // 2^TREE_DEPTH

/// TTL extension (in ledgers) for persistent storage entries. ~5.8 days at
/// ~5s/ledger. Applied on every active interaction that writes a persistent key.
const TTL_EXTEND: u32 = 100_000;

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DataKey {
Expand Down Expand Up @@ -72,6 +76,9 @@ impl ZkCredentialContract {
env.storage()
.persistent()
.set(&DataKey::KnownRoots(initial_root.clone()), &true);
env.storage()
.persistent()
.extend_ttl(&DataKey::KnownRoots(initial_root), TTL_EXTEND, TTL_EXTEND);

Ok(())
}
Expand Down Expand Up @@ -108,6 +115,9 @@ impl ZkCredentialContract {
env.storage()
.persistent()
.set(&DataKey::Leaf(count), &commitment);
env.storage()
.persistent()
.extend_ttl(&DataKey::Leaf(count), TTL_EXTEND, TTL_EXTEND);
let new_count = count + 1;
env.storage()
.instance()
Expand All @@ -121,6 +131,9 @@ impl ZkCredentialContract {
env.storage()
.persistent()
.set(&DataKey::KnownRoots(new_root.clone()), &true);
env.storage()
.persistent()
.extend_ttl(&DataKey::KnownRoots(new_root), TTL_EXTEND, TTL_EXTEND);

// Emit buy event
env.events().publish(
Expand Down Expand Up @@ -172,6 +185,9 @@ impl ZkCredentialContract {
env.storage()
.persistent()
.set(&DataKey::Nullifier(nullifier_hash.clone()), &true);
env.storage()
.persistent()
.extend_ttl(&DataKey::Nullifier(nullifier_hash.clone()), TTL_EXTEND, TTL_EXTEND);

// Emit spend event
env.events()
Expand Down
Loading
Loading