Skip to content

feat(buy-sol) PR 2: settle native SOL buys from the state PDA - #4986

Merged
squadgazzz merged 7 commits into
mainfrom
solana-driver/be-330-settle-native-sol-buys
Sep 29, 2026
Merged

squadgazzz merged 7 commits into
mainfrom
solana-driver/be-330-settle-native-sol-buys

Conversation

@squadgazzz

@squadgazzz squadgazzz commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Description

Stacked on #4985.

FinalizeSettle pays a native SOL buy from the state PDA's lamports, so the settlement has to put the SOL there first. After #4985 the swap lands as wSOL in the taker's wSOL ATA, so this PR unwraps it and funds the state PDA in the same transaction:

create the taker's wSOL ATA (idempotent)
BeginSettle
interactions                          swap lands in the wSOL ATA
Transfer(wSOL ATA to itself, sum)     fails if the swap delivered less
CloseAccount(wSOL ATA to the taker)   unwraps it
Transfer(taker to state PDA, sum)
FinalizeSettle                        pays the wallets

The self-transfer moves nothing, it only checks the balance. Without it, a short swap gets topped up from the taker's own SOL and the simulation still passes. Classic SPL Token and p-token both check the balance before they skip the move.

The transfer to the state PDA has to be the exact sum. Until SC-403, lamports leave the state PDA only through pushes, so anything extra gets stuck there. That's also why the ATA closes to the taker and not into the state PDA, and why the solver fee on a native buy stays with the taker. Moving the fee as wSOL into the wSOL buffer would also work. I took the simpler option and I'm open to switching.

The driver creates the wSOL ATA on every settlement that uses it. Settlements aren't serialized yet, so a parallel one can close the ATA after our snapshot. A wSOL sell pays one extra idempotent create for that.

The route also has to leave the wSOL ATA open. Something like Jupiter with wrapAndUnwrapSol: true would close it first, and then our CloseAccount reverts. Our solver has that flag off, so this is about external solvers, and the openapi and solver DTOs spell it out now.

Native buys add a few keys and instructions, so a route near the 1,232-byte limit could win at /solve and fail at /settle. /solve now builds each solution's transaction and drops the ones that don't fit, at one getMultipleAccounts per solution. This covers all solutions, not only native ones, and a solution it can't build stays in.

Nothing reaches this path before BE-331 and BE-332 land. Those drop payouts under 890,880 lamports, since a smaller one into a missing wallet fails the whole settlement, and wallets the System Program doesn't own, which covers the state PDA.

Changes

  • Native SOL buys skip the buy-mint buffer, and the taker's wSOL ATA joins the setup accounts
  • The settlement checks the wSOL ATA covers the native payouts, unwraps it and funds the state PDA with the exact sum
  • The driver creates the taker's wSOL ATA whenever a settlement uses it
  • /solve drops solutions whose transaction is over the size limit
  • The openapi, the solver DTOs and the solver fee docs cover native buys

How to test

New unit and API tests. The workspace has no program harness yet, so barn is the first end to end run. The pre-send simulation stops a broken sequence before it lands.

Related issues

BE-330

@linear-code

linear-code Bot commented Sep 28, 2026

Copy link
Copy Markdown

BE-330

@squadgazzz squadgazzz changed the title solana-driver: settle native SOL buys from the state PDA feat(buy-sol) PR 2: settle native SOL buys from the state PDA Sep 29, 2026
@squadgazzz
squadgazzz marked this pull request as ready for review September 29, 2026 10:59
@squadgazzz
squadgazzz requested a review from a team as a code owner September 29, 2026 10:59
@claude

claude Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @squadgazzz's task in 4m 42s —— View job


PR Review: settle native SOL buys from the state PDA

  • Read PR diff against origin/solana-driver/be-329-native-sol-buys-as-wsol
  • Analyze settlement encoding + funding logic
  • Cross-check funding total vs. FinalizeSettle pushes
  • Post review

This is clean and well-tested. The close → transfer(total) → FinalizeSettle sequence is internally consistent: the transfer sum and the native pushes both derive from buy_amount, so the state PDA always nets back to its baseline balance (never dropping below its rent-exempt reserve). The design tradeoffs (fee stays with taker, ATA closes to taker to reclaim rent, unconditional wSOL ATA create) are all sound and acknowledged in the description.

I posted one minor inline note about the two different "is native SOL buy" predicates. No blocking issues.

One non-blocking heads-up for when BE-331/332 make native buys live: the added CloseAccount + Transfer (plus the extra idempotent wSOL ATA create) consume compute beyond the solver's cu_estimate. It's caught by pre-send simulation, but worth confirming the CU budget accommodates them once native buys can enter an auction.
· solana-driver/be-330-settle-native-sol-buys

Comment thread crates/solana-driver/src/domain/settlement.rs
@github-actions

Copy link
Copy Markdown

Reminder: Please consider backward compatibility when modifying the API specification.
If breaking changes are unavoidable, ensure:

  • You explicitly pointed out breaking changes.
  • You communicate the changes to affected teams (at least Frontend team and SAFE team).
  • You provide proper versioning and migration mechanisms.

Caused by:

Base automatically changed from solana-driver/be-329-native-sol-buys-as-wsol to main September 29, 2026 19:39
@squadgazzz
squadgazzz added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit 59b72b0 Sep 29, 2026
23 checks passed
@squadgazzz
squadgazzz deleted the solana-driver/be-330-settle-native-sol-buys branch September 29, 2026 20:07
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants