Skip to content

Describe chain payment modes, profile, validation and enablement - #383

Merged
ctfbruce merged 23 commits into
mainfrom
docs/payments-operator-profile
Oct 5, 2026
Merged

ctfbruce merged 23 commits into
mainfrom
docs/payments-operator-profile

Conversation

@ctfbruce

@ctfbruce ctfbruce commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Behaviour

Documentation only. docs/operations/payments.md gains, around the existing lifecycle and reconciliation sections (unchanged):

  • Modes and what each records: the disabled and enabled modes (every shipped configuration is disabled), and the rows each payment method writes (transactions, debuglet_order, order_settlements, earnings, payment_receipts with its five dispositions, chain_transfers, the listener cursor).

  • Supported chain profile: Sui Testnet, the testnet USDC coin type the dispatcher carries (to be verified against the issuer's published identifier before enabling), testnet SUI for gas with the budget the transfer sets, no mainnet operation, no customer deposits; custody of the dispatcher's key by the host administrator through a dedicated deployment key in the keystore file, never a personal wallet.

  • Startup validation: the refusal of each [sui] field and of the keystore (the key must belong to the configured address), and the later checks of the stored cursor and of the indexer's reported coverage.

  • Enabling chain payments: an explicit operator decision that nothing in the repository or its CI performs; six steps ending in a rehearsal with one payment and one payout, and the checks that remain open until a live service confirms them (the GraphQL availableRange and Event.sequenceNumber fields, the stream and GraphQL event positions agreeing, catch-up receipts without a checkpoint, the receipt layout and coin type string, the computed digest against the chain's).

  • Schedules: the daily payout tick at local midnight, reconciliation every minute over at most 100 open transfers with reserved rows stale after ten minutes, the settlement pass every 30 seconds over at most 32 orders, and the two-minute submission bound.

  • Backups and restore: the backup page covers the TEST state only; a database restored from before its last chain transfer brings back balances and owed refunds that were already paid and nothing in the dispatcher prevents paying them again, so chain payments are switched off and the restored database reconciled against the address's chain history first.

docs/operations/configuration.md documents the [sui] keys and their startup checks; docs/README.md links the page.

Proof

Every statement is taken from the code on this branch (validation messages, coin type constant, gas budget, log lines, dispositions and states); the link check passes (66 links, 0 broken). No daemon, wallet or network is involved.

Upgrade

None.

Stacked on #381 (the payout and refund lifecycle the page describes); its commits show in the diff against main until it merges.

Limits

The enablement checklist describes operator steps; it performs nothing and no live-network step has been run. Usage allowances are documented with their own change (#380).

GitHub issue #87.

Candidate CI

The branch then took the corrected payout branch and the corrected allowances branch by merge (4a0cfce, then e5c2d9f with the allowances branch's composed head; the configuration reference keeps both new sections, usage allowances then chain payments); Run 37310342339 on e5c2d9f: 16 of 16 lanes and required succeeded. Run 37294990364 on 2cffd28: 16 of 16 lanes and required succeeded (the first head's run passed on attempt 2 after the local lane's known TestInstalledRecovery/terminated failure on code this branch does not touch).

TheodorAdrienIsaak Mattli added 7 commits October 5, 2026 10:36
A client could only learn a batch's price by creating a payment intent,
and could not see which payment features a dispatcher offers or page its
own intents. POST /payment/quote prices a batch with the same function
the intent uses and stops there: it writes nothing and issues no auth
key; a batch the intent would refuse is quoted with every problem on the
order it concerns and no total. The intent response carries the same
quote of the prices it stored, so a client can compare the two exactly.
GET /me reports the payment methods admitted now, whether chain payments
are enabled and whether allowances are offered; GET /me/orders pages the
account's intents with their orders, settlements and admitted runs. The
API contract moves to 1.15 and the Go client gains Quote and Orders.

GitHub issues #214 and #215.
Brings in the maintenance pass that retries only local settlements and
scans pending orders fairly, so this branch builds on the same settlement
behaviour its order history reads.

GitHub issues #214 and #215.
…work

Compose the corrected receipts and transfers head with the corrected
Sui adapter head (prepared transfers with a persisted identity, coin
selection without repeated objects) as the base of the payout
reservation and refund change, which uses both.

GitHub issue #80.
Compose the quotes and economics head with the corrected receipts and
transfers head (dispatcher schema 22) as the base of the allowance
grants change, which adds schema 23 above it and reports settlements
from the ledger both carry.

GitHub issue #83.
Dispatcher schema 23 adds immutable allowance grants per account. With
allowances enabled, a TEST intent is created by one guarded insert
inside the intent transaction when the sum of grants less the price of
settled orders (credit or refund alike) and of reserved orders covers
the new price; a refusal answers 429 allowance_exceeded and writes
nothing, and expired unused intents of the account are released first.
Nothing is granted at sign-up and grants do not renew. Add the
allowance view, the operator grant route (session only, idempotent by
key) and a read-only earnings view for executor owners, with scopes,
OpenAPI, documentation and client types. Disabled in every shipped
configuration.

GitHub issues #83 and #215.
Executor payouts zeroed the balance after the transfer, so earnings
credited in between were lost; refunds and payouts held a SQL
transaction across the chain call, and a transaction-wide refund wrote
order states unconditionally and refunded credited orders.

Give payouts and refunds one lifecycle: prepare the transfer (a chain
read), commit the local decision together with a reserved chain
transfer row carrying the digest, the signed transaction and its
signature, broadcast the signed transaction under a two-minute bound,
and record the outcome by a conditional write: sent, failed (a failed
payout releases its amount in the same write) or unknown. Reconcile
sent, unknown and stale reserved rows on the payout loop's ticker with
one lookup: confirmed with the expected effects, failed, or resubmitted
once from the identical stored bytes when the chain does not know the
transaction; anything unverified stays unknown. A payout reserves
exactly the balance it read and is refused while another is open;
refunds change the transaction status and each outstanding order
conditionally, with a refund settlement row, before the chain call.
The maintenance pass settles chain refunds of failed runs through the
same lifecycle and never selects an order with a refund transfer again.

GitHub issues #80 and #81.
The operations page explained the transfer lifecycle and reconciliation
but not what each payment method records, which chain profile this
build supports, what the dispatcher refuses at startup or how an
operator enables chain payments. Add those sections: the records of
each method in both modes; the supported profile (Sui Testnet, the
testnet USDC coin type to verify against the issuer's published
identifier, testnet SUI for gas, no mainnet, no deposits) and the
custody of the dispatcher's key by the host administrator through a
dedicated deployment key; the startup checks of every [sui] field and
of the keystore, and the later checks of the stored cursor and the
indexer's coverage; and the enablement checklist, an explicit operator
decision that nothing in the repository performs, ending in a rehearsal
with one payment and one payout and listing the checks that stay open
until a live service confirms them. Document the [sui] keys in the
configuration reference and link the page from the documentation index.

GitHub issue #87.
@ctfbruce ctfbruce added the In progress Implementation is active. label Oct 5, 2026
The page named the reconciliation interval and the stale bound only in
passing and said nothing about restoring a database. Add a schedules
list: the daily payout tick at local midnight, reconciliation every
minute over at most 100 open transfers with reserved rows stale after
ten minutes, the settlement pass every 30 seconds over at most 32
orders, and the two-minute submission bound after which an outcome is
unknown. Add a restore caveat under enablement: the backup page covers
the TEST state only, a database restored from before its last chain
transfer brings back balances and owed refunds that were already paid
and nothing in the dispatcher prevents paying them again, so chain
payments are switched off and the restored database is reconciled
against the address's chain history before the payout or settlement
pass runs again.

GitHub issue #87.
@ctfbruce ctfbruce added Review Implementation is ready for review and required validation. and removed In progress Implementation is active. labels Oct 5, 2026
@ctfbruce
ctfbruce marked this pull request as ready for review October 5, 2026 10:21
TheodorAdrienIsaak Mattli added 8 commits October 5, 2026 13:05
Bring the adapter branch at its corrected head, which validates a
listed coin's object id before normalizing it, under the payout and
refund lifecycle, so that the composed tree carries the correction the
transfer tests run against.

GitHub issues #80 and #81.
A quote priced an order whose start timestamp was impossible, or whose
policy required ICMP from an executor without it, without any error,
although the submission refuses both deterministically; the quote's
contract is to report every problem the dispatcher would report. Apply
the existing start-timestamp validation and the read-only capability
check in the pricing path, so that a quote and an intent report these
problems alike as per-order field errors; the quote still reserves
nothing and the submission still validates again. Correct the Go
client's description of Quote: the high-level submission does not
expose the intent's quote, so callers compare prices through the quote
itself or the raw intent response.

GitHub issues #214 and #215.
Bring the quotes and economics branch at its corrected head, where a
quote and an intent report start-time and capability problems alike,
under the allowance grants change, so that the composed tree carries
the correction the allowance intent path builds on.

GitHub issues #83 and #215.
Bring the receipts and transfers branch at its corrected head
(dispatcher schema 22) under the quotes and economics change, keeping
both version notes: the schema 22 paragraph and the API 1.15 paragraph
describe different boundaries and land on the same lines.

GitHub issues #214 and #215.
The remaining allowance was computed by unchecked 64-bit arithmetic
over three separately aggregated totals, so an account whose settled
TEST orders summed to the 64-bit maximum, with a further order
reserved, was shown a wrapped positive balance once allowances were
enabled; such history is reachable, since an executor may announce the
maximum price and an order priced at it is accepted. Check that each
aggregate and the subtraction fit before an allowance or a grant
response is produced, and answer a typed range refusal when the history
cannot be represented; nothing is wrapped or clamped, and the
reservation keeps failing closed on its single sum.

GitHub issues #83 and #215.
After a refund decision was committed, the transfer lifecycle returned
no outcome to its caller, so a buyer refused during maintenance was told
the payment had been refunded even when the transfer failed or its
outcome was unknown, and later requests repeated it. Return the
recorded outcome and word the refusal as sent, pending confirmation, or
recorded but not sent and owed; a repeated request reads the refund
transfer's state. The order stays unspendable after the decision.

A reconciliation lookup ran under the daemon's lifetime context on an
SDK path with no deadline, so one lookup that never completed stopped
every later row and all payouts. Bound each lookup; a timeout is
recorded as an unknown outcome with the reservation kept, and the pass
continues with the next row.

GitHub issues #80 and #81.
Bring the payout and refund branch at its corrected head under the
page, so that the page is published with the behaviour it describes:
the refund outcome reported to a refused buyer and the bounded
reconciliation lookups, together with the adapter's id validation.

GitHub issue #87.
Bring the allowances branch at its corrected head under the page, so
that the configuration reference keeps both of its new sections, usage
allowances and chain payments, which land on the same lines.

GitHub issue #87.
@ctfbruce
ctfbruce marked this pull request as draft October 5, 2026 12:10
@ctfbruce ctfbruce added In progress Implementation is active. and removed Review Implementation is ready for review and required validation. labels Oct 5, 2026
TheodorAdrienIsaak Mattli added 3 commits October 5, 2026 14:16
Bring the payout and refund branch at its corrected head, which carries
the corrected adapter and the listener fixture built for its payment
handler constructor, under the quotes and economics change, so that the
composed tree builds and tests as one.

GitHub issues #214 and #215.
Bring the quotes and economics branch at its composed head, which now
carries the payout and refund lifecycle and the corrected adapter, under
the allowance grants change, so that the composed tree builds and tests
as one; the allowance tests adapt to the payment handler constructor
that reports a configuration error.

GitHub issues #83 and #215.
Bring the allowances branch at its composed head, which carries the
quotes change on the payout branch and tests built for the payment
handler constructor that reports a configuration error, under the page,
so that the composed tree builds and tests as one.

GitHub issue #87.
@ctfbruce ctfbruce added Review Implementation is ready for review and required validation. and removed In progress Implementation is active. labels Oct 5, 2026
@ctfbruce
ctfbruce marked this pull request as ready for review October 5, 2026 13:30
TheodorAdrienIsaak Mattli added 4 commits October 5, 2026 15:47
Include the accepted runtime, deployment, monitoring and SDK updates alongside payout reservation and refund reconciliation.

GitHub issues #80 and #81.
Keep quote pricing and account economics together with the current payout recovery, runtime, deployment and SDK updates.

GitHub issues #214 and #215.
Keep allowance accounting and owner earnings together with current quote pricing, payout recovery and main updates.

GitHub issues #83 and #215.
Keep the payment profile and enablement documentation together with the current allowance, payout recovery and main updates.

GitHub issue #87.
@ctfbruce
ctfbruce marked this pull request as draft October 5, 2026 14:03
@ctfbruce
ctfbruce marked this pull request as ready for review October 5, 2026 14:17
@ctfbruce
ctfbruce merged commit 465f808 into main Oct 5, 2026
16 checks passed
@vincent10400094
vincent10400094 deleted the docs/payments-operator-profile branch October 8, 2026 00:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review Implementation is ready for review and required validation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant