Skip to content

Feature Request: Recover LUT rent after randomnessClose #9

@savage0099

Description

@savage0099

Problem

randomnessClose correctly closes the randomness account + wSOL ATA and deactivates the per-randomness LUT, but the LUT rent cannot be recovered due to Solana's Address Lookup Table 512-slot cooldown requirement.

We're building Savage Protocol, a fully on-chain jackpot game on Solana (~144 rounds/day). Each round uses Switchboard On-Demand randomness. The unrecoverable LUT rent costs us ~0.28 SOL/day (~102 SOL/year).

Root Cause

Solana ALT closure requires a two-step process:

  1. DeactivateLookupTable → start cooldown
  2. Wait ~512 slots (~3-4 minutes)
  3. CloseLookupTable → recover rent

randomnessClose performs step 1 (deactivate) in a single CPI call. But step 3 (close) fails because the cooldown hasn't elapsed yet within the same instruction.

Calling randomnessClose a second time after cooldown fails with error 3007 because the randomness account is already closed and can't be deserialized.

Calling CloseLookupTable directly is impossible because the LUT authority is lutSigner (a PDA of the Switchboard program), and only the Switchboard program can sign for it.

Devnet Proof

We tested the full lifecycle on devnet:

Step Result
randomnessInit ✅ Created randomness + ATA + LUT (152 bytes, 1,948,800 lamports)
randomnessClose (1st call) ✅ Closed randomness + ATA, deactivated LUT
Wait 512+ slots ✅ Cooldown passed
randomnessClose (2nd call) ❌ Error 3007 — randomness account already closed
Direct CloseLookupTable ❌ Missing signature for lutSigner PDA

Evidence on devnet:

  • LUT: 69oknVfLSvapF4vv172ovw56PEmcPeEr8LhJzEPUV82m — deactivated at slot 454464732, still holding 1,948,800 lamports
  • Randomness: 3UCNMCcmMzqGQV2XBK3fiTBFRwCnYERrkzmjqckZHB6i — successfully closed

Additional Finding

randomnessReveal does not reference the LUT at all (no lut, lutSigner, or addressLookupTableProgram in its account list). The LUT is created during randomnessInit but never actually used by any subsequent instruction in the commit-reveal flow.

Suggested Solutions (any would work)

Option A: randomnessCloseLut instruction
A new instruction that takes randomness_pubkey + lut_slot as parameters (for PDA derivation only, no account data needed), derives lutSigner, and CPI-calls CloseLookupTable on a deactivated LUT.

Option B: Make randomnessClose idempotent
On second call, skip the already-closed randomness/ATA accounts and only process the LUT closure if it's deactivated and cooldown has passed.

Option C: skip_lut flag in randomnessInit
Since randomnessReveal doesn't use the LUT, allow callers to opt out of LUT creation entirely.

Impact

Metric Value
LUT rent per round 1,948,800 lamports (0.00195 SOL)
Rounds per day ~144
Daily cost ~0.28 SOL
Annual cost ~102 SOL

Happy to test any fix on devnet immediately. Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions