@faremeter/payment-solana/flex/client to pay for an HTTP resource.
For a complete reference implementation including transaction confirmation, grace-period waits, and full teardown, see scripts/solana-example/flex-payment.ts in the faremeter monorepo.
Prerequisites
- Node.js 18+
- A Solana devnet keypair with some SOL for rent and transaction fees
- Devnet USDC in the keypair’s token account (Circle faucet, select Solana devnet)
- The address of a Flex-capable facilitator (the same key the merchant declares as
facilitatorin their requirements)
Set up the RPC, signer, and helpers
Create
main.ts. The sendInstructions and confirmSignature helpers below are reused throughout the rest of the steps.main.ts
Create the escrow
main.ts
The escrow PDA is derived from
[b"escrow", owner, index]. Pass a unique
index per escrow you want to keep open with the same facilitator.
Date.now() is used here for convenience — production code should track
indices deliberately.Deposit funds
main.ts
MAX_MINTS = 8 distinct token mints.Register a session key
main.ts
sessionKeyPair somewhere durable. You’ll use it for every payment authorization until you revoke it. Treat it like any other private key — leaking it lets an attacker sign authorizations, though they still can’t drain funds without colluding with the facilitator.What just happened
The handler:- Inspects the server’s payment requirements and matches on
(scheme, network, mint). - Picks a
maxAmountfrom the requirements and a freshauthorizationId. - Builds a serialized authorization using
serializePaymentAuthorizationand signs it with the session key. - Returns the signed payload;
@faremeter/fetchretries the request with thePAYMENT-SIGNATUREheader set.
Cleanup (optional)
Tearing down state cleanly requires coordination with the facilitator (who must co-signclose_escrow). The end-to-end sequence is:
- Wait for in-flight settlements to land on-chain. Poll
fetchEscrowAccountuntilpendingCountreflects everything you expect. - Issue refunds for any pending settlements you don’t want finalized. This is a facilitator-signed instruction (
getRefundInstruction); merchants typically trigger it via their own tooling. - Revoke the session key, wait out the grace period, then close it (
getRevokeSessionKeyInstruction→getCloseSessionKeyInstruction). - Close the escrow.
getCloseEscrowInstructionneeds both the owner and the facilitator asTransactionSigners, plusmint_count * 2writable remaining accounts (alternatingvaultPDA + owner-controlled destination per mint).
flex-payment.ts in the faremeter monorepo.
If the facilitator has gone dark, the owner can recover funds without their cooperation. Once current_slot > last_activity_slot + deadman_timeout_slots, run void_pending for each open pending settlement (escrow owner is allowed to call it under deadman conditions), revoke and close every session key, then call emergency_close. emergency_close requires pending_count == 0 AND session_key_count == 0, so the cleanup order matters.
What’s next
- Concepts — the protocol-level model behind these calls.
- Facilitator — the operator side: hold management and settlement.
- Program Reference — every on-chain instruction, account, and constraint.
- API Reference — the full
@faremeter/flex-solanasurface.