Main site

Integration

Connecting an application to a reserve.

This page will cover connecting an application to a reserve: obtaining spending rights, submitting intents, and handling settlement. The shape is described below so the structure is clear; the specifics need the implementation to be pinned down first.

This page is a scaffold. Everything below describes what an integration involves, based on the protocol model. It contains no endpoints, addresses, signatures or parameters, because inventing those would be worse than leaving them out. Fill each section in against the real implementation.

What an integration involves

  1. Choose a reserve

    An application spends against a specific reserve, whose policy determines what it can do. Selecting one is the first decision, and it is a product decision as much as a technical one.

  2. Obtain spending rights

    A user must be granted rights against that reserve before anything can be spent. This is the step with the most surface area, and the one to document most carefully.

  3. Submit an intent

    State the action and its parameters, bound to the right being exercised. See Intents.

  4. Handle the outcome

    Settlement or failure. Because nothing moves unless verification passes, there is no partial state to reconcile, which makes error handling simpler than in a transfer-based flow.

The shape of it

Illustrative only. The names below are not an API; they exist to show how the pieces relate, and to make the difference from a transfer-based flow concrete.

// 1. a reserve, and the policy it enforces
const reserve = await null.reserve(RESERVE_ID)

// 2. rights are granted against that reserve, bounded and conditional.
//    note what is absent: no balance is read, and nothing is sent to the user.
const right = await reserve.grant({
  to:     userKey,
  amount: 25_000_000n,   // a ceiling, not a transfer
})

// 3. an intent says what should happen. On its own it does nothing.
const intent = {
  action: 'pay',
  to:     payee,
  amount: 4_000_000n,
}

// 4. the proof binds the right to this intent, so it cannot be
//    redirected to a different outcome.
const proof = await right.prove(intent)

// 5. verification is the gate. No valid proof, no settlement,
//    and no partial state to unwind if it fails.
await reserve.settle(intent, proof)

The line to notice is the one that is missing. There is no getBalance, because the user does not have one. An application asks what a user is permitted to do, never what they have.

To fill in

  • Supported chains, and the contract addresses on each.
  • How an application requests rights on a user's behalf, and what the user approves.
  • The intent format, and how it is bound to a right.
  • Submission: direct contract calls, an SDK, or an endpoint.
  • Errors, and which are retryable.
  • Fees, and who pays them.
  • Test environment, and how to get funded rights on it.

A note on shape

Integrations should be written against the authorization model rather than translated from a transfer model. The common mistake will be reaching for "check the user's balance", which has no equivalent here. The question an application asks is not how much do they have, but what are they permitted to do.