1Do App

Session Pay

The wallet signs session boundaries, the session key authorizes only increasing cumulative totals, and any relayer may submit while the chain pays only the delta.

6 sectionsonedo-session-pay
01

Grant structure

Session Pay has no createSession transaction. The wallet signs SessionGrant offchain, and every settle call resubmits the grant, wallet signature, and session-key signature; the full authorization is not stored onchain.

The EIP-712 domain is Session Pay on 1Do / 1, bound to the current chainId and wallet verifyingContract. The wallet signature is checked through ERC-1271.

  • sessionKey and payee must be nonzero, and spendLimit must be greater than zero.
  • token fixes the payment asset: address(0) is native currency and any other address is ERC-20.
  • spendLimit is the cumulative cap for the entire session, not a per-payment limit.
  • sessionExpiresAt is the final submission timestamp. The grant remains valid exactly at that time and fails afterward; zero is immediately expired, not unlimited.
  • salt distinguishes independent grants whose other fields are identical.
Signed grant and settlement authorization
struct SessionGrant {
  address sessionKey;
  address payee;
  address token; // address(0) = native asset
  uint256 spendLimit;
  uint256 sessionExpiresAt;
  bytes32 salt;
}

struct SettlementAuthorization {
  bytes32 sessionId;
  uint256 newTotalPaid;
}
02

sessionId and two signatures

sessionId is the EIP-712 struct hash of SessionGrant, not the full domain-separated digest. Because it does not itself include chainId or the wallet, index and database keys should include at least chainId + wallet + sessionId.

The wallet selfSig authorizes the full grant boundary, while sessionSig covers only SettlementAuthorization(sessionId, newTotalPaid). Both signatures are checked on every settlement.

  • selfSig is verified through ERC-1271 on the executing wallet, binding the grant to that wallet and chain.
  • sessionSig uses standard ECDSA recovery and must recover grant.sessionKey; a contract wallet cannot currently act directly as the session key.
  • Any address may relay settle but cannot change payee, token, cap, expiry, or cumulative total.
03

Cumulative delta settlement

Step 1

Read onchain progress

The client reads previousTotalPaid and revoked for the wallet-scoped sessionId.

Step 2

Sign a new cumulative total

The session key signs newTotalPaid strictly above the previous value and no greater than spendLimit.

Step 3

Submit complete proof

A relayer submits grant, authorization, selfSig, and sessionSig; the app rechecks expiry, revocation, and both signatures.

Step 4

Pay only the delta

Payment equals newTotalPaid - previousTotalPaid. State advances first, then native currency or ERC-20 goes directly from the wallet to the fixed payee.

The cumulative total replaces a conventional nonce

There is no separate incrementing nonce for a sessionId. Old, equal, or lower totals fail the strict-increase check, so replaying an old authorization cannot pay again.

04

Revocation and lifecycle

  • revokeSession(sessionId) requires a wallet self-call. Revocation has no undo operation, and repeated calls do not emit another event.
  • Disabling the app does not clear totalPaid or revoked. Re-enabling the same logic lets an unexpired, unrevoked session continue from its prior total.
  • Expiry, cap exhaustion, and revocation are not stored as one status enum; clients derive them from the grant and wallet state.
  • An unknown sessionId and a new unpaid session both return totalPaid = 0 and revoked = false, so those values alone do not prove an offchain grant exists.
05

State reads, events, and SDK

  • Read totalPaid(sessionId), revoked(sessionId), and sessionState(sessionId) in the target wallet Runtime context.
  • SessionSettled records sessionId, payee, token, paymentAmount, newTotalPaid, and sessionKey; SessionRevoked records sessionId. The wallet is the event emitter.
  • sessionIdOf(grant) computes the struct hash. The SDK's technical OneDoSessionPay namespace provides grant/authorization hashes, typed data, and session-key signing helpers.
06

Funding and failure boundaries

  • A grant does not reserve funds or schedule automatic debits. settle is nonpayable, so the wallet must already hold enough native currency or ERC-20 when execution occurs.
  • Funds go directly from the wallet to grant.payee, never through the relayer. A token-transfer or native-recipient failure reverts the totalPaid update.
  • ERC-20 uses SafeERC20, but there is no net-receipt check for fee-on-transfer or rebasing tokens. paymentAmount is the requested wallet outflow, not a guarantee of identical payee receipt.
  • Invalid, expired, or revoked grants; mismatched sessionIds; non-increasing or over-limit totals; and either invalid signature all fail.
  • The asset and payee stay fixed for the grant. Changing any field produces a different sessionId and requires a new wallet signature.