pyth-network / pyth-network/pyth-crosschain
[price_pusher/solana] Encoded VAA accounts leak when an update tx fails (18.7k accounts / 143 SOL on one pusher wallet)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 247
- Forks
- 348
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 27
Description
Summary
The Solana price pusher (apps/price_pusher/src/solana/solana.ts, v13.0.0) relies on closeUpdateAccounts: true, so the closeEncodedVaa instructions are appended to the end of the transaction batch built by buildVersionedTransactions. If any transaction in that batch fails, sendTransactions throws, updatePriceFeed logs the error and returns, and the encoded VAA account is never closed. Nothing retries the close later. The SDK already has addClosePreviousEncodedVaasInstructions() for exactly this case (its doc comment describes it), but price_pusher never calls it.
The most common failure I see is update_price_feed running out of compute. With tightComputeBudget: true it gets the hard-coded UPDATE_PRICE_FEED_COMPUTE_BUDGET = 55_000, and some updates need more than that.
Evidence (mainnet, 2026-09-16)
Wallet 4p16wya1Vw2u9w22oah4yXQgySb6eWKRRLMsEXCreish pushes shard-0 sponsored feeds through pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT. Is this a Pyth-operated pusher?
- It is the write authority of 18,734 open
EncodedVaaaccounts underHDwcJBJXjL9FpJ7UBsYBtaDjsBUhuLCUYoz3zr8SWWaQ, holding 143.11 SOL of rent. The count went up by 4 over a few hours today. - The oldest leftovers I found date back to 2025:
73LkscNLkJS56thftKSLiWM31EURromdA1Tu3bC4YzZe(2025-09-07, status Writing) and838BC4LMBqUgDP4adEaEgjHf9QCbyZadYfzJS8qUNWrR(2025-12-25, status Verified). - None of the sampled leaked accounts was touched again after its failed transaction.
Example 1: buffer FHxy8nAq5SEwXEKTMGZWbf6j8pEZPT1ppiHhYR6wmdUL
init_encoded_vaa+write_encoded_vaa: okwrite_encoded_vaa+verify_encoded_vaa_v1+update_price_feed: okupdate_price_feed×2: okupdate_price_feed×2: okupdate_price_feed(+ close): failed, tx1274WAypYJVmyCXefvuDhfBE43jDY3i5yN8jGW2xzG1wY1tDt8asxnT2GzUwtaYErazuqcRRWuX8JfqYiycvYRmi
Program rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ failed: exceeded CUs meter at BPF instruction
Program pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT consumed 55000 of 55000 compute units
Example 2: buffer Fkdq7321xi9qRs9LsHgy4JvXTN92dw8rxsZi3KJE6YQ9. Its second transaction (write + verify + update_price_feed) failed with ComputationalBudgetExceeded at 408,000 CU (350k verify + 55k update + 3k write): 4RS4wkHxEd25jSjsqwWqPorN1P71aXnJgBSENkD8B8rCpRAqYrYKbZ5f7k5gbjEXZjuheBhuX6fpiAJ6Uy5pXWLE
The rent is recoverable. I simulated a transaction with 10 closeEncodedVaa instructions as that write authority (sigVerify: false), and it succeeds on verified accounts.
This isn't limited to one wallet. Across mainnet there are currently 127,129 open EncodedVaa accounts (~998 SOL) from 634 write authorities, so other SDK users probably hit the same path.
Suggested fixes
- price_pusher: after a failed update (or every N minutes), call
addClosePreviousEncodedVaasInstructions()and send the resulting transactions. - SDK: make
UPDATE_PRICE_FEED_COMPUTE_BUDGETconfigurable, or add headroom whentightComputeBudgetis set. Some updates currently need more than 55k. - SDK: add
dataSlice: { offset: 0, length: 0 }tofindEncodedVaaAccountsByWriteAuthority. It currently downloads the full data of every account (about 1 KB each), which gets heavy with thousands of leftovers.
One-off cleanup
For the existing accounts, something like the following, run in a loop until nothing is left:
const builder = pythSolanaReceiver.newTransactionBuilder({});
await builder.addClosePreviousEncodedVaasInstructions(500);
const txs = await builder.buildVersionedTransactions({ computeUnitPriceMicroLamports: 10_000 });
await sendTransactions(txs, pythSolanaReceiver.connection, pythSolanaReceiver.wallet);
Happy to help test a fix.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/price_pusher/src/solana/solana.ts and trace updatePriceFeed, sendTransactions, and the SDK method addClosePreviousEncodedVaasInstructions(). Compare the failed-transaction path with the existing closeUpdateAccounts flow and review the SDK handling of UPDATE_PRICE_FEED_COMPUTE_BUDGET and findEncodedVaaAccountsByWriteAuthority. Done means the agreed failure-recovery behavior prevents leaked EncodedVaa accounts, with the selected SDK changes validated against the reported cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- blockchain
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100