x402 icon indicating copy to clipboard operation
x402 copied to clipboard

Feature Request: Add Solana support to x402

Open edgarpavlovsky opened this issue 8 months ago • 20 comments

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 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
  • 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.

edgarpavlovsky avatar May 08 '25 01:05 edgarpavlovsky

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.

lqk8 avatar May 08 '25 02:05 lqk8

@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:

  1. resource server responds with: token_address, amount, fee_payer_address, pay_to_address
  2. client assembles a transaction to send SPL tokens specified, with feePayer set, to the pay_to_address, and paritally signs
  3. client sends partially sign tx in X-PAYMENT header
  4. 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 avatar May 08 '25 03:05 erikreppel-cb

@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:

  1. legacy
  2. 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

edgarpavlovsky avatar May 08 '25 19:05 edgarpavlovsky

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

erikreppel-cb avatar May 09 '25 19:05 erikreppel-cb

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:

  1. 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.
  2. Handling blockhash expirations and retries
  3. 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.
  4. 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?)
  5. 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 avatar May 09 '25 23:05 alfonso-paella

@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.

erikreppel-cb avatar May 13 '25 00:05 erikreppel-cb

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)

edgarpavlovsky avatar May 13 '25 17:05 edgarpavlovsky

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

erikreppel-cb avatar May 14 '25 00:05 erikreppel-cb

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 avatar May 14 '25 01:05 jnwng

@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

erikreppel-cb avatar May 14 '25 04:05 erikreppel-cb

Would be happy to help with this @edgarpavlovsky

notorious-d-e-v avatar May 16 '25 06:05 notorious-d-e-v

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

edgarpavlovsky avatar May 19 '25 02:05 edgarpavlovsky

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.

erikreppel-cb avatar May 27 '25 01:05 erikreppel-cb

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.

notorious-d-e-v avatar Jun 06 '25 13:06 notorious-d-e-v

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.

ngundotra avatar Jul 10 '25 21:07 ngundotra

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!

notorious-d-e-v avatar Jul 10 '25 22:07 notorious-d-e-v

@ngundotra amazing, excited for this!

erikreppel-cb avatar Jul 11 '25 01:07 erikreppel-cb

Hey all, just submitted a PR for this!

Looking forward to gathering community feedback and implement changes!

https://github.com/coinbase/x402/pull/283

notorious-d-e-v avatar Jul 11 '25 03:07 notorious-d-e-v

feel like we should close this

pvams avatar Oct 10 '25 15:10 pvams

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>

edgarpavlovsky avatar Oct 10 '25 15:10 edgarpavlovsky