Skip to main content

Program Escrow Storage Layout

Last updated: 16 August 2026

Documents a contract that does not exist

The only Soroban contract in this project is grainhack-escrow (initialise, fund, publish_root, claim, is_claimed, sweep), and it has never been deployed. The program-escrow and bounty-escrow surfaces this page describes — publish_program, lock_program_funds, single_payout, batch_payout, create_bounty and the rest — have no implementation in any repository, verified 16 August 2026.

This page is kept as a design record. Do not read it as a description of working software, and do not implement against it without checking what the contract actually exposes. See Payout path — what exists today.

Overview​

The program-escrow contract utilizes two parallel storage models for storing ProgramData:

  1. Legacy Singleton Storage: PROGRAM_DATA key. This was the original storage model where the contract only managed a single program.
  2. Multi-Program Registry Storage: DataKey::Program(program_id) key. This was introduced later to support multiple programs within the same contract instance.

Why Both Exist​

The legacy singleton storage (PROGRAM_DATA) is retained for backward compatibility. Many older indexers and downstream clients may still depend on the get_program_info function, which explicitly queries the PROGRAM_DATA key.

To support multiple programs without breaking existing clients, the contract maintains both models. When a program is initialized via initialize_program, its data is stored in the multi-program registry (DataKey::Program(id)) and is also dual-written to PROGRAM_DATA (making it the "active" or "primary" program from the legacy perspective).

Interactions and Synchronization​

Initialization and payout paths (like initialize_program, lock_program_funds, single_payout_internal, and batch_payout_internal) explicitly synchronize both storage locations. Whenever a program's state is mutated, the contract checks if the mutated program matches the one stored in PROGRAM_DATA. If it does, the updated ProgramData is written to both locations to prevent desynchronization.

Migration Strategy​

  • get_program_info has been marked as deprecated.
  • All new integrations and internal contract logic should prefer get_program_info_v2(program_id) to explicitly query a specific program.
  • Eventually, once downstream clients have migrated to the multi-program registry accessors, the PROGRAM_DATA singleton dual-writes can be phased out in a future upgrade.