Skip to content

πŸ”΄ All factory bookkeeping lives in instance storage β€” the factory will eventually brick itselfΒ #1007

Description

@Ejirowebfi

Area: Smart contract Β· lib.rs (all storage access)

Description

Every piece of per-token state β€” TokenInfo(index), CreatorTokens(Address) (an append-only
Vec<u32>), TokenIndex(Address), Metadata(Address), the per-token owner and supply keys, and
the whitelist entries β€” is written to env.storage().instance(). Soroban instance storage is a
single ledger entry shared with the contract instance itself, subject to the ledger-entry size limit
(~64 KiB) and loaded/serialized in full on every invocation.

Consequences as adoption grows:

  1. Hard brick: once cumulative instance data approaches the entry-size limit, every state-writing
    call (create_token, set_metadata, even pause) starts failing. There is no admin action that
    can fix it β€” the factory is permanently unusable and all token bookkeeping is trapped.
  2. Cost blow-up before the brick: every invocation pays read/write fees proportional to the entire
    instance entry, so create_token becomes progressively more expensive for all users as unrelated
    tokens accumulate.
  3. Single TTL: one archival event takes down all bookkeeping at once (see Issue 7).

The MAX_TOKENS_BY_CREATOR_PAGE cap addresses the read path only; the underlying write-side growth
is unbounded. This is the single largest scalability defect in the contract and requires a storage
migration to persistent storage with per-key TTLs.

Tasks

  • Move TokenInfo, TokenIndex, Metadata, owner, supply, and whitelist keys to
    env.storage().persistent(); keep only FactoryState (and the fee split) in instance storage.
  • Replace the monolithic CreatorTokens Vec<u32> with paginated persistent buckets (e.g.
    CreatorTokens(Address, page: u32) holding at most N indices each) so no single entry grows
    unboundedly.
  • Implement extend_ttl correctly per persistent key on access (see Issue 7).
  • Bump CURRENT_SCHEMA_VERSION and write a migrate step that moves existing instance entries to
    persistent storage; the migration must be idempotent and chunk-safe (callable repeatedly if it
    cannot complete in one invocation's resource budget).
  • Add a stress test that creates several hundred tokens and asserts instance-entry size stays flat.
  • Update the storage documentation in docs/contract-abi.md and the README architecture section.

Acceptance criteria

  • Instance storage size is O(1) with respect to token count, demonstrated by the stress test.
  • All existing view/mutation entrypoints behave identically after migration (full test suite green).
  • migrate converts a pre-migration state snapshot correctly and is proven idempotent by tests.

Issue 3 of 20 from the codebase audit tracked in ISSUES.md.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26auditFrom the ISSUES.md codebase auditreleasedseverity: criticalFunds/consensus/permanent-brick risk

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions