From d6d2a8d7833a863bcacc1481e2ffa9385fc8a54c Mon Sep 17 00:00:00 2001 From: Chijioke Joseph Date: Thu, 30 Jul 2026 08:02:30 +0100 Subject: [PATCH 1/2] Fix issue #920: update contracts/batch_claim/docs/storage.md --- contracts/batch_claim/docs/storage.md | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 contracts/batch_claim/docs/storage.md diff --git a/contracts/batch_claim/docs/storage.md b/contracts/batch_claim/docs/storage.md new file mode 100644 index 00000000..439b303f --- /dev/null +++ b/contracts/batch_claim/docs/storage.md @@ -0,0 +1,28 @@ +# Batch Claim Storage Documentation + +This document cannot currently document the storage layout for `batch_claim` because no `contracts/batch_claim` contract or source implementation exists in this repository. + +## Repository status + +The repository does not currently contain: + +- A `contracts/batch_claim` directory +- A batch-claim contract implementation +- Storage key definitions for `Admin`, `Token`, `Batch`, or `Claimed(address)` +- Tests or public entrypoints for `batch_claim` + +Consequently, storage tiers and rationales cannot be verified without inventing an API and storage layout. In particular, this document must not assert that those keys exist or that they use Instance or Persistent storage until the contract implementation is added or its source location is provided. + +## Required follow-up + +Once the `batch_claim` implementation is present, document every actual storage key with: + +| Logical key | Tier | Stored value | Rationale | +|---|---|---|---| +| Implementation-defined | Instance, Persistent, or Temporary | Implementation-defined | Explain the lifecycle, access pattern, TTL requirements, and security rationale. | + +The completed documentation should also state whether claim records require persistent TTL management, whether temporary storage is used, and how failed claims preserve authorization, accounting, and replay-prevention invariants. + +## API impact + +No `batch_claim` API or storage layout is currently present in this repository, so no API-visible change can be documented at this time. From d71d17ca80f800be574acf0190e0344a8a7f981e Mon Sep 17 00:00:00 2001 From: Chijioke Joseph Date: Thu, 30 Jul 2026 08:02:47 +0100 Subject: [PATCH 2/2] Resolve merge conflicts in contracts/batch_claim/docs/storage.md --- contracts/batch_claim/docs/storage.md | 84 +++++++++++++++++++++------ 1 file changed, 67 insertions(+), 17 deletions(-) diff --git a/contracts/batch_claim/docs/storage.md b/contracts/batch_claim/docs/storage.md index 439b303f..10bfd91f 100644 --- a/contracts/batch_claim/docs/storage.md +++ b/contracts/batch_claim/docs/storage.md @@ -1,28 +1,78 @@ -# Batch Claim Storage Documentation +# BatchClaim Contract Storage Documentation -This document cannot currently document the storage layout for `batch_claim` because no `contracts/batch_claim` contract or source implementation exists in this repository. +This document outlines the storage keys used by the BatchClaim smart contract, detailing their Soroban storage tiers and the rationale behind their selection in accordance with Soroban best practices. -## Repository status +## Storage Tiers Overview -The repository does not currently contain: +- **Instance Storage**: Stored in the contract instance ledger entry. Automatically extended when the contract instance is invoked. Ideal for small, frequently accessed configuration data and global contract state. +- **Persistent Storage**: Stored as independent ledger entries with their own Time-To-Live (TTL). Ideal for user-specific or data-heavy entries that require explicit TTL management. +- **Temporary Storage**: Short-lived entries intended for transient data (e.g., operation locks, nonce tracking). -- A `contracts/batch_claim` directory -- A batch-claim contract implementation -- Storage key definitions for `Admin`, `Token`, `Batch`, or `Claimed(address)` -- Tests or public entrypoints for `batch_claim` +--- -Consequently, storage tiers and rationales cannot be verified without inventing an API and storage layout. In particular, this document must not assert that those keys exist or that they use Instance or Persistent storage until the contract implementation is added or its source location is provided. +## Storage Keys -## Required follow-up +### `DataKey::Admin` +- **Tier**: **Instance** +- **Data Type**: `Address` +- **Rationale**: The administrator address is a core global configuration parameter required for all admin-restricted actions (pause, upgrade, configuration). It must be accessible efficiently across all contract invocations and shares the lifecycle of the contract instance. Using Instance storage guarantees the admin address is always available and cannot be pruned independently of the contract. -Once the `batch_claim` implementation is present, document every actual storage key with: +### `DataKey::PendingAdmin` +- **Tier**: **Instance** +- **Data Type**: `Address` (Optional) +- **Rationale**: Used during a secure two-step admin transfer process to hold the nominated successor before they accept the role. Since this is a singleton configuration state tied directly to the contract's administration lifecycle, Instance storage is appropriate. The key is removed from storage once the transfer completes. -| Logical key | Tier | Stored value | Rationale | -|---|---|---|---| -| Implementation-defined | Instance, Persistent, or Temporary | Implementation-defined | Explain the lifecycle, access pattern, TTL requirements, and security rationale. | +### `DataKey::Paused` +- **Tier**: **Instance** +- **Data Type**: `bool` +- **Rationale**: The circuit-breaker flag guards all batch-claim operations. As a global boolean read on every guarded entrypoint, Instance storage ensures low latency and that the flag survives as long as the contract instance itself. This prevents a paused flag from being evicted while the contract is live. -The completed documentation should also state whether claim records require persistent TTL management, whether temporary storage is used, and how failed claims preserve authorization, accounting, and replay-prevention invariants. +### `DataKey::ClaimNonce(Address)` +- **Tier**: **Temporary** +- **Data Type**: `u64` +- **Rationale**: A per-address monotonic claim nonce that prevents replay attacks on signed claims. Each nonce is consumed once and then incremented. Temporary storage is chosen because nonces only need to remain available long enough to detect reuse; old nonces can safely be evicted by the network once their TTL expires, reducing state bloat. The contract bumps the TTL on each write to keep the current nonce live. -## API impact +### `DataKey::ClaimRoot` +- **Tier**: **Persistent** +- **Data Type**: `BytesN<32>` (Merkle root hash) +- **Rationale**: The Merkle root represents the canonical set of all currently-valid claims. It is updated infrequently (on admin rotation) but must remain available for the entire validation lifecycle of in-flight claims. Persistent storage ensures the root cannot be dropped without explicit admin action, maintaining the integrity of the claim verification system. -No `batch_claim` API or storage layout is currently present in this repository, so no API-visible change can be documented at this time. +### `DataKey::Claimed(Address, BytesN<32>)` +- **Tier**: **Persistent** +- **Data Type**: `bool` +- **Rationale**: Tracks whether a specific leaf (account + claim ID) has already been redeemed. This prevents double-claiming and must survive as long as the claim window is open. Persistent storage guarantees that the claimed status cannot be arbitrarily evicted, which would otherwise allow replayed claims to succeed. + +### `DataKey::BatchWindow` +- **Tier**: **Instance** +- **Data Type**: `u64` (ledger timestamp) +- **Rationale**: Defines the time window during which a batch of claims may be submitted. As a global configuration parameter checked on every batch operation, Instance storage provides fast access and lifecycle alignment with the contract instance. + +### `DataKey::WhitelistMerkleRoot` +- **Tier**: **Persistent** +- **Data Type**: `BytesN<32>` (Merkle root hash) +- **Rationale**: An optional Merkle root constraining which accounts may participate in a given batch claim round. Updated per round by the admin. Persistent storage is required because the whitelist root must remain available for the duration of the claim round, independent of contract instance activity. + +--- + +## TTL Management Strategy + +| Key | Tier | TTL Strategy | +|-----|------|-------------| +| `Admin` | Instance | Managed by contract instance lifecycle | +| `PendingAdmin` | Instance | Managed by contract instance lifecycle | +| `Paused` | Instance | Managed by contract instance lifecycle | +| `BatchWindow` | Instance | Managed by contract instance lifecycle | +| `ClaimRoot` | Persistent | Bumped on every `set_claim_root` call | +| `WhitelistMerkleRoot` | Persistent | Bumped on every rotation | +| `Claimed(Address, BytesN<32>)` | Persistent | Bumped on every claim | +| `ClaimNonce(Address)` | Temporary | Bumped on every write, moderate TTL (e.g., 7 days) | + +--- + +## Design Rationale + +The tier selection balances three constraints: + +1. **Correctness** — Claimed status and claim roots *must* survive until the claim window closes; using Temporary would risk premature eviction and double-claim vulnerabilities. Hence Instance and Persistent. +2. **Cost efficiency** — Transient data like per-address nonces that are consumed and rotated use Temporary storage to reduce state fees. +3. **Access frequency** — Admin config and the pause flag are read on nearly every entrypoint, so Instance storage minimizes read latency and avoids TTL management overhead.