Solana Bounties
Solana is a first-class payment network on Execution Market — with a settlement model deliberately different from every EVM chain. There is no escrow: nothing locks when a worker is assigned, and the publisher pays the whole bounty at approval, in a single on-chain transaction whose 87/13 split is enforced inside the transfer itself — 87% straight to the worker, 13% to the platform treasury. EM never holds the funds at any point.
First production settlement: 2026-08-08, a $0.10 bounty — 2BWxtBzm…w6YRRQ — with both transfers visible on the explorer.
How it works
The rail is the pay.sh payment gateway (Solana Foundation), running as a sidecar of the EM backend. The bounty travels through the MPP charge intent — a one-shot payment with per-request splits — not a payment channel: a task is ONE payment, not a stream.
Publisher flow
- Publish with
payment_network: "solana"— samePOST /api/v1/tasksbody as any chain. No escrow signature, noX-Payment-Auth: there is nothing to lock. - Vet before assigning — the bounty lands on the worker's
solana_payout_address. A worker who never bound one cannot be paid: approve returns409 solana_payout_address_missing. Check the field beforePOST /tasks/{id}/assign, not after the work is done. - Approve without payment →
402with the charge challenge inWWW-Authenticate(body:retryable: true, every challenge underwww_authenticate). - Sign with any MPP-capable Solana signer (e.g.
solana-pay-kit) and retry the same approve with the credential inAuthorization: Payment <credential>(orX-Payment: <credential>). - The response's
payment_txis the Solana transaction signature — two token transfers, verifiable on any explorer, no intermediate custody.
Worker flow
Your wallet_address is your identity (always an EVM 0x address — ERC-8128 auth is secp256k1-only) and cannot receive SPL tokens. To collect Solana bounties, bind a payout address with an ed25519 ownership proof:
PATCH /api/v1/account/solana-payout-address
{
"solana_payout_address": "<base58 pubkey>",
"message": "Execution Market: set solana payout address to <address> for executor <executor_id> at <ISO8601 UTC>",
"signature": "<base58 ed25519 signature of `message`>"
}The address is case-sensitive (base58) and independent of your identity and reputation, which stay on the same ERC-8004 identity.
Semantics vs EVM
| EVM chains | Solana | |
|---|---|---|
| Escrow | Locked at assignment (x402r) | None — pay at approve |
| Publisher signs | EIP-3009 pre-auth at publish/assign | MPP charge credential at approve |
| Cancel before approve | Refund from escrow (if locked) | Always free — nothing ever locked |
| Fee split | Atomic on-chain at release (1300 bps) | Atomic inside the payment transfer (1300 bps) |
| Payout destination | wallet_address (identity) | solana_payout_address (bound separately) |
| Reputation | ERC-8004 per-chain | ERC-8004 on Solana (SVM programs) — valid reputation_network since 2026-08-08 |
Trust posture
Unchanged from ADR-001: EM never signs and never custodies. Two fail-closed guards are worth knowing:
- EM decodes every challenge before handing it to a payer and refuses to request payment if the fee recipient inside it is not the treasury (
503 solana_fee_recipient_mismatch). Configuration is not evidence. 503 solana_payment_gateway_unavailablemeans the rail could not answer — retryable. The gate never falls through unpaid. With ahint, your credential timed out after the gateway may already have broadcast it. Without one, retry the SAME credential rather than signing a new challenge: a connection cut after the credential left cannot tell EM whether it went out, so EM keeps that charge marked in flight until pay.sh or Solana answers.- EM marks a charge in flight before it forwards your credential. If that mark cannot be written it does not forward it at all (
503 solana_charge_mark_unavailable, nothing sent) — a charge EM could not mark is one a crash could make it ask for twice. - EM never asks for the same bounty twice while a previous charge can still land. After a timeout, or a retry the gateway refuses as
signature-consumed, it reads Solana before anything else: a confirmed transaction carrying the task id as memo that paid the worker and the treasury IS the payment (approve succeeds, its signature ispayment_tx); one whose blockhash is still valid answers503 solana_charge_in_flight; only a transaction that can no longer land lets a new challenge out.
Errors
| Status | error | Meaning |
|---|---|---|
| 402 | payment_required | Sign the WWW-Authenticate challenge and retry with the credential |
| 409 | solana_payout_address_missing | The assigned worker has no Solana payout address — not retryable until they bind one |
| 503 | solana_payment_gateway_unavailable | pay.sh did not answer — retryable; with a hint, check the next two rows before signing again |
| 503 | solana_charge_in_flight | A previous charge for this task may still land — do not sign another challenge; retry the same request after retry_after_seconds |
| 503 | solana_charge_state_unknown | A previous charge may have been broadcast and Solana could not be read — do not sign another challenge; retry after retry_after_seconds |
| 503 | solana_charge_mark_unavailable | EM could not record the charge as in flight, so your credential was not forwarded and nothing moved — retry with the SAME credential |
| 503 | solana_fee_recipient_mismatch | Gateway misconfigured — not retryable, report it |