Solana charge intent specification#188
Conversation
| "description": "Marketplace purchase", | ||
| "methodDetails": { | ||
| "network": "mainnet-beta", | ||
| "splToken": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", |
There was a problem hiding this comment.
nit: why not just token? spl is a bit redundant here given scope
| account to cover transaction fees | ||
| - MUST verify the transaction contents before signing | ||
| (see {{transaction-verification}}) | ||
| - MAY recover fee costs through pricing or other business |
There was a problem hiding this comment.
nit: probably not necessary for spec -- technical spec itself doesn't need to define social rules around how to monetize
| Details, with `Content-Type: application/problem+json`. | ||
| The following problem types are defined for this intent: | ||
|
|
||
| https://paymentauth.org/problems/solana/malformed-credential |
There was a problem hiding this comment.
for non-solana specific ones I think we can just use the standard error types
| ~~~json | ||
| { | ||
| "amount": "10000000", | ||
| "currency": "SOL", |
There was a problem hiding this comment.
can we use a lowercase currency here?
There was a problem hiding this comment.
in other cases we also just make this the token address directly (e.g. EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) -- do we need to define splToken? I imagine this may stem from the split of the SPL tokens vs native sol?
There was a problem hiding this comment.
Gotcha I think the mix symbol / address got me confused. I thought the "currency" had to be a ticker / human readable.
We'll match Tempo's approach.
| to present the same signature to the server. The | ||
| challenge binding (the credential echoes the challenge | ||
| `id`, which is HMAC-verified) and single-use signature | ||
| enforcement mitigate this: only the party that received |
There was a problem hiding this comment.
Question on push mode security semantics: is there intended to be any challenge-specific onchain binding beyond matching payment terms?
I see the credential echoing the challenge, and I see the server verifying an unused signature plus a transaction that matches amount / recipient / token. What I’m not sure about is whether the transaction itself is meant to prove that it was constructed for this specific challenge, rather than just for a payment with the same parameters.
For example, if two valid challenges exist for the same payment terms, could a party watching the chain present a matching transaction signature against their own challenge first? If the intent is to provide stronger challenge-specific guarantees in push mode, would it make sense to require a Memo carrying the challenge id, or some other onchain marker, so the transaction is explicitly tied to the issued challenge?
If not, it may be worth documenting push mode as having weaker challenge-specific binding than pull mode.
There was a problem hiding this comment.
Per my understanding, this does not materially diverge from the Tempo charge intent: requiring the memo to carry the challenge-id would strengthen challenge-instance binding, but it would also force additional on-chain correlation metadata, so the base spec leaves that privacy vs binding tradeoff to implementations.
Would love to get @brendanjryan's take!
There was a problem hiding this comment.
You are free to do whatever you want here, as long as you call out the tradeoffs.
In the tempo charge spec we are actively considering doing something like what was suggested in order to strengthen invariants, but this should be back compat
There was a problem hiding this comment.
Thanks @brendanjryan. added a note in 0c86f19
| MUST have the server's `feePayerKey` set as the fee | ||
| payer account. | ||
|
|
||
| 3. Simulate the transaction using the `simulateTransaction` |
There was a problem hiding this comment.
This reads like a MUST here, but the fee payer risks section later frames simulation as SHOULD.
For fee-payer mode, MUST seems right since the server is taking fee risk. For non-fee-payer mode, SHOULD seems reasonable
There was a problem hiding this comment.
Thanks, I did some back and forth on that one, it deserves a last pass I agree.
| ~~~json | ||
| { |
There was a problem hiding this comment.
This example is out of sync with the receipt schema above.
The schema defines challengeId, but this decoded receipt omits it. If challengeId is intended to be part of emitted receipts, it should appear here too.
| (`TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) or | ||
| the Token-2022 Program | ||
| (`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`). | ||
| If omitted, clients MUST determine the correct token |
There was a problem hiding this comment.
Worth specifying failure behavior here.
If the mint-owner lookup fails, clients should fail closed rather than falling back to the legacy Token Program, especially for Token-2022 assets.
alexanderattar
left a comment
There was a problem hiding this comment.
Overall this looks strong and close. The main thing I wanted to call out was push-mode challenge-specific binding. I left a few smaller consistency and operational comments as well.
| to present the same signature to the server. The | ||
| challenge binding (the credential echoes the challenge | ||
| `id`, which is HMAC-verified) and single-use signature | ||
| enforcement mitigate this: only the party that received |
There was a problem hiding this comment.
You are free to do whatever you want here, as long as you call out the tradeoffs.
In the tempo charge spec we are actively considering doing something like what was suggested in order to strengthen invariants, but this should be back compat
| 2. Verify the `mint` field matches the top-level | ||
| `currency` field from the challenge request. | ||
|
|
||
| 3. Verify the `tokenAmount.amount` field matches the |
There was a problem hiding this comment.
is this still true for splits as well? wouldn't this fail on a split payment of
account A: 10
account B: 1
we would check for 11 (10 + 1), when in reality the transfer should be 10
Spec Preview
Download spec artifacts (HTML, TXT, XML, PDF) |
Summary
Defines the charge intent for the solana payment method within the HTTP Payment Authentication Scheme. Supports
one-time payments in native SOL and SPL tokens (including Token-2022).
Settlement modes
retry.
Key features
Token-2022, etc.)
Request schema
Shared fields: amount, currency, recipient, description, externalId
Method details: network, splToken, decimals, tokenProgram, reference, feePayer, feePayerKey, splits, recentBlockhash
Reference implementation
solana-mpp-sdk - includes unit tests, integration tests, and an interactive demo.
AI assistance (Claude + Codex) were used in drafting this specification. All content has been reviewed for accuracy and RFC compliance.