Feature Request: Add Solana support to x402
To help expand payment rails for x402, @darkresearch would love to add Solana support to the protocol.
We're comfortable following guidelines in CONTRIBUTING.md and expect Solana support to comply with existing (and nearly upcoming) schemes.
As a starting point, we'd love to implement exact scheme support. We're open to input on implementation design specifics -- the Solana ecosystem also has variety of payment infrastructure solutions that can be built on top of or from which inspiration can be taken, including:
Couple considerations to kick off the conversation:
- The current
x402implementation requires the facilitator to settle transactions -- is there room for client-side tx settlement? Given Solana speed (and relevant to other similarly performant blockchains), this could allow the facilitator to verify by tx signature on chain and support a faster process - SPL-USDC support is likely the most interesting, but given
x402is designed to be multi-currency we're happy to add mutlicurrency support down the line / in a separate PR.
Hope that X402 can support Solana—this would bring greater prosperity to the Solana ecosystem and potentially catalyze an "AI-driven economic ecosystem," such as automated resource leasing negotiations between AI Agents.
@edgarpavlovsky would love to collaborate!
The current x402 implementation requires the facilitator to settle transactions -- is there room for client-side tx settlement? Given Solana speed (and relevant to other similarly performant blockchains), this could allow the facilitator to verify by tx signature on chain and support a faster process
A large reason that the facilitator settles transactions is to prevent tx reuse, without having to keep state of which transactions have been seen before, my preference would be to keep that paradigm. I don't think having the facilitator submit the tx vs the client should add much meaningful latency
SPL-USDC support is likely the most interesting, but given x402 is designed to be multi-currency we're happy to add mutlicurrency support down the line / in a separate PR.
SPL-USDC would be a great, but we may be able to support all SPL tokens out of the box with a few tweaks (evm-exact supports any token that implements EIP-3009).
I my head exact on solana looked something like:
- resource server responds with:
token_address,amount,fee_payer_address,pay_to_address - client assembles a transaction to send SPL tokens specified, with
feePayerset, to thepay_to_address, and paritally signs - client sends partially sign tx in
X-PAYMENTheader - resources server either settles themself or forwards to facilitator for verify & settle
Let me know your thoughts, @John-peterson-coinbase also I think has some ideas here
@erikreppel-cb cool:
A large reason that the facilitator settles transactions is to prevent tx reuse, without having to keep state of which transactions have been seen before, my preference would be to keep that paradigm. I don't think having the facilitator submit the tx vs the client should add much meaningful latency
gotcha -- happy to keep the current approach
SPL-USDC would be a great, but we may be able to support all SPL tokens out of the box with a few tweaks (evm-exact supports any token that implements https://github.com/ethereum/EIPs/issues/3010).
agree -- should be able to specify token address with the asset field. as an fyi, solana has two different token standards -- legacy TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA and the emerging TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb, but given adoption (and where it's heading) it's worth only supporting the legacy standard for now imo.
on implementation -- the steps you laid out make sense. what's the value of partially signing vs. full sign?
finally, for posterity: note that solana supports two types of transactions:
- legacy
- v0 (versioned) transactions
Versioned transactions are prevalent enough that I'd wager legacy transactions don't need to be supported, but we can look into adding both if preference is to be comprehensive & the spec has room for it
but given adoption (and where it's heading) it's worth only supporting the legacy standard for now imo.
You likely have better visibility than I into this, defer to your judgement.
on implementation -- the steps you laid out make sense. what's the value of partially signing vs. full sign?
this could just be a knowledge gap on my side. The goal to accomplish is to have the facilitator pay the tx gas, partial vs full signing I'm not super opinionated on, as long as the facilitator and resource server can't move additional funds
on implementation -- the steps you laid out make sense. what's the value of partially signing vs. full sign?
The facilitator (feePayer) must sign in order to pay fees.
Some considerations for the design:
- It's paramount for the facilitator to do transaction introspection to ensure it's only accepting transactions that strictly perform the intended payment. Otherwise, a malicious client can compromise the facilitator (relayer)'s funds by adding some malicious transactions for it to sign.
- Handling blockhash expirations and retries
- Ensuring smart wallets (e.g. squads protocol based) work with the facilitator. I expect most AI agents will run with smart wallets (due to the programmatic ability to be controlled / limited by a separate owner). Happy to assist here or bring someone from squads to do so.
- Handling the case that the server-side doesn't have a token account open (or requiring an account to be open prior to being able to receive payments?)
- Handling priority fees -- an ideal design lets the facilitator set these at the time of sending but it wouldn't be possible if the transaction is partially signed by the client. Next best approach may be to have the facilitator send recommended parameters so the resource server can send those to the client before transaction construction.
As a bonus, I suspect that to get true adoption in Solana, with the high rent costs needed to open a token account, we'd need to support zkCompression (compressed SPL) down the line. Probably not a v1 item, but worth noting, in case the design can be future-proofed to it.
@alfonso-paella +1, all great considerations. I'm less familiar with smart wallets in the solana ecosystem, but if there are any additional considerations you or the squads team think need to be made either at the client layer of facilitator layer definitely please raise in this issue.
thanks @alfonso-paella -- appreciate the considerations
caught up with @littlejohntj (worked on solana pay) to get another perspective, to address the comments:
It's paramount for the facilitator to do transaction introspection to ensure it's only accepting transactions that strictly perform the intended payment. Otherwise, a malicious client can compromise the facilitator (relayer)'s funds by adding some malicious transactions for it to sign.
agree here -- best starting point imo is to reject transactions that do anything but a simple payment transfer to the facilitator. ideal state is more friendly -- (1) inspect for the payment ix (2) inspect that the facilitator isn't being asked to do anything other than pay the fee -- but can be adjusted for that later on
Handling blockhash expirations and retries
👍
Ensuring smart wallets (e.g. squads protocol based) work with the facilitator. I expect most AI agents will run with smart wallets (due to the programmatic ability to be controlled / limited by a separate owner). Happy to assist here or bring someone from squads to do so.
will chat with the squads folks (know them well), i don't see any immediate blockers
Handling the case that the server-side doesn't have a token account open (or requiring an account to be open prior to being able to receive payments?)
easiest starting point is to require an account to be open server-side before being able to receive payment imo -- in the future, cleanest way to support arbitrary token payments would be to include an exact out swap ix in the tx (sending arbitrary tokens to the facilitator would be pretty messy to manage on the facilitator side)
Handling priority fees -- an ideal design lets the facilitator set these at the time of sending but it wouldn't be possible if the transaction is partially signed by the client. Next best approach may be to have the facilitator send recommended parameters so the resource server can send those to the client before transaction construction.
will have to think about this -- not 100% sure off the top of my head what will work with the spec best. @erikreppel-cb thoughts?
As a bonus, I suspect that to get true adoption in Solana, with the high rent costs needed to open a token account, we'd need to support zkCompression (compressed SPL) down the line. Probably not a v1 item, but worth noting, in case the design can be future-proofed to it.
agree this isn't something we need to worry about immediately -- if we require token accounts to be created facilitator-side beforehand, we solve for this by putting the upfront work on the facilitator side (for now)
Next best approach may be to have the facilitator send recommended parameters so the resource server can send those to the client before transaction construction.
I'm definitely not the most educated on priority fees for solana, but we have considered adding an extra key to the response returned from /verify, that could be used to convey priority fee parameters on solana
A large reason that the facilitator settles transactions is to prevent tx reuse, without having to keep state of which transactions have been seen before, my preference would be to keep that paradigm.
this is already addressed with transaction signatures on Solana, deduplication happens at the validator level; we don't use nonces on Solana (prototypically) so there's no state management on the side of the facilitator, they can just crank out pre-signed transactions that require a second signature from the sender for debiting the token account
Handling the case that the server-side doesn't have a token account open (or requiring an account to be open prior to being able to receive payments?)
probably fine to assume the receiver of payments has a token account open denominated in the mint being requested in the payment, otherwise it wouldn't request payment in that token. one-time setup fee
Handling priority fees -- an ideal design lets the facilitator set these at the time of sending but it wouldn't be possible if the transaction is partially signed by the client. Next best approach may be to have the facilitator send recommended parameters so the resource server can send those to the client before transaction construction.
since the assumption is facilitator is paying for gas (this is a stablecoin payment) then facilitator should also send a fully pre-signed transaction covering relevant base + priority fees. end user just needs to sign for the debit of the stablecoin + send it and return the transaction signature to be verified by the backend
- this also addresses the scenario in which a facilitator is being asked to sign unknown transactions, since the facilitator is the one surfacing the relevant transaction to begin with
agree -- should be able to specify token address with the asset field. as an fyi, solana has two different token standards -- legacy TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA and the emerging TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb, but given adoption (and where it's heading) it's worth only supporting the legacy standard for now imo.
shouldn't matter, the mint addresses are unique anyway
the Payment Required payload can look identical to the Solana Pay transfer request which denominates:
- mint
- destination
- amount
- reference key (required)
which provides enough information for the client to handle settlement (see Solana Pay transfer request)
wallets increasingly handle transaction settlement because nefarious servers / dApps can opt to front-run user transactions, so having settlement out-of-band of the server is slightly safer. see Solana Pay validateTransfer
here's what it could look like:
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /api
Server->>Client: HTTP 402 - Payment Required
Client->>Client: Simulate, sign, send transaction
Client->>Server: Include Header: X-Payment: transaction signature
Server->>Solana: Verify transaction inclusion
Solana->>Server: Tx confirmed
Server->>Client: return response x-payment-response
the gasless version is slightly more complex since we don't know which token account to debit from, so in that flow the Payment Required payload has an endpoint to retrieve the relevant transaction by sending a POST { account } to retrieve a serialized transaction:
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /api
Server->>Client: HTTP 402 - Payment Required
Client->>Server: POST { account: pubkey }
Server->>Client: Return gasless transaction
Client->>Client: Simulate, sign, send transaction
Client->>Server: Include Header: X-Payment: transaction signature
Server->>Solana: Verify transaction inclusion
Solana->>Server: Tx confirmed
Server->>Client: return response x-payment-response
@jnwng this is great input
this is already addressed with transaction signatures on Solana, deduplication happens at the validator level; we don't use nonces on Solana (prototypically)
This actually isn't about the chain, its about the client being and to claim a payment has been made that was made in the past. In the send tx signature scenario an adversarial client can make multiple requests with the same tx signature that was processed onchain previously to get repeated resources access. If the facilitator or server isn't submitting the tx, one of them needs to store state of what txs have already been seen. If the facilitator or server is submitting the tx, they know for a fact its a new tx.
since the assumption is facilitator is paying for gas (this is a stablecoin payment) then facilitator should also send a fully pre-signed transaction covering relevant base + priority fees. end user just needs to sign for the debit of the stablecoin + send it and return the transaction signature to be verified by the backend
this also addresses the scenario in which a facilitator is being asked to sign unknown transactions, since the facilitator is the one surfacing the relevant transaction to begin with
this seems reasonable, so long as the client implementation has logic to verify transactions are as expected, blind signing a request from an server also seems bad. Facilitator propose, client confirm legit + partially sign, facilitator broadcast, seems like a good path here, let me know what you think
Would be happy to help with this @edgarpavlovsky
since the assumption is facilitator is paying for gas (this is a stablecoin payment) then facilitator should also send a fully pre-signed transaction covering relevant base + priority fees. end user just needs to sign for the debit of the stablecoin + send it and return the transaction signature to be verified by the backend
this also addresses the scenario in which a facilitator is being asked to sign unknown transactions, since the facilitator is the one surfacing the relevant transaction to begin with
this seems reasonable, so long as the client implementation has logic to verify transactions are as expected, blind signing a request from an server also seems bad. Facilitator propose, client confirm legit + partially sign, facilitator broadcast, seems like a good path here, let me know what you think
i see the intention here, but we'd either need to (a) refactor the entire protocol to follow facilitator-driven transaction construction (b) update the spec to include another field for the facilitator to return a partially-signed solana transaction in case the client wants to pay with solana, or (c) require an extra step in the flow where the client requests a partially signed transaction after being given the 402 response and indicating to the facilitator that they'd prefer to pay with solana
i'm open to these options (cc @erikreppel-cb), but for simplicity we'll put up a PR that follows client-side tx construction first and go from there so we have code on the board and don't get too buried in discussion alone
apologies for the delay, was on vacation.
Could the client not check the transaction they've received to see what programs are being called with which values? That would be my preference here as the client can then make an informed decision. In this scenario the resource server would include an transaction to sign in the extra field of the payment requirements object, meaning still 1 hop.
I liked @jnwng 's proposal as it feels like a clean fit for Solana.
One thing to consider for that design if it gets implemented is this:
The tx signature that the client sends back to the server needs to be signed by the client and verified by the server/facilitator.
This ensures that the correct payer is sending the tx signature to the server/facilitator, instead of a malicious actor that's watching for payments and then trying to use those tx signatures to get access to a resource that they did not pay for.
Had an offline chat with @erikreppel-cb .
x402 values protocol adoption, and wants to remove as much blockchain info from Resource Servers as possible. To make this happen, we've moved transaction creation out of the Server to the Client. In order to support gasless payments, Servers will include the Solana address of their facilitator in the extra field of their paymentRequirements response. Facilitators will cosign the transaction, send it & verify it on behalf of servers as usual.
Here's the updated sequence diagram:
sequenceDiagram
participant Client
participant Server
participant Facilitator
Client->>Server: GET /api
Server->>Client: HTTP 402 - Payment Required with { extra: { account: pubkey } }
Client->>Solana: GET /blockhash
Client->>Client: Form templated transaction, cosign, serialize
Client->>Server: Include Header: X-PAYMENT b64 payload
Server->>Facilitator: /verify
Facilitator->>Solana: Simulate, sign, send transaction
Solana->>Facilitator: Verify transaction inclusion
Facilitator->>Server: Confirm
Server->>Client: return response x-payment-response
We will put up a PR to support a reference implementation here soon.
Hey @ngundotra nice work!
That's more or less the implementation that I've been working on over the last month or so.
PR is almost finished cooking, I'll put it up later today as I've gone through most of the heavy lifting.
Hope it can be used!
@ngundotra amazing, excited for this!
Hey all, just submitted a PR for this!
Looking forward to gathering community feedback and implement changes!
https://github.com/coinbase/x402/pull/283
feel like we should close this
agree
Sent via Superhuman iOS ( @.*** )
On Fri, Oct 10, 2025 at 9:42 AM, pontus < @.*** > wrote:
pvams left a comment (coinbase/x402#131) ( https://github.com/coinbase/x402/issues/131#issuecomment-3390843917 )
feel like we should close this
— Reply to this email directly, view it on GitHub ( https://github.com/coinbase/x402/issues/131#issuecomment-3390843917 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AC32YXS3YHZVJIX5CAJSNST3W7HYHAVCNFSM6AAAAAB4VISKNWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGOJQHA2DGOJRG4 ). You are receiving this because you were mentioned. Message ID: <coinbase/x402/issues/131/3390843917 @ github. com>