accounts
Version:
Tempo Accounts SDK
833 lines (784 loc) • 26.8 kB
text/typescript
import type { SignatureEnvelope } from 'ox/tempo'
import * as z from 'zod/mini'
import * as Schema from '../internal/schema.js'
import * as u from './utils.js'
export const log = z.object({
address: u.address(),
blockHash: u.hex(),
blockNumber: u.bigint(),
data: u.hex(),
logIndex: u.number(),
removed: z.boolean(),
topics: z.readonly(z.array(u.hex())),
transactionHash: u.hex(),
transactionIndex: u.number(),
})
export const receipt = z.object({
blobGasPrice: z.optional(u.bigint()),
blobGasUsed: z.optional(u.bigint()),
blockHash: u.hex(),
blockNumber: u.bigint(),
contractAddress: z.nullable(u.address()),
cumulativeGasUsed: u.bigint(),
effectiveGasPrice: u.bigint(),
feePayer: z.optional(u.address()),
feeToken: z.optional(u.address()),
from: u.address(),
gasUsed: u.bigint(),
logs: z.array(log),
logsBloom: u.hex(),
root: z.optional(u.hex()),
status: z.codec(u.hex(), z.enum(['success', 'reverted']), {
decode: (value) => (value === '0x1' ? 'success' : 'reverted'),
encode: (value) => (value === 'success' ? '0x1' : '0x0'),
}),
to: z.nullable(u.address()),
transactionHash: u.hex(),
transactionIndex: u.number(),
type: u.hex(),
})
export const signatureEnvelope = z.custom<SignatureEnvelope.SignatureEnvelopeRpc>()
export const keyType = z.union([z.literal('secp256k1'), z.literal('p256'), z.literal('webAuthn')])
export const keyAuthorization = z.object({
address: z.optional(u.address()),
chainId: u.bigint(),
expiry: z.union([u.number(), z.null(), z.undefined()]),
keyId: u.address(),
keyType,
limits: z.optional(
z.readonly(
z.array(z.object({ token: u.address(), limit: u.bigint(), period: z.optional(u.number()) })),
),
),
signature: signatureEnvelope,
})
export const call = z.object({
data: z.optional(u.hex()),
to: z.optional(u.address()),
value: z.optional(u.bigint()),
})
export const transactionRequest = z.object({
accessList: z.optional(
z.array(z.object({ address: u.address(), storageKeys: z.array(u.hex()) })),
),
calls: z.optional(z.readonly(z.array(call))),
chainId: z.optional(u.number()),
data: z.optional(u.hex()),
feePayer: z.optional(z.union([z.boolean(), z.string()])),
feePayerSignature: z.optional(z.record(z.string(), z.unknown())),
feeToken: z.optional(u.address()),
from: z.optional(u.address()),
gas: z.optional(u.bigint()),
keyAuthorization: z.optional(keyAuthorization),
keyData: z.optional(u.hex()),
keyId: z.optional(u.address()),
keyType: z.optional(keyType),
maxFeePerGas: z.optional(u.bigint()),
maxPriorityFeePerGas: z.optional(u.bigint()),
nonce: z.optional(u.number()),
nonceKey: z.optional(u.bigint()),
to: z.optional(u.address()),
validAfter: z.optional(u.number()),
validBefore: z.optional(u.number()),
value: z.optional(u.bigint()),
})
export namespace eth_accounts {
export const schema = Schema.defineItem({
method: z.literal('eth_accounts'),
params: undefined,
returns: z.readonly(z.array(u.address())),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace eth_chainId {
export const schema = Schema.defineItem({
method: z.literal('eth_chainId'),
params: undefined,
returns: u.hex(),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace eth_requestAccounts {
export const schema = Schema.defineItem({
method: z.literal('eth_requestAccounts'),
params: undefined,
returns: z.readonly(z.array(u.address())),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace eth_sendTransaction {
export const schema = Schema.defineItem({
method: z.literal('eth_sendTransaction'),
params: z.readonly(z.tuple([transactionRequest])),
returns: u.hex(),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace eth_fillTransaction {
const balanceDiff = z.object({
address: u.address(),
decimals: z.number(),
direction: z.enum(['incoming', 'outgoing']),
formatted: z.string(),
name: z.string(),
recipients: z.readonly(z.array(u.address())),
symbol: z.string(),
value: u.hex(),
})
const swapAmount = z.object({
decimals: z.number(),
formatted: z.string(),
name: z.string(),
symbol: z.string(),
token: u.address(),
value: u.hex(),
})
export const schema = Schema.defineItem({
method: z.literal('eth_fillTransaction'),
params: z.readonly(z.tuple([transactionRequest])),
returns: z.object({
capabilities: z.object({
balanceDiffs: z.optional(z.record(u.address(), z.readonly(z.array(balanceDiff)))),
error: z.optional(
z.object({
abiItem: z.optional(z.record(z.string(), z.unknown())),
data: z.optional(u.hex()),
errorName: z.string(),
message: z.string(),
}),
),
fee: z.optional(
z.object({
amount: u.hex(),
decimals: z.number(),
formatted: z.string(),
symbol: z.string(),
}),
),
requireFunds: z.optional(
z.object({
amount: u.hex(),
decimals: z.number(),
formatted: z.string(),
token: u.address(),
symbol: z.string(),
}),
),
autoSwap: z.optional(
z.object({
maxIn: swapAmount,
minOut: swapAmount,
slippage: z.number(),
}),
),
sponsor: z.optional(
z.object({
address: u.address(),
name: z.optional(z.string()),
url: z.optional(z.string()),
}),
),
sponsored: z.boolean(),
}),
tx: z.record(z.string(), z.unknown()),
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace eth_signTransaction {
export const schema = Schema.defineItem({
method: z.literal('eth_signTransaction'),
params: z.readonly(z.tuple([transactionRequest])),
returns: u.hex(),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace eth_sendTransactionSync {
export const schema = Schema.defineItem({
method: z.literal('eth_sendTransactionSync'),
params: z.readonly(z.tuple([transactionRequest])),
returns: receipt,
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace eth_signTypedData_v4 {
export const schema = Schema.defineItem({
method: z.literal('eth_signTypedData_v4'),
params: z.readonly(z.tuple([u.address(), z.string()])),
returns: u.hex(),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace personal_sign {
export const schema = Schema.defineItem({
method: z.literal('personal_sign'),
params: z.readonly(z.tuple([u.hex(), u.address()])),
returns: u.hex(),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
const sendCallsCapabilities = z.optional(
z.object({
feePayer: z.optional(z.union([z.boolean(), z.string()])),
sync: z.optional(z.boolean()),
}),
)
export namespace wallet_sendCalls {
export const schema = Schema.defineItem({
method: z.literal('wallet_sendCalls'),
params: z.optional(
z.readonly(
z.tuple([
z.object({
atomicRequired: z.optional(z.boolean()),
calls: z.readonly(z.array(call)),
capabilities: sendCallsCapabilities,
chainId: z.optional(u.number()),
from: z.optional(u.address()),
version: z.optional(z.string()),
}),
]),
),
),
returns: z.object({
atomic: z.optional(z.boolean()),
capabilities: sendCallsCapabilities,
chainId: z.optional(u.number()),
id: z.string(),
receipts: z.optional(z.array(receipt)),
status: z.optional(z.number()),
version: z.optional(z.string()),
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_getBalances {
export const schema = Schema.defineItem({
method: z.literal('wallet_getBalances'),
params: z.optional(
z.readonly(
z.tuple([
z.object({
account: z.optional(u.address()),
chainId: z.optional(u.number()),
tokens: z.optional(z.readonly(z.array(u.address()))),
}),
]),
),
),
returns: z.readonly(
z.array(
z.object({
address: u.address(),
balance: u.bigint(),
decimals: z.number(),
display: z.string(),
name: z.string(),
symbol: z.string(),
}),
),
),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_getCapabilities {
export const schema = Schema.defineItem({
method: z.literal('wallet_getCapabilities'),
params: z.optional(
z.readonly(
z.union([z.tuple([u.address()]), z.tuple([u.address(), z.readonly(z.array(u.hex()))])]),
),
),
returns: z.record(
u.hex(),
z.object({
accessKeys: z.optional(
z.object({
status: z.union([z.literal('supported'), z.literal('unsupported')]),
}),
),
atomic: z.object({
status: z.union([z.literal('supported'), z.literal('ready'), z.literal('unsupported')]),
}),
feePayer: z.optional(
z.object({
status: z.union([z.literal('supported'), z.literal('unsupported')]),
}),
),
}),
),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_authorizeAccessKey {
export const parameters = z.object({
address: z.optional(u.address()),
chainId: z.optional(u.bigint()),
expiry: z.number(),
keyType: z.optional(keyType),
limits: z.optional(
z.readonly(
z.array(
z.object({ token: u.address(), limit: u.bigint(), period: z.optional(z.number()) }),
),
),
),
publicKey: z.optional(u.hex()),
scopes: z.optional(
z.readonly(
z.array(
z.object({
address: u.address(),
selector: z.optional(z.union([u.hex(), z.string()])),
recipients: z.optional(z.readonly(z.array(u.address()))),
}),
),
),
),
})
export const returns = z.object({
keyAuthorization,
rootAddress: u.address(),
})
export const schema = Schema.defineItem({
method: z.literal('wallet_authorizeAccessKey'),
params: z.readonly(z.tuple([parameters])),
returns,
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_authorizeAccessKey_strict {
export const parameters = z.object({
address: z.optional(u.address()),
expiry: z.number(),
keyType: z.optional(keyType),
limits: z.readonly(
z
.array(z.object({ token: u.address(), limit: u.bigint(), period: z.optional(z.number()) }))
.check(z.minLength(1)),
),
publicKey: z.optional(u.hex()),
scopes: z.readonly(
z
.array(
z.object({
address: u.address(),
selector: z.optional(z.union([u.hex(), z.string()])),
recipients: z.optional(z.readonly(z.array(u.address()))),
}),
)
.check(z.minLength(1)),
),
})
}
export namespace wallet_revokeAccessKey {
export const schema = Schema.defineItem({
method: z.literal('wallet_revokeAccessKey'),
params: z.readonly(
z.tuple([z.object({ address: u.address(), accessKeyAddress: u.address() })]),
),
returns: undefined,
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_connect {
export const authorizeAccessKey = z.optional(wallet_authorizeAccessKey.parameters)
/**
* SIWE round-trip configuration. Bare string is shorthand for `{ url }`.
*
* - `auth: '/api/auth'` derives `${url}/challenge`, `${url}` (verify), `${url}/logout`.
* - Object form lets callers override individual endpoints, opt into a
* `{ token }` body via `returnToken`, etc.
*
* Cross-field validation (must include `url` or both `challenge` + `verify`)
* is enforced inside `prepareSiwe`, not in zod, so the error message can be
* specific.
*/
export const auth = z.optional(
z.union([
z.string(),
z.object({
/** Base URL. SDK derives `${url}/challenge` and `${url}/logout`; `${url}` itself is verify. */
url: z.optional(z.string()),
/** Override individual endpoints. Either `url` or both `challenge` + `verify` must be set. */
challenge: z.optional(z.string()),
verify: z.optional(z.string()),
logout: z.optional(z.string()),
/**
* Ask the verify endpoint to also return `{ token }` in the JSON body.
* Default `false` — cookie mode relies on `Set-Cookie` only.
* Set this for non-browser clients (RN, CLI) that can't store cookies, or
* to surface the JWT alongside a cookie in dual-transport setups.
*/
returnToken: z.optional(z.boolean()),
}),
]),
)
/**
* Request a `personal_sign` (EIP-191) over the supplied message during
* `wallet_connect`. The wallet computes `hashMessage(message)` and signs
* the resulting 32-byte digest in the same passkey ceremony that loads
* or creates the account, so this costs no extra prompt over a plain
* `wallet_connect`. The signature is returned via the top-level
* `capabilities.signature` field on the connected account.
*/
export const personalSign = z.optional(
z.object({
/** Message to sign. The wallet applies the EIP-191 prehash. */
message: z.string(),
}),
)
export const capabilities = {
request: z.optional(
z.union([
z.object({
digest: z.optional(u.hex()),
authorizeAccessKey,
auth,
method: z.literal('register'),
name: z.optional(z.string()),
personalSign,
userId: z.optional(z.string()),
}),
z.object({
digest: z.optional(u.hex()),
credentialId: z.optional(z.string()),
authorizeAccessKey,
auth,
method: z.optional(z.literal('login')),
personalSign,
selectAccount: z.optional(z.boolean()),
}),
]),
),
result: z.object({
email: z.optional(z.nullable(z.string())),
keyAuthorization: z.optional(keyAuthorization),
/**
* Echo of the `personalSign` request, present iff the caller set
* `capabilities.personalSign` (or `capabilities.auth` folded a SIWE
* message into the same slot). The signature itself lives on the
* top-level `capabilities.signature` field.
*/
personalSign: z.optional(
z.object({
message: z.string(),
}),
),
signature: z.optional(u.hex()),
username: z.optional(z.nullable(z.string())),
/**
* SIWE round-trip output, populated when the request `auth` capability was set.
* `token` is present in JWT mode or when the request set `returnToken: true`.
* Cookie-mode default = `{}` (the session arrived via `Set-Cookie`).
*/
auth: z.optional(
z.object({
token: z.optional(z.string()),
}),
),
}),
}
export const schema = Schema.defineItem({
method: z.literal('wallet_connect'),
params: z.optional(
z.readonly(
z.tuple([
z.object({
capabilities: capabilities.request,
chainId: z.optional(u.number()),
version: z.optional(z.string()),
}),
]),
),
),
returns: z.object({
accounts: z.readonly(
z.array(
z.object({
address: u.address(),
capabilities: capabilities.result,
}),
),
),
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_connect_strict {
const authorizeAccessKey = z.optional(wallet_authorizeAccessKey_strict.parameters)
const auth = wallet_connect.auth
const personalSign = wallet_connect.personalSign
export const parameters = z.object({
capabilities: z.optional(
z.union([
z.object({
digest: z.optional(u.hex()),
authorizeAccessKey,
auth,
method: z.literal('register'),
name: z.optional(z.string()),
personalSign,
userId: z.optional(z.string()),
}),
z.object({
digest: z.optional(u.hex()),
credentialId: z.optional(z.string()),
authorizeAccessKey,
auth,
method: z.optional(z.literal('login')),
personalSign,
selectAccount: z.optional(z.boolean()),
}),
]),
),
chainId: z.optional(u.number()),
version: z.optional(z.string()),
})
}
export namespace wallet_disconnect {
export const schema = Schema.defineItem({
method: z.literal('wallet_disconnect'),
params: undefined,
returns: undefined,
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_getCallsStatus {
export const schema = Schema.defineItem({
method: z.literal('wallet_getCallsStatus'),
params: z.optional(z.readonly(z.tuple([z.string()]))),
returns: z.object({
atomic: z.boolean(),
chainId: u.number(),
id: z.string(),
receipts: z.optional(z.array(receipt)),
status: z.number(),
version: z.string(),
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_transfer {
/**
* Parameters for `wallet_transfer`.
*
* Discriminated on `editable`:
*
* - omitted or `false` (default): Read-only. `amount` is a
* human-readable string (e.g. `"1.5"`), `to` and `token` are
* required, no editable UI is shown. Uses an access key when one
* matches (signs without UI), otherwise falls back to a confirm
* dialog the user has to approve.
* - `true`: Editable. Wallet shows a UI with optional fields
* pre-filled; the user confirms or edits before signing.
*/
export const parameters = z.discriminatedUnion('editable', [
z.object({
/** Human-readable amount to transfer (e.g. `"1.5"`). */
amount: z.string(),
/** Chain id. Defaults to the active chain. */
chainId: z.optional(u.number()),
/** Skip the editable wallet UI (Read-only mode). @default false */
editable: z.optional(z.literal(false)),
/**
* Fee payer override. `false` to disable the wallet's default fee
* payer, a URL string to use a custom fee payer service.
*/
feePayer: z.optional(z.union([z.boolean(), z.string()])),
/**
* Address to transfer tokens from. Defaults to the active account.
* When set to a different address, the call uses `transferFrom` and
* requires the active account to have an allowance from `from`.
*/
from: z.optional(u.address()),
/**
* UTF-8 memo to attach to the transfer (max 32 bytes when encoded
* as UTF-8). Sent via `transferWithMemo` / `transferFromWithMemo`.
*/
memo: z.optional(z.string()),
/** Recipient address. */
to: u.address(),
/**
* Token to transfer, accepted as either a contract address or a
* curated tokenlist symbol (case-insensitive, e.g. `"pathUsd"`).
* Symbols are resolved against the curated tokenlist on the active
* chain.
*/
token: z.union([u.address(), z.string()]),
}),
z.object({
/** Human-readable amount to pre-fill (e.g. `"1.5"`). */
amount: z.optional(z.string()),
/** Chain id. Defaults to the active chain. */
chainId: z.optional(u.number()),
/** Show the wallet UI for the user to confirm or edit. */
editable: z.literal(true),
/**
* Fee payer override. `false` to disable the wallet's default fee
* payer, a URL string to use a custom fee payer service.
*/
feePayer: z.optional(z.union([z.boolean(), z.string()])),
/**
* UTF-8 memo (max 32 bytes) to attach to the transfer. Wallet
* rejects the request if the selected token does not support
* memos (non-TIP-20).
*/
memo: z.optional(z.string()),
/** Recipient address to pre-fill. */
to: z.optional(u.address()),
/**
* Token to pre-fill, accepted as either a contract address or a
* curated tokenlist symbol (case-insensitive, e.g. `"pathUsd"`).
* Symbols are resolved against the curated tokenlist on the active
* chain. Omit to let the user choose.
*/
token: z.optional(z.union([u.address(), z.string()])),
}),
])
export const schema = Schema.defineItem({
method: z.literal('wallet_transfer'),
params: z.optional(z.readonly(z.tuple([parameters]))),
returns: z.object({
/** Chain id the send is to. */
chainId: u.number(),
/** Receipt of the submitted send. */
receipt,
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
const swapParameters = z.object({
/** Human-readable amount to pre-fill (e.g. "1.5"). */
amount: z.optional(z.string()),
/** Other side of the swap pair. For buys, this is the token to sell. For sells, this is the token to buy. */
pairToken: z.optional(u.address()),
/** Maximum allowed slippage as a decimal fraction (for example `0.05` for 5%). */
slippage: z.optional(z.number().check(z.minimum(0), z.maximum(1))),
/** Token to buy or sell. Omit to let the user choose. */
token: z.optional(u.address()),
/** Whether the amount is an exact buy amount (`swapExactAmountOut`) or sell amount (`swapExactAmountIn`). */
type: z.optional(z.union([z.literal('buy'), z.literal('sell')])),
})
/** Opens the wallet swap flow with optional pre-filled swap intent fields. */
export namespace wallet_swap {
export const schema = Schema.defineItem({
method: z.literal('wallet_swap'),
params: z.optional(z.readonly(z.tuple([swapParameters]))),
returns: z.object({
/** Receipt of the submitted swap. */
receipt,
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_switchEthereumChain {
export const schema = Schema.defineItem({
method: z.literal('wallet_switchEthereumChain'),
params: z.readonly(z.tuple([z.object({ chainId: u.number() })])),
returns: undefined,
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
export namespace wallet_deposit {
export const schema = Schema.defineItem({
method: z.literal('wallet_deposit'),
params: z.readonly(
z.tuple([
z.object({
address: z.optional(u.address()),
chainId: z.optional(u.number()),
displayName: z.optional(z.string()),
token: z.optional(u.address()),
value: z.optional(z.string()),
}),
]),
),
returns: z.optional(
z.object({
/**
* Receipts of any onchain operations performed during the
* deposit (e.g. testnet faucet drops). Absent for offchain
* paths like Apple Pay where funds arrive asynchronously.
*/
receipts: z.optional(z.readonly(z.array(receipt))),
}),
),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
/** Opens the wallet zone-deposit flow with optional pre-filled fields. */
export namespace wallet_depositZone {
/** Parameters object for `wallet_depositZone`. */
export const parameters = z.object({
/** Human-readable amount to pre-fill (e.g. "1.5"). */
amount: z.optional(z.string()),
/**
* Fee payer override. `false` to disable the wallet's default fee
* payer, a URL string to use a custom fee payer service.
*/
feePayer: z.optional(z.union([z.boolean(), z.string()])),
/** Token contract address to pre-fill. Omit to let the user choose. */
token: z.optional(u.address()),
/** Zone id to deposit into. */
zoneId: z.optional(u.number()),
})
export const schema = Schema.defineItem({
method: z.literal('wallet_depositZone'),
params: z.optional(z.readonly(z.tuple([parameters]))),
returns: z.object({
/** Receipt of the submitted deposit. */
receipt,
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
/** Opens the wallet zone-withdraw flow with optional pre-filled fields. */
export namespace wallet_withdrawZone {
/** Parameters object for `wallet_withdrawZone`. */
export const parameters = z.object({
/** Human-readable amount to pre-fill (e.g. "1.5"). */
amount: z.optional(z.string()),
/** Token contract address to pre-fill. Omit to let the user choose. */
token: z.optional(u.address()),
/** Zone id to withdraw from. */
zoneId: z.optional(u.number()),
})
export const schema = Schema.defineItem({
method: z.literal('wallet_withdrawZone'),
params: z.optional(z.readonly(z.tuple([parameters]))),
returns: z.object({
/** Receipt of the submitted withdrawal. */
receipt,
}),
})
export type Encoded = Schema.Encoded<typeof schema>
export type Decoded = Schema.Decoded<typeof schema>
}
/** Strict parameter schemas keyed by method name. */
export const strictParameters = {
wallet_authorizeAccessKey: wallet_authorizeAccessKey_strict.parameters,
wallet_connect: wallet_connect_strict.parameters,
} satisfies Partial<Record<string, z.ZodMiniType>>