For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Accept Tempo wallets signing with secp256k1, raw P-256, WebAuthn passkeys, or Keychain V2 access-key envelopes for EVM credits redemption on the Tempo chain.
Overview
Coinflow’s Tempo credits-redemption path accepts four signature shapes
through the same <CoinflowPurchase> integration:
secp256k1 — the standard EVM curve used by MetaMask and any EIP-1193
wallet.
P-256 (raw) — secp256r1 / NIST-P-256 keys signing a digest directly,
without the WebAuthn envelope. Useful for non-browser signers.
WebAuthn — P-256 keys held in a passkey authenticator (browser, OS
keychain, hardware key). Coinflow accepts root WebAuthn passkey signatures
for credits-only redemptions, so users do not need a separate
MetaMask-style secp256k1 wallet.
Keychain V2 access keys (0x04) — an authorized access key signing on
behalf of a root Tempo account, wrapped in a canonical Keychain V2
envelope. The wallet must register the access key on-chain via Tempo’s
AccountKeychain precompile before signing — see Tempo access-key wallets
(Keychain V2) below.
All four resolve through the same Coinflow checkout API. The merchant’s
<CoinflowPurchase> integration stays the same regardless of which signer
the user holds — only the bytes inside the permitCredits field differ.
Your app owns the registration / sign-in UI and passes a compatible
EthWallet adapter into <CoinflowPurchase>. Coinflow does not create or
store keys or passkeys for the merchant.
If you are also settling to a merchant contract on Tempo, your contract must
be whitelisted first. See Whitelist Your
Contracts.
What’s supported
Flow
Supported on Tempo
Notes
secp256k1 wallet redemption
✅
Works with any EIP-1193 wallet the same as on other EVM chains.
Raw P-256 (P256) wallet redemption
✅
Sign with a raw P-256 key via viem/tempoAccount.fromP256.
WebAuthn / passkey wallet redemption
✅
Integrated through Tempo’s webAuthn connector and a standard Coinflow EthWallet adapter.
Tempo access-key wallets (Keychain V2)
✅
Inner signature wrapped in a canonical 0x04 envelope. Requires prior on-chain access-key registration via AccountKeychain. See section below.
Tempo access-key wallets (Keychain V1)
❌
The 0x03 envelope was deprecated by the Tempo protocol post-T1C. Wallets must emit V2 (0x04).
Tempo access-key wallets (Keychain V2)
Tempo lets a root account authorize a separate access key to sign on its
behalf, sparing users a root-passkey prompt on every transaction. Coinflow
accepts these access-key signatures when the wallet emits a canonical
Keychain V2 envelope:
The wallet must complete the following BEFORE the customer reaches
checkout — Coinflow performs only the verification step:
Authorize the access key on-chain. The wallet submits a Tempo AA
transaction (type 0x76) carrying a key_authorization field, signed by
the root account’s secp256k1 / P-256 / WebAuthn key. The Tempo node
writes the authorization into the AccountKeychain precompile at
0xaAAA…0000. See Tempo’s
AccountKeychain spec
for the canonical registration flow.
Sign with the access key. The wallet signs the credits-auth digest
with the registered access key, wraps the inner signature in the V2
envelope, and returns the resulting bytes through EthWallet.signMessage
as usual.
Match the registered signature type. The on-chain signatureType
recorded for the access key (0=Secp256k1, 1=P-256, 2=WebAuthn) must
match the inner signature’s scheme. Mismatched types reject on-chain per
Tempo’s validate_keychain_authorization rule.
Common failure: unregistered access key
If the wallet emits a V2 envelope without registering the access key
first, Coinflow’s on-chain verification surfaces “Invalid credits auth
signature” to the user. The wallet team must either:
Implement the authorizeKey AA-transaction registration flow above, or
Downgrade to raw secp256k1 / 0x01 P-256 / 0x02 WebAuthn signatures,
which require no AccountKeychain registration.
Merchant integration impact
None. The merchant’s <CoinflowPurchase> integration code stays
identical — the customer’s wallet emits the V2 envelope, your EthWallet
adapter forwards the opaque bytes unchanged, and Coinflow’s contract
performs the keychain composition (TIP-1020 inner-signature recovery
followed by AccountKeychain authorization lookup) on-chain. No new SDK
parameters and no new API fields.
How it works
Your app — hosts the registration / sign-in UI, manages the signer
session, and exposes a standard EthWallet adapter to
<CoinflowPurchase>. The adapter routes Coinflow’s signMessage request
to whichever signer the user chose (secp256k1, raw P-256, or WebAuthn).
Nothing else in your Coinflow integration changes.
Coinflow — forwards the opaque signature bytes to Tempo’s on-chain
signature-verification precompile, which accepts any of the three types.
Coinflow does not need to know which type the user used.
Networks — Coinflow supports Tempo mainnet and the Moderato testnet.
Switch between them by changing the wagmi chain id — no other
configuration.
Constructing each signer with viem
The snippets below show the minimum viem / viem/tempo calls to construct
each signer type. In a real merchant integration, wrap the resulting
Account (or wagmi connection) inside an EthWallet adapter — see
Adapt the wagmi session to an EthWallet
below for the WebAuthn path; the secp256k1 / P-256 paths follow the same
shape.
The snippets below generate ephemeral keys at runtime for illustration only.
In production, derive keys from your secure key-management system and
never commit private keys to source control.
secp256k1
1
import {generatePrivateKey, privateKeyToAccount} from 'viem/accounts';
2
import {hashMessage, type Hex} from 'viem';
3
4
const privateKey = generatePrivateKey();
5
const account = privateKeyToAccount(privateKey);
6
7
const message = 'coinflow login challenge';
8
const digest = hashMessage(message) as Hex;
9
const signature = (await account.sign({hash: digest})) as Hex;
10
// 65-byte r||s||v signature ready to forward as `permitCredits`.
Raw P-256
1
import {Account as TempoAccount, P256 as TempoP256} from 'viem/tempo';
const signature = (await account.sign({hash: digest})) as Hex;
10
// Raw P-256 envelope (typeId 0x01) ready to forward as `permitCredits`.
WebAuthn (passkey)
For production browser flows, use Tempo’s wagmi webAuthn connector with a
remote KeyManager (covered in detail below). For headless / non-browser
contexts and tests, Account.fromHeadlessWebAuthn constructs a WebAuthn
signer from a P-256 key:
1
import {Account as TempoAccount, P256 as TempoP256} from 'viem/tempo';
The walkthrough below targets the WebAuthn / passkey case, which has the
most setup. The secp256k1 and raw P-256 paths reuse the same
<CoinflowPurchase> integration; only the signer backing
EthWallet.signMessage differs. For secp256k1 or P-256, use any wagmi
connector (injected, walletConnect, or a custom one wrapping a
viem/tempoAccount) and skip to
Adapt the wagmi session to an EthWallet.
1. Configure the Tempo webAuthn connector in your wagmi config
Register Tempo’s WebAuthn connector alongside your existing EVM
connectors. Use a remote key manager in production. Use
KeyManager.localStorage() for demos only: it stores the credential /
public-key mapping in the browser, so clearing storage or switching
devices breaks lookup. (The passkey key material itself stays in the
authenticator.)
KeyManager.localStorage() is demo-only — ship a server-backed
KeyManager.http(url) before production. The snippet below disables the
connector entirely in production builds when VITE_TEMPO_KEY_MANAGER_URL
is missing, preventing silent fallback to browser storage.
1
// ContextWrapper.tsx
2
import {KeyManager, webAuthn} from '@wagmi/core/tempo';
3
import {createConfig, http, WagmiProvider} from 'wagmi';
4
import {
5
tempo,
6
tempoModerato /* ...plus your other chains */,
7
} from 'wagmi/chains';
8
import {injected, walletConnect} from 'wagmi/connectors';
The connector accepts a capabilities argument on connect() that
selects between registering a new passkey (sign-up) and authenticating
with an existing one (sign-in). Pass the Tempo chain id when connecting
so the connector session targets the same Tempo network Coinflow uses.
1
import {tempo, tempoModerato} from 'wagmi/chains';
2
import {useConnect, useConnections, useDisconnect} from 'wagmi';
3
import {TEMPO_WEBAUTHN_CONNECTOR_TYPE} from './ContextWrapper';
3. Adapt the wagmi session to an EthWallet for <CoinflowPurchase>
Coinflow’s iframe passes EIP-712 typed data into signMessage as a
JSON-stringified object — the same shape secp256k1 merchants already
handle. Parse the string, detect the EIP-712 shape, and route typed data
through wagmi’s useSignTypedData (which invokes the chosen connector).
Let typed-data errors surface — do not retry as personal_sign.
1
import {useCallback} from 'react';
2
import {useConnections, useSignMessage, useSignTypedData} from 'wagmi';
3
import type {Hex} from 'viem';
4
import type {EthWallet} from '@coinflowlabs/react';
5
import {TEMPO_WEBAUTHN_CONNECTOR_TYPE} from './ContextWrapper';
The signMessage adapter from step 3 also handles Coinflow’s login
challenge. Users sign in with their Tempo signer (secp256k1, P-256, or
WebAuthn) with no extra client-side code.
Errors your users may see
The Coinflow iframe surfaces this message to the user during the Tempo
signature flow:
When it happens
What the user sees
The signature cannot be verified on-chain
Invalid credits auth signature.
Operational notes
Production key storage (WebAuthn). Point KeyManager.http(url) at a
server-side key store. KeyManager.localStorage() is demo-only — it
stores the credential / public-key mapping in the browser, so the app
loses the mapping when browser storage is cleared or the user switches
devices.
Same OpenAPI shape across all three signer types. Coinflow adds no
new request / response fields. The permitCredits field carries the
opaque signature bytes for whichever signer the user used.