From 5dc29ae9fab402c9ddc640ce121197d7e73a16cb Mon Sep 17 00:00:00 2001 From: Chris Hunter Date: Tue, 29 Sep 2026 20:02:22 -0400 Subject: [PATCH 1/6] build(vendor/aa): bundle Keystore-free eip8130 core from feat/aa-tx-split Bundle straight from the viem TypeScript sources instead of the stale _esm build, export only what the app imports, and rewrite index.d.ts to the EOA + delegation + ERC-8168 surface (no Keystore, WebAuthn or 4337). --- vendor/aa/build.mjs | 5 +- vendor/aa/entry.mjs | 61 +- vendor/aa/index.d.ts | 1172 ++--- vendor/aa/index.js | 10641 +++++++++-------------------------------- 4 files changed, 2461 insertions(+), 9418 deletions(-) diff --git a/vendor/aa/build.mjs b/vendor/aa/build.mjs index f51db800..9dbb3976 100644 --- a/vendor/aa/build.mjs +++ b/vendor/aa/build.mjs @@ -1,8 +1,9 @@ // Builds the self-contained AA vendor bundle from the sibling viem checkout. // // Prereqs: -// - ../viem checked out on branch feat/eip-8130-production -// - viem built: (cd ../viem && pnpm build) — produces src/_esm +// - ../viem checked out on branch feat/aa-tx-split +// - its dependencies installed: (cd ../viem && pnpm install) — the entry +// bundles the TypeScript sources directly, so no viem build is needed // // Run: bun run vendor/aa/build.mjs // diff --git a/vendor/aa/entry.mjs b/vendor/aa/entry.mjs index 77029124..015e724a 100644 --- a/vendor/aa/entry.mjs +++ b/vendor/aa/entry.mjs @@ -1,67 +1,60 @@ // Bundle entry for the self-contained "account abstraction" vendor module. // -// We can't `npm/bun install` viem 2.52.2 here: the cbhq registry mirror lacks -// its exact-pinned transitive deps (ox@0.14.29, @noble/*), and npmjs.org is -// unreachable. So we bundle the needed viem (+ ox/@noble) surface into a single -// self-contained ESM artifact (vendor/aa/index.js) with no external deps. +// The EIP-8130 / ERC-8168 surface isn't in a published viem release, so we +// bundle the needed viem (+ ox/@noble) surface into a single self-contained ESM +// artifact (vendor/aa/index.js) with no external deps. Only what the app +// imports from `@aa` is exported; keep index.d.ts in sync. // -// Source: the sibling viem checkout (../viem) on branch -// feat/eip-8130-production, built to src/_esm. Rebuild with: +// Source: the sibling viem checkout (../viem) on branch feat/aa-tx-split, +// bundled straight from its TypeScript sources (the Keystore-free `eip8130` +// core, not `experimental/keystore`). Rebuild with: // `bun run vendor/aa/build.mjs` (see build.mjs). // Core viem export { - concatHex, createPublicClient, - createWalletClient, - custom, decodeAbiParameters, encodeAbiParameters, encodeFunctionData, - formatEther, - hexToBigInt, http, - keccak256, parseAbi, parseEther, parseUnits, - slice, toHex, zeroAddress, -} from '../../../viem/src/_esm/index.js' +} from '../../../viem/src/index.ts' // Local accounts export { generatePrivateKey, privateKeyToAccount, -} from '../../../viem/src/_esm/accounts/index.js' +} from '../../../viem/src/accounts/index.ts' -// ERC-4337 / WebAuthn +// EIP-8130 (native account abstraction) — secp256k1 EOA senders with optional +// code delegation. export { - createBundlerClient, - createWebAuthnCredential, - entryPoint07Abi, - entryPoint07Address, - toWebAuthnAccount, -} from '../../../viem/src/_esm/account-abstraction/index.js' - -// EIP-8130 (native account abstraction) — includes toDelegateSigner / -// delegateAuthSize (sub-account delegate signing). -export * from '../../../viem/src/_esm/eip8130/index.js' + allPhasesSucceeded, + delegationCost, + estimateGas, + getTransactionCount, + getTransactionReceipt, + k1AuthCost, + k1Authenticator, + nonceFreeCost, + nonceKeyMax, + parseReceiptFields, + prepareTransactionRequest, + sendTransaction, + toEoaAccount, + txValueCost, +} from '../../../viem/src/eip8130/index.ts' // ERC-8168 (payer / sponsorship) export { - buildSponsoredCalls, createPayerClient, encodeTokenTransfer, isDeclinedOffer, - isSelectableOffer, - isSponsoredOffer, isTokenOffer, parsePayerError, - payerErrorCode, - payerRejectedCode, selectPaymentOption, - sendSponsoredCalls, - sponsorshipDeclineCode, -} from '../../../viem/src/_esm/eip8168/index.js' +} from '../../../viem/src/eip8168/index.ts' diff --git a/vendor/aa/index.d.ts b/vendor/aa/index.d.ts index 21cc6399..41094562 100644 --- a/vendor/aa/index.d.ts +++ b/vendor/aa/index.d.ts @@ -1,6 +1,9 @@ // Hand-written types for the self-contained AA vendor bundle (index.js). -// Covers the surface the vibenet account demo uses. Generated artifact pairing: -// `bun run vendor/aa/build.mjs` rebuilds index.js from the sibling viem branch. +// Covers exactly the surface entry.mjs exports. Generated artifact pairing: +// `bun run vendor/aa/build.mjs` rebuilds index.js from the sibling viem branch +// (feat/aa-tx-split). The chain runs with the EIP-8130 Keystore disabled, so +// only the Keystore-free core is declared: secp256k1 EOA senders, optional +// `delegation` account changes, and ERC-8168 payers. export type Hex = `0x${string}` export type Address = `0x${string}` @@ -13,9 +16,10 @@ export type LocalAccount = { address: Address publicKey: Hex sign?: (parameters: { hash: Hex }) => Promise - signMessage: (parameters: { message: string | { raw: Hex } }) => Promise + signMessage: (parameters: { message: string | { raw: Hex | Uint8Array } }) => Promise signTypedData: (parameters: any) => Promise - type: string + source: string + type: 'local' } export type Client = { @@ -25,1007 +29,381 @@ export type Client = { } export function http(url?: string, config?: any): any -export function custom(provider: any, config?: any): any export function createPublicClient(parameters: any): Client -export function createWalletClient(parameters: any): Client -export function createBundlerClient(parameters: any): Client export function encodeAbiParameters(params: readonly any[], values: readonly any[]): Hex export function decodeAbiParameters(params: readonly any[], data: Hex): readonly any[] export function encodeFunctionData(parameters: any): Hex export function parseAbi(signatures: readonly string[]): any -export function keccak256(value: Hex | Uint8Array): Hex -export function slice(value: Hex, start?: number, end?: number): Hex export function toHex(value: string | number | bigint | boolean | Uint8Array, opts?: any): Hex -export function hexToBigInt(hex: Hex, opts?: any): bigint -export function concatHex(values: readonly Hex[]): Hex export function parseEther(ether: string): bigint export function parseUnits(value: string, decimals: number): bigint -export function formatEther(wei: bigint): string export const zeroAddress: Address // --------------------------------------------------------------------------- -// Accounts +// Local accounts // --------------------------------------------------------------------------- export function generatePrivateKey(): Hex export function privateKeyToAccount(privateKey: Hex): LocalAccount // --------------------------------------------------------------------------- -// WebAuthn (ERC-4337 / passkeys) +// EIP-8130 (native account abstraction, Keystore-free core) // --------------------------------------------------------------------------- -export type P256Credential = { id: string; publicKey: Hex; raw: unknown } -export function createWebAuthnCredential(parameters: { - name?: string - [key: string]: any -}): Promise - -export type WebAuthnAccount = { - id: string - publicKey: Hex - sign: (parameters: { hash: Hex }) => Promise<{ - signature: Hex - webauthn: { - authenticatorData: Hex - clientDataJSON: string - challengeIndex: number - typeIndex: number - } - raw: unknown - }> -} -export function toWebAuthnAccount(parameters: { - credential: { id: string; publicKey: Hex } - getFn?: any - rpId?: string -}): WebAuthnAccount +/** A call within a phase: dispatched from `sender` with `msg.value = value`. */ +export type AaCall = { to: Address; data?: Hex | undefined; value?: bigint | undefined } +/** Ordered call phases; each phase is atomic, and a reverted phase skips the rest. */ +export type AaCalls = readonly (readonly AaCall[])[] -export const entryPoint07Address: Address -export const entryPoint07Abi: readonly any[] +/** + * `delegation` account change: EIP-7702-style code delegation for the sender, + * authorized by `sender_auth`. The zero address clears it. At most one per + * transaction. + */ +export type AaAccountChangeDelegation = { type: 'delegation'; target: Address } +export type AaAccountChange = AaAccountChangeDelegation -// --------------------------------------------------------------------------- -// EIP-8130 -// --------------------------------------------------------------------------- +/** The `payer` wire field: a named payer address, or `'0x00'` for open mode. */ +export type AaPayer = Address | '0x00' -export type AaActor = { - actorId: Hex - authenticator: Address - /** `uint16` scope bitmask committed at creation. `0`/omitted = admin. */ - scope?: number - /** `manager || commitment` — required iff `scope & SCOPE_POLICY`. */ - policyData?: Hex -} -/** `authorizeActor` op (`ChangeType` 0x00) within a `SignedAccountChanges` batch. */ -export type AaAuthorizeActor = { - changeType: 0x00 - actorId: Hex - authenticator: Address - scope?: number - /** Actor expiry (unix SECONDS, `uint48`). `0`/omitted = no expiry. */ - expiry?: bigint - policyData?: Hex -} -/** `revokeActor` op (`ChangeType` 0x01). */ -export type AaRevokeActor = { changeType: 0x01; actorId: Hex } -/** `incrementLocalEpoch` op (`ChangeType` 0x02): invalidates unlanded local-channel sigs. */ -export type AaIncrementLocalEpoch = { changeType: 0x02 } -/** `lock` op (`ChangeType` 0x03): local channel only, sole op in the batch. */ -export type AaLock = { changeType: 0x03; unlockDelay: number } -/** `unlock` op (`ChangeType` 0x04): local channel only, sole op in the batch. */ -export type AaUnlock = { changeType: 0x04 } -/** A single op within a `SignedAccountChanges` batch. */ -export type AaChange = - | AaAuthorizeActor - | AaRevokeActor - | AaIncrementLocalEpoch - | AaLock - | AaUnlock -/** @deprecated retained alias; use {@link AaChange}. */ -export type AaActorChange = AaAuthorizeActor | AaRevokeActor -/** Replay domain a `SignedAccountChanges` batch binds to. */ -export type AaChangeChannel = 'local' | 'multichain' -export type AaAccountChangeCreate = { - type: 'create' - userSalt: Hex - code: Hex - initialActors: readonly AaActor[] -} -/** A signed `SignedAccountChanges` batch (`applySignedAccountChanges`). */ -export type AaAccountChangeConfig = { - type: 'config' - /** `'local'` binds `block.chainid` + epoch/sequence; `'multichain'` binds chain id 0. */ - channel: AaChangeChannel - /** `uint64` channel sequence. Local: `localEpoch(hi 32) || localSequence(lo 32)`. */ - sequence: bigint - /** Ordered ops applied all-or-nothing. */ - changes: readonly AaChange[] - /** Authorization signature over the batch digest (`authenticator || data`). */ - signature: Hex -} -export type AaAccountChangeDelegation = { type: 'delegation'; target: Address } -export type AaAccountChange = - | AaAccountChangeCreate - | AaAccountChangeConfig - | AaAccountChangeDelegation -export type AaCall = { to: Address; data?: Hex; value?: bigint } -export type AaCalls = readonly (readonly AaCall[])[] +export type TransactionSerializable8130 = { + chainId: number + /** Names the sender; omit to recover it from a raw 65-byte `senderAuth`. */ + from?: Address | undefined + /** Nonce channel. `nonceKeyMax` selects nonce-free (expiring) mode. */ + nonceKey?: bigint | undefined + nonceSequence?: bigint | undefined + /** Unix ms (or seconds below `timestampMsThreshold`). `0`/omitted = none. */ + validAfter?: bigint | undefined + /** Unix ms (or seconds below `timestampMsThreshold`). Required non-zero in nonce-free mode. */ + validBefore?: bigint | undefined + maxPriorityFeePerGas?: bigint | undefined + maxFeePerGas?: bigint | undefined + gas?: bigint | undefined + accountChanges?: readonly AaAccountChange[] | undefined + calls?: AaCalls | undefined + /** Opaque top-level metadata, authenticated by sender and payer. */ + metadata?: Hex | undefined + payer?: AaPayer | undefined + senderAuth?: Hex | undefined + payerAuth?: Hex | undefined +} +export type TransactionSerialized8130 = Hex export type Signer = { address: Address - sign?: (parameters: { hash: Hex }) => Promise - authenticator?: Address + sign?: ((parameters: { hash: Hex }) => Promise) | undefined + /** Defaults to `k1Authenticator` (native secp256k1). */ + authenticator?: Address | undefined } -export type Policy = { type: number; manager: Address; commitment: Hex } -export type AuthorizeActorOptions = { - scope?: number - expiry?: bigint - policy?: Policy -} - -export const key: { - k1(address: Address): AaActor - p256(publicKey: { x: Hex; y: Hex } | Hex, options?: { authenticator?: Address }): AaActor - passkey(publicKey: { x: Hex; y: Hex } | Hex, options?: { authenticator?: Address }): AaActor - delegate(delegatedAccount: Address, options?: { authenticator?: Address }): AaActor - trustedExecutor(caller: Address): AaActor - /** No-code external-pull policy actor (uses `externalPolicyAuthenticator`). */ - externalPull(caller: Address): AaActor +/** An account that can send AA transactions: it names the sender and signs `sender_auth`. */ +export type AaAccount = { + readonly address: Address + readonly signer: Signer + signTransaction( + transaction: TransactionSerializable8130, + options?: { payer?: { account: Signer; address?: AaPayer | undefined } | undefined }, + ): Promise } -export const externalPolicyAuthenticator: Address -export function authorizeActor(actor: AaActor, options?: AuthorizeActorOptions): AaAuthorizeActor -export function revokeActor(actor: AaActor | Hex): AaRevokeActor -export function incrementLocalEpoch(): AaIncrementLocalEpoch -export function toScope(...flags: number[]): number -export function encodePolicyData(policy: Policy): Hex -export const actorScope: { - /** `OPERATOR` — ungated initiation (may originate to any `call.to`). Formerly `sender`. */ - operator: number - /** `SELF_PAYER` — may pay for its own transactions (`payer == sender`). */ - selfPayer: number - /** `SPONSOR_PAYER` — may sponsor others (`payer != sender`). */ - sponsorPayer: number - /** `POLICY` — gated initiation: actor is gated to its policy manager. */ - policy: number - /** `NONCE` — may use sequenced nonce keys; without it, nonce-free only. */ - nonce: number -} -export const scopeUnrestricted: number -export const accountStateFlags: { - revokeDefaultEoa: number - locked: number - unlockInitiated: number -} -/** `SignedAccountChanges` op discriminants. */ -export const changeType: { - authorizeActor: 0x00 - revokeActor: 0x01 - incrementLocalEpoch: 0x02 - lock: 0x03 - unlock: 0x04 -} -/** Top-level account-change entry discriminants (create / config / delegation). */ -export const accountChangeType: { - create: 0x00 - config: 0x01 - delegation: 0x02 -} -/** Whether an actor with `scope` may use sequenced (counter-backed) nonce keys. */ -export function canUseSequencedNonce(scope: number | undefined): boolean -/** Whether an actor with `scope` is restricted to nonce-free (expiring) txs. */ -export function isNoncelessOnly(scope: number | undefined): boolean -export const policyDataLength: number -export const replayIdType: Hex -export const nonceFreeExpiryWindow: bigint -export const nonceFreeMaxExpiryWindow: bigint -/** Nonce-free mode selector: `nonceKey === nonceKeyMax` (2**256 - 1). */ -export const nonceKeyMax: bigint -export const replayBufferCapacity: bigint -export const nonceFreeCost: bigint -export const nonceKeyFirstUseCost: bigint -export const nonceKeyExistingCost: bigint -export const ecrecoverAuthenticator: Address -export const trustedExecutorAuthenticator: Address -export const canonicalAuthenticators: { - k1: Address - p256: Address - passkey: Address - delegate: Address +export type ToEoaAccountReturnType = AaAccount & { + readonly type: 'local' + readonly source: 'eip8130' + readonly publicKey: Hex + signMessage(parameters: { message: string | { raw: Hex | Uint8Array } }): Promise + signTypedData(parameters: any): Promise + /** Builds a `delegation` account change setting (or, with the zero address, clearing) this EOA's code. */ + delegate(target: Address): AaAccountChangeDelegation } -/** - * Representative auth-payload byte length (bytes after a prefixed blob's - * 20-byte selector) for each canonical authenticator, keyed by *lowercased* - * address. Used by `estimateGas8130`'s `senderAuthVerifier`/`payerAuthVerifier` - * hint to synthesize a stub blob without the caller specifying an exact size. - */ -export const canonicalAuthDataLength: Record -/** - * The EIP-8130 keystore (`AccountConfiguration`) system contract address. - * Enshrined in the execution client — identical on every supported chain and - * not configurable (using any other address derives a different account - * address and fails the create tx). - */ -export const keystoreAddress: Address -export const defaultAccountAddress: Address -export const nonceManagerAddress: Address -export const nonceManagerAbi: readonly any[] - -// --- EIP-8130 RPC extensions (base eip8130 RPC support) -------------------- /** - * Reads the current config-change sequences for an EIP-8130 account. - * Use `local` as the `sequence` parameter when building the next AccountChange. + * Wraps a secp256k1 EOA signer for AA transactions. The EOA key is the account: + * `sender_auth` is `k1Authenticator || r || s || v` when the sender is named, + * or a raw 65-byte signature when it is recovered. */ -export function getConfigSequence( - client: Client, - parameters: { - account: Address - }, -): Promise<{ local: bigint; multichain: bigint }> - -// --- EIP-8130 account locking (SignedAccountChanges ops) ------------------- -// -// NOTE: lock/unlock are `ChangeType` ops inside a `SignedAccountChanges` batch -// (build via {@link lockChange}/{@link unlockChange}, sign via `account.change` -// / `signAccountChanges` on the `'local'` channel, apply via -// `encodeApplySignedAccountChangesData`). The enshrined node currently DEFERS -// them — a batch carrying one is rejected on the native path. - -/** Maximum `unlockDelay` (`uint16`). */ -export const maxUnlockDelay: number -export type LockChangeParameters = { unlockDelay: number } -/** Builds a `lock` op ({@link AaLock}); local channel only, sole op in the batch. */ -export function lockChange(parameters: LockChangeParameters): AaLock -/** Builds an `unlock` op ({@link AaUnlock}); local channel only, sole op in the batch. */ -export function unlockChange(): AaUnlock - -/** Reads whether an EIP-8130 account is currently locked. */ -export function isLocked( - client: Client, - parameters: { account: Address }, -): Promise - -/** Reads the full lock status of an EIP-8130 account. */ -export function getLockStatus( - client: Client, - parameters: { account: Address }, -): Promise<{ - locked: boolean - hasInitiatedUnlock: boolean - unlocksAt: number - unlockDelay: number -}> +export function toEoaAccount(signer: Signer): ToEoaAccountReturnType -/** Live SessionPolicy spend for one token limit (getCurrentSpend). */ -export function getSessionSpend( - client: Client, - parameters: { - commitment: Hex - tokenLimit: SessionPolicyTokenLimit - sessionPolicy?: Address - }, -): Promise<{ - allowance: bigint - period: number - spent: bigint - remaining: bigint - periodStart: number | bigint - periodEnd: number | bigint -}> +export const k1Authenticator: Address +/** Nonce-free mode selector: `nonceKey === nonceKeyMax` (2**256 - 1). */ +export const nonceKeyMax: bigint +export const k1AuthCost: bigint +export const txValueCost: bigint +export const delegationCost: bigint +export const nonceFreeCost: bigint /** Read the EIP-8130 nonce via `eth_getTransactionCount` (2D channel-nonce). */ export function getTransactionCount( client: Client, parameters: { address: Address - nonceKey?: bigint - blockNumber?: bigint - blockTag?: string + /** `nonceKeyMax` has no counter; the node rejects it. */ + nonceKey?: bigint | undefined + blockNumber?: bigint | undefined + blockTag?: string | undefined }, ): Promise /** * Estimate gas for an `AA_TX_TYPE` call via the EIP-8130 `eth_estimateGas`. - * - * The node prices authentication gas from the auth blob's *shape*, never a - * real signature. Provide at most one of, in priority order: - * `senderAuth` (raw blob, priced verbatim) > `senderAuthAuthenticator` - * (+ optional `senderAuthSize`, synthesizes `authenticator || filler`) > nothing (node - * default: configured k1 stub if `sender`/`from` names a configured account, - * else the default-EOA bare k1 stub). Same for payer authentication. + * Authentication gas is priced from the auth blob's shape: `senderAuth` (raw + * blob) > `senderAuthAuthenticator` (+ optional `senderAuthSize`) > the node + * default. Same for the payer. */ export function estimateGas( client: Client, parameters: { - /** Sender account. Interchangeable with `sender` (must agree if both set). */ - from?: Address - /** The EIP-8130 sender account. Interchangeable with `from`. */ - sender?: Address + from?: Address | undefined + sender?: Address | undefined // Simplified mode (no accountChanges/calls) - to?: Address - data?: Hex - value?: bigint + to?: Address | undefined + data?: Hex | undefined + value?: bigint | undefined // Full-body mode - accountChanges?: readonly AaAccountChange[] - calls?: readonly (readonly { to: Address; value?: bigint; data?: Hex }[])[] - nonceKey?: bigint - nonceSequence?: number - // Sender authentication - /** Raw `senderAuth` blob, priced verbatim. Takes priority over `senderAuthAuthenticator`. */ - senderAuth?: Hex - /** Authenticator address hint; see `canonicalAuthenticators`. */ - senderAuthAuthenticator?: Address - /** Overrides the verifier's default auth-payload length, or (alone) prices a bare filler blob of this length. */ - senderAuthSize?: number - /** - * Acting actor id. Names the actor the node resolves for simulation so - * policy-gated session keys and owner authorization bundles price - * correctly instead of falling back to the account's self actor. - */ - senderActorId?: Hex - // Common - payer?: Address - /** Raw `payerAuth` blob, priced verbatim. Takes priority over `payerAuthAuthenticator`. */ - payerAuth?: Hex - /** Payer authenticator address hint. */ - payerAuthAuthenticator?: Address - /** Payer auth-payload byte length override. See `senderAuthSize`. */ - payerAuthSize?: number - dataSuffix?: Hex - blockNumber?: bigint - blockTag?: string + accountChanges?: readonly AaAccountChange[] | undefined + /** A flat list is one phase; a nested array prices explicit phases. */ + calls?: readonly AaCall[] | AaCalls | undefined + nonceKey?: bigint | undefined + validAfter?: bigint | undefined + /** The deadline you will sign with (required for nonce-free sends). */ + validBefore?: bigint | undefined + senderAuth?: Hex | undefined + senderAuthAuthenticator?: Address | undefined + senderAuthSize?: number | undefined + senderActorId?: Hex | undefined + payer?: AaPayer | undefined + payerAuth?: Hex | undefined + payerAuthAuthenticator?: Address | undefined + payerAuthSize?: number | undefined + /** Written to the transaction's `metadata` field. */ + dataSuffix?: Hex | undefined + blockNumber?: bigint | undefined + blockTag?: string | undefined }, ): Promise +export type SendTransactionPayer = { + account: Signer + address?: AaPayer | undefined +} + +type FeeOverrides = { + maxFeePerGas?: bigint | undefined + maxPriorityFeePerGas?: bigint | undefined +} + +export type PrepareTransactionRequestParameters = FeeOverrides & { + account: AaAccount + calls: AaCalls + accountChanges?: readonly AaAccountChange[] | undefined + payer?: SendTransactionPayer | undefined + gas: bigint + nonceKey?: bigint | undefined + nonceSequence?: bigint | undefined + validAfter?: bigint | undefined + validBefore?: bigint | undefined + /** "Now" (unix ms) for the auto-computed nonce-free `validBefore`. */ + now?: bigint | undefined + /** Window (ms) added to `now` for a nonce-free send; defaults to 15s. */ + expiryWindow?: bigint | undefined + dataSuffix?: Hex | undefined +} + +/** Fills chain id, nonce sequence and fees; requires `client.chain`. */ +export function prepareTransactionRequest( + client: Client, + parameters: PrepareTransactionRequestParameters, +): Promise + +export type SendTransactionParameters = Omit & { + calls: readonly AaCall[] | AaCalls + onTransaction?: ((transaction: TransactionSerializable8130) => void) | undefined +} + +/** Prepares, signs (sender and, when set, payer) and submits an AA transaction. */ +export function sendTransaction(client: Client, parameters: SendTransactionParameters): Promise + export type ReceiptFields = { - payer?: Address - phaseStatuses?: readonly Hex[] - metadata?: Hex + payer?: Address | undefined + phaseStatuses?: readonly Hex[] | undefined + metadata?: Hex | undefined } -/** @deprecated alias of {@link ReceiptFields}. */ -export type Eip8130ReceiptFields = ReceiptFields /** Parse the EIP-8130 fields off a raw JSON-RPC receipt (graceful if absent). */ export function parseReceiptFields(receipt: any): ReceiptFields /** Returns `true` when every reported call phase succeeded. */ -export function allPhasesSucceeded(fields: { - phaseStatuses?: readonly Hex[] -}): boolean +export function allPhasesSucceeded(fields: { phaseStatuses?: readonly Hex[] | undefined }): boolean /** Fetch a receipt and surface the EIP-8130 AA fields under `.eip8130`. */ export function getTransactionReceipt( client: Client, parameters: { hash: Hex }, ): Promise<(Record & { eip8130: ReceiptFields }) | null> -/** - * Poll `eth_getTransactionReceipt` until an EIP-8130 tx is mined. - * Skips replacement-detection (which breaks on 2D nonces) and surfaces the - * EIP-8130 fields under `.eip8130`. - */ -export function waitForTransactionReceipt( - client: Client, - parameters: { - hash: Hex - pollingInterval?: number - timeout?: number - /** Upper validity bound (unix ms) to stop polling an expired nonce-free tx. */ - validBefore?: bigint - }, -): Promise & { eip8130: ReceiptFields }> +// --------------------------------------------------------------------------- +// ERC-8168 (payer / sponsorship) +// --------------------------------------------------------------------------- -/** Fetch an EIP-8130 transaction by hash with strong typing. */ -export type Transaction = { - type: '0x79' - hash: Hex - from: Address - chainId: number - nonceKey: Hex - nonceSequence: number - /** Lower validity bound (unix ms). `0` = none. */ - validAfter: bigint - /** Upper validity bound (unix ms). `0` = none. */ - validBefore: bigint - maxFeePerGas: bigint - maxPriorityFeePerGas: bigint - gas: bigint - calls: readonly (readonly any[])[] - accountChanges: readonly any[] - metadata: Hex - payer: Address | null - senderAuth: Hex - payerAuth: Hex - gasPrice: bigint | null - blockHash: Hex | null - blockNumber: bigint | null - transactionIndex: number | null -} -/** @deprecated alias of {@link Transaction}. */ -export type Transaction8130 = Transaction -export function getTransaction( - client: Client, - parameters: { hash: Hex }, -): Promise +export type PayerRpcCall = { to: Address; value?: Hex | undefined; data?: Hex | undefined } -// --- Actor policies (EIP-8130 restricted actors) --------------------------- -export type PolicyBinding = { - account: Address - policy: Address - policyConfig: Hex - validAfter: bigint - validUntil: bigint - salt: bigint +export type BalanceLimit = { + unit: 'asset' | 'count' + available: Hex + limit?: Hex | undefined + spent?: Hex | undefined + asset?: string | undefined + symbol?: string | undefined + decimals?: number | undefined } -export type SessionPolicy = { - manager: Address - policy: Address - binding: PolicyBinding - commitment: Hex - actorPolicy: Policy - /** Wraps an action as `PolicyManager.execute` (session key dispatches as the account). */ - executeCall(executionData: Hex | SessionPolicyAction): AaCall - /** Wraps an action as `PolicyManager.executeFor` (external pull actor drives the account). */ - executeForCall(executionData: Hex | SessionPolicyAction): AaCall -} -export function commitmentOf(binding: PolicyBinding): Hex -export function defineSessionPolicy(parameters: { - account: Address - policyConfig: Hex - policy?: Address - manager?: Address - validAfter?: bigint - validUntil?: bigint - salt?: bigint - policyType?: number -}): SessionPolicy -export type SessionPolicyTokenLimit = { - token: Address - limit: bigint - period?: bigint -} -export type SessionPolicySelectorRule = { - selector: Hex - recipients?: readonly Address[] -} -export type SessionPolicyCallScope = { - target: Address - selectorRules?: readonly SessionPolicySelectorRule[] -} -export type SessionPolicyConfig = { - tokenLimits?: readonly SessionPolicyTokenLimit[] - callScopes?: readonly SessionPolicyCallScope[] +export type PayerBalance = { + kind: 'sponsorship' | 'credit' + limits: readonly BalanceLimit[] + validFor?: number | undefined + payer?: Address | undefined + endpoint?: string | undefined + name?: string | undefined } -export type SessionPolicyAction = { - target: Address - value?: bigint - data?: Hex -} -export const sessionPolicyAddress: Address -export function encodeSessionPolicyConfig(config: SessionPolicyConfig): Hex -export function encodeSessionPolicyAction(action: SessionPolicyAction): Hex -export const policyManagerAbi: readonly unknown[] -export const sessionPolicyAbi: readonly unknown[] -// --------------------------------------------------------------------------- -// ERC-7715 grants / ERC-7895 sub-accounts / ERC-5792 capabilities (high level) -// --------------------------------------------------------------------------- +export type PayerGasEstimate = { gasLimit: Hex; maxFeePerGas: Hex; maxPriorityFeePerGas: Hex } -/** ERC-7715 policy attached to a requested permission. */ -export type GrantedPolicy = - | { type: 'token-allowance'; data: { allowance: bigint } } - | { type: 'gas-limit'; data: { limit: bigint } } - | { type: 'rate-limit'; data: { count: number; interval: number } } - | { type: string; data?: unknown } -/** ERC-7715 permission requested by a dApp. */ -export type Permission = { - type: - | 'native-token-transfer' - | 'erc20-token-transfer' - | 'contract-call' - | string - data?: any - policies?: readonly GrantedPolicy[] +export type PayerConditions = { + /** Upper bound on the transaction's expiry, in seconds from now. */ + maxExpiry?: number | undefined + maxGasLimit?: Hex | undefined + maxCost?: Hex | undefined } -export type GrantRole = 'session' | 'pull' - -export function toSessionPolicyConfig( - permissions: readonly Permission[], -): SessionPolicyConfig - -export function toSessionPolicy(parameters: { - account: Address - permissions: readonly Permission[] - expiry?: number | bigint - policy?: Address - manager?: Address - validAfter?: bigint - salt?: bigint -}): SessionPolicy +export type PayerProvider = { name: string; icon?: string | undefined } -export type FulfillGrantPermissionsParameters = { - account: Address - grantee: Address - permissions: readonly Permission[] - role?: GrantRole - expiry?: number | bigint - assumeManagerRegistered?: boolean - policy?: Address - manager?: Address - validAfter?: bigint - salt?: bigint +export type BaseOffer = { + payer: Address + endpoint?: string | undefined + /** Optional methods beyond `payer_getTerms` / `payer_sendTransaction` (e.g. `payer_signTransaction`). */ + methods?: readonly string[] | undefined + ttl: number + conditions?: PayerConditions | undefined + provider?: PayerProvider | undefined } -export type FulfillGrantPermissionsReturnType = { - actor: AaActor - change: AaAuthorizeActor - managerChange?: AaAuthorizeActor - changes: readonly AaChange[] - session: SessionPolicy - /** Opaque, self-describing ERC-7715 permissionsContext for this grant. */ - permissionsContext: Hex -} -export function fulfillGrantPermissions( - client: Client, - parameters: FulfillGrantPermissionsParameters, -): Promise -export type ParsePermissionsContextReturnType = { - account: Address - role: GrantRole - actor: AaActor - session: SessionPolicy +export type SponsoredOfferSelectable = BaseOffer & { + kind: 'sponsored' + balance?: PayerBalance | undefined } -export function toPermissionsContext(parameters: { - role: GrantRole - actor: AaActor - session: SessionPolicy -}): Hex -export function parsePermissionsContext( - context: Hex, -): ParsePermissionsContextReturnType -export type RoutePermissionedCallsReturnType = - ParsePermissionsContextReturnType & { calls: readonly AaCall[] } -export function routePermissionedCalls(parameters: { - context: Hex - calls: readonly SessionPolicyAction[] -}): RoutePermissionedCallsReturnType -export type SubAccountKey = { - publicKey: Hex | { x: Hex; y: Hex } - type: 'address' | 'p256' | 'webauthn-p256' | 'secp256k1' -} -export type FulfillAddSubAccountParameters = { - parent: Address - signer: Signer - keys?: readonly SubAccountKey[] - keyScope?: number - keyPolicy?: Policy - proxy?: 'erc1167' | 'upgradeable' - implementation?: Address - salt?: Hex - code?: Hex -} -export type FulfillAddSubAccountReturnType = ToAccountReturnType & { - createChange: AaAccountChangeCreate - parentActor: AaActor - initialActors: readonly AaActor[] - response: { address: Address } +export type SponsoredOfferDeclined = { + kind: 'sponsored_declined' + code: string + reason?: string | undefined + balance?: PayerBalance | undefined + gas?: { estimatedCost: Hex; maxCost: Hex } | undefined + provider?: PayerProvider | undefined } -export function fulfillAddSubAccount( - parameters: FulfillAddSubAccountParameters, -): FulfillAddSubAccountReturnType -export type Eip8130Capabilities = Record -export function eip8130Capabilities(parameters?: { - paymasterService?: boolean - signerTypes?: readonly string[] - permissionTypes?: readonly string[] - policyTypes?: readonly string[] - subAccountKeyTypes?: readonly string[] -}): Eip8130Capabilities -export function eip8130CapabilitiesByChain( - chainIds: readonly number[], - parameters?: Parameters[0], -): Record +export type SponsoredOffer = SponsoredOfferSelectable | SponsoredOfferDeclined -export function erc1167Bytecode(implementation: Address): Hex -export function upgradeableProxyBytecode(implementation: Address): Hex - -export function computeAddress(parameters: { - userSalt: Hex - code: Hex - initialActors: readonly AaActor[] -}): Address -/** The 32-byte deployment header committed into the CREATE2 salt. */ -export function deploymentHeader(parameters: { - code: Hex - initialActors: readonly AaActor[] -}): Hex - -export type ChangeOptions = { - channel?: AaChangeChannel - chainId?: number - sequence?: bigint -} -export type ToAccountReturnType = { - readonly address: Address - readonly signer: Signer - readonly initialActors: readonly AaActor[] - readonly scope?: number - readonly actorId?: Hex - create(): AaAccountChangeCreate - /** Signs a `SignedAccountChanges` batch into a `config` entry. */ - change( - changes: readonly AaChange[], - options?: ChangeOptions, - ): Promise - delegate(target: Address): AaAccountChangeDelegation - signTransaction(transaction: any, options?: any): Promise +export type TokenChoice = { + token: Address + symbol: string + decimals: number + /** Phase-0 amount, quoted against the terms' `gasEstimate`. */ + paymentAmount: Hex + feeRecipient?: Address | undefined + rate: { numerator: Hex; denominator: Hex } + fiatRate?: Hex | undefined + refund?: { window: number } | undefined } -/** @deprecated alias of {@link ToAccountReturnType}. */ -export type To8130AccountReturnType = ToAccountReturnType -/** - * Two shapes: - * - Smart account: supply userSalt + code + initialActors (address derived via CREATE2) - * - Delegated EOA: supply address only (no salt/code/actors; use delegate(impl) in first tx) - */ -export function toAccount(parameters: ( - | { - signer: Signer - userSalt: Hex - code: Hex - initialActors: readonly AaActor[] - authenticator?: Address - scope?: number - actorId?: Hex - address?: Address - } - | { - signer: Signer - address: Address - authenticator?: Address - scope?: number - actorId?: Hex - userSalt?: undefined - code?: undefined - initialActors?: undefined - } -)): ToAccountReturnType -export type NewSmartAccountReturnType = ToAccountReturnType & { - /** The `create` account-change — include in `accountChanges` for the first tx. */ - readonly createChange: AaAccountChangeCreate +export type TokenPaymentOffer = BaseOffer & { + kind: 'token' + tokens: readonly TokenChoice[] + paymentMode?: 'transfer' | 'any' | undefined } -/** - * Creates a new EIP-8130 smart account from a signer. Automatically derives the - * actor, bytecode, and counterfactual address. Include `account.createChange` in - * the first transaction's `accountChanges` to deploy the account. - * - * Supports K1 (secp256k1), P-256, and WebAuthn signers (detected automatically). - */ -export function newSmartAccount(parameters: { - signer: Signer & { publicKey?: Hex | { x: Hex; y: Hex } } - salt?: Hex - /** @default 'upgradeable' — requires an `implementation` until one is enshrined. */ - proxy?: 'erc1167' | 'upgradeable' - implementation?: Address - code?: Hex - admins?: readonly AaActor[] - extraActors?: readonly AaActor[] -}): NewSmartAccountReturnType - -/** - * Wraps a parent ADMIN signer into a `Signer` that authenticates a sub-account - * through the DelegateAuthenticator (one hop). Its `sign` returns the delegate - * `data` payload (`delegate(20) || nestedAuthenticator(20) || nestedSignature`), - * so `to8130Account`'s configured-actor path serializes the full delegate - * `senderAuth` (`DELEGATE_AUTHENTICATOR || data`) automatically. Pass the result - * as `signer` (and its `authenticator`) to `to8130Account` for an account whose - * only owner is `key.delegate(parent)`. The parent must be deployed. - */ -export function toDelegateSigner(parameters: { - delegateAccount: Address - nestedSigner: Signer - nestedAuthenticator?: Address - authenticator?: Address -}): Signer & { authenticator: Address } +export type PaymentOption = SponsoredOffer | TokenPaymentOffer -/** - * Byte length of a delegate `senderAuth`/`auth` blob for a given nested-auth - * payload length (default 65-byte K1 sig). Use as `senderAuthSize` when - * estimating gas for a delegate-signed tx (the delegate authenticator has no - * fixed default length). Layout: DELEGATE(20) || delegate(20) || nested(20) || data. - */ -export function delegateAuthSize(nestedDataLength?: number): number - -/** - * Wraps a secp256k1 EOA for EIP-8130 transactions using the implicit self-actor - * path. `senderAuth` is a raw 65-byte ECDSA sig (no authenticator prefix); the - * node recovers the sender via ecrecover. Use when the EOA address IS the account - * and no smart-contract deployment is needed. - */ -export function toEoaAccount(signer: Signer, parameters?: { scope?: number }): { - readonly address: Address - readonly signer: Signer - readonly scope?: number - /** EIP-7702 delegation change — include in first tx's accountChanges. */ - delegate(target: Address): AaAccountChangeDelegation - /** Sign a `SignedAccountChanges` batch (e.g. add P256 key alongside K1). */ - change( - changes: readonly AaChange[], - options?: ChangeOptions, - ): Promise - /** Raw 65-byte K1 sig — no authenticator prefix, no `from` field. */ - signTransaction( - transaction: TransactionSerializable8130, - options?: { payer?: { account: Signer; address?: Address } }, - ): Promise +export type GetTermsParameters = { + chainId: Hex + from: Address + calls: readonly PayerRpcCall[] + gasLimit?: Hex | undefined + preferredTokens?: readonly Address[] | undefined + fiatCurrency?: string | undefined + context?: Record | undefined } -export type TransactionSerializable8130 = { - chainId: number - from?: Address - nonceKey?: bigint - nonceSequence?: bigint - /** Lower validity bound (unix MILLISECONDS). `0`/omitted = none. */ - validAfter?: bigint - /** Upper validity bound (unix MILLISECONDS). Required non-zero in nonce-free mode. */ - validBefore?: bigint - maxPriorityFeePerGas?: bigint - maxFeePerGas?: bigint - gas?: bigint - accountChanges?: readonly AaAccountChange[] - calls?: readonly (readonly AaCall[])[] - metadata?: Hex - payer?: Address - senderAuth?: Hex - payerAuth?: Hex +export type GetTermsReturnType = { + options: readonly PaymentOption[] + gasEstimate?: PayerGasEstimate | undefined + fiatCurrency?: string | undefined } -export function parseTransaction(serialized: Hex): TransactionSerializable8130 - -export function serializeTransaction( - transaction: TransactionSerializable8130, -): Hex -/** Serialize just the ordered call phases (wire form). */ -export function toCallsList(calls: AaCalls): readonly any[] -/** Serialize the account-change entries (wire form). */ -export function toAccountChangesList( - changes: readonly AaAccountChange[], -): readonly any[] -/** Build the RLP transaction body array. */ -export function toTransactionBody(transaction: TransactionSerializable8130): readonly any[] - -/** Sender signature hash — fields through `payer`. */ -export function getSenderSignatureHash( - transaction: TransactionSerializable8130 & { to?: "hex" | "bytes" }, -): Hex - -/** - * Resolves the sender (`from`) of an EIP-8130 tx. Returns `transaction.from` - * when set; otherwise (EOA path) recovers it via ecrecover over the sender hash. - */ -export function recoverSenderAddress(parameters: { - transaction: TransactionSerializable8130; -}): Promise
- -/** Payer signature hash — fields through `calls`/`metadata`, excluding `payer`. */ -export function getPayerSignatureHash( - transaction: TransactionSerializable8130 & { to?: "hex" | "bytes" }, -): Hex +export type TokenCharged = { token: Address; amount: Hex } -export function encodeWalletCalls(parameters: { - account: Address - calls: readonly (readonly AaCall[])[] - encodeExecute?: (parameters: { - account: Address - calls: readonly { to: Address; data: Hex; value: bigint }[] - }) => AaCall -}): readonly (readonly AaCall[])[] - -export type SendCallsParameters = { - account: ToAccountReturnType - calls: readonly AaCall[] | readonly (readonly AaCall[])[] - accountChanges?: readonly AaAccountChange[] - payer?: { account: Signer; address?: Address } - gas: bigint - nonceKey?: bigint - nonceSequence?: bigint - /** Lower validity bound (unix ms; 0/omitted = none). */ - validAfter?: bigint - /** Upper validity bound (unix ms; required non-zero in nonce-free mode). */ - validBefore?: bigint - dataSuffix?: Hex - maxFeePerGas?: bigint - maxPriorityFeePerGas?: bigint - encodeExecute?: (parameters: any) => AaCall - /** Fires with the fully-resolved tx just before signing (thread `validBefore`). */ - onTransaction?: (transaction: TransactionSerializable8130) => void +export type PayerSendTransactionParameters = { + signedTransaction: Hex + context?: Record | undefined } -export function sendCalls( - client: Client, - parameters: SendCallsParameters, -): Promise -/** Builds a fully-populated transaction body (nonce, fees, validBefore) without sending. */ -export function prepareTransaction( - client: Client, - parameters: Omit & { - calls: readonly (readonly AaCall[])[] - }, -): Promise - -export function toSmartAccount(parameters: { - owner: Address | LocalAccount - client: Client - authenticator?: Address - sign?: (hash: Hex) => Promise - stubData?: Hex - userSalt?: Hex - initialActors?: readonly AaActor[] - implementation?: Address - code?: Hex - address?: Address - [key: string]: any -}): Promise - -// --- Account-change signing / encoding ------------------------------------- - -/** 32-byte actor id derived from an address (`bytes32(bytes20(address))`). */ -export function actorIdFromAddress(address: Address): Hex -/** 32-byte actor id derived from a public key (`{ x, y }` or 64-byte hex). */ -export function actorIdFromPublicKey(publicKey: { x: Hex; y: Hex } | Hex): Hex - -export const accountChangeTypehash: Hex -export const signedAccountChangesTypehash: Hex -export const signedActorChangesMagic: Hex - -/** Digest an admin actor signs to authorize a `SignedAccountChanges` batch. */ -export function hashAccountChanges(parameters: { - account: Address - channel?: AaChangeChannel - chainId?: number - sequence?: bigint - changes: readonly AaChange[] -}): Hex - -/** Signs a `SignedAccountChanges` batch into an `AaAccountChangeConfig` entry. */ -export function signAccountChanges(parameters: { - signer: Signer - account: Address - channel?: AaChangeChannel - chainId?: number - sequence?: bigint - changes: readonly AaChange[] - authenticator?: Address -}): Promise - -/** ABI-encodes a single change op's payload (by `changeType`). */ -export function encodeChangePayload(change: AaChange): Hex -/** Decodes an `authorizeActor` payload back into its fields. */ -export function decodeAuthorizeActorPayload(payload: Hex): { - actorId: Hex - authenticator: Address - expiry: bigint - scope: number - policyData: Hex +export type PayerSendTransactionReturnType = { transactionHash: Hex; tokenCharged?: TokenCharged | undefined } +export type PayerSignTransactionParameters = { + signedTransaction: Hex + context?: Record | undefined } -/** `authenticator || data` wire form for a signed change set. */ -export function encodeSignedActorChangesSignature(parameters: any): Hex - -/** Calldata for `AccountConfiguration.createAccount(...)`. */ -export function encodeCreateAccountData(parameters: { - userSalt: Hex - code: Hex - initialActors: readonly AaActor[] -}): Hex -/** Calldata for `AccountConfiguration.applySignedAccountChanges(...)`. */ -export function encodeApplySignedAccountChangesData( - parameters: { account: Address } & Omit, -): Hex -/** ERC-4337 factory args (`factory`, `factoryData`) for a create entry. */ -export function toFactoryArgs(parameters: { - userSalt: Hex - code: Hex - initialActors: readonly AaActor[] -}): { factory: Address; factoryData: Hex } +export type PayerSignTransactionReturnType = { signedTransaction: Hex; tokenCharged?: TokenCharged | undefined } -export type Eip8130Deployment = { - accounts: { - upgradeable?: Address - default: Address - defaultHighRate: Address - erc4337?: Address - } - authenticators: { - k1: Address - p256: Address - webAuthn: Address - delegate: Address - alwaysValid: Address - } - policies?: { - manager: Address - sessionPolicy: Address - } -} -export const canonicalEip8130Deployment: Eip8130Deployment & { - policies: { manager: Address; sessionPolicy: Address } -} -export const baseSepoliaDeployment: Eip8130Deployment & { - policies: { manager: Address; sessionPolicy: Address } -} -export const vibenetDevnetDeployment: Eip8130Deployment & { - policies: { manager: Address; sessionPolicy: Address } +export type GetSponsorshipBalanceParameters = { + from: Address + chainId?: Hex | undefined + payer?: Address | undefined + endpoint?: string | undefined + kind?: readonly ('sponsorship' | 'credit')[] | undefined + context?: Record | undefined } -export const eip8130Deployments: Record -export function getEip8130Deployment(chainId: number): Eip8130Deployment | undefined - -export const eip8130ChainIds: Set -export function register8130Chains(...chainIds: number[]): void -export function is8130Enabled(chain: number | { id: number }, parameters?: { chainIds?: Iterable }): boolean +export type GetSponsorshipBalanceReturnType = { balances: readonly PayerBalance[]; ttl: number } -export function toP256Signer(parameters: { - privateKey: Hex - authenticator?: Address - address?: Address -}): Signer & { publicKey: { x: Hex; y: Hex } } - -export type WebAuthnSignSource = { - publicKey: Hex | { x: Hex; y: Hex } - sign: (parameters: { hash: Hex }) => Promise<{ - signature: Hex - webauthn: { - authenticatorData: Hex - clientDataJSON: string - challengeIndex: number - typeIndex: number - } - }> +export type PayerClient = { + getTerms(parameters: GetTermsParameters): Promise + sendTransaction(parameters: PayerSendTransactionParameters): Promise + /** Only when the picked offer lists `payer_signTransaction` in `methods`. */ + signTransaction(parameters: PayerSignTransactionParameters): Promise + getSponsorshipBalance(parameters: GetSponsorshipBalanceParameters): Promise } -export function toWebAuthnSigner( - source: WebAuthnSignSource, - parameters?: { authenticator?: Address; address?: Address }, -): Signer & { publicKey: { x: Hex; y: Hex } } -// --------------------------------------------------------------------------- -// ERC-8168 (payer / sponsorship) -// --------------------------------------------------------------------------- +export function createPayerClient(parameters: { url?: string | undefined; transport?: any }): PayerClient -export type PayerClient = { - getTerms(parameters: any): Promise - sendTransaction(parameters: any): Promise - signTransaction(parameters: any): Promise - getSponsorshipBalance(parameters: any): Promise +export type SelectPaymentOptionReturnType = { + option: SponsoredOfferSelectable | TokenPaymentOffer + tokenChoice?: TokenChoice | undefined } -export function createPayerClient(parameters: { url?: string; transport?: any }): PayerClient -export function sendSponsoredCalls(client: Client, parameters: any): Promise -export function buildSponsoredCalls(parameters: any): any -export function selectPaymentOption(terms: any, parameters?: any): any -export function isTokenOffer(option: any): boolean -export function isSponsoredOffer(option: any): boolean -export function isDeclinedOffer(option: any): boolean -export function isSelectableOffer(option: any): boolean -export function encodeTokenTransfer(parameters: { token: Address; to: Address; amount: bigint }): any +/** Picks one selectable offer: the matching token offer when `token` is set, else sponsorship first. */ +export function selectPaymentOption( + terms: GetTermsReturnType, + parameters?: { token?: Address | undefined }, +): SelectPaymentOptionReturnType +export function isTokenOffer(option: PaymentOption): option is TokenPaymentOffer +export function isDeclinedOffer(option: PaymentOption): option is SponsoredOfferDeclined + +/** Builds the phase-0 `IERC20.transfer(to, amount)` call. */ +export function encodeTokenTransfer(parameters: { token: Address; to: Address; amount: bigint }): AaCall export type PayerRequote = { token: Address paymentAmount: Hex - feeRecipient?: Address - rate?: { numerator: Hex; denominator: Hex } - ttl?: number + feeRecipient?: Address | undefined + rate?: { numerator: Hex; denominator: Hex } | undefined + ttl?: number | undefined } + +/** `error.data` on a `-32000` payer rejection; branch on the string `code`. */ export type PayerRejectedData = { code: string - reason?: string - balance?: any - gas?: { estimatedCost: Hex; maxCost: Hex } - minGasLimit?: Hex - requote?: PayerRequote + reason?: string | undefined + balance?: PayerBalance | undefined + gas?: { estimatedCost: Hex; maxCost: Hex } | undefined + /** `GAS_TOO_LOW`: the smallest gas limit the calls need. */ + minGasLimit?: Hex | undefined + /** `PAYMENT_INSUFFICIENT`: the corrected phase-0 transfer. */ + requote?: PayerRequote | undefined } -/** Extracts the `PAYER_REJECTED` `data` payload from a thrown payer error (or `undefined`). */ + +/** Extracts {@link PayerRejectedData} from a thrown payer error; `undefined` for other errors. */ export function parsePayerError(error: unknown): PayerRejectedData | undefined -export const payerErrorCode: Record -export const payerRejectedCode: -32000 -export const sponsorshipDeclineCode: Record diff --git a/vendor/aa/index.js b/vendor/aa/index.js index 23aa6c12..2032306e 100644 --- a/vendor/aa/index.js +++ b/vendor/aa/index.js @@ -897,14 +897,14 @@ var init_exports = __esm(() => { init_parseAbiParameters(); }); -// ../viem/src/_esm/accounts/utils/parseAccount.js +// ../viem/src/accounts/utils/parseAccount.ts function parseAccount(account) { if (typeof account === "string") return { address: account, type: "json-rpc" }; return account; } -// ../viem/src/_esm/constants/abis.js +// ../viem/src/constants/abis.ts var multicall3Abi, batchGatewayAbi, universalResolverErrors, universalResolverResolveAbi, universalResolverReverseAbi, textResolverAbi, addressResolverAbi, erc1271Abi, erc6492SignatureValidatorAbi, erc20Abi; var init_abis = __esm(() => { multicall3Abi = [ @@ -1448,7 +1448,7 @@ var init_abis = __esm(() => { ]; }); -// ../viem/src/_esm/utils/abi/formatAbiItem.js +// ../viem/src/utils/abi/formatAbiItem.ts function formatAbiItem2(abiItem, { includeName = false } = {}) { if (abiItem.type !== "function" && abiItem.type !== "event" && abiItem.type !== "error") throw new InvalidDefinitionTypeError(abiItem.type); @@ -1469,7 +1469,7 @@ var init_formatAbiItem2 = __esm(() => { init_abi(); }); -// ../viem/src/_esm/utils/data/isHex.js +// ../viem/src/utils/data/isHex.ts function isHex(value, { strict = true } = {}) { if (!value) return false; @@ -1478,7 +1478,7 @@ function isHex(value, { strict = true } = {}) { return strict ? /^0x[0-9a-fA-F]*$/.test(value) : value.startsWith("0x"); } -// ../viem/src/_esm/utils/data/size.js +// ../viem/src/utils/data/size.ts function size2(value) { if (isHex(value, { strict: false })) return Math.ceil((value.length - 2) / 2); @@ -1486,10 +1486,10 @@ function size2(value) { } var init_size = () => {}; -// ../viem/src/_esm/errors/version.js +// ../viem/src/errors/version.ts var version2 = "2.56.0"; -// ../viem/src/_esm/errors/base.js +// ../viem/src/errors/base.ts function walk(err, fn) { if (fn?.(err)) return err; @@ -1500,10 +1500,20 @@ function walk(err, fn) { var errorConfig, BaseError2; var init_base = __esm(() => { errorConfig = { - getDocsUrl: ({ docsBaseUrl, docsPath = "", docsSlug }) => docsPath ? `${docsBaseUrl ?? "https://viem.sh"}${docsPath}${docsSlug ? `#${docsSlug}` : ""}` : undefined, + getDocsUrl: ({ + docsBaseUrl, + docsPath = "", + docsSlug + }) => docsPath ? `${docsBaseUrl ?? "https://viem.sh"}${docsPath}${docsSlug ? `#${docsSlug}` : ""}` : undefined, version: `viem@${version2}` }; BaseError2 = class BaseError2 extends Error { + details; + docsPath; + metaMessages; + shortMessage; + version; + name = "BaseError"; constructor(shortMessage, args = {}) { const details = (() => { if (args.cause instanceof BaseError2) @@ -1528,42 +1538,6 @@ var init_base = __esm(() => { ].join(` `); super(message, args.cause ? { cause: args.cause } : undefined); - Object.defineProperty(this, "details", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "docsPath", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "metaMessages", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "shortMessage", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "version", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "BaseError" - }); this.details = details; this.docsPath = docsPath; this.metaMessages = args.metaMessages; @@ -1577,7 +1551,7 @@ var init_base = __esm(() => { }; }); -// ../viem/src/_esm/errors/abi.js +// ../viem/src/errors/abi.ts var AbiConstructorNotFoundError, AbiConstructorParamsNotFoundError, AbiDecodingDataSizeTooSmallError, AbiDecodingZeroDataError, AbiEncodingArrayLengthMismatchError, AbiEncodingBytesSizeMismatchError, AbiEncodingLengthMismatchError, AbiErrorInputsNotFoundError, AbiErrorNotFoundError, AbiErrorSignatureNotFoundError, AbiEventSignatureEmptyTopicsError, AbiEventSignatureNotFoundError, AbiEventNotFoundError, AbiFunctionNotFoundError, AbiFunctionOutputsNotFoundError, AbiFunctionSignatureNotFoundError, AbiItemAmbiguityError, BytesSizeMismatchError, DecodeLogDataMismatch, DecodeLogTopicsMismatch, InvalidAbiEncodingTypeError, InvalidAbiDecodingTypeError, InvalidArrayError, InvalidDefinitionTypeError; var init_abi = __esm(() => { init_formatAbiItem2(); @@ -1608,7 +1582,14 @@ var init_abi = __esm(() => { } }; AbiDecodingDataSizeTooSmallError = class AbiDecodingDataSizeTooSmallError extends BaseError2 { - constructor({ data, params, size: size3 }) { + data; + params; + size; + constructor({ + data, + params, + size: size3 + }) { super([`Data size of ${size3} bytes is too small for given parameters.`].join(` `), { metaMessages: [ @@ -1617,24 +1598,6 @@ var init_abi = __esm(() => { ], name: "AbiDecodingDataSizeTooSmallError" }); - Object.defineProperty(this, "data", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "params", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "size", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.data = data; this.params = params; this.size = size3; @@ -1649,7 +1612,11 @@ var init_abi = __esm(() => { } }; AbiEncodingArrayLengthMismatchError = class AbiEncodingArrayLengthMismatchError extends BaseError2 { - constructor({ expectedLength, givenLength, type }) { + constructor({ + expectedLength, + givenLength, + type + }) { super([ `ABI encoding array length mismatch for type ${type}.`, `Expected length: ${expectedLength}`, @@ -1664,7 +1631,10 @@ var init_abi = __esm(() => { } }; AbiEncodingLengthMismatchError = class AbiEncodingLengthMismatchError extends BaseError2 { - constructor({ expectedLength, givenLength }) { + constructor({ + expectedLength, + givenLength + }) { super([ "ABI encoding params/values length mismatch.", `Expected length (params): ${expectedLength}`, @@ -1699,7 +1669,11 @@ var init_abi = __esm(() => { } }; AbiErrorSignatureNotFoundError = class AbiErrorSignatureNotFoundError extends BaseError2 { - constructor(signature, { docsPath, cause }) { + signature; + constructor(signature, { + docsPath, + cause + }) { super([ `Encoded error signature "${signature}" not found on ABI.`, "Make sure you are using the correct ABI and that the error exists on it.", @@ -1710,12 +1684,6 @@ var init_abi = __esm(() => { name: "AbiErrorSignatureNotFoundError", cause }); - Object.defineProperty(this, "signature", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.signature = signature; } }; @@ -1805,14 +1773,26 @@ var init_abi = __esm(() => { } }; BytesSizeMismatchError = class BytesSizeMismatchError extends BaseError2 { - constructor({ expectedSize, givenSize }) { + constructor({ + expectedSize, + givenSize + }) { super(`Expected bytes${expectedSize}, got bytes${givenSize}.`, { name: "BytesSizeMismatchError" }); } }; DecodeLogDataMismatch = class DecodeLogDataMismatch extends BaseError2 { - constructor({ abiItem, data, params, size: size3 }) { + abiItem; + data; + params; + size; + constructor({ + abiItem, + data, + params, + size: size3 + }) { super([ `Data size of ${size3} bytes is too small for non-indexed event parameters.` ].join(` @@ -1823,30 +1803,6 @@ var init_abi = __esm(() => { ], name: "DecodeLogDataMismatch" }); - Object.defineProperty(this, "abiItem", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "data", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "params", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "size", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.abiItem = abiItem; this.data = data; this.params = params; @@ -1854,17 +1810,15 @@ var init_abi = __esm(() => { } }; DecodeLogTopicsMismatch = class DecodeLogTopicsMismatch extends BaseError2 { - constructor({ abiItem, param }) { + abiItem; + constructor({ + abiItem, + param + }) { super([ `Expected a topic for indexed event parameter${param.name ? ` "${param.name}"` : ""} on event "${formatAbiItem2(abiItem, { includeName: true })}".` ].join(` `), { name: "DecodeLogTopicsMismatch" }); - Object.defineProperty(this, "abiItem", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.abiItem = abiItem; } }; @@ -1905,7 +1859,7 @@ var init_abi = __esm(() => { }; }); -// ../viem/src/_esm/errors/address.js +// ../viem/src/errors/address.ts var InvalidAddressError; var init_address = __esm(() => { init_base(); @@ -1922,28 +1876,40 @@ var init_address = __esm(() => { }; }); -// ../viem/src/_esm/errors/data.js +// ../viem/src/errors/data.ts var SliceOffsetOutOfBoundsError, SizeExceedsPaddingSizeError, InvalidBytesLengthError; var init_data = __esm(() => { init_base(); SliceOffsetOutOfBoundsError = class SliceOffsetOutOfBoundsError extends BaseError2 { - constructor({ offset, position, size: size3 }) { + constructor({ + offset, + position, + size: size3 + }) { super(`Slice ${position === "start" ? "starting" : "ending"} at offset "${offset}" is out-of-bounds (size: ${size3}).`, { name: "SliceOffsetOutOfBoundsError" }); } }; SizeExceedsPaddingSizeError = class SizeExceedsPaddingSizeError extends BaseError2 { - constructor({ size: size3, targetSize, type }) { + constructor({ + size: size3, + targetSize, + type + }) { super(`${type.charAt(0).toUpperCase()}${type.slice(1).toLowerCase()} size (${size3}) exceeds padding size (${targetSize}).`, { name: "SizeExceedsPaddingSizeError" }); } }; InvalidBytesLengthError = class InvalidBytesLengthError extends BaseError2 { - constructor({ size: size3, targetSize, type }) { + constructor({ + size: size3, + targetSize, + type + }) { super(`${type.charAt(0).toUpperCase()}${type.slice(1).toLowerCase()} is expected to be ${targetSize} ${type} long, but is ${size3} ${type} long.`, { name: "InvalidBytesLengthError" }); } }; }); -// ../viem/src/_esm/utils/data/pad.js +// ../viem/src/utils/data/pad.ts function pad(hexOrBytes, { dir, size: size3 = 32 } = {}) { if (typeof hexOrBytes === "string") return padHex(hexOrBytes, { dir, size: size3 }); @@ -1981,12 +1947,18 @@ var init_pad = __esm(() => { init_data(); }); -// ../viem/src/_esm/errors/encoding.js -var IntegerOutOfRangeError, InvalidBytesBooleanError, InvalidHexBooleanError, InvalidHexValueError, RlpDepthLimitExceededError, RlpListBoundaryExceededError, RlpTrailingBytesError, SizeOverflowError; +// ../viem/src/errors/encoding.ts +var IntegerOutOfRangeError, InvalidBytesBooleanError, InvalidHexBooleanError, SizeOverflowError; var init_encoding = __esm(() => { init_base(); IntegerOutOfRangeError = class IntegerOutOfRangeError extends BaseError2 { - constructor({ max, min, signed, size: size3, value }) { + constructor({ + max, + min, + signed, + size: size3, + value + }) { super(`Number "${value}" is not in safe ${size3 ? `${size3 * 8}-bit ${signed ? "signed" : "unsigned"} ` : ""}integer range ${max ? `(${min} to ${max})` : `(above ${min})`}`, { name: "IntegerOutOfRangeError" }); } }; @@ -2002,28 +1974,6 @@ var init_encoding = __esm(() => { super(`Hex value "${hex}" is not a valid boolean. The hex value must be "0x0" (false) or "0x1" (true).`, { name: "InvalidHexBooleanError" }); } }; - InvalidHexValueError = class InvalidHexValueError extends BaseError2 { - constructor(value) { - super(`Hex value "${value}" is an odd length (${value.length}). It must be an even length.`, { name: "InvalidHexValueError" }); - } - }; - RlpDepthLimitExceededError = class RlpDepthLimitExceededError extends BaseError2 { - constructor({ limit }) { - super(`RLP depth limit of \`${limit}\` exceeded.`, { - name: "RlpDepthLimitExceededError" - }); - } - }; - RlpListBoundaryExceededError = class RlpListBoundaryExceededError extends BaseError2 { - constructor({ consumed, declared }) { - super(`RLP list items consumed \`${consumed}\` bytes but the list declared a length of \`${declared}\`.`, { name: "RlpListBoundaryExceededError" }); - } - }; - RlpTrailingBytesError = class RlpTrailingBytesError extends BaseError2 { - constructor({ count }) { - super(`RLP payload encodes a single item, but \`${count}\` trailing ${count === 1 ? "byte remains" : "bytes remain"}.`, { name: "RlpTrailingBytesError" }); - } - }; SizeOverflowError = class SizeOverflowError extends BaseError2 { constructor({ givenSize, maxSize }) { super(`Size cannot exceed ${maxSize} bytes. Given size: ${givenSize} bytes.`, { name: "SizeOverflowError" }); @@ -2031,7 +1981,7 @@ var init_encoding = __esm(() => { }; }); -// ../viem/src/_esm/utils/data/trim.js +// ../viem/src/utils/data/trim.ts function trim(hexOrBytes, { dir = "left" } = {}) { let data = typeof hexOrBytes === "string" ? hexOrBytes.replace("0x", "") : hexOrBytes; let sliceLength = 0; @@ -2050,7 +2000,7 @@ function trim(hexOrBytes, { dir = "left" } = {}) { return data; } -// ../viem/src/_esm/utils/encoding/fromHex.js +// ../viem/src/utils/encoding/fromHex.ts function assertSize(hexOrBytes, { size: size3 }) { if (size2(hexOrBytes) > size3) throw new SizeOverflowError({ @@ -2101,7 +2051,7 @@ var init_fromHex = __esm(() => { init_size(); }); -// ../viem/src/_esm/utils/encoding/toHex.js +// ../viem/src/utils/encoding/toHex.ts function toHex(value, opts = {}) { if (typeof value === "number" || typeof value === "bigint") return numberToHex(value, opts); @@ -2173,7 +2123,7 @@ var init_toHex = __esm(() => { encoder = /* @__PURE__ */ new TextEncoder; }); -// ../viem/src/_esm/utils/encoding/toBytes.js +// ../viem/src/utils/encoding/toBytes.ts function toBytes(value, opts = {}) { if (typeof value === "number" || typeof value === "bigint") return numberToBytes(value, opts); @@ -2267,11 +2217,7 @@ function split(lst, le = false) { } return [Ah, Al]; } -function add(Ah, Al, Bh, Bl) { - const l = (Al >>> 0) + (Bl >>> 0); - return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 }; -} -var U32_MASK64, _32n, shrSH = (h, _l, s) => h >>> s, shrSL = (h, l, s) => h << 32 - s | l >>> s, rotrSH = (h, l, s) => h >>> s | l << 32 - s, rotrSL = (h, l, s) => h << 32 - s | l >>> s, rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32, rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s, rotlSH = (h, l, s) => h << s | l >>> 32 - s, rotlSL = (h, l, s) => l << s | h >>> 32 - s, rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s, rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s, add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0), add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0, add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0), add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0, add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0), add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0; +var U32_MASK64, _32n, rotlSH = (h, l, s) => h << s | l >>> 32 - s, rotlSL = (h, l, s) => l << s | h >>> 32 - s, rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s, rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s; var init__u64 = __esm(() => { U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); _32n = /* @__PURE__ */ BigInt(32); @@ -2575,7 +2521,7 @@ var init_sha3 = __esm(() => { keccak_256 = /* @__PURE__ */ (() => gen(1, 136, 256 / 8))(); }); -// ../viem/src/_esm/utils/hash/keccak256.js +// ../viem/src/utils/hash/keccak256.ts function keccak256(value, to_) { const to = to_ || "hex"; const bytes = keccak_256(isHex(value, { strict: false }) ? toBytes(value) : value); @@ -2589,18 +2535,13 @@ var init_keccak256 = __esm(() => { init_toHex(); }); -// ../viem/src/_esm/utils/lru.js +// ../viem/src/utils/lru.ts var LruMap; var init_lru = __esm(() => { LruMap = class LruMap extends Map { + maxSize; constructor(size3) { super(); - Object.defineProperty(this, "maxSize", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.maxSize = size3; } get(key) { @@ -2625,7 +2566,7 @@ var init_lru = __esm(() => { }; }); -// ../viem/src/_esm/utils/address/isAddress.js +// ../viem/src/utils/address/isAddress.ts function isAddress(address, options) { const { strict = true } = options ?? {}; const cacheKey = `${address}.${strict}`; @@ -2651,7 +2592,7 @@ var init_isAddress = __esm(() => { isAddressCache = /* @__PURE__ */ new LruMap(8192); }); -// ../viem/src/_esm/utils/address/getAddress.js +// ../viem/src/utils/address/getAddress.ts function checksumAddress(address_, chainId) { if (checksumAddressCache.has(`${address_}.${chainId}`)) return checksumAddressCache.get(`${address_}.${chainId}`); @@ -2685,7 +2626,7 @@ var init_getAddress = __esm(() => { checksumAddressCache = /* @__PURE__ */ new LruMap(8192); }); -// ../viem/src/_esm/errors/cursor.js +// ../viem/src/errors/cursor.ts var NegativeOffsetError, PositionOutOfBoundsError, RecursiveReadLimitExceededError; var init_cursor = __esm(() => { init_base(); @@ -2708,7 +2649,7 @@ var init_cursor = __esm(() => { }; }); -// ../viem/src/_esm/utils/cursor.js +// ../viem/src/utils/cursor.ts function createCursor(bytes, { recursiveReadLimit = 8192 } = {}) { const cursor = Object.create(staticCursor); cursor.bytes = bytes; @@ -2881,7 +2822,7 @@ var init_cursor2 = __esm(() => { }; }); -// ../viem/src/_esm/utils/data/slice.js +// ../viem/src/utils/data/slice.ts function slice(value, start, end, { strict } = {}) { if (isHex(value, { strict: false })) return sliceHex(value, start, end, { @@ -2927,7 +2868,7 @@ var init_slice = __esm(() => { init_size(); }); -// ../viem/src/_esm/utils/encoding/fromBytes.js +// ../viem/src/utils/encoding/fromBytes.ts function bytesToBigInt(bytes, opts = {}) { if (typeof opts.size !== "undefined") assertSize(bytes, { size: opts.size }); @@ -2964,7 +2905,7 @@ var init_fromBytes = __esm(() => { init_toHex(); }); -// ../viem/src/_esm/utils/data/concat.js +// ../viem/src/utils/data/concat.ts function concat(values) { if (typeof values[0] === "string") return concatHex(values); @@ -2987,14 +2928,14 @@ function concatHex(values) { return `0x${values.reduce((acc, x) => acc + x.replace("0x", ""), "")}`; } -// ../viem/src/_esm/utils/regex.js +// ../viem/src/utils/regex.ts var bytesRegex2, integerRegex2; var init_regex2 = __esm(() => { bytesRegex2 = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/; integerRegex2 = /^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/; }); -// ../viem/src/_esm/utils/abi/encodeAbiParameters.js +// ../viem/src/utils/abi/encodeAbiParameters.ts function encodeAbiParameters(params, values) { if (params.length !== values.length) throw new AbiEncodingLengthMismatchError({ @@ -3007,14 +2948,20 @@ function encodeAbiParameters(params, values) { }); return encodeParams(preparedParams); } -function prepareParams({ params, values }) { +function prepareParams({ + params, + values +}) { const preparedParams = []; for (let i = 0;i < params.length; i++) { preparedParams.push(prepareParam({ param: params[i], value: values[i] })); } return preparedParams; } -function prepareParam({ param, value }) { +function prepareParam({ + param, + value +}) { const arrayComponents = getArrayComponents(param.type); if (arrayComponents) { const [length, type] = arrayComponents; @@ -3078,7 +3025,10 @@ function encodeAddress(value) { throw new InvalidAddressError({ address: value }); return { dynamic: false, encoded: padHex(value.toLowerCase()) }; } -function encodeArray(value, { length, param }) { +function encodeArray(value, { + length, + param +}) { const dynamic = length === null; if (!Array.isArray(value)) throw new InvalidArrayError(value); @@ -3232,7 +3182,7 @@ var init_encodeAbiParameters = __esm(() => { init_regex2(); }); -// ../viem/src/_esm/utils/abi/decodeAbiParameters.js +// ../viem/src/utils/abi/decodeAbiParameters.ts function decodeAbiParameters(params, data) { const bytes = typeof data === "string" ? hexToBytes(data) : data; const cursor = createCursor(bytes); @@ -3438,7 +3388,7 @@ var init_decodeAbiParameters = __esm(() => { init_encodeAbiParameters(); }); -// ../viem/src/_esm/utils/hash/hashSignature.js +// ../viem/src/utils/hash/hashSignature.ts function hashSignature(sig) { return hash(sig); } @@ -3448,7 +3398,7 @@ var init_hashSignature = __esm(() => { init_keccak256(); }); -// ../viem/src/_esm/utils/hash/normalizeSignature.js +// ../viem/src/utils/hash/normalizeSignature.ts function normalizeSignature(signature) { let active = true; let current = ""; @@ -3495,7 +3445,7 @@ var init_normalizeSignature = __esm(() => { init_base(); }); -// ../viem/src/_esm/utils/hash/toSignature.js +// ../viem/src/utils/hash/toSignature.ts var toSignature = (def) => { const def_ = (() => { if (typeof def === "string") @@ -3509,7 +3459,7 @@ var init_toSignature = __esm(() => { init_normalizeSignature(); }); -// ../viem/src/_esm/utils/hash/toSignatureHash.js +// ../viem/src/utils/hash/toSignatureHash.ts function toSignatureHash(fn) { return hashSignature(toSignature(fn)); } @@ -3518,21 +3468,21 @@ var init_toSignatureHash = __esm(() => { init_toSignature(); }); -// ../viem/src/_esm/utils/hash/toEventSelector.js +// ../viem/src/utils/hash/toEventSelector.ts var toEventSelector; var init_toEventSelector = __esm(() => { init_toSignatureHash(); toEventSelector = toSignatureHash; }); -// ../viem/src/_esm/utils/hash/toFunctionSelector.js +// ../viem/src/utils/hash/toFunctionSelector.ts var toFunctionSelector = (fn) => slice(toSignatureHash(fn), 0, 4); var init_toFunctionSelector = __esm(() => { init_slice(); init_toSignatureHash(); }); -// ../viem/src/_esm/utils/abi/getAbiItem.js +// ../viem/src/utils/abi/getAbiItem.ts function getAbiItem(parameters) { const { abi, args = [], name } = parameters; const isSelector = isHex(name, { strict: false }); @@ -3649,7 +3599,7 @@ var init_getAbiItem = __esm(() => { init_toFunctionSelector(); }); -// ../viem/src/_esm/utils/abi/decodeFunctionResult.js +// ../viem/src/utils/abi/decodeFunctionResult.ts function decodeFunctionResult(parameters) { const { abi, args, functionName, data } = parameters; let abiItem = abi[0]; @@ -3677,7 +3627,7 @@ var init_decodeFunctionResult = __esm(() => { init_getAbiItem(); }); -// ../viem/src/_esm/utils/abi/prepareEncodeFunctionData.js +// ../viem/src/utils/abi/prepareEncodeFunctionData.ts function prepareEncodeFunctionData(parameters) { const { abi, args, functionName } = parameters; let abiItem = abi[0]; @@ -3706,7 +3656,7 @@ var init_prepareEncodeFunctionData = __esm(() => { init_getAbiItem(); }); -// ../viem/src/_esm/utils/abi/encodeFunctionData.js +// ../viem/src/utils/abi/encodeFunctionData.ts function encodeFunctionData(parameters) { const { args } = parameters; const { abi, functionName } = (() => { @@ -3724,12 +3674,16 @@ var init_encodeFunctionData = __esm(() => { init_prepareEncodeFunctionData(); }); -// ../viem/src/_esm/errors/chain.js -var ChainDoesNotSupportContract, ChainMismatchError, ChainNotFoundError, ClientChainNotConfiguredError, InvalidChainIdError; +// ../viem/src/errors/chain.ts +var ChainDoesNotSupportContract, ClientChainNotConfiguredError, InvalidChainIdError; var init_chain = __esm(() => { init_base(); ChainDoesNotSupportContract = class ChainDoesNotSupportContract extends BaseError2 { - constructor({ blockNumber, chain, contract }) { + constructor({ + blockNumber, + chain, + contract + }) { super(`Chain "${chain.name}" does not support contract "${contract.name}".`, { metaMessages: [ "This could be due to any of the following:", @@ -3743,28 +3697,6 @@ var init_chain = __esm(() => { }); } }; - ChainMismatchError = class ChainMismatchError extends BaseError2 { - constructor({ chain, currentChainId }) { - super(`The current chain of the wallet (id: ${currentChainId}) does not match the target chain for the transaction (id: ${chain.id} – ${chain.name}).`, { - metaMessages: [ - `Current Chain ID: ${currentChainId}`, - `Expected Chain ID: ${chain.id} – ${chain.name}` - ], - name: "ChainMismatchError" - }); - } - }; - ChainNotFoundError = class ChainNotFoundError extends BaseError2 { - constructor() { - super([ - "No chain was provided to the request.", - "Please provide a chain with the `chain` argument on the Action, or by supplying a `chain` to WalletClient." - ].join(` -`), { - name: "ChainNotFoundError" - }); - } - }; ClientChainNotConfiguredError = class ClientChainNotConfiguredError extends BaseError2 { constructor() { super("No chain was provided to the Client.", { @@ -3779,8 +3711,12 @@ var init_chain = __esm(() => { }; }); -// ../viem/src/_esm/utils/chain/getChainContractAddress.js -function getChainContractAddress({ blockNumber, chain, contract: name }) { +// ../viem/src/utils/chain/getChainContractAddress.ts +function getChainContractAddress({ + blockNumber, + chain, + contract: name +}) { const contract = chain?.contracts?.[name]; if (!contract) throw new ChainDoesNotSupportContract({ @@ -3802,7 +3738,7 @@ var init_getChainContractAddress = __esm(() => { init_chain(); }); -// ../viem/src/_esm/constants/solidity.js +// ../viem/src/constants/solidity.ts var panicReasons, solidityError, solidityPanic; var init_solidity = __esm(() => { panicReasons = { @@ -3838,7 +3774,7 @@ var init_solidity = __esm(() => { }; }); -// ../viem/src/_esm/utils/abi/decodeErrorResult.js +// ../viem/src/utils/abi/decodeErrorResult.ts function decodeErrorResult(parameters) { const { abi, data, cause } = parameters; const signature = slice(data, 0, 4); @@ -3866,14 +3802,19 @@ var init_decodeErrorResult = __esm(() => { init_formatAbiItem2(); }); -// ../viem/src/_esm/utils/stringify.js +// ../viem/src/utils/stringify.ts var stringify = (value, replacer, space) => JSON.stringify(value, (key, value_) => { const value2 = typeof value_ === "bigint" ? value_.toString() : value_; return typeof replacer === "function" ? replacer(key, value2) : value2; }, space); -// ../viem/src/_esm/utils/abi/formatAbiItemWithArgs.js -function formatAbiItemWithArgs({ abiItem, args, includeFunctionName = true, includeName = false }) { +// ../viem/src/utils/abi/formatAbiItemWithArgs.ts +function formatAbiItemWithArgs({ + abiItem, + args, + includeFunctionName = true, + includeName = false +}) { if (!("name" in abiItem)) return; if (!("inputs" in abiItem)) @@ -3884,7 +3825,7 @@ function formatAbiItemWithArgs({ abiItem, args, includeFunctionName = true, incl } var init_formatAbiItemWithArgs = () => {}; -// ../viem/src/_esm/utils/unit/Value.js +// ../viem/src/utils/unit/Value.ts function format(value, decimals = 0) { if (!Number.isInteger(decimals) || decimals < 0) throw new InvalidDecimalsError({ decimals }); @@ -3968,30 +3909,20 @@ var init_Value = __esm(() => { ether: 18 }; InvalidDecimalNumberError = class InvalidDecimalNumberError extends Error { + name = "Value.InvalidDecimalNumberError"; constructor({ value }) { super(`Value \`${value}\` is not a valid decimal number.`); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "Value.InvalidDecimalNumberError" - }); } }; InvalidDecimalsError = class InvalidDecimalsError extends Error { + name = "Value.InvalidDecimalsError"; constructor({ decimals }) { super(`\`decimals\` must be a non-negative integer. Got \`${decimals}\`.`); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "Value.InvalidDecimalsError" - }); } }; }); -// ../viem/src/_esm/utils/unit/formatEther.js +// ../viem/src/utils/unit/formatEther.ts function formatEther2(wei, unit = "wei") { return formatEther(wei, unit); } @@ -3999,7 +3930,7 @@ var init_formatEther = __esm(() => { init_Value(); }); -// ../viem/src/_esm/utils/unit/formatGwei.js +// ../viem/src/utils/unit/formatGwei.ts function formatGwei2(wei, unit = "wei") { return formatGwei(wei, unit); } @@ -4007,7 +3938,7 @@ var init_formatGwei = __esm(() => { init_Value(); }); -// ../viem/src/_esm/errors/stateOverride.js +// ../viem/src/errors/stateOverride.ts function prettyStateMapping(stateMapping) { return stateMapping.reduce((pretty, { slot, value }) => { return `${pretty} ${slot}: ${value} @@ -4060,7 +3991,7 @@ var init_stateOverride = __esm(() => { }; }); -// ../viem/src/_esm/errors/transaction.js +// ../viem/src/errors/transaction.ts function prettyPrint(args) { const entries = Object.entries(args).map(([key, value]) => { if (value === undefined || value === false) @@ -4077,7 +4008,10 @@ var init_transaction = __esm(() => { init_formatGwei(); init_base(); FeePayerNonceMismatchError = class FeePayerNonceMismatchError extends BaseError2 { - constructor({ filledNonce, requestedNonce }) { + constructor({ + filledNonce, + requestedNonce + }) { super("The filled transaction nonce does not match the requested nonce.", { metaMessages: [ `Requested Nonce: ${requestedNonce}`, @@ -4121,7 +4055,20 @@ var init_transaction = __esm(() => { } }; TransactionExecutionError = class TransactionExecutionError extends BaseError2 { - constructor(cause, { account, docsPath: docsPath3, chain, data, gas, gasPrice, maxFeePerGas, maxPriorityFeePerGas, nonce, to, value }) { + cause; + constructor(cause, { + account, + docsPath: docsPath3, + chain, + data, + gas, + gasPrice, + maxFeePerGas, + maxPriorityFeePerGas, + nonce, + to, + value + }) { const prettyArgs = prettyPrint({ chain: chain && `${chain?.name} (id: ${chain?.id})`, from: account?.address, @@ -4144,17 +4091,17 @@ var init_transaction = __esm(() => { ].filter(Boolean), name: "TransactionExecutionError" }); - Object.defineProperty(this, "cause", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.cause = cause; } }; TransactionNotFoundError = class TransactionNotFoundError extends BaseError2 { - constructor({ blockHash, blockNumber, blockTag, hash: hash2, index: index2 }) { + constructor({ + blockHash, + blockNumber, + blockTag, + hash: hash2, + index: index2 + }) { let identifier = "Transaction"; if (blockTag && index2 !== undefined) identifier = `Transaction at block time "${blockTag}" at index "${index2}"`; @@ -4177,6 +4124,7 @@ var init_transaction = __esm(() => { } }; TransactionReceiptRevertedError = class TransactionReceiptRevertedError extends BaseError2 { + receipt; constructor({ receipt }) { super(`Transaction with hash "${receipt.transactionHash}" reverted.`, { metaMessages: [ @@ -4188,12 +4136,6 @@ var init_transaction = __esm(() => { ], name: "TransactionReceiptRevertedError" }); - Object.defineProperty(this, "receipt", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.receipt = receipt; } }; @@ -4204,7 +4146,7 @@ var init_transaction = __esm(() => { }; }); -// ../viem/src/_esm/errors/utils.js +// ../viem/src/errors/utils.ts function getAbortError(signal) { if (signal?.reason) return signal.reason; @@ -4230,7 +4172,7 @@ var getContractAddress = (address) => address, getUrl = (url) => { } }; -// ../viem/src/_esm/errors/contract.js +// ../viem/src/errors/contract.ts var CallExecutionError, ContractFunctionExecutionError, ContractFunctionRevertedError, ContractFunctionZeroDataError, CounterfactualDeploymentFailedError, RawContractError; var init_contract = __esm(() => { init_solidity(); @@ -4245,7 +4187,21 @@ var init_contract = __esm(() => { init_stateOverride(); init_transaction(); CallExecutionError = class CallExecutionError extends BaseError2 { - constructor(cause, { account: account_, docsPath: docsPath3, chain, data, gas, gasPrice, maxFeePerGas, maxPriorityFeePerGas, nonce, to, value, stateOverride }) { + cause; + constructor(cause, { + account: account_, + docsPath: docsPath3, + chain, + data, + gas, + gasPrice, + maxFeePerGas, + maxPriorityFeePerGas, + nonce, + to, + value, + stateOverride + }) { const account = account_ ? parseAccount(account_) : undefined; let prettyArgs = prettyPrint({ from: account?.address, @@ -4272,17 +4228,25 @@ ${prettyStateOverride(stateOverride)}`; ].filter(Boolean), name: "CallExecutionError" }); - Object.defineProperty(this, "cause", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.cause = cause; } }; ContractFunctionExecutionError = class ContractFunctionExecutionError extends BaseError2 { - constructor(cause, { abi, args, contractAddress, docsPath: docsPath3, functionName, sender }) { + abi; + args; + cause; + contractAddress; + formattedArgs; + functionName; + sender; + constructor(cause, { + abi, + args, + contractAddress, + docsPath: docsPath3, + functionName, + sender + }) { const abiItem = getAbiItem({ abi, args, name: functionName }); const formattedArgs = abiItem ? formatAbiItemWithArgs({ abiItem, @@ -4307,48 +4271,6 @@ ${prettyStateOverride(stateOverride)}`; ].filter(Boolean), name: "ContractFunctionExecutionError" }); - Object.defineProperty(this, "abi", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "args", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "cause", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "contractAddress", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "formattedArgs", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "functionName", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "sender", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.abi = abi; this.args = args; this.cause = cause; @@ -4358,7 +4280,17 @@ ${prettyStateOverride(stateOverride)}`; } }; ContractFunctionRevertedError = class ContractFunctionRevertedError extends BaseError2 { - constructor({ abi, data, functionName, message, cause: error }) { + data; + raw; + reason; + signature; + constructor({ + abi, + data, + functionName, + message, + cause: error + }) { let cause; let decodedData; let metaMessages; @@ -4408,30 +4340,6 @@ ${prettyStateOverride(stateOverride)}`; metaMessages, name: "ContractFunctionRevertedError" }); - Object.defineProperty(this, "data", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "raw", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "reason", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "signature", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.data = decodedData; this.raw = data; this.reason = reason; @@ -4439,7 +4347,10 @@ ${prettyStateOverride(stateOverride)}`; } }; ContractFunctionZeroDataError = class ContractFunctionZeroDataError extends BaseError2 { - constructor({ functionName, cause }) { + constructor({ + functionName, + cause + }) { super(`The contract function "${functionName}" returned no data ("0x").`, { metaMessages: [ "This could be due to any of the following:", @@ -4465,26 +4376,19 @@ ${prettyStateOverride(stateOverride)}`; } }; RawContractError = class RawContractError extends BaseError2 { - constructor({ data, message }) { + code = 3; + data; + constructor({ + data, + message + }) { super(message || "", { name: "RawContractError" }); - Object.defineProperty(this, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 3 - }); - Object.defineProperty(this, "data", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.data = data; } }; }); -// ../viem/src/_esm/utils/abi/decodeFunctionData.js +// ../viem/src/utils/abi/decodeFunctionData.ts function decodeFunctionData(parameters) { const { abi, data } = parameters; const signature = slice(data, 0, 4); @@ -4506,7 +4410,7 @@ var init_decodeFunctionData = __esm(() => { init_formatAbiItem2(); }); -// ../viem/src/_esm/utils/abi/encodeErrorResult.js +// ../viem/src/utils/abi/encodeErrorResult.ts function encodeErrorResult(parameters) { const { abi, errorName, args } = parameters; let abiItem = abi[0]; @@ -4537,7 +4441,7 @@ var init_encodeErrorResult = __esm(() => { init_getAbiItem(); }); -// ../viem/src/_esm/utils/abi/encodeFunctionResult.js +// ../viem/src/utils/abi/encodeFunctionResult.ts function encodeFunctionResult(parameters) { const { abi, functionName, result } = parameters; let abiItem = abi[0]; @@ -4569,10 +4473,12 @@ var init_encodeFunctionResult = __esm(() => { init_getAbiItem(); }); -// ../viem/src/_esm/utils/ens/localBatchGatewayRequest.js +// ../viem/src/utils/ens/localBatchGatewayRequest.ts async function localBatchGatewayRequest(parameters) { const { data, ccipRequest } = parameters; - const { args: [queries] } = decodeFunctionData({ abi: batchGatewayAbi, data }); + const { + args: [queries] + } = decodeFunctionData({ abi: batchGatewayAbi, data }); const failures = []; const responses = []; await Promise.all(queries.map(async (query, i) => { @@ -4612,12 +4518,23 @@ var init_localBatchGatewayRequest = __esm(() => { init_encodeFunctionResult(); }); -// ../viem/src/_esm/errors/request.js +// ../viem/src/errors/request.ts var HttpRequestError, ResponseBodyTooLargeError, RpcRequestError, TimeoutError; var init_request = __esm(() => { init_base(); HttpRequestError = class HttpRequestError extends BaseError2 { - constructor({ body, cause, details, headers, status, url }) { + body; + headers; + status; + url; + constructor({ + body, + cause, + details, + headers, + status, + url + }) { super("HTTP request failed.", { cause, details, @@ -4628,30 +4545,6 @@ var init_request = __esm(() => { ].filter(Boolean), name: "HttpRequestError" }); - Object.defineProperty(this, "body", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "headers", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "status", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "url", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.body = body; this.headers = headers; this.status = status; @@ -4659,112 +4552,86 @@ var init_request = __esm(() => { } }; ResponseBodyTooLargeError = class ResponseBodyTooLargeError extends BaseError2 { + maxSize; + size; constructor({ maxSize, size: size3 }) { super("HTTP response body exceeded the size limit.", { metaMessages: [`Max: ${maxSize} bytes`, `Received: ${size3} bytes`], name: "ResponseBodyTooLargeError" }); - Object.defineProperty(this, "maxSize", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "size", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.maxSize = maxSize; this.size = size3; } }; RpcRequestError = class RpcRequestError extends BaseError2 { - constructor({ body, error, url }) { + code; + data; + url; + constructor({ + body, + error, + url + }) { super("RPC Request failed.", { cause: error, details: error.message, metaMessages: [`URL: ${getUrl(url)}`, `Request body: ${stringify(body)}`], name: "RpcRequestError" }); - Object.defineProperty(this, "code", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "data", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - Object.defineProperty(this, "url", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.code = error.code; this.data = error.data; this.url = url; } }; TimeoutError = class TimeoutError extends BaseError2 { - constructor({ body, url }) { + url; + constructor({ + body, + url + }) { super("The request took too long to respond.", { details: "The request timed out.", metaMessages: [`URL: ${getUrl(url)}`, `Request body: ${stringify(body)}`], name: "TimeoutError" }); - Object.defineProperty(this, "url", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.url = url; } }; }); -// ../viem/src/_esm/errors/rpc.js +// ../viem/src/errors/rpc.ts var unknownErrorCode = -1, RpcError, ProviderRpcError, ParseRpcError, InvalidRequestRpcError, MethodNotFoundRpcError, InvalidParamsRpcError, InternalRpcError, InvalidInputRpcError, ResourceNotFoundRpcError, ResourceUnavailableRpcError, TransactionRejectedRpcError, MethodNotSupportedRpcError, LimitExceededRpcError, JsonRpcVersionUnsupportedError, UserRejectedRequestError, UnauthorizedProviderError, UnsupportedProviderMethodError, ProviderDisconnectedError, ChainDisconnectedError, SwitchChainError, UnsupportedNonOptionalCapabilityError, UnsupportedChainIdError, DuplicateIdError, UnknownBundleIdError, BundleTooLargeError, AtomicReadyWalletRejectedUpgradeError, AtomicityNotSupportedError, WalletConnectSessionSettlementError, UnknownRpcError; var init_rpc = __esm(() => { init_base(); init_request(); RpcError = class RpcError extends BaseError2 { - constructor(cause, { code, docsPath: docsPath5, metaMessages, name, shortMessage }) { + code; + constructor(cause, { + code, + docsPath: docsPath5, + metaMessages, + name, + shortMessage + }) { super(shortMessage, { cause, docsPath: docsPath5, metaMessages: metaMessages || cause?.metaMessages, name: name || "RpcError" }); - Object.defineProperty(this, "code", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.name = name || cause.name; this.code = cause instanceof RpcRequestError ? cause.code : code ?? unknownErrorCode; } }; ProviderRpcError = class ProviderRpcError extends RpcError { + data; constructor(cause, options) { super(cause, options); - Object.defineProperty(this, "data", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.data = options.data; } }; ParseRpcError = class ParseRpcError extends RpcError { + static code = -32700; constructor(cause) { super(cause, { code: ParseRpcError.code, @@ -4773,13 +4640,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(ParseRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32700 - }); InvalidRequestRpcError = class InvalidRequestRpcError extends RpcError { + static code = -32600; constructor(cause) { super(cause, { code: InvalidRequestRpcError.code, @@ -4788,13 +4650,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(InvalidRequestRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32600 - }); MethodNotFoundRpcError = class MethodNotFoundRpcError extends RpcError { + static code = -32601; constructor(cause, { method } = {}) { super(cause, { code: MethodNotFoundRpcError.code, @@ -4803,13 +4660,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(MethodNotFoundRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32601 - }); InvalidParamsRpcError = class InvalidParamsRpcError extends RpcError { + static code = -32602; constructor(cause) { super(cause, { code: InvalidParamsRpcError.code, @@ -4822,13 +4674,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(InvalidParamsRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32602 - }); InternalRpcError = class InternalRpcError extends RpcError { + static code = -32603; constructor(cause) { super(cause, { code: InternalRpcError.code, @@ -4837,13 +4684,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(InternalRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32603 - }); InvalidInputRpcError = class InvalidInputRpcError extends RpcError { + static code = -32000; constructor(cause) { super(cause, { code: InvalidInputRpcError.code, @@ -4856,34 +4698,19 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(InvalidInputRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32000 - }); ResourceNotFoundRpcError = class ResourceNotFoundRpcError extends RpcError { + name = "ResourceNotFoundRpcError"; + static code = -32001; constructor(cause) { super(cause, { code: ResourceNotFoundRpcError.code, name: "ResourceNotFoundRpcError", shortMessage: "Requested resource not found." }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "ResourceNotFoundRpcError" - }); } }; - Object.defineProperty(ResourceNotFoundRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32001 - }); ResourceUnavailableRpcError = class ResourceUnavailableRpcError extends RpcError { + static code = -32002; constructor(cause) { super(cause, { code: ResourceUnavailableRpcError.code, @@ -4892,13 +4719,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(ResourceUnavailableRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32002 - }); TransactionRejectedRpcError = class TransactionRejectedRpcError extends RpcError { + static code = -32003; constructor(cause) { super(cause, { code: TransactionRejectedRpcError.code, @@ -4907,13 +4729,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(TransactionRejectedRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32003 - }); MethodNotSupportedRpcError = class MethodNotSupportedRpcError extends RpcError { + static code = -32004; constructor(cause, { method } = {}) { super(cause, { code: MethodNotSupportedRpcError.code, @@ -4922,13 +4739,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(MethodNotSupportedRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32004 - }); LimitExceededRpcError = class LimitExceededRpcError extends RpcError { + static code = -32005; constructor(cause) { super(cause, { code: LimitExceededRpcError.code, @@ -4937,13 +4749,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(LimitExceededRpcError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32005 - }); JsonRpcVersionUnsupportedError = class JsonRpcVersionUnsupportedError extends RpcError { + static code = -32006; constructor(cause) { super(cause, { code: JsonRpcVersionUnsupportedError.code, @@ -4952,13 +4759,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(JsonRpcVersionUnsupportedError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32006 - }); UserRejectedRequestError = class UserRejectedRequestError extends ProviderRpcError { + static code = 4001; constructor(cause) { super(cause, { code: UserRejectedRequestError.code, @@ -4967,13 +4769,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(UserRejectedRequestError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 4001 - }); UnauthorizedProviderError = class UnauthorizedProviderError extends ProviderRpcError { + static code = 4100; constructor(cause) { super(cause, { code: UnauthorizedProviderError.code, @@ -4982,13 +4779,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(UnauthorizedProviderError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 4100 - }); UnsupportedProviderMethodError = class UnsupportedProviderMethodError extends ProviderRpcError { + static code = 4200; constructor(cause, { method } = {}) { super(cause, { code: UnsupportedProviderMethodError.code, @@ -4997,13 +4789,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(UnsupportedProviderMethodError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 4200 - }); ProviderDisconnectedError = class ProviderDisconnectedError extends ProviderRpcError { + static code = 4900; constructor(cause) { super(cause, { code: ProviderDisconnectedError.code, @@ -5012,13 +4799,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(ProviderDisconnectedError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 4900 - }); ChainDisconnectedError = class ChainDisconnectedError extends ProviderRpcError { + static code = 4901; constructor(cause) { super(cause, { code: ChainDisconnectedError.code, @@ -5027,13 +4809,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(ChainDisconnectedError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 4901 - }); SwitchChainError = class SwitchChainError extends ProviderRpcError { + static code = 4902; constructor(cause) { super(cause, { code: SwitchChainError.code, @@ -5042,13 +4819,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(SwitchChainError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 4902 - }); UnsupportedNonOptionalCapabilityError = class UnsupportedNonOptionalCapabilityError extends ProviderRpcError { + static code = 5700; constructor(cause) { super(cause, { code: UnsupportedNonOptionalCapabilityError.code, @@ -5057,13 +4829,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(UnsupportedNonOptionalCapabilityError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 5700 - }); UnsupportedChainIdError = class UnsupportedChainIdError extends ProviderRpcError { + static code = 5710; constructor(cause) { super(cause, { code: UnsupportedChainIdError.code, @@ -5072,13 +4839,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(UnsupportedChainIdError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 5710 - }); DuplicateIdError = class DuplicateIdError extends ProviderRpcError { + static code = 5720; constructor(cause) { super(cause, { code: DuplicateIdError.code, @@ -5087,13 +4849,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(DuplicateIdError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 5720 - }); UnknownBundleIdError = class UnknownBundleIdError extends ProviderRpcError { + static code = 5730; constructor(cause) { super(cause, { code: UnknownBundleIdError.code, @@ -5102,13 +4859,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(UnknownBundleIdError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 5730 - }); BundleTooLargeError = class BundleTooLargeError extends ProviderRpcError { + static code = 5740; constructor(cause) { super(cause, { code: BundleTooLargeError.code, @@ -5117,13 +4869,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(BundleTooLargeError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 5740 - }); AtomicReadyWalletRejectedUpgradeError = class AtomicReadyWalletRejectedUpgradeError extends ProviderRpcError { + static code = 5750; constructor(cause) { super(cause, { code: AtomicReadyWalletRejectedUpgradeError.code, @@ -5132,13 +4879,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(AtomicReadyWalletRejectedUpgradeError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 5750 - }); AtomicityNotSupportedError = class AtomicityNotSupportedError extends ProviderRpcError { + static code = 5760; constructor(cause) { super(cause, { code: AtomicityNotSupportedError.code, @@ -5147,13 +4889,8 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(AtomicityNotSupportedError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 5760 - }); WalletConnectSessionSettlementError = class WalletConnectSessionSettlementError extends ProviderRpcError { + static code = 7000; constructor(cause) { super(cause, { code: WalletConnectSessionSettlementError.code, @@ -5162,12 +4899,6 @@ var init_rpc = __esm(() => { }); } }; - Object.defineProperty(WalletConnectSessionSettlementError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 7000 - }); UnknownRpcError = class UnknownRpcError extends RpcError { constructor(cause) { super(cause, { @@ -5888,10 +5619,10 @@ function assert2(value, options = {}) { throw new InvalidHexTypeError(value); if (strict) { if (!/^0x[0-9a-fA-F]*$/.test(value)) - throw new InvalidHexValueError2(value); + throw new InvalidHexValueError(value); } if (!value.startsWith("0x")) - throw new InvalidHexValueError2(value); + throw new InvalidHexValueError(value); } function concat2(...values) { return `0x${values.reduce((acc, x) => acc + x.replace("0x", ""), "")}`; @@ -6003,7 +5734,7 @@ function validate2(value, options = {}) { return false; } } -var encoder4, hexes3, IntegerOutOfRangeError2, InvalidHexTypeError, InvalidHexValueError2, SizeOverflowError3, SliceOffsetOutOfBoundsError3, SizeExceedsPaddingSizeError3; +var encoder4, hexes3, IntegerOutOfRangeError2, InvalidHexTypeError, InvalidHexValueError, SizeOverflowError3, SliceOffsetOutOfBoundsError3, SizeExceedsPaddingSizeError3; var init_Hex = __esm(() => { init_Errors(); init_hex(); @@ -6033,7 +5764,7 @@ var init_Hex = __esm(() => { }); } }; - InvalidHexValueError2 = class InvalidHexValueError2 extends BaseError3 { + InvalidHexValueError = class InvalidHexValueError extends BaseError3 { constructor(value) { super(`Value \`${value}\` is an invalid hex value.`, { metaMessages: [ @@ -6130,13 +5861,13 @@ var init_BlockOverrides = __esm(() => { init_Withdrawal(); }); -// ../viem/src/_esm/constants/contract.js +// ../viem/src/constants/contract.ts var aggregate3Signature = "0x82ad56cb"; -// ../viem/src/_esm/constants/contracts.js +// ../viem/src/constants/contracts.ts var deploylessCallViaBytecodeBytecode = "0x608060405234801561001057600080fd5b5060405161018e38038061018e83398101604081905261002f91610124565b6000808351602085016000f59050803b61004857600080fd5b6000808351602085016000855af16040513d6000823e81610067573d81fd5b3d81f35b634e487b7160e01b600052604160045260246000fd5b600082601f83011261009257600080fd5b81516001600160401b038111156100ab576100ab61006b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156100d9576100d961006b565b6040528181528382016020018510156100f157600080fd5b60005b82811015610110576020818601810151838301820152016100f4565b506000918101602001919091529392505050565b6000806040838503121561013757600080fd5b82516001600160401b0381111561014d57600080fd5b61015985828601610081565b602085015190935090506001600160401b0381111561017757600080fd5b61018385828601610081565b915050925092905056fe", deploylessCallViaFactoryBytecode = "0x608060405234801561001057600080fd5b506040516102c03803806102c083398101604081905261002f916101e6565b836001600160a01b03163b6000036100e457600080836001600160a01b03168360405161005c9190610270565b6000604051808303816000865af19150503d8060008114610099576040519150601f19603f3d011682016040523d82523d6000602084013e61009e565b606091505b50915091508115806100b857506001600160a01b0386163b155b156100e1578060405163101bb98d60e01b81526004016100d8919061028c565b60405180910390fd5b50505b6000808451602086016000885af16040513d6000823e81610103573d81fd5b3d81f35b80516001600160a01b038116811461011e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561015457818101518382015260200161013c565b50506000910152565b600082601f83011261016e57600080fd5b81516001600160401b0381111561018757610187610123565b604051601f8201601f19908116603f011681016001600160401b03811182821017156101b5576101b5610123565b6040528181528382016020018510156101cd57600080fd5b6101de826020830160208701610139565b949350505050565b600080600080608085870312156101fc57600080fd5b61020585610107565b60208601519094506001600160401b0381111561022157600080fd5b61022d8782880161015d565b93505061023c60408601610107565b60608601519092506001600160401b0381111561025857600080fd5b6102648782880161015d565b91505092959194509250565b60008251610282818460208701610139565b9190910192915050565b60208152600082518060208401526102ab816040850160208701610139565b601f01601f1916919091016040019291505056fe", erc6492SignatureValidatorByteCode = "0x608060405234801561001057600080fd5b5060405161069438038061069483398101604081905261002f9161051e565b600061003c848484610048565b9050806000526001601ff35b60007f64926492649264926492649264926492649264926492649264926492649264926100748361040c565b036101e7576000606080848060200190518101906100929190610577565b60405192955090935091506000906001600160a01b038516906100b69085906105dd565b6000604051808303816000865af19150503d80600081146100f3576040519150601f19603f3d011682016040523d82523d6000602084013e6100f8565b606091505b50509050876001600160a01b03163b60000361016057806101605760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90610190908b9087906004016105f9565b602060405180830381865afa1580156101ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d19190610633565b6001600160e01b03191614945050505050610405565b6001600160a01b0384163b1561027a57604051630b135d3f60e11b808252906001600160a01b03861690631626ba7e9061022790879087906004016105f9565b602060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102689190610633565b6001600160e01b031916149050610405565b81516041146102df5760405162461bcd60e51b815260206004820152603a602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e6774680000000000006064820152608401610157565b6102e7610425565b5060208201516040808401518451859392600091859190811061030c5761030c61065d565b016020015160f81c9050601b811480159061032b57508060ff16601c14155b1561038c5760405162461bcd60e51b815260206004820152603b602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c756500000000006064820152608401610157565b60408051600081526020810180835289905260ff83169181019190915260608101849052608081018390526001600160a01b0389169060019060a0016020604051602081039080840390855afa1580156103ea573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149450505050505b9392505050565b600060208251101561041d57600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b038116811461045857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561048c578181015183820152602001610474565b50506000910152565b600082601f8301126104a657600080fd5b81516001600160401b038111156104bf576104bf61045b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104ed576104ed61045b565b60405281815283820160200185101561050557600080fd5b610516826020830160208701610471565b949350505050565b60008060006060848603121561053357600080fd5b835161053e81610443565b6020850151604086015191945092506001600160401b0381111561056157600080fd5b61056d86828701610495565b9150509250925092565b60008060006060848603121561058c57600080fd5b835161059781610443565b60208501519093506001600160401b038111156105b357600080fd5b6105bf86828701610495565b604086015190935090506001600160401b0381111561056157600080fd5b600082516105ef818460208701610471565b9190910192915050565b828152604060208201526000825180604084015261061e816060850160208701610471565b601f01601f1916919091016060019392505050565b60006020828403121561064557600080fd5b81516001600160e01b03198116811461040557600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572", multicall3Bytecode = "0x608060405234801561001057600080fd5b506115b9806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e14610325578063bce38bd714610350578063c3077fa914610380578063ee82ac5e146103b2576100f3565b80634d2301cc1461026257806372425d9d1461029f57806382ad56cb146102ca57806386d516e8146102fa576100f3565b80633408e470116100c65780633408e470146101af578063399542e9146101da5780633e64a6961461020c57806342cbb15c14610237576100f3565b80630f28c97d146100f8578063174dea7114610123578063252dba421461015357806327e86d6e14610184575b600080fd5b34801561010457600080fd5b5061010d6103ef565b60405161011a9190610c0a565b60405180910390f35b61013d60048036038101906101389190610c94565b6103f7565b60405161014a9190610e94565b60405180910390f35b61016d60048036038101906101689190610f0c565b610615565b60405161017b92919061101b565b60405180910390f35b34801561019057600080fd5b506101996107ab565b6040516101a69190611064565b60405180910390f35b3480156101bb57600080fd5b506101c46107b7565b6040516101d19190610c0a565b60405180910390f35b6101f460048036038101906101ef91906110ab565b6107bf565b6040516102039392919061110b565b60405180910390f35b34801561021857600080fd5b506102216107e1565b60405161022e9190610c0a565b60405180910390f35b34801561024357600080fd5b5061024c6107e9565b6040516102599190610c0a565b60405180910390f35b34801561026e57600080fd5b50610289600480360381019061028491906111a7565b6107f1565b6040516102969190610c0a565b60405180910390f35b3480156102ab57600080fd5b506102b4610812565b6040516102c19190610c0a565b60405180910390f35b6102e460048036038101906102df919061122a565b61081a565b6040516102f19190610e94565b60405180910390f35b34801561030657600080fd5b5061030f6109e4565b60405161031c9190610c0a565b60405180910390f35b34801561033157600080fd5b5061033a6109ec565b6040516103479190611286565b60405180910390f35b61036a600480360381019061036591906110ab565b6109f4565b6040516103779190610e94565b60405180910390f35b61039a60048036038101906103959190610f0c565b610ba6565b6040516103a99392919061110b565b60405180910390f35b3480156103be57600080fd5b506103d960048036038101906103d491906112cd565b610bca565b6040516103e69190611064565b60405180910390f35b600042905090565b60606000808484905090508067ffffffffffffffff81111561041c5761041b6112fa565b5b60405190808252806020026020018201604052801561045557816020015b610442610bd5565b81526020019060019003908161043a5790505b5092503660005b828110156105c957600085828151811061047957610478611329565b5b6020026020010151905087878381811061049657610495611329565b5b90506020028101906104a89190611367565b925060008360400135905080860195508360000160208101906104cb91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16818580606001906104f2919061138f565b604051610500929190611431565b60006040518083038185875af1925050503d806000811461053d576040519150601f19603f3d011682016040523d82523d6000602084013e610542565b606091505b5083600001846020018290528215151515815250505081516020850135176105bc577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b826001019250505061045c565b5082341461060c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610603906114a7565b60405180910390fd5b50505092915050565b6000606043915060008484905090508067ffffffffffffffff81111561063e5761063d6112fa565b5b60405190808252806020026020018201604052801561067157816020015b606081526020019060019003908161065c5790505b5091503660005b828110156107a157600087878381811061069557610694611329565b5b90506020028101906106a791906114c7565b92508260000160208101906106bc91906111a7565b73ffffffffffffffffffffffffffffffffffffffff168380602001906106e2919061138f565b6040516106f0929190611431565b6000604051808303816000865af19150503d806000811461072d576040519150601f19603f3d011682016040523d82523d6000602084013e610732565b606091505b5086848151811061074657610745611329565b5b60200260200101819052819250505080610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078c9061153b565b60405180910390fd5b81600101915050610678565b5050509250929050565b60006001430340905090565b600046905090565b6000806060439250434091506107d68686866109f4565b905093509350939050565b600048905090565b600043905090565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b600044905090565b606060008383905090508067ffffffffffffffff81111561083e5761083d6112fa565b5b60405190808252806020026020018201604052801561087757816020015b610864610bd5565b81526020019060019003908161085c5790505b5091503660005b828110156109db57600084828151811061089b5761089a611329565b5b602002602001015190508686838181106108b8576108b7611329565b5b90506020028101906108ca919061155b565b92508260000160208101906108df91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060400190610905919061138f565b604051610913929190611431565b6000604051808303816000865af19150503d8060008114610950576040519150601f19603f3d011682016040523d82523d6000602084013e610955565b606091505b5082600001836020018290528215151515815250505080516020840135176109cf577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b8160010191505061087e565b50505092915050565b600045905090565b600041905090565b606060008383905090508067ffffffffffffffff811115610a1857610a176112fa565b5b604051908082528060200260200182016040528015610a5157816020015b610a3e610bd5565b815260200190600190039081610a365790505b5091503660005b82811015610b9c576000848281518110610a7557610a74611329565b5b60200260200101519050868683818110610a9257610a91611329565b5b9050602002810190610aa491906114c7565b9250826000016020810190610ab991906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060200190610adf919061138f565b604051610aed929190611431565b6000604051808303816000865af19150503d8060008114610b2a576040519150601f19603f3d011682016040523d82523d6000602084013e610b2f565b606091505b508260000183602001829052821515151581525050508715610b90578060000151610b8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b869061153b565b60405180910390fd5b5b81600101915050610a58565b5050509392505050565b6000806060610bb7600186866107bf565b8093508194508295505050509250925092565b600081409050919050565b6040518060400160405280600015158152602001606081525090565b6000819050919050565b610c0481610bf1565b82525050565b6000602082019050610c1f6000830184610bfb565b92915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610c5457610c53610c2f565b5b8235905067ffffffffffffffff811115610c7157610c70610c34565b5b602083019150836020820283011115610c8d57610c8c610c39565b5b9250929050565b60008060208385031215610cab57610caa610c25565b5b600083013567ffffffffffffffff811115610cc957610cc8610c2a565b5b610cd585828601610c3e565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60008115159050919050565b610d2281610d0d565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610d62578082015181840152602081019050610d47565b83811115610d71576000848401525b50505050565b6000601f19601f8301169050919050565b6000610d9382610d28565b610d9d8185610d33565b9350610dad818560208601610d44565b610db681610d77565b840191505092915050565b6000604083016000830151610dd96000860182610d19565b5060208301518482036020860152610df18282610d88565b9150508091505092915050565b6000610e0a8383610dc1565b905092915050565b6000602082019050919050565b6000610e2a82610ce1565b610e348185610cec565b935083602082028501610e4685610cfd565b8060005b85811015610e825784840389528151610e638582610dfe565b9450610e6e83610e12565b925060208a01995050600181019050610e4a565b50829750879550505050505092915050565b60006020820190508181036000830152610eae8184610e1f565b905092915050565b60008083601f840112610ecc57610ecb610c2f565b5b8235905067ffffffffffffffff811115610ee957610ee8610c34565b5b602083019150836020820283011115610f0557610f04610c39565b5b9250929050565b60008060208385031215610f2357610f22610c25565b5b600083013567ffffffffffffffff811115610f4157610f40610c2a565b5b610f4d85828601610eb6565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000610f918383610d88565b905092915050565b6000602082019050919050565b6000610fb182610f59565b610fbb8185610f64565b935083602082028501610fcd85610f75565b8060005b858110156110095784840389528151610fea8582610f85565b9450610ff583610f99565b925060208a01995050600181019050610fd1565b50829750879550505050505092915050565b60006040820190506110306000830185610bfb565b81810360208301526110428184610fa6565b90509392505050565b6000819050919050565b61105e8161104b565b82525050565b60006020820190506110796000830184611055565b92915050565b61108881610d0d565b811461109357600080fd5b50565b6000813590506110a58161107f565b92915050565b6000806000604084860312156110c4576110c3610c25565b5b60006110d286828701611096565b935050602084013567ffffffffffffffff8111156110f3576110f2610c2a565b5b6110ff86828701610eb6565b92509250509250925092565b60006060820190506111206000830186610bfb565b61112d6020830185611055565b818103604083015261113f8184610e1f565b9050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061117482611149565b9050919050565b61118481611169565b811461118f57600080fd5b50565b6000813590506111a18161117b565b92915050565b6000602082840312156111bd576111bc610c25565b5b60006111cb84828501611192565b91505092915050565b60008083601f8401126111ea576111e9610c2f565b5b8235905067ffffffffffffffff81111561120757611206610c34565b5b60208301915083602082028301111561122357611222610c39565b5b9250929050565b6000806020838503121561124157611240610c25565b5b600083013567ffffffffffffffff81111561125f5761125e610c2a565b5b61126b858286016111d4565b92509250509250929050565b61128081611169565b82525050565b600060208201905061129b6000830184611277565b92915050565b6112aa81610bf1565b81146112b557600080fd5b50565b6000813590506112c7816112a1565b92915050565b6000602082840312156112e3576112e2610c25565b5b60006112f1848285016112b8565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160800383360303811261138357611382611358565b5b80830191505092915050565b600080833560016020038436030381126113ac576113ab611358565b5b80840192508235915067ffffffffffffffff8211156113ce576113cd61135d565b5b6020830192506001820236038313156113ea576113e9611362565b5b509250929050565b600081905092915050565b82818337600083830152505050565b600061141883856113f2565b93506114258385846113fd565b82840190509392505050565b600061143e82848661140c565b91508190509392505050565b600082825260208201905092915050565b7f4d756c746963616c6c333a2076616c7565206d69736d61746368000000000000600082015250565b6000611491601a8361144a565b915061149c8261145b565b602082019050919050565b600060208201905081810360008301526114c081611484565b9050919050565b6000823560016040038336030381126114e3576114e2611358565b5b80830191505092915050565b7f4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000600082015250565b600061152560178361144a565b9150611530826114ef565b602082019050919050565b6000602082019050818103600083015261155481611518565b9050919050565b60008235600160600383360303811261157757611576611358565b5b8083019150509291505056fea264697066735822122020c1bc9aacf8e4a6507193432a895a8e77094f45a1395583f07b24e860ef06cd64736f6c634300080c0033"; -// ../viem/src/_esm/utils/abi/encodeDeployData.js +// ../viem/src/utils/abi/encodeDeployData.ts function encodeDeployData(parameters) { const { abi, args, bytecode } = parameters; if (!args || args.length === 0) @@ -6157,7 +5888,7 @@ var init_encodeDeployData = __esm(() => { init_encodeAbiParameters(); }); -// ../viem/src/_esm/utils/address/isAddressEqual.js +// ../viem/src/utils/address/isAddressEqual.ts function isAddressEqual(a, b) { if (!isAddress(a, { strict: false })) throw new InvalidAddressError({ address: a }); @@ -6170,7 +5901,7 @@ var init_isAddressEqual = __esm(() => { init_isAddress(); }); -// ../viem/src/_esm/utils/block/formatBlockParameter.js +// ../viem/src/utils/block/formatBlockParameter.ts function formatBlockParameter(parameters) { const { blockHash, blockNumber, blockTag, requireCanonical } = parameters; if (requireCanonical !== undefined && !blockHash) @@ -6186,13 +5917,18 @@ var init_formatBlockParameter = __esm(() => { init_toHex(); }); -// ../viem/src/_esm/errors/node.js +// ../viem/src/errors/node.ts var ExecutionRevertedError, FeeCapTooHighError, FeeCapTooLowError, NonceTooHighError, NonceTooLowError, NonceMaxValueError, InsufficientFundsError, IntrinsicGasTooHighError, IntrinsicGasTooLowError, TransactionTypeNotSupportedError, TipAboveFeeCapError, UnknownNodeError; var init_node = __esm(() => { init_formatGwei(); init_base(); ExecutionRevertedError = class ExecutionRevertedError extends BaseError2 { - constructor({ cause, message } = {}) { + static code = 3; + static nodeMessage = /execution reverted|gas required exceeds allowance/; + constructor({ + cause, + message + } = {}) { const reason = message?.replace("execution reverted: ", "")?.replace("execution reverted", ""); super(`Execution reverted ${reason ? `with reason: ${reason}` : "for an unknown reason"}.`, { cause, @@ -6200,59 +5936,45 @@ var init_node = __esm(() => { }); } }; - Object.defineProperty(ExecutionRevertedError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: 3 - }); - Object.defineProperty(ExecutionRevertedError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /execution reverted|gas required exceeds allowance/ - }); FeeCapTooHighError = class FeeCapTooHighError extends BaseError2 { - constructor({ cause, maxFeePerGas } = {}) { + static nodeMessage = /max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/; + constructor({ + cause, + maxFeePerGas + } = {}) { super(`The fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei2(maxFeePerGas)} gwei` : ""}) cannot be higher than the maximum allowed value (2^256-1).`, { cause, name: "FeeCapTooHighError" }); } }; - Object.defineProperty(FeeCapTooHighError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/ - }); FeeCapTooLowError = class FeeCapTooLowError extends BaseError2 { - constructor({ cause, maxFeePerGas } = {}) { + static nodeMessage = /max fee per gas less than block base fee|fee cap less than block base fee|transaction is outdated/; + constructor({ + cause, + maxFeePerGas + } = {}) { super(`The fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei2(maxFeePerGas)}` : ""} gwei) cannot be lower than the block base fee.`, { cause, name: "FeeCapTooLowError" }); } }; - Object.defineProperty(FeeCapTooLowError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /max fee per gas less than block base fee|fee cap less than block base fee|transaction is outdated/ - }); NonceTooHighError = class NonceTooHighError extends BaseError2 { - constructor({ cause, nonce } = {}) { + static nodeMessage = /nonce too high/; + constructor({ + cause, + nonce + } = {}) { super(`Nonce provided for the transaction ${nonce ? `(${nonce}) ` : ""}is higher than the next one expected.`, { cause, name: "NonceTooHighError" }); } }; - Object.defineProperty(NonceTooHighError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /nonce too high/ - }); NonceTooLowError = class NonceTooLowError extends BaseError2 { - constructor({ cause, nonce } = {}) { + static nodeMessage = /nonce too low|transaction already imported|already known/; + constructor({ + cause, + nonce + } = {}) { super([ `Nonce provided for the transaction ${nonce ? `(${nonce}) ` : ""}is lower than the current nonce of the account.`, "Try increasing the nonce or find the latest nonce with `getTransactionCount`." @@ -6260,24 +5982,17 @@ var init_node = __esm(() => { `), { cause, name: "NonceTooLowError" }); } }; - Object.defineProperty(NonceTooLowError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /nonce too low|transaction already imported|already known/ - }); NonceMaxValueError = class NonceMaxValueError extends BaseError2 { - constructor({ cause, nonce } = {}) { + static nodeMessage = /nonce has max value/; + constructor({ + cause, + nonce + } = {}) { super(`Nonce provided for the transaction ${nonce ? `(${nonce}) ` : ""}exceeds the maximum allowed nonce.`, { cause, name: "NonceMaxValueError" }); } }; - Object.defineProperty(NonceMaxValueError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /nonce has max value/ - }); InsufficientFundsError = class InsufficientFundsError extends BaseError2 { + static nodeMessage = /insufficient funds|exceeds transaction sender account balance/; constructor({ cause } = {}) { super([ "The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account." @@ -6298,41 +6013,32 @@ var init_node = __esm(() => { }); } }; - Object.defineProperty(InsufficientFundsError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /insufficient funds|exceeds transaction sender account balance/ - }); IntrinsicGasTooHighError = class IntrinsicGasTooHighError extends BaseError2 { - constructor({ cause, gas } = {}) { + static nodeMessage = /intrinsic gas too high|gas limit reached/; + constructor({ + cause, + gas + } = {}) { super(`The amount of gas ${gas ? `(${gas}) ` : ""}provided for the transaction exceeds the limit allowed for the block.`, { cause, name: "IntrinsicGasTooHighError" }); } }; - Object.defineProperty(IntrinsicGasTooHighError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /intrinsic gas too high|gas limit reached/ - }); IntrinsicGasTooLowError = class IntrinsicGasTooLowError extends BaseError2 { - constructor({ cause, gas } = {}) { + static nodeMessage = /intrinsic gas too low/; + constructor({ + cause, + gas + } = {}) { super(`The amount of gas ${gas ? `(${gas}) ` : ""}provided for the transaction is too low.`, { cause, name: "IntrinsicGasTooLowError" }); } }; - Object.defineProperty(IntrinsicGasTooLowError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /intrinsic gas too low/ - }); TransactionTypeNotSupportedError = class TransactionTypeNotSupportedError extends BaseError2 { + static nodeMessage = /transaction type not valid/; constructor({ cause }) { super("The transaction type is not supported for this chain.", { cause, @@ -6340,14 +6046,13 @@ var init_node = __esm(() => { }); } }; - Object.defineProperty(TransactionTypeNotSupportedError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /transaction type not valid/ - }); TipAboveFeeCapError = class TipAboveFeeCapError extends BaseError2 { - constructor({ cause, maxPriorityFeePerGas, maxFeePerGas } = {}) { + static nodeMessage = /max priority fee per gas higher than max fee per gas|tip higher than fee cap/; + constructor({ + cause, + maxPriorityFeePerGas, + maxFeePerGas + } = {}) { super([ `The provided tip (\`maxPriorityFeePerGas\`${maxPriorityFeePerGas ? ` = ${formatGwei2(maxPriorityFeePerGas)} gwei` : ""}) cannot be higher than the fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei2(maxFeePerGas)} gwei` : ""}).` ].join(` @@ -6357,12 +6062,6 @@ var init_node = __esm(() => { }); } }; - Object.defineProperty(TipAboveFeeCapError, "nodeMessage", { - enumerable: true, - configurable: true, - writable: true, - value: /max priority fee per gas higher than max fee per gas|tip higher than fee cap/ - }); UnknownNodeError = class UnknownNodeError extends BaseError2 { constructor({ cause }) { super(`An error occurred while executing: ${cause?.shortMessage}`, { @@ -6373,7 +6072,7 @@ var init_node = __esm(() => { }; }); -// ../viem/src/_esm/utils/errors/getNodeError.js +// ../viem/src/utils/errors/getNodeError.ts function getNodeError(err, args) { const message = (err.details || "").toLowerCase(); const executionRevertedError = err instanceof BaseError2 ? err.walk((e) => e?.code === ExecutionRevertedError.code) : err; @@ -6426,8 +6125,11 @@ var init_getNodeError = __esm(() => { init_node(); }); -// ../viem/src/_esm/utils/errors/getCallError.js -function getCallError(err, { docsPath: docsPath6, ...args }) { +// ../viem/src/utils/errors/getCallError.ts +function getCallError(err, { + docsPath: docsPath6, + ...args +}) { const cause = (() => { const cause2 = getNodeError(err, args); if (cause2 instanceof UnknownNodeError) @@ -6445,7 +6147,7 @@ var init_getCallError = __esm(() => { init_getNodeError(); }); -// ../viem/src/_esm/utils/formatters/extract.js +// ../viem/src/utils/formatters/extract.ts function extract(value_, { format: format2 }) { if (!format2) return {}; @@ -6464,29 +6166,7 @@ function extract(value_, { format: format2 }) { return value; } -// ../viem/src/_esm/utils/formatters/formatter.js -function defineFormatter(type, format2) { - return ({ exclude, format: overrides }) => { - return { - exclude, - format: (args, action) => { - const formatted = format2(args, action); - if (exclude) { - for (const key of exclude) { - delete formatted[key]; - } - } - return { - ...formatted, - ...overrides(args, action) - }; - }, - type - }; - }; -} - -// ../viem/src/_esm/utils/formatters/transactionRequest.js +// ../viem/src/utils/formatters/transactionRequest.ts function formatTransactionRequest(request, _) { const rpcRequest = {}; if (typeof request.authorizationList !== "undefined") @@ -6550,7 +6230,7 @@ var init_transactionRequest = __esm(() => { }; }); -// ../viem/src/_esm/utils/promise/withResolvers.js +// ../viem/src/utils/promise/withResolvers.ts function withResolvers() { let resolve = () => { return; @@ -6565,8 +6245,14 @@ function withResolvers() { return { promise, resolve, reject }; } -// ../viem/src/_esm/utils/promise/createBatchScheduler.js -function createBatchScheduler({ fn, id, shouldSplitBatch, wait = 0, sort }) { +// ../viem/src/utils/promise/createBatchScheduler.ts +function createBatchScheduler({ + fn, + id, + shouldSplitBatch, + wait = 0, + sort +}) { const exec = async () => { const scheduler = getScheduler(); flush(); @@ -6614,7 +6300,7 @@ var init_createBatchScheduler = __esm(() => { schedulerCache = /* @__PURE__ */ new Map; }); -// ../viem/src/_esm/utils/stateOverride.js +// ../viem/src/utils/stateOverride.ts function serializeStateMapping(stateMapping) { if (!stateMapping || stateMapping.length === 0) return; @@ -6674,7 +6360,7 @@ var init_stateOverride2 = __esm(() => { init_toHex(); }); -// ../viem/src/_esm/constants/number.js +// ../viem/src/constants/number.ts var maxInt8, maxInt16, maxInt24, maxInt32, maxInt40, maxInt48, maxInt56, maxInt64, maxInt72, maxInt80, maxInt88, maxInt96, maxInt104, maxInt112, maxInt120, maxInt128, maxInt136, maxInt144, maxInt152, maxInt160, maxInt168, maxInt176, maxInt184, maxInt192, maxInt200, maxInt208, maxInt216, maxInt224, maxInt232, maxInt240, maxInt248, maxInt256, minInt8, minInt16, minInt24, minInt32, minInt40, minInt48, minInt56, minInt64, minInt72, minInt80, minInt88, minInt96, minInt104, minInt112, minInt120, minInt128, minInt136, minInt144, minInt152, minInt160, minInt168, minInt176, minInt184, minInt192, minInt200, minInt208, minInt216, minInt224, minInt232, minInt240, minInt248, minInt256, maxUint8, maxUint16, maxUint24, maxUint32, maxUint40, maxUint48, maxUint56, maxUint64, maxUint72, maxUint80, maxUint88, maxUint96, maxUint104, maxUint112, maxUint120, maxUint128, maxUint136, maxUint144, maxUint152, maxUint160, maxUint168, maxUint176, maxUint184, maxUint192, maxUint200, maxUint208, maxUint216, maxUint224, maxUint232, maxUint240, maxUint248, maxUint256; var init_number = __esm(() => { maxInt8 = 2n ** (8n - 1n) - 1n; @@ -6775,7 +6461,7 @@ var init_number = __esm(() => { maxUint256 = 2n ** 256n - 1n; }); -// ../viem/src/_esm/utils/transaction/assertRequest.js +// ../viem/src/utils/transaction/assertRequest.ts function assertRequest(args) { const { account: account_, maxFeePerGas, maxPriorityFeePerGas, to } = args; const account = account_ ? parseAccount(account_) : undefined; @@ -6795,12 +6481,19 @@ var init_assertRequest = __esm(() => { init_isAddress(); }); -// ../viem/src/_esm/errors/ccip.js +// ../viem/src/errors/ccip.ts var OffchainLookupError, OffchainLookupResponseMalformedError, OffchainLookupSenderMismatchError; var init_ccip = __esm(() => { init_base(); OffchainLookupError = class OffchainLookupError extends BaseError2 { - constructor({ callbackSelector, cause, data, extraData, sender, urls }) { + constructor({ + callbackSelector, + cause, + data, + extraData, + sender, + urls + }) { super(cause.shortMessage || "An error occurred while fetching for an offchain result.", { cause, metaMessages: [ @@ -6844,7 +6537,7 @@ var init_ccip = __esm(() => { }; }); -// ../viem/src/_esm/utils/ccip.js +// ../viem/src/utils/ccip.ts var exports_ccip = {}; __export(exports_ccip, { offchainLookupSignature: () => offchainLookupSignature, @@ -6852,7 +6545,13 @@ __export(exports_ccip, { offchainLookup: () => offchainLookup, ccipRequest: () => ccipRequest }); -async function offchainLookup(client, { blockNumber, blockTag, data, requestOptions, to }) { +async function offchainLookup(client, { + blockNumber, + blockTag, + data, + requestOptions, + to +}) { const { args } = decodeErrorResult({ data, abi: [offchainLookupAbiItem] @@ -6893,7 +6592,12 @@ async function offchainLookup(client, { blockNumber, blockTag, data, requestOpti }); } } -async function ccipRequest({ data, requestOptions, sender, urls }) { +async function ccipRequest({ + data, + requestOptions, + sender, + urls +}) { let error = new Error("An unknown error occurred."); for (let i = 0;i < urls.length; i++) { if (requestOptions?.signal?.aborted) @@ -6984,17 +6688,43 @@ var init_ccip2 = __esm(() => { }; }); -// ../viem/src/_esm/actions/public/call.js +// ../viem/src/actions/public/call.ts async function call(client, args) { - const { account: account_ = client.account, authorizationList, batch = Boolean(client.batch?.multicall), blockHash, blockNumber, blockTag = client.experimental_blockTag ?? "latest", requireCanonical, accessList, blobs, blockOverrides, code, data: data_, factory, factoryData, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, nonce, requestOptions, to, value, stateOverride, ...rest } = args; - const account = account_ ? parseAccount(account_) : undefined; - if (code && (factory || factoryData)) - throw new BaseError2("Cannot provide both `code` & `factory`/`factoryData` as parameters."); - if (code && to) - throw new BaseError2("Cannot provide both `code` & `to` as parameters."); - const deploylessCallViaBytecode = code && data_; - const deploylessCallViaFactory = factory && factoryData && to && data_; - const deploylessCall = deploylessCallViaBytecode || deploylessCallViaFactory; + const { + account: account_ = client.account, + authorizationList, + batch = Boolean(client.batch?.multicall), + blockHash, + blockNumber, + blockTag = client.experimental_blockTag ?? "latest", + requireCanonical, + accessList, + blobs, + blockOverrides, + code, + data: data_, + factory, + factoryData, + gas, + gasPrice, + maxFeePerBlobGas, + maxFeePerGas, + maxPriorityFeePerGas, + nonce, + requestOptions, + to, + value, + stateOverride, + ...rest + } = args; + const account = account_ ? parseAccount(account_) : undefined; + if (code && (factory || factoryData)) + throw new BaseError2("Cannot provide both `code` & `factory`/`factoryData` as parameters."); + if (code && to) + throw new BaseError2("Cannot provide both `code` & `to` as parameters."); + const deploylessCallViaBytecode = code && data_; + const deploylessCallViaFactory = factory && factoryData && to && data_; + const deploylessCall = deploylessCallViaBytecode || deploylessCallViaFactory; const data = (() => { if (deploylessCallViaBytecode) return toDeploylessCallViaBytecodeData({ @@ -7124,8 +6854,22 @@ function getRequestOptionsId(requestOptions) { return nextId; } async function scheduleMulticall(client, args) { - const { batchSize = 1024, deployless = false, wait = 0 } = typeof client.batch?.multicall === "object" ? client.batch.multicall : {}; - const { blockHash, blockNumber, blockTag = client.experimental_blockTag ?? "latest", requireCanonical, data, multicallAddress: multicallAddress_, requestOptions, rpcStateOverride, to } = args; + const { + batchSize = 1024, + deployless = false, + wait = 0 + } = typeof client.batch?.multicall === "object" ? client.batch.multicall : {}; + const { + blockHash, + blockNumber, + blockTag = client.experimental_blockTag ?? "latest", + requireCanonical, + data, + multicallAddress: multicallAddress_, + requestOptions, + rpcStateOverride, + to + } = args; const multicallAddress = multicallAddress_ !== undefined ? multicallAddress_ : getMulticallAddress(client, { blockNumber, deployless @@ -7263,7 +7007,7 @@ function Chi(a, b, c) { function Maj(a, b, c) { return a & b ^ a & c ^ b & c; } -var HashMD, SHA256_IV, SHA384_IV, SHA512_IV; +var HashMD, SHA256_IV; var init__md = __esm(() => { init_utils2(); HashMD = class HashMD extends Hash { @@ -7366,49 +7110,12 @@ var init__md = __esm(() => { 528734635, 1541459225 ]); - SHA384_IV = /* @__PURE__ */ Uint32Array.from([ - 3418070365, - 3238371032, - 1654270250, - 914150663, - 2438529370, - 812702999, - 355462360, - 4144912697, - 1731405415, - 4290775857, - 2394180231, - 1750603025, - 3675008525, - 1694076839, - 1203062813, - 3204075428 - ]); - SHA512_IV = /* @__PURE__ */ Uint32Array.from([ - 1779033703, - 4089235720, - 3144134277, - 2227873595, - 1013904242, - 4271175723, - 2773480762, - 1595750129, - 1359893119, - 2917565137, - 2600822924, - 725511199, - 528734635, - 4215389547, - 1541459225, - 327033209 - ]); }); // ../viem/node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha2.js -var SHA256_K, SHA256_W, SHA256, K512, SHA512_Kh, SHA512_Kl, SHA512_W_H, SHA512_W_L, SHA512, SHA384, sha256, sha512, sha384; +var SHA256_K, SHA256_W, SHA256, sha256; var init_sha2 = __esm(() => { init__md(); - init__u64(); init_utils2(); SHA256_K = /* @__PURE__ */ Uint32Array.from([ 1116352408, @@ -7546,225 +7253,7 @@ var init_sha2 = __esm(() => { clean(this.buffer); } }; - K512 = /* @__PURE__ */ (() => split([ - "0x428a2f98d728ae22", - "0x7137449123ef65cd", - "0xb5c0fbcfec4d3b2f", - "0xe9b5dba58189dbbc", - "0x3956c25bf348b538", - "0x59f111f1b605d019", - "0x923f82a4af194f9b", - "0xab1c5ed5da6d8118", - "0xd807aa98a3030242", - "0x12835b0145706fbe", - "0x243185be4ee4b28c", - "0x550c7dc3d5ffb4e2", - "0x72be5d74f27b896f", - "0x80deb1fe3b1696b1", - "0x9bdc06a725c71235", - "0xc19bf174cf692694", - "0xe49b69c19ef14ad2", - "0xefbe4786384f25e3", - "0x0fc19dc68b8cd5b5", - "0x240ca1cc77ac9c65", - "0x2de92c6f592b0275", - "0x4a7484aa6ea6e483", - "0x5cb0a9dcbd41fbd4", - "0x76f988da831153b5", - "0x983e5152ee66dfab", - "0xa831c66d2db43210", - "0xb00327c898fb213f", - "0xbf597fc7beef0ee4", - "0xc6e00bf33da88fc2", - "0xd5a79147930aa725", - "0x06ca6351e003826f", - "0x142929670a0e6e70", - "0x27b70a8546d22ffc", - "0x2e1b21385c26c926", - "0x4d2c6dfc5ac42aed", - "0x53380d139d95b3df", - "0x650a73548baf63de", - "0x766a0abb3c77b2a8", - "0x81c2c92e47edaee6", - "0x92722c851482353b", - "0xa2bfe8a14cf10364", - "0xa81a664bbc423001", - "0xc24b8b70d0f89791", - "0xc76c51a30654be30", - "0xd192e819d6ef5218", - "0xd69906245565a910", - "0xf40e35855771202a", - "0x106aa07032bbd1b8", - "0x19a4c116b8d2d0c8", - "0x1e376c085141ab53", - "0x2748774cdf8eeb99", - "0x34b0bcb5e19b48a8", - "0x391c0cb3c5c95a63", - "0x4ed8aa4ae3418acb", - "0x5b9cca4f7763e373", - "0x682e6ff3d6b2b8a3", - "0x748f82ee5defb2fc", - "0x78a5636f43172f60", - "0x84c87814a1f0ab72", - "0x8cc702081a6439ec", - "0x90befffa23631e28", - "0xa4506cebde82bde9", - "0xbef9a3f7b2c67915", - "0xc67178f2e372532b", - "0xca273eceea26619c", - "0xd186b8c721c0c207", - "0xeada7dd6cde0eb1e", - "0xf57d4f7fee6ed178", - "0x06f067aa72176fba", - "0x0a637dc5a2c898a6", - "0x113f9804bef90dae", - "0x1b710b35131c471b", - "0x28db77f523047d84", - "0x32caab7b40c72493", - "0x3c9ebe0a15c9bebc", - "0x431d67c49c100d4c", - "0x4cc5d4becb3e42b6", - "0x597f299cfc657e2a", - "0x5fcb6fab3ad6faec", - "0x6c44198c4a475817" - ].map((n) => BigInt(n))))(); - SHA512_Kh = /* @__PURE__ */ (() => K512[0])(); - SHA512_Kl = /* @__PURE__ */ (() => K512[1])(); - SHA512_W_H = /* @__PURE__ */ new Uint32Array(80); - SHA512_W_L = /* @__PURE__ */ new Uint32Array(80); - SHA512 = class SHA512 extends HashMD { - constructor(outputLen = 64) { - super(128, outputLen, 16, false); - this.Ah = SHA512_IV[0] | 0; - this.Al = SHA512_IV[1] | 0; - this.Bh = SHA512_IV[2] | 0; - this.Bl = SHA512_IV[3] | 0; - this.Ch = SHA512_IV[4] | 0; - this.Cl = SHA512_IV[5] | 0; - this.Dh = SHA512_IV[6] | 0; - this.Dl = SHA512_IV[7] | 0; - this.Eh = SHA512_IV[8] | 0; - this.El = SHA512_IV[9] | 0; - this.Fh = SHA512_IV[10] | 0; - this.Fl = SHA512_IV[11] | 0; - this.Gh = SHA512_IV[12] | 0; - this.Gl = SHA512_IV[13] | 0; - this.Hh = SHA512_IV[14] | 0; - this.Hl = SHA512_IV[15] | 0; - } - get() { - const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl]; - } - set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) { - this.Ah = Ah | 0; - this.Al = Al | 0; - this.Bh = Bh | 0; - this.Bl = Bl | 0; - this.Ch = Ch | 0; - this.Cl = Cl | 0; - this.Dh = Dh | 0; - this.Dl = Dl | 0; - this.Eh = Eh | 0; - this.El = El | 0; - this.Fh = Fh | 0; - this.Fl = Fl | 0; - this.Gh = Gh | 0; - this.Gl = Gl | 0; - this.Hh = Hh | 0; - this.Hl = Hl | 0; - } - process(view, offset) { - for (let i = 0;i < 16; i++, offset += 4) { - SHA512_W_H[i] = view.getUint32(offset); - SHA512_W_L[i] = view.getUint32(offset += 4); - } - for (let i = 16;i < 80; i++) { - const W15h = SHA512_W_H[i - 15] | 0; - const W15l = SHA512_W_L[i - 15] | 0; - const s0h = rotrSH(W15h, W15l, 1) ^ rotrSH(W15h, W15l, 8) ^ shrSH(W15h, W15l, 7); - const s0l = rotrSL(W15h, W15l, 1) ^ rotrSL(W15h, W15l, 8) ^ shrSL(W15h, W15l, 7); - const W2h = SHA512_W_H[i - 2] | 0; - const W2l = SHA512_W_L[i - 2] | 0; - const s1h = rotrSH(W2h, W2l, 19) ^ rotrBH(W2h, W2l, 61) ^ shrSH(W2h, W2l, 6); - const s1l = rotrSL(W2h, W2l, 19) ^ rotrBL(W2h, W2l, 61) ^ shrSL(W2h, W2l, 6); - const SUMl = add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]); - const SUMh = add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]); - SHA512_W_H[i] = SUMh | 0; - SHA512_W_L[i] = SUMl | 0; - } - let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - for (let i = 0;i < 80; i++) { - const sigma1h = rotrSH(Eh, El, 14) ^ rotrSH(Eh, El, 18) ^ rotrBH(Eh, El, 41); - const sigma1l = rotrSL(Eh, El, 14) ^ rotrSL(Eh, El, 18) ^ rotrBL(Eh, El, 41); - const CHIh = Eh & Fh ^ ~Eh & Gh; - const CHIl = El & Fl ^ ~El & Gl; - const T1ll = add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]); - const T1h = add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]); - const T1l = T1ll | 0; - const sigma0h = rotrSH(Ah, Al, 28) ^ rotrBH(Ah, Al, 34) ^ rotrBH(Ah, Al, 39); - const sigma0l = rotrSL(Ah, Al, 28) ^ rotrBL(Ah, Al, 34) ^ rotrBL(Ah, Al, 39); - const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch; - const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl; - Hh = Gh | 0; - Hl = Gl | 0; - Gh = Fh | 0; - Gl = Fl | 0; - Fh = Eh | 0; - Fl = El | 0; - ({ h: Eh, l: El } = add(Dh | 0, Dl | 0, T1h | 0, T1l | 0)); - Dh = Ch | 0; - Dl = Cl | 0; - Ch = Bh | 0; - Cl = Bl | 0; - Bh = Ah | 0; - Bl = Al | 0; - const All = add3L(T1l, sigma0l, MAJl); - Ah = add3H(All, T1h, sigma0h, MAJh); - Al = All | 0; - } - ({ h: Ah, l: Al } = add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0)); - ({ h: Bh, l: Bl } = add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0)); - ({ h: Ch, l: Cl } = add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0)); - ({ h: Dh, l: Dl } = add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0)); - ({ h: Eh, l: El } = add(this.Eh | 0, this.El | 0, Eh | 0, El | 0)); - ({ h: Fh, l: Fl } = add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0)); - ({ h: Gh, l: Gl } = add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0)); - ({ h: Hh, l: Hl } = add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0)); - this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl); - } - roundClean() { - clean(SHA512_W_H, SHA512_W_L); - } - destroy() { - clean(this.buffer); - this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - }; - SHA384 = class SHA384 extends SHA512 { - constructor() { - super(48); - this.Ah = SHA384_IV[0] | 0; - this.Al = SHA384_IV[1] | 0; - this.Bh = SHA384_IV[2] | 0; - this.Bl = SHA384_IV[3] | 0; - this.Ch = SHA384_IV[4] | 0; - this.Cl = SHA384_IV[5] | 0; - this.Dh = SHA384_IV[6] | 0; - this.Dl = SHA384_IV[7] | 0; - this.Eh = SHA384_IV[8] | 0; - this.El = SHA384_IV[9] | 0; - this.Fh = SHA384_IV[10] | 0; - this.Fl = SHA384_IV[11] | 0; - this.Gh = SHA384_IV[12] | 0; - this.Gl = SHA384_IV[13] | 0; - this.Hh = SHA384_IV[14] | 0; - this.Hl = SHA384_IV[15] | 0; - } - }; sha256 = /* @__PURE__ */ createHasher(() => new SHA256); - sha512 = /* @__PURE__ */ createHasher(() => new SHA512); - sha384 = /* @__PURE__ */ createHasher(() => new SHA384); }); // ../viem/node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/hmac.js @@ -8132,7 +7621,7 @@ function calcWOpts(W, scalarBits) { const shiftBy = BigInt(W); return { windows, windowSize, mask, maxNumber, shiftBy }; } -function calcOffsets(n, window2, wOpts) { +function calcOffsets(n, window, wOpts) { const { windowSize, mask, maxNumber, shiftBy } = wOpts; let wbits = Number(n & mask); let nextN = n >> shiftBy; @@ -8140,11 +7629,11 @@ function calcOffsets(n, window2, wOpts) { wbits -= maxNumber; nextN += _1n4; } - const offsetStart = window2 * windowSize; + const offsetStart = window * windowSize; const offset = offsetStart + Math.abs(wbits) - 1; const isZero = wbits === 0; const isNeg = wbits < 0; - const isNegF = window2 % 2 !== 0; + const isNegF = window % 2 !== 0; const offsetF = offsetStart; return { nextN, offset, isZero, isNeg, isNegF, offsetF }; } @@ -8188,7 +7677,7 @@ function wNAF(c, bits) { const points = []; let p = elm; let base = p; - for (let window2 = 0;window2 < windows; window2++) { + for (let window = 0;window < windows; window++) { base = p; points.push(base); for (let i = 1;i < windowSize; i++) { @@ -8203,8 +7692,8 @@ function wNAF(c, bits) { let p = c.ZERO; let f = c.BASE; const wo = calcWOpts(W, bits); - for (let window2 = 0;window2 < wo.windows; window2++) { - const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window2, wo); + for (let window = 0;window < wo.windows; window++) { + const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo); n = nextN; if (isZero) { f = f.add(constTimeNegate(isNegF, precomputes[offsetF])); @@ -8216,10 +7705,10 @@ function wNAF(c, bits) { }, wNAFUnsafe(W, precomputes, n, acc = c.ZERO) { const wo = calcWOpts(W, bits); - for (let window2 = 0;window2 < wo.windows; window2++) { + for (let window = 0;window < wo.windows; window++) { if (n === _0n4) break; - const { nextN, offset, isZero, isNeg } = calcOffsets(n, window2, wo); + const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo); n = nextN; if (isZero) { continue; @@ -9618,9 +9107,9 @@ var init_secp256k1 = __esm(() => { encodeToCurve = /* @__PURE__ */ (() => secp256k1_hasher.encodeToCurve)(); }); -// ../viem/src/_esm/index.js +// ../viem/src/index.ts init_exports(); -// ../viem/src/_esm/utils/uid.js +// ../viem/src/utils/uid.ts var size = 256; var index = size; var buffer; @@ -9635,9 +9124,18 @@ function uid(length = 11) { return buffer.substring(index, index++ + length); } -// ../viem/src/_esm/clients/createClient.js +// ../viem/src/clients/createClient.ts function createClient(parameters) { - const { batch, chain, ccipRead, dataSuffix, key = "base", name = "Base Client", tokens, type = "base" } = parameters; + const { + batch, + chain, + ccipRead, + dataSuffix, + key = "base", + name = "Base Client", + tokens, + type = "base" + } = parameters; const experimental_blockTag = parameters.experimental_blockTag ?? (typeof chain?.experimental_preconfirmationTime === "number" ? "pending" : undefined); const blockTime = chain?.blockTime ?? 12000; const defaultPollingInterval = Math.min(Math.max(Math.floor(blockTime / 2), 500), 4000); @@ -9716,7 +9214,7 @@ function bindActionDecorators(client, action) { return wrapped; } -// ../viem/src/_esm/actions/ens/getEnsAddress.js +// ../viem/src/actions/ens/getEnsAddress.ts init_abis(); init_decodeFunctionResult(); init_encodeFunctionData(); @@ -9725,7 +9223,7 @@ init_getChainContractAddress(); init_size(); init_toHex(); -// ../viem/src/_esm/utils/ens/errors.js +// ../viem/src/utils/ens/errors.ts init_base(); init_contract(); function isNullUniversalResolverError(err) { @@ -9749,15 +9247,15 @@ function isNullUniversalResolverError(err) { return false; } -// ../viem/src/_esm/actions/ens/getEnsAddress.js +// ../viem/src/actions/ens/getEnsAddress.ts init_localBatchGatewayRequest(); -// ../viem/src/_esm/utils/ens/namehash.js +// ../viem/src/utils/ens/namehash.ts init_toBytes(); init_toHex(); init_keccak256(); -// ../viem/src/_esm/utils/ens/encodedLabelToLabelhash.js +// ../viem/src/utils/ens/encodedLabelToLabelhash.ts function encodedLabelToLabelhash(label) { if (label.length !== 66) return null; @@ -9771,7 +9269,7 @@ function encodedLabelToLabelhash(label) { return hash2; } -// ../viem/src/_esm/utils/ens/namehash.js +// ../viem/src/utils/ens/namehash.ts function namehash(name) { let result = new Uint8Array(32).fill(0); if (!name) @@ -9785,15 +9283,15 @@ function namehash(name) { return bytesToHex(result); } -// ../viem/src/_esm/utils/ens/packetToBytes.js +// ../viem/src/utils/ens/packetToBytes.ts init_toBytes(); -// ../viem/src/_esm/utils/ens/encodeLabelhash.js +// ../viem/src/utils/ens/encodeLabelhash.ts function encodeLabelhash(hash2) { return `[${hash2.slice(2)}]`; } -// ../viem/src/_esm/utils/ens/labelhash.js +// ../viem/src/utils/ens/labelhash.ts init_toBytes(); init_toHex(); init_keccak256(); @@ -9804,7 +9302,7 @@ function labelhash(label) { return encodedLabelToLabelhash(label) || keccak256(stringToBytes(label)); } -// ../viem/src/_esm/utils/ens/packetToBytes.js +// ../viem/src/utils/ens/packetToBytes.ts function packetToBytes(packet) { const value = packet.replace(/^\.|\.$/gm, ""); if (value.length === 0) @@ -9825,7 +9323,7 @@ function packetToBytes(packet) { return bytes; } -// ../viem/src/_esm/utils/getAction.js +// ../viem/src/utils/getAction.ts function getAction(client, actionFn, name) { const action_implicit = client[actionFn.name]; if (typeof action_implicit === "function") @@ -9836,18 +9334,25 @@ function getAction(client, actionFn, name) { return (params) => actionFn(client, params); } -// ../viem/src/_esm/actions/public/readContract.js +// ../viem/src/actions/public/readContract.ts init_decodeFunctionResult(); init_encodeFunctionData(); -// ../viem/src/_esm/utils/errors/getContractError.js +// ../viem/src/utils/errors/getContractError.ts init_abi(); init_base(); init_contract(); init_request(); init_rpc(); var EXECUTION_REVERTED_ERROR_CODE = 3; -function getContractError(err, { abi, address, args, docsPath: docsPath5, functionName, sender }) { +function getContractError(err, { + abi, + address, + args, + docsPath: docsPath5, + functionName, + sender +}) { const error = err instanceof RawContractError ? err : err instanceof BaseError2 ? err.walk((err2) => ("data" in err2)) || err.walk() : {}; const { code, data, details, message, shortMessage } = error; const cause = (() => { @@ -9874,7 +9379,7 @@ function getContractError(err, { abi, address, args, docsPath: docsPath5, functi }); } -// ../viem/src/_esm/actions/public/readContract.js +// ../viem/src/actions/public/readContract.ts init_call(); async function readContract(client, parameters) { const { abi, address, args, functionName, ...rest } = parameters; @@ -9906,7 +9411,7 @@ async function readContract(client, parameters) { } } -// ../viem/src/_esm/actions/ens/getEnsAddress.js +// ../viem/src/actions/ens/getEnsAddress.ts async function getEnsAddress(client, parameters) { const { blockNumber, blockTag, coinType, name, gatewayUrls, strict } = parameters; const { chain } = client; @@ -9965,7 +9470,11 @@ async function getEnsAddress(client, parameters) { throw err; } } -function decodeAddress2({ coinType, data, args }) { +function decodeAddress2({ + coinType, + data, + args +}) { try { return decodeFunctionResult({ abi: addressResolverAbi, @@ -9983,7 +9492,7 @@ function decodeAddress2({ coinType, data, args }) { } } -// ../viem/src/_esm/errors/ens.js +// ../viem/src/errors/ens.ts init_base(); class EnsAvatarInvalidMetadataError extends BaseError2 { @@ -10019,7 +9528,7 @@ class EnsAvatarUnsupportedNamespaceError extends BaseError2 { } } -// ../viem/src/_esm/utils/ens/avatar/utils.js +// ../viem/src/utils/ens/avatar/utils.ts var networkRegex = /(?https?:\/\/[^/]*|ipfs:\/|ipns:\/|ar:\/)?(?\/)?(?ipfs\/|ipns\/)?(?[\w\-.]+)(?\/.*)?/; var ipfsHashRegex = /^(Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,})(\/(?[\w\-.]+))?(?\/.*)?$/; var base64Regex = /^data:([a-zA-Z\-/+]*);base64,([^"].*)/; @@ -10057,14 +9566,22 @@ function getGateway(custom, defaultGateway) { return custom.slice(0, -1); return custom; } -function resolveAvatarUri({ uri, gatewayUrls }) { +function resolveAvatarUri({ + uri, + gatewayUrls +}) { const isEncoded = base64Regex.test(uri); if (isEncoded) return { uri, isOnChain: true, isEncoded }; const ipfsGateway = getGateway(gatewayUrls?.ipfs, "https://ipfs.io"); const arweaveGateway = getGateway(gatewayUrls?.arweave, "https://arweave.net"); const networkRegexMatch = uri.match(networkRegex); - const { protocol, subpath, target, subtarget = "" } = networkRegexMatch?.groups || {}; + const { + protocol, + subpath, + target, + subtarget = "" + } = networkRegexMatch?.groups || {}; const isIPNS = protocol === "ipns:/" || subpath === "ipns/"; const isIPFS = protocol === "ipfs:/" || subpath === "ipfs/" || ipfsHashRegex.test(uri); if (uri.startsWith("http") && !isIPNS && !isIPFS) { @@ -10106,7 +9623,10 @@ function getJsonImage(data) { } return data.image || data.image_url || data.image_data; } -async function getMetadataAvatarUri({ gatewayUrls, uri }) { +async function getMetadataAvatarUri({ + gatewayUrls, + uri +}) { try { const res = await fetch(uri).then((res2) => res2.json()); const image = await parseAvatarUri({ @@ -10118,7 +9638,10 @@ async function getMetadataAvatarUri({ gatewayUrls, uri }) { throw new EnsAvatarUriResolutionError({ uri }); } } -async function parseAvatarUri({ gatewayUrls, uri }) { +async function parseAvatarUri({ + gatewayUrls, + uri +}) { const { uri: resolvedURI, isOnChain } = resolveAvatarUri({ uri, gatewayUrls }); if (isOnChain) return resolvedURI; @@ -10190,16 +9713,26 @@ async function getNftTokenUri(client, { nft }) { throw new EnsAvatarUnsupportedNamespaceError({ namespace: nft.namespace }); } -// ../viem/src/_esm/utils/ens/avatar/parseAvatarRecord.js -async function parseAvatarRecord(client, { gatewayUrls, record }) { +// ../viem/src/utils/ens/avatar/parseAvatarRecord.ts +async function parseAvatarRecord(client, { + gatewayUrls, + record +}) { if (/eip155:/i.test(record)) return parseNftAvatarUri(client, { gatewayUrls, record }); return parseAvatarUri({ uri: record, gatewayUrls }); } -async function parseNftAvatarUri(client, { gatewayUrls, record }) { +async function parseNftAvatarUri(client, { + gatewayUrls, + record +}) { const nft = parseNftUri(record); const nftUri = await getNftTokenUri(client, { nft }); - const { uri: resolvedNftUri, isOnChain, isEncoded } = resolveAvatarUri({ uri: nftUri, gatewayUrls }); + const { + uri: resolvedNftUri, + isOnChain, + isEncoded + } = resolveAvatarUri({ uri: nftUri, gatewayUrls }); if (isOnChain && (resolvedNftUri.includes("data:application/json;base64,") || resolvedNftUri.startsWith("{"))) { const encodedJson = isEncoded ? atob(resolvedNftUri.replace("data:application/json;base64,", "")) : resolvedNftUri; const decoded = JSON.parse(encodedJson); @@ -10214,7 +9747,7 @@ async function parseNftAvatarUri(client, { gatewayUrls, record }) { }); } -// ../viem/src/_esm/actions/ens/getEnsText.js +// ../viem/src/actions/ens/getEnsText.ts init_abis(); init_decodeFunctionResult(); init_encodeFunctionData(); @@ -10274,8 +9807,16 @@ async function getEnsText(client, parameters) { } } -// ../viem/src/_esm/actions/ens/getEnsAvatar.js -async function getEnsAvatar(client, { blockNumber, blockTag, assetGatewayUrls, name, gatewayUrls, strict, universalResolverAddress }) { +// ../viem/src/actions/ens/getEnsAvatar.ts +async function getEnsAvatar(client, { + blockNumber, + blockTag, + assetGatewayUrls, + name, + gatewayUrls, + strict, + universalResolverAddress +}) { const record = await getAction(client, getEnsText, "getEnsText")({ blockNumber, blockTag, @@ -10297,12 +9838,19 @@ async function getEnsAvatar(client, { blockNumber, blockTag, assetGatewayUrls, n } } -// ../viem/src/_esm/actions/ens/getEnsName.js +// ../viem/src/actions/ens/getEnsName.ts init_abis(); init_getChainContractAddress(); init_localBatchGatewayRequest(); async function getEnsName(client, parameters) { - const { address, blockNumber, blockTag, coinType = 60n, gatewayUrls, strict } = parameters; + const { + address, + blockNumber, + blockTag, + coinType = 60n, + gatewayUrls, + strict + } = parameters; const { chain } = client; const universalResolverAddress = (() => { if (parameters.universalResolverAddress) @@ -10336,7 +9884,7 @@ async function getEnsName(client, parameters) { } } -// ../viem/src/_esm/actions/ens/getEnsResolver.js +// ../viem/src/actions/ens/getEnsResolver.ts init_getChainContractAddress(); init_toHex(); async function getEnsResolver(client, parameters) { @@ -10379,17 +9927,31 @@ async function getEnsResolver(client, parameters) { return resolverAddress; } -// ../viem/src/_esm/clients/decorators/public.js +// ../viem/src/clients/decorators/public.ts init_call(); -// ../viem/src/_esm/actions/public/createAccessList.js +// ../viem/src/actions/public/createAccessList.ts init_base(); init_toHex(); init_getCallError(); init_transactionRequest(); init_assertRequest(); async function createAccessList(client, args) { - const { account: account_ = client.account, blockNumber, blockTag = "latest", blobs, data, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, to, value, ...rest } = args; + const { + account: account_ = client.account, + blockNumber, + blockTag = "latest", + blobs, + data, + gas, + gasPrice, + maxFeePerBlobGas, + maxFeePerGas, + maxPriorityFeePerGas, + to, + value, + ...rest + } = args; const account = account_ ? parseAccount(account_) : undefined; try { assertRequest(args); @@ -10429,18 +9991,23 @@ async function createAccessList(client, args) { } } -// ../viem/src/_esm/utils/filters/createFilterRequestScope.js +// ../viem/src/utils/filters/createFilterRequestScope.ts function createFilterRequestScope(client, { method }) { const requestMap = {}; if (client.transport.type === "fallback") - client.transport.onResponse?.(({ method: method_, response: id, status, transport }) => { + client.transport.onResponse?.(({ + method: method_, + response: id, + status, + transport + }) => { if (status === "success" && method === method_) requestMap[id] = transport.request; }); return (id) => requestMap[id] || client.request; } -// ../viem/src/_esm/actions/public/createBlockFilter.js +// ../viem/src/actions/public/createBlockFilter.ts async function createBlockFilter(client) { const getRequest = createFilterRequestScope(client, { method: "eth_newBlockFilter" @@ -10451,10 +10018,10 @@ async function createBlockFilter(client) { return { id, request: getRequest(id), type: "block" }; } -// ../viem/src/_esm/utils/abi/encodeEventTopics.js +// ../viem/src/utils/abi/encodeEventTopics.ts init_abi(); -// ../viem/src/_esm/errors/log.js +// ../viem/src/errors/log.ts init_base(); class FilterTypeNotSupportedError extends BaseError2 { @@ -10465,7 +10032,7 @@ class FilterTypeNotSupportedError extends BaseError2 { } } -// ../viem/src/_esm/utils/abi/encodeEventTopics.js +// ../viem/src/utils/abi/encodeEventTopics.ts init_toBytes(); init_keccak256(); init_toEventSelector(); @@ -10502,7 +10069,10 @@ function encodeEventTopics(parameters) { const signature = toEventSelector(definition); return [signature, ...topics]; } -function encodeArg({ param, value }) { +function encodeArg({ + param, + value +}) { if (param.type === "string" || param.type === "bytes") return keccak256(toBytes(value)); if (param.type === "tuple" || param.type.match(/^(.*)\[(\d+)?\]$/)) @@ -10510,7 +10080,7 @@ function encodeArg({ param, value }) { return encodeAbiParameters([param], [value]); } -// ../viem/src/_esm/actions/public/createContractEventFilter.js +// ../viem/src/actions/public/createContractEventFilter.ts init_toHex(); async function createContractEventFilter(client, parameters) { const { address, abi, args, eventName, fromBlock, strict, toBlock } = parameters; @@ -10544,9 +10114,17 @@ async function createContractEventFilter(client, parameters) { }; } -// ../viem/src/_esm/actions/public/createEventFilter.js +// ../viem/src/actions/public/createEventFilter.ts init_toHex(); -async function createEventFilter(client, { address, args, event, events: events_, fromBlock, strict, toBlock } = {}) { +async function createEventFilter(client, { + address, + args, + event, + events: events_, + fromBlock, + strict, + toBlock +} = {}) { const events = events_ ?? (event ? [event] : undefined); const getRequest = createFilterRequestScope(client, { method: "eth_newFilter" @@ -10586,7 +10164,7 @@ async function createEventFilter(client, { address, args, event, events: events_ }; } -// ../viem/src/_esm/actions/public/createPendingTransactionFilter.js +// ../viem/src/actions/public/createPendingTransactionFilter.ts async function createPendingTransactionFilter(client) { const getRequest = createFilterRequestScope(client, { method: "eth_newPendingTransactionFilter" @@ -10597,13 +10175,13 @@ async function createPendingTransactionFilter(client) { return { id, request: getRequest(id), type: "transaction" }; } -// ../viem/src/_esm/actions/public/estimateContractGas.js +// ../viem/src/actions/public/estimateContractGas.ts init_encodeFunctionData(); -// ../viem/src/_esm/actions/public/estimateGas.js +// ../viem/src/actions/public/estimateGas.ts init_base(); -// ../viem/src/_esm/accounts/utils/publicKeyToAddress.js +// ../viem/src/accounts/utils/publicKeyToAddress.ts init_getAddress(); init_keccak256(); function publicKeyToAddress(publicKey) { @@ -10611,11 +10189,14 @@ function publicKeyToAddress(publicKey) { return checksumAddress(`0x${address}`); } -// ../viem/src/_esm/utils/signature/recoverPublicKey.js +// ../viem/src/utils/signature/recoverPublicKey.ts init_size(); init_fromHex(); init_toHex(); -async function recoverPublicKey({ hash: hash2, signature }) { +async function recoverPublicKey({ + hash: hash2, + signature +}) { const hashHex = isHex(hash2) ? hash2 : toHex(hash2); const { secp256k1: secp256k12 } = await Promise.resolve().then(() => (init_secp256k1(), exports_secp256k1)); const signature_ = (() => { @@ -10645,16 +10226,19 @@ function toRecoveryBit(yParityOrV) { throw new Error("Invalid yParityOrV value"); } -// ../viem/src/_esm/utils/signature/recoverAddress.js -async function recoverAddress({ hash: hash2, signature }) { +// ../viem/src/utils/signature/recoverAddress.ts +async function recoverAddress({ + hash: hash2, + signature +}) { return publicKeyToAddress(await recoverPublicKey({ hash: hash2, signature })); } -// ../viem/src/_esm/utils/authorization/hashAuthorization.js +// ../viem/src/utils/authorization/hashAuthorization.ts init_toBytes(); init_toHex(); -// ../viem/src/_esm/utils/encoding/toRlp.js +// ../viem/src/utils/encoding/toRlp.ts init_base(); init_cursor2(); init_toBytes(); @@ -10747,7 +10331,7 @@ function getSizeOfLength(length) { throw new BaseError2("Length is too large."); } -// ../viem/src/_esm/utils/authorization/hashAuthorization.js +// ../viem/src/utils/authorization/hashAuthorization.ts init_keccak256(); function hashAuthorization(parameters) { const { chainId, nonce, to } = parameters; @@ -10765,7 +10349,7 @@ function hashAuthorization(parameters) { return hash2; } -// ../viem/src/_esm/utils/authorization/recoverAuthorizationAddress.js +// ../viem/src/utils/authorization/recoverAuthorizationAddress.ts async function recoverAuthorizationAddress(parameters) { const { authorization, signature } = parameters; return recoverAddress({ @@ -10774,17 +10358,30 @@ async function recoverAuthorizationAddress(parameters) { }); } -// ../viem/src/_esm/actions/public/estimateGas.js +// ../viem/src/actions/public/estimateGas.ts init_toHex(); -// ../viem/src/_esm/errors/estimateGas.js +// ../viem/src/errors/estimateGas.ts init_formatEther(); init_formatGwei(); init_base(); init_transaction(); class EstimateGasExecutionError extends BaseError2 { - constructor(cause, { account, docsPath: docsPath7, chain, data, gas, gasPrice, maxFeePerGas, maxPriorityFeePerGas, nonce, to, value }) { + cause; + constructor(cause, { + account, + docsPath: docsPath7, + chain, + data, + gas, + gasPrice, + maxFeePerGas, + maxPriorityFeePerGas, + nonce, + to, + value + }) { const prettyArgs = prettyPrint({ from: account?.address, to, @@ -10806,20 +10403,17 @@ class EstimateGasExecutionError extends BaseError2 { ].filter(Boolean), name: "EstimateGasExecutionError" }); - Object.defineProperty(this, "cause", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); this.cause = cause; } } -// ../viem/src/_esm/utils/errors/getEstimateGasError.js +// ../viem/src/utils/errors/getEstimateGasError.ts init_node(); init_getNodeError(); -function getEstimateGasError(err, { docsPath: docsPath7, ...args }) { +function getEstimateGasError(err, { + docsPath: docsPath7, + ...args +}) { const cause = (() => { const cause2 = getNodeError(err, args); if (cause2 instanceof UnknownNodeError) @@ -10832,11 +10426,11 @@ function getEstimateGasError(err, { docsPath: docsPath7, ...args }) { }); } -// ../viem/src/_esm/actions/public/estimateGas.js +// ../viem/src/actions/public/estimateGas.ts init_transactionRequest(); init_stateOverride2(); init_assertRequest(); -// ../viem/src/_esm/errors/fee.js +// ../viem/src/errors/fee.ts init_formatGwei(); init_base(); @@ -10862,14 +10456,17 @@ class MaxFeePerGasTooLowError extends BaseError2 { } } -// ../viem/src/_esm/actions/public/estimateMaxPriorityFeePerGas.js +// ../viem/src/actions/public/estimateMaxPriorityFeePerGas.ts init_fromHex(); -// ../viem/src/_esm/errors/block.js +// ../viem/src/errors/block.ts init_base(); class BlockNotFoundError extends BaseError2 { - constructor({ blockHash, blockNumber }) { + constructor({ + blockHash, + blockNumber + }) { let identifier = "Block"; if (blockHash) identifier = `Block at hash "${blockHash}"`; @@ -10879,10 +10476,10 @@ class BlockNotFoundError extends BaseError2 { } } -// ../viem/src/_esm/actions/public/getBlock.js +// ../viem/src/actions/public/getBlock.ts init_toHex(); -// ../viem/src/_esm/utils/formatters/transaction.js +// ../viem/src/utils/formatters/transaction.ts init_fromHex(); var transactionType = { "0x0": "legacy", @@ -10956,7 +10553,7 @@ function formatAuthorizationList2(authorizationList) { })); } -// ../viem/src/_esm/utils/formatters/block.js +// ../viem/src/utils/formatters/block.ts function formatBlock(block, _) { const transactions = (block.transactions ?? []).map((transaction) => { if (typeof transaction === "string") @@ -10982,8 +10579,13 @@ function formatBlock(block, _) { }; } -// ../viem/src/_esm/actions/public/getBlock.js -async function getBlock(client, { blockHash, blockNumber, blockTag = client.experimental_blockTag ?? "latest", includeTransactions: includeTransactions_ } = {}) { +// ../viem/src/actions/public/getBlock.ts +async function getBlock(client, { + blockHash, + blockNumber, + blockTag = client.experimental_blockTag ?? "latest", + includeTransactions: includeTransactions_ +} = {}) { const includeTransactions = includeTransactions_ ?? false; const blockNumberHex = blockNumber !== undefined ? numberToHex(blockNumber) : undefined; let block = null; @@ -11004,7 +10606,7 @@ async function getBlock(client, { blockHash, blockNumber, blockTag = client.expe return format2(block, "getBlock"); } -// ../viem/src/_esm/actions/public/getGasPrice.js +// ../viem/src/actions/public/getGasPrice.ts async function getGasPrice(client) { const gasPrice = await client.request({ method: "eth_gasPrice" @@ -11012,7 +10614,7 @@ async function getGasPrice(client) { return BigInt(gasPrice); } -// ../viem/src/_esm/actions/public/estimateMaxPriorityFeePerGas.js +// ../viem/src/actions/public/estimateMaxPriorityFeePerGas.ts async function estimateMaxPriorityFeePerGas(client, args) { return internal_estimateMaxPriorityFeePerGas(client, args); } @@ -11051,12 +10653,17 @@ async function internal_estimateMaxPriorityFeePerGas(client, args) { } } -// ../viem/src/_esm/actions/public/estimateFeesPerGas.js +// ../viem/src/actions/public/estimateFeesPerGas.ts async function estimateFeesPerGas(client, args) { return internal_estimateFeesPerGas(client, args); } async function internal_estimateFeesPerGas(client, args) { - const { block: block_, chain = client.chain, request, type = "eip1559" } = args || {}; + const { + block: block_, + chain = client.chain, + request, + type = "eip1559" + } = args || {}; const baseFeeMultiplier = await (async () => { if (typeof chain?.fees?.baseFeeMultiplier === "function") return chain.fees.baseFeeMultiplier({ @@ -11104,10 +10711,16 @@ async function internal_estimateFeesPerGas(client, args) { }; } -// ../viem/src/_esm/actions/public/getTransactionCount.js +// ../viem/src/actions/public/getTransactionCount.ts init_formatBlockParameter(); init_fromHex(); -async function getTransactionCount(client, { address, blockHash, blockNumber, blockTag = "latest", requireCanonical }) { +async function getTransactionCount(client, { + address, + blockHash, + blockNumber, + blockTag = "latest", + requireCanonical +}) { const block = formatBlockParameter({ blockHash, blockNumber, @@ -11123,10 +10736,10 @@ async function getTransactionCount(client, { address, blockHash, blockNumber, bl return hexToNumber(count); } -// ../viem/src/_esm/actions/wallet/prepareTransactionRequest.js +// ../viem/src/actions/wallet/prepareTransactionRequest.ts init_transaction(); -// ../viem/src/_esm/utils/blob/blobsToCommitments.js +// ../viem/src/utils/blob/blobsToCommitments.ts init_toBytes(); init_toHex(); function blobsToCommitments(parameters) { @@ -11139,7 +10752,7 @@ function blobsToCommitments(parameters) { return to === "bytes" ? commitments : commitments.map((x) => bytesToHex(x)); } -// ../viem/src/_esm/utils/blob/blobsToProofs.js +// ../viem/src/utils/blob/blobsToProofs.ts init_toBytes(); init_toHex(); function blobsToProofs(parameters) { @@ -11156,14 +10769,14 @@ function blobsToProofs(parameters) { return to === "bytes" ? proofs : proofs.map((x) => bytesToHex(x)); } -// ../viem/src/_esm/utils/blob/commitmentToVersionedHash.js +// ../viem/src/utils/blob/commitmentToVersionedHash.ts init_toHex(); // ../viem/node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha256.js init_sha2(); var sha2562 = sha256; -// ../viem/src/_esm/utils/hash/sha256.js +// ../viem/src/utils/hash/sha256.ts init_toBytes(); init_toHex(); function sha2563(value, to_) { @@ -11174,7 +10787,7 @@ function sha2563(value, to_) { return toHex(bytes); } -// ../viem/src/_esm/utils/blob/commitmentToVersionedHash.js +// ../viem/src/utils/blob/commitmentToVersionedHash.ts function commitmentToVersionedHash(parameters) { const { commitment, version: version4 = 1 } = parameters; const to = parameters.to ?? (typeof commitment === "string" ? "hex" : "bytes"); @@ -11183,7 +10796,7 @@ function commitmentToVersionedHash(parameters) { return to === "bytes" ? versionedHash : bytesToHex(versionedHash); } -// ../viem/src/_esm/utils/blob/commitmentsToVersionedHashes.js +// ../viem/src/utils/blob/commitmentsToVersionedHashes.ts function commitmentsToVersionedHashes(parameters) { const { commitments, version: version4 } = parameters; const to = parameters.to ?? (typeof commitments[0] === "string" ? "hex" : "bytes"); @@ -11198,17 +10811,17 @@ function commitmentsToVersionedHashes(parameters) { return hashes; } -// ../viem/src/_esm/constants/blob.js +// ../viem/src/constants/blob.ts var blobsPerTransaction = 6; var bytesPerFieldElement = 32; var fieldElementsPerBlob = 4096; var bytesPerBlob = bytesPerFieldElement * fieldElementsPerBlob; var maxBytesPerTransaction = bytesPerBlob * blobsPerTransaction - 1 - 1 * fieldElementsPerBlob * blobsPerTransaction; -// ../viem/src/_esm/constants/kzg.js +// ../viem/src/constants/kzg.ts var versionedHashVersionKzg = 1; -// ../viem/src/_esm/errors/blob.js +// ../viem/src/errors/blob.ts init_base(); class BlobSizeTooLargeError extends BaseError2 { @@ -11227,7 +10840,10 @@ class EmptyBlobError extends BaseError2 { } class InvalidVersionedHashSizeError extends BaseError2 { - constructor({ hash: hash2, size: size5 }) { + constructor({ + hash: hash2, + size: size5 + }) { super(`Versioned hash "${hash2}" size is invalid.`, { metaMessages: ["Expected: 32", `Received: ${size5}`], name: "InvalidVersionedHashSizeError" @@ -11236,7 +10852,10 @@ class InvalidVersionedHashSizeError extends BaseError2 { } class InvalidVersionedHashVersionError extends BaseError2 { - constructor({ hash: hash2, version: version4 }) { + constructor({ + hash: hash2, + version: version4 + }) { super(`Versioned hash "${hash2}" version is invalid.`, { metaMessages: [ `Expected: ${versionedHashVersionKzg}`, @@ -11247,7 +10866,7 @@ class InvalidVersionedHashVersionError extends BaseError2 { } } -// ../viem/src/_esm/utils/blob/toBlobs.js +// ../viem/src/utils/blob/toBlobs.ts init_cursor2(); init_size(); init_toBytes(); @@ -11286,7 +10905,7 @@ function toBlobs(parameters) { return to === "bytes" ? blobs.map((x) => x.bytes) : blobs.map((x) => bytesToHex(x.bytes)); } -// ../viem/src/_esm/utils/blob/toBlobSidecars.js +// ../viem/src/utils/blob/toBlobSidecars.ts function toBlobSidecars(parameters) { const { data, kzg, to } = parameters; const blobs = parameters.blobs ?? toBlobs({ data, to }); @@ -11302,11 +10921,11 @@ function toBlobSidecars(parameters) { return sidecars; } -// ../viem/src/_esm/actions/wallet/prepareTransactionRequest.js +// ../viem/src/actions/wallet/prepareTransactionRequest.ts init_lru(); init_assertRequest(); -// ../viem/src/_esm/utils/transaction/getTransactionType.js +// ../viem/src/utils/transaction/getTransactionType.ts init_transaction(); function getTransactionType(transaction) { if (transaction.type) @@ -11325,10 +10944,10 @@ function getTransactionType(transaction) { } throw new InvalidSerializableTransactionError({ transaction }); } -// ../viem/src/_esm/actions/public/fillTransaction.js +// ../viem/src/actions/public/fillTransaction.ts init_transaction(); -// ../viem/src/_esm/utils/errors/getTransactionError.js +// ../viem/src/utils/errors/getTransactionError.ts init_node(); init_transaction(); init_getNodeError(); @@ -11344,11 +10963,11 @@ function getTransactionError(err, { docsPath: docsPath7, ...args }) { ...args }); } -// ../viem/src/_esm/actions/public/fillTransaction.js +// ../viem/src/actions/public/fillTransaction.ts init_transactionRequest(); init_assertRequest(); -// ../viem/src/_esm/actions/public/getChainId.js +// ../viem/src/actions/public/getChainId.ts init_fromHex(); async function getChainId(client) { const chainIdHex = await client.request({ @@ -11357,9 +10976,28 @@ async function getChainId(client) { return hexToNumber(chainIdHex); } -// ../viem/src/_esm/actions/public/fillTransaction.js +// ../viem/src/actions/public/fillTransaction.ts async function fillTransaction(client, parameters) { - const { account = client.account, accessList, authorizationList, chain = client.chain, blobVersionedHashes, blobs, data, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, nonce: nonce_, nonceManager, to, type, value, ...rest } = parameters; + const { + account = client.account, + accessList, + authorizationList, + chain = client.chain, + blobVersionedHashes, + blobs, + data, + gas, + gasPrice, + maxFeePerBlobGas, + maxFeePerGas, + maxPriorityFeePerGas, + nonce: nonce_, + nonceManager, + to, + type, + value, + ...rest + } = parameters; const nonce = await (async () => { if (!account) return nonce_; @@ -11467,7 +11105,7 @@ async function fillTransaction(client, parameters) { } } -// ../viem/src/_esm/actions/wallet/prepareTransactionRequest.js +// ../viem/src/actions/wallet/prepareTransactionRequest.ts var defaultParameters = [ "blobVersionedHashes", "chainId", @@ -11482,7 +11120,12 @@ async function prepareTransactionRequest(client, args) { let request = args; request.account ??= client.account; request.parameters ??= defaultParameters; - const { account: account_, chain = client.chain, nonceManager, parameters } = request; + const { + account: account_, + chain = client.chain, + nonceManager, + parameters + } = request; const prepareTransactionRequest2 = (() => { if (typeof chain?.prepareTransactionRequest === "function") return { @@ -11548,7 +11191,18 @@ async function prepareTransactionRequest(client, args) { return false; })(); const fillResult = attemptFill ? await getAction(client, fillTransaction, "fillTransaction")({ ...request, nonce }).then((result) => { - const { chainId: chainId2, from: from4, gas: gas2, gasPrice, nonce: nonce2, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, type: type2, ...rest } = result.transaction; + const { + chainId: chainId2, + from: from4, + gas: gas2, + gasPrice, + nonce: nonce2, + maxFeePerBlobGas, + maxFeePerGas, + maxPriorityFeePerGas, + type: type2, + ...rest + } = result.transaction; const feeToken = "feeToken" in rest ? rest.feeToken : undefined; const hasFilledFeePayerSignature = "feePayerSignature" in rest && rest.feePayerSignature !== null && typeof rest.feePayerSignature !== "undefined"; const shouldUseFilledFeeToken = typeof feeToken !== "undefined" && feeToken !== null && (!("feeToken" in request) || hasFilledFeePayerSignature); @@ -11698,7 +11352,7 @@ async function prepareTransactionRequest(client, args) { return request; } -// ../viem/src/_esm/actions/public/estimateGas.js +// ../viem/src/actions/public/estimateGas.ts async function estimateGas(client, args) { const { account: account_ = client.account, prepare = true } = args; const account = account_ ? parseAccount(account_) : undefined; @@ -11721,7 +11375,24 @@ async function estimateGas(client, args) { }); return; })(); - const { accessList, authorizationList, blobs, blobVersionedHashes, blockNumber, blockTag, data, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, nonce, value, stateOverride, ...rest } = prepare ? await prepareTransactionRequest(client, { + const { + accessList, + authorizationList, + blobs, + blobVersionedHashes, + blockNumber, + blockTag, + data, + gas, + gasPrice, + maxFeePerBlobGas, + maxFeePerGas, + maxPriorityFeePerGas, + nonce, + value, + stateOverride, + ...rest + } = prepare ? await prepareTransactionRequest(client, { ...args, parameters, to @@ -11767,9 +11438,16 @@ async function estimateGas(client, args) { } } -// ../viem/src/_esm/actions/public/estimateContractGas.js +// ../viem/src/actions/public/estimateContractGas.ts async function estimateContractGas(client, parameters) { - const { abi, address, args, functionName, dataSuffix = typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value, ...request } = parameters; + const { + abi, + address, + args, + functionName, + dataSuffix = typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value, + ...request + } = parameters; const data = encodeFunctionData({ abi, args, @@ -11795,13 +11473,19 @@ async function estimateContractGas(client, parameters) { } } -// ../viem/src/_esm/actions/public/getBalance.js +// ../viem/src/actions/public/getBalance.ts init_abis(); init_decodeFunctionResult(); init_encodeFunctionData(); init_formatBlockParameter(); init_call(); -async function getBalance(client, { address, blockHash, blockNumber, blockTag = client.experimental_blockTag ?? "latest", requireCanonical }) { +async function getBalance(client, { + address, + blockHash, + blockNumber, + blockTag = client.experimental_blockTag ?? "latest", + requireCanonical +}) { const block = formatBlockParameter({ blockHash, blockNumber, @@ -11837,7 +11521,7 @@ async function getBalance(client, { address, blockHash, blockNumber, blockTag = return BigInt(balance); } -// ../viem/src/_esm/actions/public/getBlobBaseFee.js +// ../viem/src/actions/public/getBlobBaseFee.ts async function getBlobBaseFee(client) { const baseFee = await client.request({ method: "eth_blobBaseFee" @@ -11845,7 +11529,7 @@ async function getBlobBaseFee(client) { return BigInt(baseFee); } -// ../viem/src/_esm/utils/promise/withCache.js +// ../viem/src/utils/promise/withCache.ts var promiseCache = /* @__PURE__ */ new Map; var responseCache = /* @__PURE__ */ new Map; function getCache(cacheKey) { @@ -11887,7 +11571,7 @@ async function withCache(fn, { cacheKey, cacheTime = Number.POSITIVE_INFINITY }) } } -// ../viem/src/_esm/actions/public/getBlockNumber.js +// ../viem/src/actions/public/getBlockNumber.ts var cacheKey = (id) => `blockNumber.${id}`; async function getBlockNumber(client, { cacheTime = client.cacheTime } = {}) { const blockNumberHex = await withCache(() => client.request({ @@ -11896,14 +11580,17 @@ async function getBlockNumber(client, { cacheTime = client.cacheTime } = {}) { return BigInt(blockNumberHex); } -// ../viem/src/_esm/actions/public/getBlockReceipts.js +// ../viem/src/actions/public/getBlockReceipts.ts init_toHex(); -// ../viem/src/_esm/utils/formatters/transactionReceipt.js +// ../viem/src/utils/formatters/transactionReceipt.ts init_fromHex(); -// ../viem/src/_esm/utils/formatters/log.js -function formatLog(log, { args, eventName } = {}) { +// ../viem/src/utils/formatters/log.ts +function formatLog(log, { + args, + eventName +} = {}) { return { ...log, blockHash: log.blockHash ? log.blockHash : null, @@ -11916,7 +11603,7 @@ function formatLog(log, { args, eventName } = {}) { }; } -// ../viem/src/_esm/utils/formatters/transactionReceipt.js +// ../viem/src/utils/formatters/transactionReceipt.ts var receiptStatuses = { "0x0": "reverted", "0x1": "success" @@ -11941,10 +11628,13 @@ function formatTransactionReceipt(transactionReceipt, _) { receipt.blobGasUsed = BigInt(transactionReceipt.blobGasUsed); return receipt; } -var defineTransactionReceipt = /* @__PURE__ */ defineFormatter("transactionReceipt", formatTransactionReceipt); -// ../viem/src/_esm/actions/public/getBlockReceipts.js -async function getBlockReceipts(client, { blockHash, blockNumber, blockTag = client.experimental_blockTag ?? "latest" } = {}) { +// ../viem/src/actions/public/getBlockReceipts.ts +async function getBlockReceipts(client, { + blockHash, + blockNumber, + blockTag = client.experimental_blockTag ?? "latest" +} = {}) { const blockNumberHex = blockNumber !== undefined ? numberToHex(blockNumber) : undefined; const receipts = await client.request({ method: "eth_getBlockReceipts", @@ -11956,10 +11646,14 @@ async function getBlockReceipts(client, { blockHash, blockNumber, blockTag = cli return receipts.map((receipt) => format2(receipt, "getBlockReceipts")); } -// ../viem/src/_esm/actions/public/getBlockTransactionCount.js +// ../viem/src/actions/public/getBlockTransactionCount.ts init_fromHex(); init_toHex(); -async function getBlockTransactionCount(client, { blockHash, blockNumber, blockTag = "latest" } = {}) { +async function getBlockTransactionCount(client, { + blockHash, + blockNumber, + blockTag = "latest" +} = {}) { const blockNumberHex = blockNumber !== undefined ? numberToHex(blockNumber) : undefined; let count; if (blockHash) { @@ -11976,9 +11670,15 @@ async function getBlockTransactionCount(client, { blockHash, blockNumber, blockT return hexToNumber(count); } -// ../viem/src/_esm/actions/public/getCode.js +// ../viem/src/actions/public/getCode.ts init_formatBlockParameter(); -async function getCode(client, { address, blockHash, blockNumber, blockTag = "latest", requireCanonical }) { +async function getCode(client, { + address, + blockHash, + blockNumber, + blockTag = "latest", + requireCanonical +}) { const block = formatBlockParameter({ blockHash, blockNumber, @@ -11996,16 +11696,16 @@ async function getCode(client, { address, blockHash, blockNumber, blockTag = "la return hex; } -// ../viem/src/_esm/actions/public/getContractEvents.js +// ../viem/src/actions/public/getContractEvents.ts init_getAbiItem(); -// ../viem/src/_esm/utils/abi/parseEventLogs.js +// ../viem/src/utils/abi/parseEventLogs.ts init_isAddressEqual(); init_toBytes(); init_keccak256(); init_toEventSelector(); -// ../viem/src/_esm/utils/abi/decodeEventLog.js +// ../viem/src/utils/abi/decodeEventLog.ts init_abi(); init_cursor(); init_size(); @@ -12014,7 +11714,12 @@ init_decodeAbiParameters(); init_formatAbiItem2(); var docsPath7 = "/docs/contract/decodeEventLog"; function decodeEventLog(parameters) { - const { abi, data, strict: strict_, topics } = parameters; + const { + abi, + data, + strict: strict_, + topics + } = parameters; const strict = strict_ ?? true; const [signature, ...argTopics] = topics; if (!signature) @@ -12098,7 +11803,7 @@ function decodeTopic({ param, value }) { return decodedArg[0]; } -// ../viem/src/_esm/utils/abi/parseEventLogs.js +// ../viem/src/utils/abi/parseEventLogs.ts function parseEventLogs(parameters) { const { abi, args, logs, strict = true } = parameters; const eventName = (() => { @@ -12202,9 +11907,18 @@ function includesArgs(parameters) { return false; } -// ../viem/src/_esm/actions/public/getLogs.js +// ../viem/src/actions/public/getLogs.ts init_toHex(); -async function getLogs(client, { address, blockHash, fromBlock, toBlock, event, events: events_, args, strict: strict_ } = {}) { +async function getLogs(client, { + address, + blockHash, + fromBlock, + toBlock, + event, + events: events_, + args, + strict: strict_ +} = {}) { const strict = strict_ ?? false; const events = events_ ?? (event ? [event] : undefined); let topics = []; @@ -12248,9 +11962,18 @@ async function getLogs(client, { address, blockHash, fromBlock, toBlock, event, }); } -// ../viem/src/_esm/actions/public/getContractEvents.js +// ../viem/src/actions/public/getContractEvents.ts async function getContractEvents(client, parameters) { - const { abi, address, args, blockHash, eventName, fromBlock, toBlock, strict } = parameters; + const { + abi, + address, + args, + blockHash, + eventName, + fromBlock, + toBlock, + strict + } = parameters; const event = eventName ? getAbiItem({ abi, name: eventName }) : undefined; const events = !event ? abi.filter((x) => x.type === "event") : undefined; return getAction(client, getLogs, "getLogs")({ @@ -12265,7 +11988,7 @@ async function getContractEvents(client, parameters) { }); } -// ../viem/src/_esm/actions/public/getDelegation.js +// ../viem/src/actions/public/getDelegation.ts init_getAddress(); init_size(); init_slice(); @@ -12283,7 +12006,7 @@ async function getDelegation(client, { address, blockNumber, blockTag = "latest" return getAddress(slice(code, 3, 23)); } -// ../viem/src/_esm/errors/eip712.js +// ../viem/src/errors/eip712.ts init_base(); class Eip712DomainNotFoundError extends BaseError2 { @@ -12300,11 +12023,19 @@ class Eip712DomainNotFoundError extends BaseError2 { } } -// ../viem/src/_esm/actions/public/getEip712Domain.js +// ../viem/src/actions/public/getEip712Domain.ts async function getEip712Domain(client, parameters) { const { address, factory, factoryData } = parameters; try { - const [fields, name, version4, chainId, verifyingContract, salt, extensions] = await getAction(client, readContract, "readContract")({ + const [ + fields, + name, + version4, + chainId, + verifyingContract, + salt, + extensions + ] = await getAction(client, readContract, "readContract")({ abi, address, functionName: "eip712Domain", @@ -12348,10 +12079,10 @@ var abi = [ } ]; -// ../viem/src/_esm/actions/public/getFeeHistory.js +// ../viem/src/actions/public/getFeeHistory.ts init_toHex(); -// ../viem/src/_esm/utils/formatters/feeHistory.js +// ../viem/src/utils/formatters/feeHistory.ts function formatFeeHistory(feeHistory) { return { baseFeePerGas: feeHistory.baseFeePerGas.map((value) => BigInt(value)), @@ -12361,8 +12092,13 @@ function formatFeeHistory(feeHistory) { }; } -// ../viem/src/_esm/actions/public/getFeeHistory.js -async function getFeeHistory(client, { blockCount, blockNumber, blockTag = "latest", rewardPercentiles }) { +// ../viem/src/actions/public/getFeeHistory.ts +async function getFeeHistory(client, { + blockCount, + blockNumber, + blockTag = "latest", + rewardPercentiles +}) { const blockNumberHex = typeof blockNumber === "bigint" ? numberToHex(blockNumber) : undefined; const feeHistory = await client.request({ method: "eth_feeHistory", @@ -12375,8 +12111,10 @@ async function getFeeHistory(client, { blockCount, blockNumber, blockTag = "late return formatFeeHistory(feeHistory); } -// ../viem/src/_esm/actions/public/getFilterChanges.js -async function getFilterChanges(_client, { filter }) { +// ../viem/src/actions/public/getFilterChanges.ts +async function getFilterChanges(_client, { + filter +}) { const strict = "strict" in filter && filter.strict; const logs = await filter.request({ method: "eth_getFilterChanges", @@ -12394,8 +12132,10 @@ async function getFilterChanges(_client, { filter }) { }); } -// ../viem/src/_esm/actions/public/getFilterLogs.js -async function getFilterLogs(_client, { filter }) { +// ../viem/src/actions/public/getFilterLogs.ts +async function getFilterLogs(_client, { + filter +}) { const strict = filter.strict ?? false; const logs = await filter.request({ method: "eth_getFilterLogs", @@ -12411,17 +12151,14 @@ async function getFilterLogs(_client, { filter }) { }); } -// ../viem/src/_esm/actions/public/getProof.js +// ../viem/src/actions/public/getProof.ts init_formatBlockParameter(); -// ../viem/src/_esm/utils/index.js +// ../viem/src/utils/index.ts init_encodeFunctionData(); -init_pad(); init_fromHex(); -init_toHex(); -init_formatGwei(); -// ../viem/src/_esm/utils/formatters/proof.js +// ../viem/src/utils/formatters/proof.ts function formatStorageProof(storageProof) { return storageProof.map((proof) => ({ ...proof, @@ -12437,8 +12174,15 @@ function formatProof(proof) { }; } -// ../viem/src/_esm/actions/public/getProof.js -async function getProof(client, { address, blockHash, blockNumber, blockTag = "latest", requireCanonical, storageKeys }) { +// ../viem/src/actions/public/getProof.ts +async function getProof(client, { + address, + blockHash, + blockNumber, + blockTag = "latest", + requireCanonical, + storageKeys +}) { const block = formatBlockParameter({ blockHash, blockNumber, @@ -12452,7 +12196,7 @@ async function getProof(client, { address, blockHash, blockNumber, blockTag = "l return formatProof(proof); } -// ../viem/src/_esm/actions/public/getRawTransaction.js +// ../viem/src/actions/public/getRawTransaction.ts init_transaction(); async function getRawTransaction(client, { hash: hash2 }) { const rawTransaction = await client.request({ @@ -12464,9 +12208,16 @@ async function getRawTransaction(client, { hash: hash2 }) { return rawTransaction; } -// ../viem/src/_esm/actions/public/getStorageAt.js +// ../viem/src/actions/public/getStorageAt.ts init_formatBlockParameter(); -async function getStorageAt(client, { address, blockHash, blockNumber, blockTag = "latest", requireCanonical, slot }) { +async function getStorageAt(client, { + address, + blockHash, + blockNumber, + blockTag = "latest", + requireCanonical, + slot +}) { const block = formatBlockParameter({ blockHash, blockNumber, @@ -12480,10 +12231,18 @@ async function getStorageAt(client, { address, blockHash, blockNumber, blockTag return data; } -// ../viem/src/_esm/actions/public/getTransaction.js +// ../viem/src/actions/public/getTransaction.ts init_transaction(); init_toHex(); -async function getTransaction(client, { blockHash, blockNumber, blockTag: blockTag_, hash: hash2, index: index2, sender, nonce }) { +async function getTransaction(client, { + blockHash, + blockNumber, + blockTag: blockTag_, + hash: hash2, + index: index2, + sender, + nonce +}) { const blockTag = blockTag_ || "latest"; const blockNumberHex = blockNumber !== undefined ? numberToHex(blockNumber) : undefined; let transaction = null; @@ -12550,7 +12309,7 @@ async function getTransaction(client, { blockHash, blockNumber, blockTag: blockT return format2(transaction, "getTransaction"); } -// ../viem/src/_esm/actions/public/getTransactionConfirmations.js +// ../viem/src/actions/public/getTransactionConfirmations.ts async function getTransactionConfirmations(client, { hash: hash2, transactionReceipt }) { const [blockNumber, transaction] = await Promise.all([ getAction(client, getBlockNumber, "getBlockNumber")({}), @@ -12562,7 +12321,7 @@ async function getTransactionConfirmations(client, { hash: hash2, transactionRec return blockNumber - transactionBlockNumber + 1n; } -// ../viem/src/_esm/actions/public/getTransactionReceipt.js +// ../viem/src/actions/public/getTransactionReceipt.ts init_transaction(); async function getTransactionReceipt(client, { hash: hash2 }) { const receipt = await client.request({ @@ -12575,7 +12334,7 @@ async function getTransactionReceipt(client, { hash: hash2 }) { return format2(receipt, "getTransactionReceipt"); } -// ../viem/src/_esm/actions/public/multicall.js +// ../viem/src/actions/public/multicall.ts init_abis(); init_abi(); init_base(); @@ -12585,7 +12344,17 @@ init_encodeFunctionData(); init_getChainContractAddress(); init_createBatchScheduler(); async function multicall(client, parameters) { - const { account, authorizationList, allowFailure = true, blockHash, blockNumber, blockOverrides, blockTag, requireCanonical, stateOverride } = parameters; + const { + account, + authorizationList, + allowFailure = true, + blockHash, + blockNumber, + blockOverrides, + blockTag, + requireCanonical, + stateOverride + } = parameters; const contracts = parameters.contracts; const batch = typeof client.batch?.multicall === "object" ? client.batch.multicall : {}; const batchSize = parameters.batchSize ?? batch.batchSize ?? 1024; @@ -12752,7 +12521,7 @@ async function scheduleMulticall2(client, parameters) { return result; } -// ../viem/src/_esm/actions/public/simulateBlocks.js +// ../viem/src/actions/public/simulateBlocks.ts init_BlockOverrides(); init_abi(); init_contract(); @@ -12765,7 +12534,14 @@ init_transactionRequest(); init_stateOverride2(); init_assertRequest(); async function simulateBlocks(client, parameters) { - const { blockNumber, blockTag = client.experimental_blockTag ?? "latest", blocks, returnFullTransactions, traceTransfers, validation } = parameters; + const { + blockNumber, + blockTag = client.experimental_blockTag ?? "latest", + blocks, + returnFullTransactions, + traceTransfers, + validation + } = parameters; try { const blockStateCalls = []; for (const block2 of blocks) { @@ -12984,7 +12760,7 @@ function fromHex3(publicKey) { x }; } -function toHex2(publicKey, options = {}) { +function toHex3(publicKey, options = {}) { assert3(publicKey); const { prefix, x, y } = publicKey; const { includePrefix = true } = options; @@ -13110,7 +12886,7 @@ function from5(address, options = {}) { return address; } function fromPublicKey(publicKey, options = {}) { - const address = keccak2563(`0x${toHex2(publicKey).slice(4)}`).substring(26); + const address = keccak2563(`0x${toHex3(publicKey).slice(4)}`).substring(26); return from5(`0x${address}`, options); } function validate3(address, options = {}) { @@ -14429,11 +14205,11 @@ function fromAbi3(abi2, name, options) { function getSelector3(abiItem) { return getSelector(abiItem); } -// ../viem/src/_esm/constants/address.js +// ../viem/src/constants/address.ts var ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; var zeroAddress = "0x0000000000000000000000000000000000000000"; -// ../viem/src/_esm/actions/public/simulateCalls.js +// ../viem/src/actions/public/simulateCalls.ts init_base(); init_contract(); init_node(); @@ -14450,7 +14226,15 @@ var tokenUriFunction = from10("function tokenURI(uint256) returns (string)"); var symbolFunction = from10("function symbol() returns (string)"); var staticCallFunction = from10("function query(address target, bytes data)"); async function simulateCalls(client, parameters) { - const { blockNumber, blockTag, calls, stateOverrides, traceAssetChanges, traceTransfers, validation } = parameters; + const { + blockNumber, + blockTag, + calls, + stateOverrides, + traceAssetChanges, + traceTransfers, + validation + } = parameters; const account = parameters.account ? parseAccount(parameters.account) : undefined; if (traceAssetChanges && !account) throw new BaseError2("`account` is required when `traceAssetChanges` is true"); @@ -14572,7 +14356,13 @@ async function simulateCalls(client, parameters) { }) ]); const block_results = blocks[0]; - const [block_ethPost, block_assetsPost, block_decimals, block_tokenURI, block_symbols] = traceAssetChanges ? blocks.slice(1) : []; + const [ + block_ethPost, + block_assetsPost, + block_decimals, + block_tokenURI, + block_symbols + ] = traceAssetChanges ? blocks.slice(1) : []; const { calls: block_calls, ...block } = block_results; const results = block_calls.slice(0, -1); const balancesPre = balanceCallsPre.map((call2) => isBalance(call2) ? hexToBigInt(call2.data) : null); @@ -14649,7 +14439,15 @@ function decodeAssetResult(call2, abiFunction) { } } async function readBalance(client, parameters) { - const { account, address, blockNumber, blockTag, data, staticCallAddress, stateOverride } = parameters; + const { + account, + address, + blockNumber, + blockTag, + data, + staticCallAddress, + stateOverride + } = parameters; try { const result = await call({ ...client, ccipRead: false }, { account: address ? zeroAddress : account, @@ -14676,12 +14474,19 @@ function getStaticCallAddress(addresses) { return `0x${value.toString(16).padStart(40, "0")}`; } -// ../viem/src/_esm/actions/public/simulateContract.js +// ../viem/src/actions/public/simulateContract.ts init_decodeFunctionResult(); init_encodeFunctionData(); init_call(); async function simulateContract(client, parameters) { - const { abi: abi2, address, args, functionName, dataSuffix = typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value, ...callRequest } = parameters; + const { + abi: abi2, + address, + args, + functionName, + dataSuffix = typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value, + ...callRequest + } = parameters; const account = callRequest.account ? parseAccount(callRequest.account) : client.account; const calldata = encodeFunctionData({ abi: abi2, args, functionName }); try { @@ -14723,7 +14528,7 @@ async function simulateContract(client, parameters) { } } -// ../viem/src/_esm/actions/public/uninstallFilter.js +// ../viem/src/actions/public/uninstallFilter.ts async function uninstallFilter(_client, { filter }) { return filter.request({ method: "eth_uninstallFilter", @@ -15043,13 +14848,6 @@ function fromRpc2(signature) { yParity }; } -function toHex3(signature) { - assert6(signature); - const r = signature.r; - const s = signature.s; - const signature_ = concat2(fromNumber(r, { size: 32 }), fromNumber(s, { size: 32 }), typeof signature.yParity === "number" ? fromNumber(yParityToV(signature.yParity), { size: 1 }) : "0x"); - return signature_; -} function toTuple(signature) { const { r, s, yParity } = signature; return [ @@ -15067,14 +14865,6 @@ function vToYParity(v) { return v % 2 === 0 ? 1 : 0; throw new InvalidVError({ value: v }); } -function yParityToV(yParity) { - if (yParity === 0) - return 27; - if (yParity === 1) - return 28; - throw new InvalidYParityError({ value: yParity }); -} - class InvalidSerializedSizeError2 extends BaseError3 { constructor({ signature }) { super(`Value \`${signature}\` is an invalid signature size.`, { @@ -15197,11 +14987,6 @@ init_Hex(); // ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/core/Secp256k1.js init_secp256k1(); init_Hex(); - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/core/internal/entropy.js -var extraEntropy = false; - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/core/Secp256k1.js function recoverAddress3(options) { return fromPublicKey(recoverPublicKey3(options)); } @@ -15287,7 +15072,7 @@ class InvalidWrappedSignatureError2 extends BaseError3 { }); } } -// ../viem/src/_esm/actions/public/verifyHash.js +// ../viem/src/actions/public/verifyHash.ts init_abis(); init_contract(); init_encodeDeployData(); @@ -15295,25 +15080,35 @@ init_encodeFunctionData(); init_getAddress(); init_isAddressEqual(); -// ../viem/src/_esm/utils/authorization/verifyAuthorization.js +// ../viem/src/utils/authorization/verifyAuthorization.ts init_getAddress(); init_isAddressEqual(); -async function verifyAuthorization2({ address, authorization, signature }) { +async function verifyAuthorization2({ + address, + authorization, + signature +}) { return isAddressEqual(getAddress(address), await recoverAuthorizationAddress({ authorization, signature })); } -// ../viem/src/_esm/actions/public/verifyHash.js +// ../viem/src/actions/public/verifyHash.ts init_fromHex(); init_toHex(); -// ../viem/src/_esm/utils/signature/serializeSignature.js +// ../viem/src/utils/signature/serializeSignature.ts init_secp256k1(); init_fromHex(); init_toBytes(); -function serializeSignature({ r, s, to = "hex", v, yParity }) { +function serializeSignature({ + r, + s, + to = "hex", + v, + yParity +}) { const yParity_ = (() => { if (yParity === 0 || yParity === 1) return yParity; @@ -15327,10 +15122,17 @@ function serializeSignature({ r, s, to = "hex", v, yParity }) { return hexToBytes(signature); } -// ../viem/src/_esm/actions/public/verifyHash.js +// ../viem/src/actions/public/verifyHash.ts init_call(); async function verifyHash2(client, parameters) { - const { address, chain = client.chain, hash: hash3, erc6492VerifierAddress: verifierAddress = parameters.universalSignatureVerifierAddress ?? chain?.contracts?.erc6492Verifier?.address, multicallAddress = parameters.multicallAddress ?? chain?.contracts?.multicall3?.address, mode = "auto" } = parameters; + const { + address, + chain = client.chain, + hash: hash3, + erc6492VerifierAddress: verifierAddress = parameters.universalSignatureVerifierAddress ?? chain?.contracts?.erc6492Verifier?.address, + multicallAddress = parameters.multicallAddress ?? chain?.contracts?.multicall3?.address, + mode = "auto" + } = parameters; if (chain?.verifyHash) return await chain.verifyHash(client, parameters); const signature = (() => { @@ -15375,8 +15177,21 @@ async function verifyHash2(client, parameters) { } } async function verifyErc8010(client, parameters) { - const { address, blockHash, blockNumber, blockTag, hash: hash3, multicallAddress, requireCanonical } = parameters; - const { authorization: authorization_ox, data: initData, signature, to } = exports_SignatureErc8010.unwrap(parameters.signature); + const { + address, + blockHash, + blockNumber, + blockTag, + hash: hash3, + multicallAddress, + requireCanonical + } = parameters; + const { + authorization: authorization_ox, + data: initData, + signature, + to + } = exports_SignatureErc8010.unwrap(parameters.signature); const code = await getCode(client, { address, blockHash, @@ -15439,7 +15254,15 @@ async function verifyErc8010(client, parameters) { throw new VerificationError; } async function verifyErc6492(client, parameters) { - const { address, factory, factoryData, hash: hash3, signature, verifierAddress, ...rest } = parameters; + const { + address, + factory, + factoryData, + hash: hash3, + signature, + verifierAddress, + ...rest + } = parameters; const wrappedSignature = await (async () => { if (!factory && !factoryData) return signature; @@ -15477,7 +15300,15 @@ async function verifyErc6492(client, parameters) { throw new VerificationError; } async function verifyErc1271(client, parameters) { - const { address, blockHash, blockNumber, blockTag, hash: hash3, requireCanonical, signature } = parameters; + const { + address, + blockHash, + blockNumber, + blockTag, + hash: hash3, + requireCanonical, + signature + } = parameters; const result = await getAction(client, readContract, "readContract")({ address, abi: erc1271Abi, @@ -15500,14 +15331,14 @@ async function verifyErc1271(client, parameters) { class VerificationError extends Error { } -// ../viem/src/_esm/utils/signature/hashMessage.js +// ../viem/src/utils/signature/hashMessage.ts init_keccak256(); -// ../viem/src/_esm/constants/strings.js +// ../viem/src/constants/strings.ts var presignMessagePrefix = `\x19Ethereum Signed Message: `; -// ../viem/src/_esm/utils/signature/toPrefixedMessage.js +// ../viem/src/utils/signature/toPrefixedMessage.ts init_size(); init_toHex(); function toPrefixedMessage(message_) { @@ -15522,13 +15353,20 @@ function toPrefixedMessage(message_) { return concat([prefix, message]); } -// ../viem/src/_esm/utils/signature/hashMessage.js +// ../viem/src/utils/signature/hashMessage.ts function hashMessage2(message, to_) { return keccak256(toPrefixedMessage(message), to_); } -// ../viem/src/_esm/actions/public/verifyMessage.js -async function verifyMessage2(client, { address, message, factory, factoryData, signature, ...callRequest }) { +// ../viem/src/actions/public/verifyMessage.ts +async function verifyMessage2(client, { + address, + message, + factory, + factoryData, + signature, + ...callRequest +}) { const hash3 = hashMessage2(message); return getAction(client, verifyHash2, "verifyHash")({ address, @@ -15540,16 +15378,16 @@ async function verifyMessage2(client, { address, message, factory, factoryData, }); } -// ../viem/src/_esm/utils/signature/hashTypedData.js +// ../viem/src/utils/signature/hashTypedData.ts init_encodeAbiParameters(); init_toHex(); init_keccak256(); -// ../viem/src/_esm/utils/typedData.js +// ../viem/src/utils/typedData.ts init_abi(); init_address(); -// ../viem/src/_esm/errors/typedData.js +// ../viem/src/errors/typedData.ts init_base(); class InvalidDomainError extends BaseError2 { @@ -15561,7 +15399,10 @@ class InvalidDomainError extends BaseError2 { } class InvalidPrimaryTypeError extends BaseError2 { - constructor({ primaryType, types }) { + constructor({ + primaryType, + types + }) { super(`Invalid primary type \`${primaryType}\` must be one of \`${JSON.stringify(Object.keys(types))}\`.`, { docsPath: "/api/glossary/Errors#typeddatainvalidprimarytypeerror", metaMessages: ["Check that the primary type is a key in `types`."] @@ -15588,36 +15429,11 @@ class InvalidTypedDataTypeError extends BaseError2 { } } -// ../viem/src/_esm/utils/typedData.js +// ../viem/src/utils/typedData.ts init_isAddress(); init_size(); init_toHex(); init_regex2(); -function serializeTypedData2(parameters) { - const { domain: domain_, message: message_, primaryType, types } = parameters; - const normalizeData = (struct, data_) => { - const data = { ...data_ }; - for (const param of struct) { - const { name, type } = param; - if (type === "address") - data[name] = data[name].toLowerCase(); - } - return data; - }; - const domain = (() => { - if (!types.EIP712Domain) - return {}; - if (!domain_) - return {}; - return normalizeData(types.EIP712Domain, domain_); - })(); - const message = (() => { - if (primaryType === "EIP712Domain") - return; - return normalizeData(types[primaryType], message_); - })(); - return stringify({ domain, message, primaryType, types }); -} function validateTypedData2(parameters) { const { domain, message, primaryType, types } = parameters; const validateData = (struct, data) => { @@ -15665,7 +15481,9 @@ function validateTypedData2(parameters) { throw new InvalidPrimaryTypeError({ primaryType, types }); } } -function getTypesForEIP712Domain({ domain }) { +function getTypesForEIP712Domain({ + domain +}) { return [ typeof domain?.name === "string" && { name: "name", type: "string" }, domain?.version && { name: "version", type: "string" }, @@ -15685,11 +15503,15 @@ function validateReference(type) { throw new InvalidStructTypeError({ type }); } -// ../viem/src/_esm/utils/signature/hashTypedData.js +// ../viem/src/utils/signature/hashTypedData.ts function hashTypedData2(parameters) { - const { domain = {}, message, primaryType } = parameters; - const types = { - EIP712Domain: getTypesForEIP712Domain({ domain }), + const { + domain = {}, + message, + primaryType + } = parameters; + const types = { + EIP712Domain: getTypesForEIP712Domain({ domain }), ...parameters.types }; validateTypedData2({ @@ -15712,14 +15534,21 @@ function hashTypedData2(parameters) { })); return keccak256(concat(parts)); } -function hashDomain({ domain, types }) { +function hashDomain({ + domain, + types +}) { return hashStruct2({ data: domain, primaryType: "EIP712Domain", types }); } -function hashStruct2({ data, primaryType, types }) { +function hashStruct2({ + data, + primaryType, + types +}) { const encoded = encodeData2({ data, primaryType, @@ -15727,7 +15556,11 @@ function hashStruct2({ data, primaryType, types }) { }); return keccak256(encoded); } -function encodeData2({ data, primaryType, types }) { +function encodeData2({ + data, + primaryType, + types +}) { const encodedTypes = [{ type: "bytes32" }]; const encodedValues = [hashType({ primaryType, types })]; for (const field of types[primaryType]) { @@ -15742,11 +15575,17 @@ function encodeData2({ data, primaryType, types }) { } return encodeAbiParameters(encodedTypes, encodedValues); } -function hashType({ primaryType, types }) { +function hashType({ + primaryType, + types +}) { const encodedHashType = toHex(encodeType({ primaryType, types })); return keccak256(encodedHashType); } -function encodeType({ primaryType, types }) { +function encodeType({ + primaryType, + types +}) { let result = ""; const unsortedDeps = findTypeDependencies({ primaryType, types }); unsortedDeps.delete(primaryType); @@ -15756,7 +15595,10 @@ function encodeType({ primaryType, types }) { } return result; } -function findTypeDependencies({ primaryType: primaryType_, types }, results = new Set) { +function findTypeDependencies({ + primaryType: primaryType_, + types +}, results = new Set) { const match = primaryType_.match(/^\w*/u); const primaryType = match?.[0]; if (results.has(primaryType) || types[primaryType] === undefined) { @@ -15768,7 +15610,12 @@ function findTypeDependencies({ primaryType: primaryType_, types }, results = ne } return results; } -function encodeField({ types, name, type, value }) { +function encodeField({ + types, + name, + type, + value +}) { if (types[type] !== undefined) { return [ { type: "bytes32" }, @@ -15795,9 +15642,19 @@ function encodeField({ types, name, type, value }) { return [{ type }, value]; } -// ../viem/src/_esm/actions/public/verifyTypedData.js +// ../viem/src/actions/public/verifyTypedData.ts async function verifyTypedData2(client, parameters) { - const { address, factory, factoryData, signature, message, primaryType, types, domain, ...callRequest } = parameters; + const { + address, + factory, + factoryData, + signature, + message, + primaryType, + types, + domain, + ...callRequest + } = parameters; const hash3 = hashTypedData2({ message, primaryType, types, domain }); return getAction(client, verifyHash2, "verifyHash")({ address, @@ -15809,10 +15666,10 @@ async function verifyTypedData2(client, parameters) { }); } -// ../viem/src/_esm/actions/public/waitForTransactionReceipt.js +// ../viem/src/actions/public/waitForTransactionReceipt.ts init_transaction(); -// ../viem/src/_esm/utils/observe.js +// ../viem/src/utils/observe.ts var listenersCache = /* @__PURE__ */ new Map; var cleanupCache = /* @__PURE__ */ new Map; var callbackCount = 0; @@ -15863,7 +15720,7 @@ function observe(observerId, callbacks, fn) { cleanupCache.set(observerId, cleanup); return unwatch; } -// ../viem/src/_esm/utils/wait.js +// ../viem/src/utils/wait.ts async function wait(time, { signal } = {}) { return new Promise((resolve, reject) => { if (signal?.aborted) { @@ -15884,8 +15741,13 @@ async function wait(time, { signal } = {}) { }); } -// ../viem/src/_esm/utils/promise/withRetry.js -function withRetry(fn, { delay: delay_ = 100, retryCount = 2, shouldRetry = () => true, signal } = {}) { +// ../viem/src/utils/promise/withRetry.ts +function withRetry(fn, { + delay: delay_ = 100, + retryCount = 2, + shouldRetry = () => true, + signal +} = {}) { return new Promise((resolve, reject) => { const attemptRetry = async ({ count = 0 } = {}) => { if (signal?.aborted) { @@ -15924,10 +15786,10 @@ function withRetry(fn, { delay: delay_ = 100, retryCount = 2, shouldRetry = () = attemptRetry().catch(reject); }); } -// ../viem/src/_esm/actions/public/watchBlockNumber.js +// ../viem/src/actions/public/watchBlockNumber.ts init_fromHex(); -// ../viem/src/_esm/utils/poll.js +// ../viem/src/utils/poll.ts function poll(fn, { emitOnBegin, initialWaitTime, interval }) { let active = true; const unwatch = () => active = false; @@ -15949,8 +15811,15 @@ function poll(fn, { emitOnBegin, initialWaitTime, interval }) { watch(); return unwatch; } -// ../viem/src/_esm/actions/public/watchBlockNumber.js -function watchBlockNumber(client, { emitOnBegin = false, emitMissed = false, onBlockNumber, onError, poll: poll_, pollingInterval = client.pollingInterval }) { +// ../viem/src/actions/public/watchBlockNumber.ts +function watchBlockNumber(client, { + emitOnBegin = false, + emitMissed = false, + onBlockNumber, + onError, + poll: poll_, + pollingInterval = client.pollingInterval +}) { const enablePolling = (() => { if (typeof poll_ !== "undefined") return poll_; @@ -16041,7 +15910,7 @@ function watchBlockNumber(client, { emitOnBegin = false, emitMissed = false, onB return enablePolling ? pollBlockNumber() : subscribeBlockNumber(); } -// ../viem/src/_esm/actions/public/waitForTransactionReceipt.js +// ../viem/src/actions/public/waitForTransactionReceipt.ts async function waitForTransactionReceipt(client, parameters) { const { checkReplacement = client.chain?.supportsTransactionReplacementDetection ?? true, @@ -16174,7 +16043,7 @@ async function waitForTransactionReceipt(client, parameters) { return promise; } -// ../viem/src/_esm/actions/public/watchBlockHeaders.js +// ../viem/src/actions/public/watchBlockHeaders.ts var blockFields = [ "size", "totalDifficulty", @@ -16182,7 +16051,10 @@ var blockFields = [ "uncles", "withdrawals" ]; -function watchBlockHeaders(client, { onBlockHeader, onError }) { +function watchBlockHeaders(client, { + onBlockHeader, + onError +}) { let prevBlockHeader; const observerId = stringify(["watchBlockHeaders", client.uid]); return observe(observerId, { onBlockHeader, onError }, (emit) => { @@ -16227,8 +16099,17 @@ function watchBlockHeaders(client, { onBlockHeader, onError }) { return () => unsubscribe(); }); } -// ../viem/src/_esm/actions/public/watchBlocks.js -function watchBlocks(client, { blockTag = client.experimental_blockTag ?? "latest", emitMissed = false, emitOnBegin = false, onBlock, onError, includeTransactions: includeTransactions_, poll: poll_, pollingInterval = client.pollingInterval }) { +// ../viem/src/actions/public/watchBlocks.ts +function watchBlocks(client, { + blockTag = client.experimental_blockTag ?? "latest", + emitMissed = false, + emitOnBegin = false, + onBlock, + onError, + includeTransactions: includeTransactions_, + poll: poll_, + pollingInterval = client.pollingInterval +}) { const enablePolling = (() => { if (typeof poll_ !== "undefined") return poll_; @@ -16341,11 +16222,23 @@ function watchBlocks(client, { blockTag = client.experimental_blockTag ?? "lates return enablePolling ? pollBlocks() : subscribeBlocks(); } -// ../viem/src/_esm/actions/public/watchContractEvent.js +// ../viem/src/actions/public/watchContractEvent.ts init_abi(); init_rpc(); function watchContractEvent(client, parameters) { - const { abi: abi2, address, args, batch = true, eventName, fromBlock, onError, onLogs, poll: poll_, pollingInterval = client.pollingInterval, strict: strict_ } = parameters; + const { + abi: abi2, + address, + args, + batch = true, + eventName, + fromBlock, + onError, + onLogs, + poll: poll_, + pollingInterval = client.pollingInterval, + strict: strict_ + } = parameters; const enablePolling = (() => { if (typeof poll_ !== "undefined") return poll_; @@ -16517,10 +16410,22 @@ function watchContractEvent(client, parameters) { return enablePolling ? pollContractEvent() : subscribeContractEvent(); } -// ../viem/src/_esm/actions/public/watchEvent.js +// ../viem/src/actions/public/watchEvent.ts init_abi(); init_rpc(); -function watchEvent(client, { address, args, batch = true, event, events, fromBlock, onError, onLogs, poll: poll_, pollingInterval = client.pollingInterval, strict: strict_ }) { +function watchEvent(client, { + address, + args, + batch = true, + event, + events, + fromBlock, + onError, + onLogs, + poll: poll_, + pollingInterval = client.pollingInterval, + strict: strict_ +}) { const enablePolling = (() => { if (typeof poll_ !== "undefined") return poll_; @@ -16680,8 +16585,14 @@ function watchEvent(client, { address, args, batch = true, event, events, fromBl }; return enablePolling ? pollEvent() : subscribeEvent(); } -// ../viem/src/_esm/actions/public/watchPendingTransactions.js -function watchPendingTransactions(client, { batch = true, onError, onTransactions, poll: poll_, pollingInterval = client.pollingInterval }) { +// ../viem/src/actions/public/watchPendingTransactions.ts +function watchPendingTransactions(client, { + batch = true, + onError, + onTransactions, + poll: poll_, + pollingInterval = client.pollingInterval +}) { const enablePolling = typeof poll_ !== "undefined" ? poll_ : client.transport.type !== "webSocket" && client.transport.type !== "ipc"; const pollPendingTransactions = () => { const observerId = stringify([ @@ -16754,7 +16665,7 @@ function watchPendingTransactions(client, { batch = true, onError, onTransaction return enablePolling ? pollPendingTransactions() : subscribePendingTransactions(); } -// ../viem/src/_esm/utils/siwe/parseSiweMessage.js +// ../viem/src/utils/siwe/parseSiweMessage.ts var siweDateTimeRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/; function isValidSiweDateTime(value) { if (!siweDateTimeRegex.test(value)) @@ -16787,11 +16698,18 @@ function parseSiweMessage(message) { var prefixRegex = /^(?:(?[a-zA-Z][a-zA-Z0-9+-.]*):\/\/)?(?[a-zA-Z0-9+-.]*(?::[0-9]{1,5})?) (?:wants you to sign in with your Ethereum account:\n)(?
0x[a-fA-F0-9]{40})\n\n(?:(?.*)\n\n)?/; var suffixRegex = /(?:URI: (?.+))\n(?:Version: (?.+))\n(?:Chain ID: (?\d+))\n(?:Nonce: (?[a-zA-Z0-9]+))\n(?:Issued At: (?.+))(?:\nExpiration Time: (?.+))?(?:\nNot Before: (?.+))?(?:\nRequest ID: (?.+))?/; -// ../viem/src/_esm/utils/siwe/validateSiweMessage.js +// ../viem/src/utils/siwe/validateSiweMessage.ts init_isAddress(); init_isAddressEqual(); function validateSiweMessage(parameters) { - const { address, domain, message, nonce, scheme, time = new Date } = parameters; + const { + address, + domain, + message, + nonce, + scheme, + time = new Date + } = parameters; if (domain && message.domain !== domain) return false; if (nonce && message.nonce !== nonce) @@ -16825,9 +16743,18 @@ function validateSiweMessage(parameters) { return true; } -// ../viem/src/_esm/actions/siwe/verifySiweMessage.js +// ../viem/src/actions/siwe/verifySiweMessage.ts async function verifySiweMessage(client, parameters) { - const { address, domain, message, nonce, scheme, signature, time = new Date, ...callRequest } = parameters; + const { + address, + domain, + message, + nonce, + scheme, + signature, + time = new Date, + ...callRequest + } = parameters; const parsed = parseSiweMessage(message); if (!parsed.address) return false; @@ -16849,299 +16776,30 @@ async function verifySiweMessage(client, parameters) { ...callRequest }); } - -// ../viem/src/_esm/actions/token/approve.js +// ../viem/src/actions/token/getAllowance.ts init_abis(); -// ../viem/src/_esm/errors/account.js -init_base(); - -class AccountNotFoundError extends BaseError2 { - constructor({ docsPath: docsPath8 } = {}) { - super([ - "Could not find an Account to execute with this Action.", - "Please provide an Account with the `account` argument on the Action, or by supplying an `account` to the Client." - ].join(` -`), { - docsPath: docsPath8, - docsSlug: "account", - name: "AccountNotFoundError" - }); - } -} - -class AccountTypeNotSupportedError extends BaseError2 { - constructor({ docsPath: docsPath8, metaMessages, type }) { - super(`Account type "${type}" is not supported.`, { - docsPath: docsPath8, - metaMessages, - name: "AccountTypeNotSupportedError" - }); - } -} - -// ../viem/src/_esm/actions/wallet/writeContract.js -init_encodeFunctionData(); -// ../viem/src/_esm/actions/wallet/sendTransaction.js -init_base(); - -// ../viem/src/_esm/utils/chain/assertCurrentChain.js -init_chain(); -function assertCurrentChain2({ chain, currentChainId }) { - if (!chain) - throw new ChainNotFoundError; - if (currentChainId !== chain.id) - throw new ChainMismatchError({ chain, currentChainId }); -} -// ../viem/src/_esm/actions/wallet/sendTransaction.js -init_transactionRequest(); -init_lru(); -init_assertRequest(); - -// ../viem/src/_esm/actions/wallet/sendRawTransaction.js -async function sendRawTransaction(client, { serializedTransaction }) { - return client.request({ - method: "eth_sendRawTransaction", - params: [serializedTransaction] - }, { retryCount: 0 }); -} - -// ../viem/src/_esm/actions/wallet/sendTransaction.js -var supportsWalletNamespace = new LruMap(128); -async function sendTransaction(client, parameters) { - const { account: account_ = client.account, assertChainId = true, chain = client.chain, accessList, authorizationList, blobs, data, dataSuffix = typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, nonce, type, value, ...rest } = parameters; - if (typeof account_ === "undefined") - throw new AccountNotFoundError({ - docsPath: "/docs/actions/wallet/sendTransaction" - }); - const account = account_ ? parseAccount(account_) : null; - let nonceManagerParameters; - try { - assertRequest(parameters); - const to = await (async () => { - if (parameters.to) - return parameters.to; - if (parameters.to === null) - return; - if (authorizationList && authorizationList.length > 0) - return await recoverAuthorizationAddress({ - authorization: authorizationList[0] - }).catch(() => { - throw new BaseError2("`to` is required. Could not infer from `authorizationList`."); - }); - return; - })(); - if (account?.type === "json-rpc" || account === null) { - let chainId; - if (chain !== null) { - chainId = await getAction(client, getChainId, "getChainId")({}); - if (assertChainId) - assertCurrentChain2({ - currentChainId: chainId, - chain - }); - } - const chainFormat = client.chain?.formatters?.transactionRequest?.format; - const format2 = chainFormat || formatTransactionRequest; - const request = format2({ - ...extract(rest, { format: chainFormat }), - accessList, - account, - authorizationList, - blobs, - chainId, - data: dataSuffix ? concat([data ?? "0x", dataSuffix]) : data, - gas, - gasPrice, - maxFeePerBlobGas, - maxFeePerGas, - maxPriorityFeePerGas, - nonce, - to, - type, - value - }, "sendTransaction"); - const isWalletNamespaceSupported = supportsWalletNamespace.get(client.uid); - const method = isWalletNamespaceSupported ? "wallet_sendTransaction" : "eth_sendTransaction"; - try { - return await client.request({ - method, - params: [request] - }, { retryCount: 0 }); - } catch (e) { - if (isWalletNamespaceSupported === false) - throw e; - const error = e; - if (error.name === "InvalidInputRpcError" || error.name === "InvalidParamsRpcError" || error.name === "MethodNotFoundRpcError" || error.name === "MethodNotSupportedRpcError") { - return await client.request({ - method: "wallet_sendTransaction", - params: [request] - }, { retryCount: 0 }).then((hash3) => { - supportsWalletNamespace.set(client.uid, true); - return hash3; - }).catch((e2) => { - const walletNamespaceError = e2; - if (walletNamespaceError.name === "MethodNotFoundRpcError" || walletNamespaceError.name === "MethodNotSupportedRpcError") { - supportsWalletNamespace.set(client.uid, false); - throw error; - } - throw walletNamespaceError; - }); - } - throw error; - } - } - if (account?.type === "local") { - const nonceManager2 = (() => { - if (!account.nonceManager || typeof nonce !== "undefined") - return account.nonceManager; - const nonceManager3 = account.nonceManager; - return { - consume(parameters2) { - nonceManagerParameters = { - address: parameters2.address, - chainId: parameters2.chainId - }; - return nonceManager3.consume(parameters2); - }, - get(parameters2) { - return nonceManager3.get(parameters2); - }, - increment(parameters2) { - return nonceManager3.increment(parameters2); - }, - reset(parameters2) { - return nonceManager3.reset(parameters2); - } - }; - })(); - const request = await getAction(client, prepareTransactionRequest, "prepareTransactionRequest")({ - account, - accessList, - authorizationList, - blobs, - chain, - data: dataSuffix ? concat([data ?? "0x", dataSuffix]) : data, - gas, - gasPrice, - maxFeePerBlobGas, - maxFeePerGas, - maxPriorityFeePerGas, - nonce, - nonceManager: nonceManager2, - parameters: [...defaultParameters, "sidecars"], - type, - value, - ...rest, - to - }); - const serializer = chain?.serializers?.transaction; - const serializedTransaction = await account.signTransaction(request, { - serializer - }); - return await getAction(client, sendRawTransaction, "sendRawTransaction")({ - serializedTransaction - }); - } - if (account?.type === "smart") - throw new AccountTypeNotSupportedError({ - metaMessages: [ - "Consider using the `sendUserOperation` Action instead." - ], - docsPath: "/docs/actions/bundler/sendUserOperation", - type: "smart" - }); - throw new AccountTypeNotSupportedError({ - docsPath: "/docs/actions/wallet/sendTransaction", - type: account?.type - }); - } catch (err) { - if (err instanceof AccountTypeNotSupportedError) - throw err; - if (nonceManagerParameters) - account?.nonceManager?.reset(nonceManagerParameters); - throw getTransactionError(err, { - ...parameters, - account, - chain: parameters.chain || undefined - }); - } -} - -// ../viem/src/_esm/actions/wallet/writeContract.js -async function writeContract(client, parameters) { - return writeContract.internal(client, sendTransaction, "sendTransaction", parameters); -} -(function(writeContract2) { - async function internal(client, actionFn, name, parameters) { - const { abi: abi2, account: account_ = client.account, address, args, functionName, ...request } = parameters; - if (typeof account_ === "undefined") - throw new AccountNotFoundError({ - docsPath: "/docs/contract/writeContract" - }); - const account = account_ ? parseAccount(account_) : null; - const data = encodeFunctionData({ - abi: abi2, - args, - functionName - }); - try { - return await getAction(client, actionFn, name)({ - data, - to: address, - account, - ...request - }); - } catch (error) { - throw getContractError(error, { - abi: abi2, - address, - args, - docsPath: "/docs/contract/writeContract", - functionName, - sender: account?.address - }); - } - } - writeContract2.internal = internal; -})(writeContract || (writeContract = {})); -// ../viem/src/_esm/actions/token/internal.js +// ../viem/src/actions/token/internal.ts init_abis(); init_isAddress(); init_isAddressEqual(); -// ../viem/src/_esm/utils/unit/formatUnits.js +// ../viem/src/utils/unit/formatUnits.ts init_Value(); function formatUnits2(value, decimals) { return format(value, decimals); } -// ../viem/src/_esm/utils/unit/parseUnits.js +// ../viem/src/utils/unit/parseUnits.ts init_Value(); function parseUnits2(value, decimals) { return from(value, decimals); } -// ../viem/src/_esm/actions/token/internal.js +// ../viem/src/actions/token/internal.ts function toAmount(amount, decimals) { return { amount, decimals, formatted: formatUnits2(amount, decimals) }; } -function toBaseUnits(amount, decimals) { - if (typeof amount === "bigint") - return amount; - const resolved = amount.decimals ?? decimals; - return parseUnits2(amount.formatted, requireTokenDecimals(resolved)); -} -function requireTokenDecimals(decimals) { - if (decimals === undefined) - throw new Error("Token decimals are required. Pass `amount.decimals` or select a declared token."); - return decimals; -} -function resolveAmountDecimals(amount, decimals) { - if (typeof amount === "bigint") - return decimals; - return amount.decimals ?? decimals; -} function resolveToken(client, parameters) { const { decimals, token } = parameters; const declared = findDeclaredToken(client, token); @@ -17218,10 +16876,6 @@ async function resolveTokenWithDecimals(client, parameters) { }) }; } -function pickWriteParameters(parameters) { - const { account, chain, gas, maxFeePerGas, maxPriorityFeePerGas, nonce } = parameters; - return { account, chain, gas, maxFeePerGas, maxPriorityFeePerGas, nonce }; -} function defineCall(call2) { return { ...call2, @@ -17230,279 +16884,7 @@ function defineCall(call2) { }; } -// ../viem/src/_esm/actions/token/approve.js -async function approve(client, parameters) { - return approve.inner(writeContract, client, parameters); -} -(function(approve2) { - async function inner(action, client, parameters) { - return await action(client, { - ...parameters, - ...approve2.call(client, parameters) - }); - } - approve2.inner = inner; - function call2(client, parameters) { - return defineCall(getCall(client, parameters)); - } - approve2.call = call2; - async function estimateGas2(client, parameters) { - return estimateContractGas(client, { - ...pickWriteParameters(parameters), - ...approve2.call(client, parameters) - }); - } - approve2.estimateGas = estimateGas2; - async function simulate(client, parameters) { - return simulateContract(client, { - ...pickWriteParameters(parameters), - ...approve2.call(client, parameters) - }); - } - approve2.simulate = simulate; - function extractEvent(logs) { - const [log] = parseEventLogs({ - abi: erc20Abi, - logs, - eventName: "Approval", - strict: true - }); - if (!log) - throw new Error("`Approval` event not found."); - return log; - } - approve2.extractEvent = extractEvent; -})(approve || (approve = {})); -function getCall(client, parameters) { - const { amount, spender, token } = parameters; - const { address, decimals } = resolveToken(client, { token }); - return { - abi: erc20Abi, - address, - args: [spender, toBaseUnits(amount, decimals)], - functionName: "approve" - }; -} -// ../viem/src/_esm/actions/wallet/sendTransactionSync.js -init_base(); -init_transaction(); -init_transactionRequest(); -init_lru(); -init_assertRequest(); - -// ../viem/src/_esm/actions/wallet/sendRawTransactionSync.js -init_transaction(); -async function sendRawTransactionSync(client, { serializedTransaction, throwOnReceiptRevert, timeout }) { - const receipt = await client.request({ - method: "eth_sendRawTransactionSync", - params: timeout ? [serializedTransaction, timeout] : [serializedTransaction] - }, { retryCount: 0 }); - const format2 = client.chain?.formatters?.transactionReceipt?.format || formatTransactionReceipt; - const formatted = format2(receipt); - if (formatted.status === "reverted" && throwOnReceiptRevert) - throw new TransactionReceiptRevertedError({ receipt: formatted }); - return formatted; -} - -// ../viem/src/_esm/actions/wallet/sendTransactionSync.js -var supportsWalletNamespace2 = new LruMap(128); -async function sendTransactionSync(client, parameters) { - const { account: account_ = client.account, assertChainId = true, chain = client.chain, accessList, authorizationList, blobs, data, dataSuffix = typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, nonce, pollingInterval, throwOnReceiptRevert, type, value, ...rest } = parameters; - const timeout = parameters.timeout ?? Math.max((chain?.blockTime ?? 0) * 3, 5000); - if (typeof account_ === "undefined") - throw new AccountNotFoundError({ - docsPath: "/docs/actions/wallet/sendTransactionSync" - }); - const account = account_ ? parseAccount(account_) : null; - let nonceManagerParameters; - try { - assertRequest(parameters); - const to = await (async () => { - if (parameters.to) - return parameters.to; - if (parameters.to === null) - return; - if (authorizationList && authorizationList.length > 0) - return await recoverAuthorizationAddress({ - authorization: authorizationList[0] - }).catch(() => { - throw new BaseError2("`to` is required. Could not infer from `authorizationList`."); - }); - return; - })(); - if (account?.type === "json-rpc" || account === null) { - let chainId; - if (chain !== null) { - chainId = await getAction(client, getChainId, "getChainId")({}); - if (assertChainId) - assertCurrentChain2({ - currentChainId: chainId, - chain - }); - } - const chainFormat = client.chain?.formatters?.transactionRequest?.format; - const format2 = chainFormat || formatTransactionRequest; - const request = format2({ - ...extract(rest, { format: chainFormat }), - accessList, - account, - authorizationList, - blobs, - chainId, - data: dataSuffix ? concat([data ?? "0x", dataSuffix]) : data, - gas, - gasPrice, - maxFeePerBlobGas, - maxFeePerGas, - maxPriorityFeePerGas, - nonce, - to, - type, - value - }, "sendTransaction"); - const isWalletNamespaceSupported = supportsWalletNamespace2.get(client.uid); - const method = isWalletNamespaceSupported ? "wallet_sendTransaction" : "eth_sendTransaction"; - const hash3 = await (async () => { - try { - return await client.request({ - method, - params: [request] - }, { retryCount: 0 }); - } catch (e) { - if (isWalletNamespaceSupported === false) - throw e; - const error = e; - if (error.name === "InvalidInputRpcError" || error.name === "InvalidParamsRpcError" || error.name === "MethodNotFoundRpcError" || error.name === "MethodNotSupportedRpcError") { - return await client.request({ - method: "wallet_sendTransaction", - params: [request] - }, { retryCount: 0 }).then((hash4) => { - supportsWalletNamespace2.set(client.uid, true); - return hash4; - }).catch((e2) => { - const walletNamespaceError = e2; - if (walletNamespaceError.name === "MethodNotFoundRpcError" || walletNamespaceError.name === "MethodNotSupportedRpcError") { - supportsWalletNamespace2.set(client.uid, false); - throw error; - } - throw walletNamespaceError; - }); - } - throw error; - } - })(); - const receipt = await getAction(client, waitForTransactionReceipt, "waitForTransactionReceipt")({ - checkReplacement: false, - hash: hash3, - pollingInterval, - timeout - }); - if (throwOnReceiptRevert && receipt.status === "reverted") - throw new TransactionReceiptRevertedError({ receipt }); - return receipt; - } - if (account?.type === "local") { - const nonceManager2 = (() => { - if (!account.nonceManager || typeof nonce !== "undefined") - return account.nonceManager; - const nonceManager3 = account.nonceManager; - return { - consume(parameters2) { - nonceManagerParameters = { - address: parameters2.address, - chainId: parameters2.chainId - }; - return nonceManager3.consume(parameters2); - }, - get(parameters2) { - return nonceManager3.get(parameters2); - }, - increment(parameters2) { - return nonceManager3.increment(parameters2); - }, - reset(parameters2) { - return nonceManager3.reset(parameters2); - } - }; - })(); - const request = await getAction(client, prepareTransactionRequest, "prepareTransactionRequest")({ - account, - accessList, - authorizationList, - blobs, - chain, - data: dataSuffix ? concat([data ?? "0x", dataSuffix]) : data, - gas, - gasPrice, - maxFeePerBlobGas, - maxFeePerGas, - maxPriorityFeePerGas, - nonce, - nonceManager: nonceManager2, - parameters: [...defaultParameters, "sidecars"], - type, - value, - ...rest, - to - }); - const serializer = chain?.serializers?.transaction; - const serializedTransaction = await account.signTransaction(request, { - serializer - }); - return await getAction(client, sendRawTransactionSync, "sendRawTransactionSync")({ - serializedTransaction, - throwOnReceiptRevert, - timeout: parameters.timeout - }); - } - if (account?.type === "smart") - throw new AccountTypeNotSupportedError({ - metaMessages: [ - "Consider using the `sendUserOperation` Action instead." - ], - docsPath: "/docs/actions/bundler/sendUserOperation", - type: "smart" - }); - throw new AccountTypeNotSupportedError({ - docsPath: "/docs/actions/wallet/sendTransactionSync", - type: account?.type - }); - } catch (err) { - if (err instanceof AccountTypeNotSupportedError) - throw err; - if (nonceManagerParameters && !(err instanceof TransactionReceiptRevertedError)) - account?.nonceManager?.reset(nonceManagerParameters); - throw getTransactionError(err, { - ...parameters, - account, - chain: parameters.chain || undefined - }); - } -} - -// ../viem/src/_esm/actions/wallet/writeContractSync.js -async function writeContractSync(client, parameters) { - return writeContract.internal(client, sendTransactionSync, "sendTransactionSync", parameters); -} - -// ../viem/src/_esm/actions/token/approveSync.js -async function approveSync(client, parameters) { - const { amount, token, throwOnReceiptRevert = true } = parameters; - const { decimals } = resolveToken(client, { token }); - const resolved = resolveAmountDecimals(amount, decimals); - const receipt = await approve.inner(writeContractSync, client, { - ...parameters, - throwOnReceiptRevert - }); - const { args } = approve.extractEvent(receipt.logs); - return { - ...args, - ...resolved === undefined ? {} : { decimals: resolved, formatted: formatUnits2(args.value, resolved) }, - receipt - }; -} -// ../viem/src/_esm/actions/token/getAllowance.js -init_abis(); +// ../viem/src/actions/token/getAllowance.ts async function getAllowance(client, parameters) { const { account, decimals, spender, token, ...rest } = parameters; const [amount, { decimals: resolved }] = await Promise.all([ @@ -17517,7 +16899,7 @@ async function getAllowance(client, parameters) { ]); return toAmount(amount, resolved); } -(function(getAllowance2) { +((getAllowance) => { function call2(client, args) { return defineCall({ address: resolveToken(client, args).address, @@ -17526,19 +16908,43 @@ async function getAllowance(client, parameters) { args: [args.account, args.spender] }); } - getAllowance2.call = call2; -})(getAllowance || (getAllowance = {})); -// ../viem/src/_esm/actions/token/getBalance.js + getAllowance.call = call2; +})(getAllowance ||= {}); +// ../viem/src/actions/token/getBalance.ts init_abis(); -async function getBalance2(client, parameters) { - const { account: account_ = client.account, decimals, token, ...rest } = parameters; - if (!account_) - throw new AccountNotFoundError; - const account = parseAccount(account_).address; - const [amount, { decimals: resolved }] = await Promise.all([ - readContract(client, { - ...rest, - ...getBalance2.call(client, { account, token }) + +// ../viem/src/errors/account.ts +init_base(); + +class AccountNotFoundError extends BaseError2 { + constructor({ docsPath: docsPath8 } = {}) { + super([ + "Could not find an Account to execute with this Action.", + "Please provide an Account with the `account` argument on the Action, or by supplying an `account` to the Client." + ].join(` +`), { + docsPath: docsPath8, + docsSlug: "account", + name: "AccountNotFoundError" + }); + } +} + +// ../viem/src/actions/token/getBalance.ts +async function getBalance2(client, parameters) { + const { + account: account_ = client.account, + decimals, + token, + ...rest + } = parameters; + if (!account_) + throw new AccountNotFoundError; + const account = parseAccount(account_).address; + const [amount, { decimals: resolved }] = await Promise.all([ + readContract(client, { + ...rest, + ...getBalance2.call(client, { account, token }) }), resolveTokenWithDecimals(client, { decimals, @@ -17547,7 +16953,7 @@ async function getBalance2(client, parameters) { ]); return toAmount(amount, resolved); } -(function(getBalance3) { +((getBalance) => { function call2(client, args) { const account_ = args.account ?? client.account; if (!account_) @@ -17560,9 +16966,9 @@ async function getBalance2(client, parameters) { args: [account] }); } - getBalance3.call = call2; -})(getBalance2 || (getBalance2 = {})); -// ../viem/src/_esm/actions/token/getMetadata.js + getBalance.call = call2; +})(getBalance2 ||= {}); +// ../viem/src/actions/token/getMetadata.ts init_abis(); async function getMetadata(client, parameters) { const { token, ...rest } = parameters; @@ -17594,7 +17000,7 @@ async function getMetadata(client, parameters) { symbol }; } -// ../viem/src/_esm/actions/token/getTotalSupply.js +// ../viem/src/actions/token/getTotalSupply.ts init_abis(); async function getTotalSupply(client, parameters) { const { decimals, token, ...rest } = parameters; @@ -17610,7 +17016,7 @@ async function getTotalSupply(client, parameters) { ]); return toAmount(amount, resolved); } -(function(getTotalSupply2) { +((getTotalSupply) => { function call2(client, args) { return defineCall({ address: resolveToken(client, args).address, @@ -17619,87 +17025,35 @@ async function getTotalSupply(client, parameters) { functionName: "totalSupply" }); } - getTotalSupply2.call = call2; -})(getTotalSupply || (getTotalSupply = {})); -// ../viem/src/_esm/actions/token/transfer.js -init_abis(); -async function transfer(client, parameters) { - return transfer.inner(writeContract, client, parameters); -} -(function(transfer2) { - async function inner(action, client, parameters) { - return await action(client, { - ...parameters, - ...transfer2.call(client, parameters) - }); - } - transfer2.inner = inner; - function call2(client, parameters) { - return defineCall(getCall2(client, parameters)); - } - transfer2.call = call2; - async function estimateGas2(client, parameters) { - return estimateContractGas(client, { - ...pickWriteParameters(parameters), - ...transfer2.call(client, parameters) - }); - } - transfer2.estimateGas = estimateGas2; - async function simulate(client, parameters) { - return simulateContract(client, { - ...pickWriteParameters(parameters), - ...transfer2.call(client, parameters) - }); - } - transfer2.simulate = simulate; - function extractEvent(logs) { - const [log] = parseEventLogs({ - abi: erc20Abi, - logs, - eventName: "Transfer", - strict: true - }); - if (!log) - throw new Error("`Transfer` event not found."); - return log; - } - transfer2.extractEvent = extractEvent; -})(transfer || (transfer = {})); -function getCall2(client, parameters) { - const { amount, from: from16, to, token } = parameters; - const { address, decimals } = resolveToken(client, { token }); - const value = toBaseUnits(amount, decimals); - if (from16) - return { - abi: erc20Abi, - address, - args: [from16, to, value], - functionName: "transferFrom" - }; - return { - abi: erc20Abi, - address, - args: [to, value], - functionName: "transfer" - }; + getTotalSupply.call = call2; +})(getTotalSupply ||= {}); +// ../viem/src/actions/wallet/sendRawTransaction.ts +async function sendRawTransaction(client, { serializedTransaction }) { + return client.request({ + method: "eth_sendRawTransaction", + params: [serializedTransaction] + }, { retryCount: 0 }); } -// ../viem/src/_esm/actions/token/transferSync.js -async function transferSync(client, parameters) { - const { amount, token, throwOnReceiptRevert = true } = parameters; - const { decimals } = resolveToken(client, { token }); - const resolved = resolveAmountDecimals(amount, decimals); - const receipt = await transfer.inner(writeContractSync, client, { - ...parameters, - throwOnReceiptRevert - }); - const { args } = transfer.extractEvent(receipt.logs); - return { - ...args, - ...resolved === undefined ? {} : { decimals: resolved, formatted: formatUnits2(args.value, resolved) }, - receipt - }; + +// ../viem/src/actions/wallet/sendRawTransactionSync.ts +init_transaction(); +async function sendRawTransactionSync(client, { + serializedTransaction, + throwOnReceiptRevert, + timeout +}) { + const receipt = await client.request({ + method: "eth_sendRawTransactionSync", + params: timeout ? [serializedTransaction, timeout] : [serializedTransaction] + }, { retryCount: 0 }); + const format2 = client.chain?.formatters?.transactionReceipt?.format || formatTransactionReceipt; + const formatted = format2(receipt); + if (formatted.status === "reverted" && throwOnReceiptRevert) + throw new TransactionReceiptRevertedError({ receipt: formatted }); + return formatted; } -// ../viem/src/_esm/clients/decorators/public.js + +// ../viem/src/clients/decorators/public.ts function publicActions(client) { return { call: (args) => call(client, args), @@ -17775,7 +17129,7 @@ function bindPublicToken(client) { }; } -// ../viem/src/_esm/clients/createPublicClient.js +// ../viem/src/clients/createPublicClient.ts function createPublicClient(parameters) { const { key = "public", name = "Public Client" } = parameters; const client = createClient({ @@ -17786,593 +17140,247 @@ function createPublicClient(parameters) { }); return client.extend(publicActions); } -// ../viem/src/_esm/actions/wallet/addChain.js -init_toHex(); -async function addChain(client, { chain }) { - const { id, name, nativeCurrency, rpcUrls, blockExplorers } = chain; - await client.request({ - method: "wallet_addEthereumChain", - params: [ - { - chainId: numberToHex(id), - chainName: name, - nativeCurrency, - rpcUrls: rpcUrls.default.http, - blockExplorerUrls: blockExplorers ? Object.values(blockExplorers).map(({ url }) => url) : undefined - } - ] - }, { dedupe: true, retryCount: 0 }); -} +// ../viem/src/clients/transports/http.ts +init_request(); -// ../viem/src/_esm/actions/wallet/deployContract.js -init_encodeDeployData(); -function deployContract(walletClient, parameters) { - const { abi: abi2, args, bytecode, ...request } = parameters; - const calldata = encodeDeployData({ abi: abi2, args, bytecode }); - return sendTransaction(walletClient, { - ...request, - ...request.authorizationList ? { to: null } : {}, - data: calldata - }); -} +// ../viem/src/errors/transport.ts +init_base(); -// ../viem/src/_esm/actions/wallet/getAddresses.js -init_getAddress(); -async function getAddresses(client) { - if (client.account?.type === "local") - return [client.account.address]; - const addresses = await client.request({ method: "eth_accounts" }, { dedupe: true }); - return addresses.map((address) => checksumAddress(address)); +class UrlRequiredError extends BaseError2 { + constructor() { + super("No URL was provided to the Transport. Please provide a valid RPC URL to the Transport.", { + docsPath: "/docs/clients/intro", + name: "UrlRequiredError" + }); + } } -// ../viem/src/_esm/actions/wallet/getCallsStatus.js -init_slice(); -init_fromHex(); +// ../viem/src/clients/transports/http.ts +init_createBatchScheduler(); -// ../viem/src/_esm/actions/wallet/sendCalls.js -init_base(); -init_rpc(); -init_encodeFunctionData(); -init_fromHex(); -init_toHex(); -var fallbackMagicIdentifier = "0x5792579257925792579257925792579257925792579257925792579257925792"; -var fallbackTransactionErrorMagicIdentifier = numberToHex(0, { - size: 32 -}); -async function sendCalls(client, parameters) { - const { account: account_ = client.account, chain = client.chain, experimental_fallback, experimental_fallbackDelay = 32, forceAtomic = false, id, version: version4 = "2.0.0" } = parameters; - const account = account_ ? parseAccount(account_) : null; - let capabilities = parameters.capabilities; - if (client.dataSuffix && !parameters.capabilities?.dataSuffix) { - if (typeof client.dataSuffix === "string") - capabilities = { - ...parameters.capabilities, - dataSuffix: { value: client.dataSuffix, optional: true } - }; - else - capabilities = { - ...parameters.capabilities, - dataSuffix: { - value: client.dataSuffix.value, - ...client.dataSuffix.required ? {} : { optional: true } - } - }; - } - const calls = parameters.calls.map((call_) => { - const call2 = call_; - const data = call2.abi ? encodeFunctionData({ - abi: call2.abi, - functionName: call2.functionName, - args: call2.args - }) : call2.data; - return { - data: call2.dataSuffix && data ? concat([data, call2.dataSuffix]) : data, - to: call2.to, - value: call2.value ? numberToHex(call2.value) : undefined - }; - }); - try { - const response = await client.request({ - method: "wallet_sendCalls", - params: [ - { - atomicRequired: forceAtomic, - calls, - capabilities, - chainId: numberToHex(chain.id), - from: account?.address, - id, - version: version4 - } - ] - }, { retryCount: 0 }); - if (typeof response === "string") - return { id: response }; - return response; - } catch (err) { - const error = err; - if (experimental_fallback && (error.name === "MethodNotFoundRpcError" || error.name === "MethodNotSupportedRpcError" || error.name === "UnknownRpcError" || error.details.toLowerCase().includes("does not exist / is not available") || error.details.toLowerCase().includes("missing or invalid. request()") || error.details.toLowerCase().includes("did not match any variant of untagged enum") || error.details.toLowerCase().includes("account upgraded to unsupported contract") || error.details.toLowerCase().includes("eip-7702 not supported") || error.details.toLowerCase().includes("unsupported wc_ method") || error.details.toLowerCase().includes("feature toggled misconfigured") || error.details.toLowerCase().includes("jsonrpcengine: response has no error or result for request"))) { - if (capabilities) { - const hasNonOptionalCapability = Object.values(capabilities).some((capability) => !capability.optional); - if (hasNonOptionalCapability) { - const message = "non-optional `capabilities` are not supported on fallback to `eth_sendTransaction`."; - throw new UnsupportedNonOptionalCapabilityError(new BaseError2(message, { - details: message - })); +// ../viem/src/utils/rpc/http.ts +init_request(); + +// ../viem/src/utils/promise/withTimeout.ts +function withTimeout(fn, { + errorInstance = new Error("timed out"), + timeout, + signal +}) { + return new Promise((resolve, reject) => { + (async () => { + let timeoutId; + const controller = new AbortController; + try { + if (timeout > 0) { + timeoutId = setTimeout(() => { + if (signal) { + controller.abort(); + } else { + reject(errorInstance); + } + }, timeout); } - } - if (forceAtomic && calls.length > 1) { - const message = "`forceAtomic` is not supported on fallback to `eth_sendTransaction`."; - throw new AtomicityNotSupportedError(new BaseError2(message, { - details: message - })); - } - const results = []; - for (const call2 of calls) { - try { - const value = await sendTransaction(client, { - account, - chain, - data: call2.data, - to: call2.to, - value: call2.value ? hexToBigInt(call2.value) : undefined - }); - results.push({ status: "fulfilled", value }); - } catch (reason) { - results.push({ reason, status: "rejected" }); + resolve(await fn({ signal: controller?.signal || null })); + } catch (err) { + if (controller?.signal.aborted && isAbortError(err)) { + reject(errorInstance); + return; } - if (experimental_fallbackDelay > 0) - await new Promise((resolve) => setTimeout(resolve, experimental_fallbackDelay)); + reject(err); + } finally { + clearTimeout(timeoutId); } - if (results.every((r) => r.status === "rejected")) - throw results[0].reason; - const hashes = results.map((result) => { - if (result.status === "fulfilled") - return result.value; - return fallbackTransactionErrorMagicIdentifier; - }); - return { - id: concat([ - ...hashes, - numberToHex(chain.id, { size: 32 }), - fallbackMagicIdentifier - ]) - }; - } - throw getTransactionError(err, { - ...parameters, - account, - chain: parameters.chain - }); - } + })(); + }); } - -// ../viem/src/_esm/actions/wallet/getCallsStatus.js -async function getCallsStatus(client, parameters) { - async function getStatus(id) { - const isTransactions = id.endsWith(fallbackMagicIdentifier.slice(2)); - if (isTransactions) { - const chainId2 = trim(sliceHex(id, -64, -32)); - const hashes = sliceHex(id, 0, -64).slice(2).match(/.{1,64}/g); - const receipts2 = await Promise.all(hashes.map((hash3) => fallbackTransactionErrorMagicIdentifier.slice(2) !== hash3 ? client.request({ - method: "eth_getTransactionReceipt", - params: [`0x${hash3}`] - }, { dedupe: true }) : undefined)); - const status2 = (() => { - if (receipts2.some((r) => r === null)) - return 100; - if (receipts2.every((r) => r?.status === "0x1")) - return 200; - if (receipts2.every((r) => r?.status === "0x0")) - return 500; - return 600; - })(); - return { - atomic: false, - chainId: hexToNumber(chainId2), - receipts: receipts2.filter(Boolean), - status: status2, - version: "2.0.0" - }; - } - return client.request({ - method: "wallet_getCallsStatus", - params: [id] - }); - } - const { atomic = false, chainId, receipts, version: version4 = "2.0.0", ...response } = await getStatus(parameters.id); - const [status, statusCode] = (() => { - const statusCode2 = response.status; - if (statusCode2 >= 100 && statusCode2 < 200) - return ["pending", statusCode2]; - if (statusCode2 >= 200 && statusCode2 < 300) - return ["success", statusCode2]; - if (statusCode2 >= 300 && statusCode2 < 700) - return ["failure", statusCode2]; - if (statusCode2 === "CONFIRMED") - return ["success", 200]; - if (statusCode2 === "PENDING") - return ["pending", 100]; - return [undefined, statusCode2]; - })(); +// ../viem/src/utils/rpc/id.ts +function createIdStore() { return { - ...response, - atomic, - chainId: chainId ? hexToNumber(chainId) : undefined, - receipts: receipts?.map((receipt) => ({ - ...receipt, - blockNumber: hexToBigInt(receipt.blockNumber), - gasUsed: hexToBigInt(receipt.gasUsed), - status: receiptStatuses[receipt.status] - })) ?? [], - statusCode, - status, - version: version4 - }; -} - -// ../viem/src/_esm/actions/wallet/getCapabilities.js -init_toHex(); -async function getCapabilities(client, parameters = {}) { - const { account = client.account, chainId } = parameters; - const account_ = account ? parseAccount(account) : undefined; - const params = chainId ? [account_?.address, [numberToHex(chainId)]] : [account_?.address]; - const capabilities_raw = await client.request({ - method: "wallet_getCapabilities", - params - }); - const capabilities = {}; - for (const [chainId2, capabilities_] of Object.entries(capabilities_raw)) { - capabilities[Number(chainId2)] = {}; - for (let [key, value] of Object.entries(capabilities_)) { - if (key === "addSubAccount") - key = "unstable_addSubAccount"; - capabilities[Number(chainId2)][key] = value; + current: 0, + take() { + return this.current++; + }, + reset() { + this.current = 0; } - } - return typeof chainId === "number" ? capabilities[chainId] : capabilities; -} - -// ../viem/src/_esm/actions/wallet/getPermissions.js -async function getPermissions(client) { - const permissions = await client.request({ method: "wallet_getPermissions" }, { dedupe: true }); - return permissions; -} -// ../viem/src/_esm/actions/wallet/prepareAuthorization.js -init_isAddressEqual(); -async function prepareAuthorization(client, parameters) { - const { account: account_ = client.account, chainId, nonce } = parameters; - if (!account_) - throw new AccountNotFoundError({ - docsPath: "/docs/eip7702/prepareAuthorization" - }); - const account = parseAccount(account_); - const executor = (() => { - if (!parameters.executor) - return; - if (parameters.executor === "self") - return parameters.executor; - return parseAccount(parameters.executor); - })(); - const authorization = { - address: parameters.contractAddress ?? parameters.address, - chainId, - nonce }; - if (typeof authorization.chainId === "undefined") - authorization.chainId = client.chain?.id ?? await getAction(client, getChainId, "getChainId")({}); - if (typeof authorization.nonce === "undefined") { - authorization.nonce = await getAction(client, getTransactionCount, "getTransactionCount")({ - address: account.address, - blockTag: "pending" - }); - if (executor === "self" || executor?.address && isAddressEqual(executor.address, account.address)) - authorization.nonce += 1; - } - return authorization; -} - -// ../viem/src/_esm/actions/wallet/requestAddresses.js -init_getAddress(); -async function requestAddresses(client) { - const addresses = await client.request({ method: "eth_requestAccounts" }, { dedupe: true, retryCount: 0 }); - return addresses.map((address) => getAddress(address)); } +var idCache = /* @__PURE__ */ createIdStore(); -// ../viem/src/_esm/actions/wallet/requestPermissions.js -async function requestPermissions(client, permissions) { - return client.request({ - method: "wallet_requestPermissions", - params: [permissions] - }, { retryCount: 0 }); -} - -// ../viem/src/_esm/actions/wallet/waitForCallsStatus.js -init_base(); - -// ../viem/src/_esm/errors/calls.js -init_base(); - -class BundleFailedError extends BaseError2 { - constructor(result) { - super(`Call bundle failed with status: ${result.statusCode}`, { - name: "BundleFailedError" - }); - Object.defineProperty(this, "result", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - this.result = result; - } -} -// ../viem/src/_esm/actions/wallet/waitForCallsStatus.js -async function waitForCallsStatus(client, parameters) { - const { - id, - pollingInterval = client.pollingInterval, - status = ({ statusCode }) => statusCode === 200 || statusCode >= 300, - retryCount = 4, - retryDelay = ({ count }) => ~~(1 << count) * 200, - timeout = 60000, - throwOnFailure = false - } = parameters; - const observerId = stringify(["waitForCallsStatus", client.uid, id]); - const { promise, resolve, reject } = withResolvers(); - let timer; - const unobserve = observe(observerId, { resolve, reject }, (emit) => { - const unpoll = poll(async () => { - const done = (fn) => { - clearTimeout(timer); - unpoll(); - fn(); - unobserve(); +// ../viem/src/utils/rpc/http.ts +var defaultMaxResponseBodySize = 10485760; +function getHttpRpcClient2(url_, options = {}) { + const { url, headers: headers_url } = parseUrl(url_); + return { + async request(params) { + const { + body, + fetchFn = options.fetchFn ?? fetch, + maxResponseBodySize = options.maxResponseBodySize ?? defaultMaxResponseBodySize, + onRequest = options.onRequest, + onResponse = options.onResponse, + timeout = options.timeout ?? 1e4 + } = params; + const fetchOptions = { + ...options.fetchOptions ?? {}, + ...params.fetchOptions ?? {} }; + const { headers, method, signal: signal_ } = fetchOptions; try { - const result = await withRetry(async () => { - const result2 = await getAction(client, getCallsStatus, "getCallsStatus")({ id }); - if (throwOnFailure && result2.status === "failure") - throw new BundleFailedError(result2); - return result2; + const response = await withTimeout(async ({ signal }) => { + const init = { + ...fetchOptions, + body: Array.isArray(body) ? stringify(body.map((body2) => ({ + jsonrpc: "2.0", + id: body2.id ?? idCache.take(), + ...body2 + }))) : stringify({ + jsonrpc: "2.0", + id: body.id ?? idCache.take(), + ...body + }), + headers: { + ...headers_url, + "Content-Type": "application/json", + ...headers + }, + method: method || "POST", + signal: signal_ || (timeout > 0 ? signal : null) + }; + const request = new Request(url, init); + const args = await onRequest?.(request, init) ?? { ...init, url }; + const response2 = await fetchFn(args.url ?? url, args); + return response2; }, { - retryCount, - delay: retryDelay + errorInstance: new TimeoutError({ body, url }), + timeout, + signal: true + }); + if (onResponse) + await onResponse(response); + let data; + const responseBody = await readResponseBody(response, { + maxResponseBodySize + }); + if (response.headers.get("Content-Type")?.startsWith("application/json")) + data = JSON.parse(responseBody); + else { + data = responseBody; + try { + data = JSON.parse(data || "{}"); + } catch (err) { + if (response.ok) + throw err; + data = { error: data }; + } + } + if (!response.ok) { + if (typeof data.error?.code === "number" && typeof data.error?.message === "string") + return data; + throw new HttpRequestError({ + body, + details: stringify(data.error) || response.statusText, + headers: response.headers, + status: response.status, + url + }); + } + return data; + } catch (err) { + if (signal_?.aborted) + throw getAbortError(signal_); + if (isAbortError(err)) + throw err; + if (err instanceof HttpRequestError) + throw err; + if (err instanceof ResponseBodyTooLargeError) + throw err; + if (err instanceof TimeoutError) + throw err; + throw new HttpRequestError({ + body, + cause: err, + url }); - if (!status(result)) - return; - done(() => emit.resolve(result)); - } catch (error) { - done(() => emit.reject(error)); - } - }, { - interval: pollingInterval, - emitOnBegin: true - }); - return unpoll; - }); - timer = timeout ? setTimeout(() => { - unobserve(); - clearTimeout(timer); - reject(new WaitForCallsStatusTimeoutError({ id })); - }, timeout) : undefined; - return await promise; -} - -class WaitForCallsStatusTimeoutError extends BaseError2 { - constructor({ id }) { - super(`Timed out while waiting for call bundle with id "${id}" to be confirmed.`, { name: "WaitForCallsStatusTimeoutError" }); - } -} - -// ../viem/src/_esm/actions/wallet/sendCallsSync.js -async function sendCallsSync(client, parameters) { - const { chain = client.chain } = parameters; - const timeout = parameters.timeout ?? Math.max((chain?.blockTime ?? 0) * 3, 5000); - const result = await getAction(client, sendCalls, "sendCalls")(parameters); - const status = await getAction(client, waitForCallsStatus, "waitForCallsStatus")({ - ...parameters, - id: result.id, - timeout - }); - return status; -} - -// ../viem/src/_esm/actions/wallet/showCallsStatus.js -async function showCallsStatus(client, parameters) { - const { id } = parameters; - await client.request({ - method: "wallet_showCallsStatus", - params: [id] - }); - return; -} -// ../viem/src/_esm/actions/wallet/signAuthorization.js -async function signAuthorization(client, parameters) { - const { account: account_ = client.account } = parameters; - if (!account_) - throw new AccountNotFoundError({ - docsPath: "/docs/eip7702/signAuthorization" - }); - const account = parseAccount(account_); - if (!account.signAuthorization) - throw new AccountTypeNotSupportedError({ - docsPath: "/docs/eip7702/signAuthorization", - metaMessages: [ - "The `signAuthorization` Action does not support JSON-RPC Accounts." - ], - type: account.type - }); - const authorization = await prepareAuthorization(client, parameters); - return account.signAuthorization(authorization); -} -// ../viem/src/_esm/actions/wallet/signMessage.js -init_toHex(); -async function signMessage(client, { account: account_ = client.account, message }) { - if (!account_) - throw new AccountNotFoundError({ - docsPath: "/docs/actions/wallet/signMessage" - }); - const account = parseAccount(account_); - if (account.signMessage) - return account.signMessage({ message }); - const message_ = (() => { - if (typeof message === "string") - return stringToHex(message); - if (message.raw instanceof Uint8Array) - return toHex(message.raw); - return message.raw; - })(); - return client.request({ - method: "personal_sign", - params: [message_, account.address] - }, { retryCount: 0 }); -} -// ../viem/src/_esm/actions/wallet/signTransaction.js -init_toHex(); -init_transactionRequest(); -init_assertRequest(); -async function signTransaction(client, parameters) { - const { account: account_ = client.account, chain = client.chain, ...transaction } = parameters; - if (!account_) - throw new AccountNotFoundError({ - docsPath: "/docs/actions/wallet/signTransaction" - }); - const account = parseAccount(account_); - assertRequest({ - account, - ...parameters - }); - const chainId = await getAction(client, getChainId, "getChainId")({}); - if (chain !== null) - assertCurrentChain2({ - currentChainId: chainId, - chain - }); - const formatters = chain?.formatters || client.chain?.formatters; - const format2 = formatters?.transactionRequest?.format || formatTransactionRequest; - if (account.signTransaction) - return account.signTransaction({ - ...transaction, - account, - chainId - }, { serializer: client.chain?.serializers?.transaction }); - return await client.request({ - method: "eth_signTransaction", - params: [ - { - ...format2({ - ...transaction, - account - }, "signTransaction"), - chainId: numberToHex(chainId), - from: account.address } - ] - }, { retryCount: 0 }); -} -// ../viem/src/_esm/actions/wallet/signTypedData.js -async function signTypedData(client, parameters) { - const { account: account_ = client.account, domain, message, primaryType } = parameters; - if (!account_) - throw new AccountNotFoundError({ - docsPath: "/docs/actions/wallet/signTypedData" - }); - const account = parseAccount(account_); - const types = { - EIP712Domain: getTypesForEIP712Domain({ domain }), - ...parameters.types + } }; - validateTypedData2({ domain, message, primaryType, types }); - if (account.signTypedData) - return account.signTypedData({ domain, message, primaryType, types }); - const typedData = serializeTypedData2({ domain, message, primaryType, types }); - return client.request({ - method: "eth_signTypedData_v4", - params: [account.address, typedData] - }, { retryCount: 0 }); } - -// ../viem/src/_esm/actions/wallet/switchChain.js -init_toHex(); -async function switchChain(client, { id }) { - await client.request({ - method: "wallet_switchEthereumChain", - params: [ - { - chainId: numberToHex(id) +async function readResponseBody(response, { maxResponseBodySize }) { + if (maxResponseBodySize === false) + return response.text(); + const contentLength = response.headers.get("Content-Length"); + if (contentLength) { + const size7 = Number(contentLength); + if (size7 > maxResponseBodySize) + throw new ResponseBodyTooLargeError({ + maxSize: maxResponseBodySize, + size: size7 + }); + } + if (!response.body) { + const body2 = await response.text(); + const size7 = new TextEncoder().encode(body2).length; + if (size7 > maxResponseBodySize) + throw new ResponseBodyTooLargeError({ + maxSize: maxResponseBodySize, + size: size7 + }); + return body2; + } + const reader = response.body.getReader(); + const decoder2 = new TextDecoder; + let body = ""; + let size6 = 0; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) + break; + size6 += value.byteLength; + if (size6 > maxResponseBodySize) { + await reader.cancel(); + throw new ResponseBodyTooLargeError({ + maxSize: maxResponseBodySize, + size: size6 + }); } - ] - }, { retryCount: 0 }); + body += decoder2.decode(value, { stream: true }); + } + body += decoder2.decode(); + return body; + } finally { + reader.releaseLock(); + } } - -// ../viem/src/_esm/actions/wallet/watchAsset.js -async function watchAsset(client, params) { - const added = await client.request({ - method: "wallet_watchAsset", - params - }, { retryCount: 0 }); - return added; +function parseUrl(url_) { + try { + const url = new URL(url_); + const result = (() => { + if (url.username) { + const credentials = `${decodeURIComponent(url.username)}:${decodeURIComponent(url.password)}`; + url.username = ""; + url.password = ""; + return { + url: url.toString(), + headers: { Authorization: `Basic ${btoa(credentials)}` } + }; + } + return; + })(); + return { url: url.toString(), ...result }; + } catch { + return { url: url_ }; + } } -// ../viem/src/_esm/clients/decorators/wallet.js -function walletActions(client) { - return { - addChain: (args) => addChain(client, args), - deployContract: (args) => deployContract(client, args), - fillTransaction: (args) => fillTransaction(client, args), - getAddresses: () => getAddresses(client), - getCallsStatus: (args) => getCallsStatus(client, args), - getCapabilities: (args) => getCapabilities(client, args), - getChainId: () => getChainId(client), - getPermissions: () => getPermissions(client), - prepareAuthorization: (args) => prepareAuthorization(client, args), - prepareTransactionRequest: (args) => prepareTransactionRequest(client, args), - requestAddresses: () => requestAddresses(client), - requestPermissions: (args) => requestPermissions(client, args), - sendCalls: (args) => sendCalls(client, args), - sendCallsSync: (args) => sendCallsSync(client, args), - sendRawTransaction: (args) => sendRawTransaction(client, args), - sendRawTransactionSync: (args) => sendRawTransactionSync(client, args), - sendTransaction: (args) => sendTransaction(client, args), - sendTransactionSync: (args) => sendTransactionSync(client, args), - showCallsStatus: (args) => showCallsStatus(client, args), - signAuthorization: (args) => signAuthorization(client, args), - signMessage: (args) => signMessage(client, args), - signTransaction: (args) => signTransaction(client, args), - signTypedData: (args) => signTypedData(client, args), - switchChain: (args) => switchChain(client, args), - waitForCallsStatus: (args) => waitForCallsStatus(client, args), - watchAsset: (args) => watchAsset(client, args), - writeContract: (args) => writeContract(client, args), - writeContractSync: (args) => writeContractSync(client, args), - token: { - approve: bindActionDecorators(client, approve), - approveSync: bindActionDecorators(client, approveSync), - transfer: bindActionDecorators(client, transfer), - transferSync: bindActionDecorators(client, transferSync) - } - }; -} - -// ../viem/src/_esm/clients/createWalletClient.js -function createWalletClient(parameters) { - const { key = "wallet", name = "Wallet Client", transport } = parameters; - const client = createClient({ - ...parameters, - key, - name, - transport, - type: "walletClient" - }); - return client.extend(walletActions); -} -// ../viem/src/_esm/utils/buildRequest.js +// ../viem/src/utils/buildRequest.ts init_base(); init_request(); init_rpc(); -// ../viem/src/_esm/utils/promise/withDedupe.js +// ../viem/src/utils/promise/withDedupe.ts init_lru(); var promiseCache2 = /* @__PURE__ */ new LruMap(8192); function withDedupe(fn, { enabled = true, id }) { @@ -18385,10 +17393,17 @@ function withDedupe(fn, { enabled = true, id }) { return promise; } -// ../viem/src/_esm/utils/buildRequest.js +// ../viem/src/utils/buildRequest.ts function buildRequest2(request, options = {}) { return async (args, overrideOptions = {}) => { - const { dedupe = false, methods, retryDelay = 150, retryCount = 3, signal, uid: uid2 } = { + const { + dedupe = false, + methods, + retryDelay = 150, + retryCount = 3, + signal, + uid: uid2 + } = { ...options, ...overrideOptions }; @@ -18541,8 +17556,17 @@ function hashString(str, seed = 0) { return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36); } -// ../viem/src/_esm/clients/transports/createTransport.js -function createTransport({ key, methods, name, request, retryCount = 3, retryDelay = 150, timeout, type }, value) { +// ../viem/src/clients/transports/createTransport.ts +function createTransport({ + key, + methods, + name, + request, + retryCount = 3, + retryDelay = 150, + timeout, + type +}, value) { const uid2 = uid(); return { config: { @@ -18560,272 +17584,47 @@ function createTransport({ key, methods, name, request, retryCount = 3, retryDel }; } -// ../viem/src/_esm/clients/transports/custom.js -function custom(provider, config = {}) { - const { key = "custom", methods, name = "Custom Provider", retryDelay } = config; - return ({ retryCount: defaultRetryCount }) => createTransport({ - key, +// ../viem/src/clients/transports/http.ts +var signalId = 0; +var signalIds = new WeakMap; +function getSignalId(signal) { + if (!signal) + return "default"; + const id = signalIds.get(signal); + if (id !== undefined) + return id; + const nextId = signalId++; + signalIds.set(signal, nextId); + return nextId; +} +function http(url, config = {}) { + const { + batch, + fetchFn, + fetchOptions, + key = "http", + maxResponseBodySize, methods, - name, - request: provider.request.bind(provider), - retryCount: config.retryCount ?? defaultRetryCount, + name = "HTTP JSON-RPC", + onFetchRequest, + onFetchResponse, retryDelay, - type: "custom" - }); -} -// ../viem/src/_esm/clients/transports/http.js -init_request(); - -// ../viem/src/_esm/errors/transport.js -init_base(); - -class UrlRequiredError extends BaseError2 { - constructor() { - super("No URL was provided to the Transport. Please provide a valid RPC URL to the Transport.", { - docsPath: "/docs/clients/intro", - name: "UrlRequiredError" - }); - } -} - -// ../viem/src/_esm/clients/transports/http.js -init_createBatchScheduler(); - -// ../viem/src/_esm/utils/rpc/http.js -init_request(); - -// ../viem/src/_esm/utils/promise/withTimeout.js -function withTimeout(fn, { errorInstance = new Error("timed out"), timeout, signal }) { - return new Promise((resolve, reject) => { - (async () => { - let timeoutId; - const controller = new AbortController; - try { - if (timeout > 0) { - timeoutId = setTimeout(() => { - if (signal) { - controller.abort(); - } else { - reject(errorInstance); - } - }, timeout); - } - resolve(await fn({ signal: controller?.signal || null })); - } catch (err) { - if (controller?.signal.aborted && isAbortError(err)) { - reject(errorInstance); - return; - } - reject(err); - } finally { - clearTimeout(timeoutId); - } - })(); - }); -} -// ../viem/src/_esm/utils/rpc/id.js -function createIdStore() { - return { - current: 0, - take() { - return this.current++; - }, - reset() { - this.current = 0; - } - }; -} -var idCache = /* @__PURE__ */ createIdStore(); - -// ../viem/src/_esm/utils/rpc/http.js -var defaultMaxResponseBodySize = 10485760; -function getHttpRpcClient2(url_, options = {}) { - const { url, headers: headers_url } = parseUrl(url_); - return { - async request(params) { - const { body, fetchFn = options.fetchFn ?? fetch, maxResponseBodySize = options.maxResponseBodySize ?? defaultMaxResponseBodySize, onRequest = options.onRequest, onResponse = options.onResponse, timeout = options.timeout ?? 1e4 } = params; - const fetchOptions = { - ...options.fetchOptions ?? {}, - ...params.fetchOptions ?? {} - }; - const { headers, method, signal: signal_ } = fetchOptions; - try { - const response = await withTimeout(async ({ signal }) => { - const init = { - ...fetchOptions, - body: Array.isArray(body) ? stringify(body.map((body2) => ({ - jsonrpc: "2.0", - id: body2.id ?? idCache.take(), - ...body2 - }))) : stringify({ - jsonrpc: "2.0", - id: body.id ?? idCache.take(), - ...body - }), - headers: { - ...headers_url, - "Content-Type": "application/json", - ...headers - }, - method: method || "POST", - signal: signal_ || (timeout > 0 ? signal : null) - }; - const request = new Request(url, init); - const args = await onRequest?.(request, init) ?? { ...init, url }; - const response2 = await fetchFn(args.url ?? url, args); - return response2; - }, { - errorInstance: new TimeoutError({ body, url }), - timeout, - signal: true - }); - if (onResponse) - await onResponse(response); - let data; - const responseBody = await readResponseBody(response, { - maxResponseBodySize - }); - if (response.headers.get("Content-Type")?.startsWith("application/json")) - data = JSON.parse(responseBody); - else { - data = responseBody; - try { - data = JSON.parse(data || "{}"); - } catch (err) { - if (response.ok) - throw err; - data = { error: data }; - } - } - if (!response.ok) { - if (typeof data.error?.code === "number" && typeof data.error?.message === "string") - return data; - throw new HttpRequestError({ - body, - details: stringify(data.error) || response.statusText, - headers: response.headers, - status: response.status, - url - }); - } - return data; - } catch (err) { - if (signal_?.aborted) - throw getAbortError(signal_); - if (isAbortError(err)) - throw err; - if (err instanceof HttpRequestError) - throw err; - if (err instanceof ResponseBodyTooLargeError) - throw err; - if (err instanceof TimeoutError) - throw err; - throw new HttpRequestError({ - body, - cause: err, - url - }); - } - } - }; -} -async function readResponseBody(response, { maxResponseBodySize }) { - if (maxResponseBodySize === false) - return response.text(); - const contentLength = response.headers.get("Content-Length"); - if (contentLength) { - const size7 = Number(contentLength); - if (size7 > maxResponseBodySize) - throw new ResponseBodyTooLargeError({ - maxSize: maxResponseBodySize, - size: size7 - }); - } - if (!response.body) { - const body2 = await response.text(); - const size7 = new TextEncoder().encode(body2).length; - if (size7 > maxResponseBodySize) - throw new ResponseBodyTooLargeError({ - maxSize: maxResponseBodySize, - size: size7 - }); - return body2; - } - const reader = response.body.getReader(); - const decoder2 = new TextDecoder; - let body = ""; - let size6 = 0; - try { - while (true) { - const { done, value } = await reader.read(); - if (done) - break; - size6 += value.byteLength; - if (size6 > maxResponseBodySize) { - await reader.cancel(); - throw new ResponseBodyTooLargeError({ - maxSize: maxResponseBodySize, - size: size6 - }); - } - body += decoder2.decode(value, { stream: true }); - } - body += decoder2.decode(); - return body; - } finally { - reader.releaseLock(); - } -} -function parseUrl(url_) { - try { - const url = new URL(url_); - const result = (() => { - if (url.username) { - const credentials = `${decodeURIComponent(url.username)}:${decodeURIComponent(url.password)}`; - url.username = ""; - url.password = ""; - return { - url: url.toString(), - headers: { Authorization: `Basic ${btoa(credentials)}` } - }; - } - return; - })(); - return { url: url.toString(), ...result }; - } catch { - return { url: url_ }; - } -} - -// ../viem/src/_esm/clients/transports/http.js -var signalId = 0; -var signalIds = new WeakMap; -function getSignalId(signal) { - if (!signal) - return "default"; - const id = signalIds.get(signal); - if (id !== undefined) - return id; - const nextId = signalId++; - signalIds.set(signal, nextId); - return nextId; -} -function http(url, config = {}) { - const { batch, fetchFn, fetchOptions, key = "http", maxResponseBodySize, methods, name = "HTTP JSON-RPC", onFetchRequest, onFetchResponse, retryDelay, raw } = config; - return ({ chain, retryCount: retryCount_, timeout: timeout_ }) => { - const { batchSize = 1000, wait: wait2 = 0 } = typeof batch === "object" ? batch : {}; - const retryCount = config.retryCount ?? retryCount_; - const timeout = timeout_ ?? config.timeout ?? 1e4; - const url_ = url || chain?.rpcUrls.default.http[0]; - if (!url_) - throw new UrlRequiredError; - const rpcClient = getHttpRpcClient2(url_, { - fetchFn, - fetchOptions, - maxResponseBodySize, - onRequest: onFetchRequest, - onResponse: onFetchResponse, - timeout + raw + } = config; + return ({ chain, retryCount: retryCount_, timeout: timeout_ }) => { + const { batchSize = 1000, wait: wait2 = 0 } = typeof batch === "object" ? batch : {}; + const retryCount = config.retryCount ?? retryCount_; + const timeout = timeout_ ?? config.timeout ?? 1e4; + const url_ = url || chain?.rpcUrls.default.http[0]; + if (!url_) + throw new UrlRequiredError; + const rpcClient = getHttpRpcClient2(url_, { + fetchFn, + fetchOptions, + maxResponseBodySize, + onRequest: onFetchRequest, + onResponse: onFetchResponse, + timeout }); return createTransport({ key, @@ -18874,32 +17673,28 @@ function http(url, config = {}) { }; } -// ../viem/src/_esm/index.js +// ../viem/src/index.ts init_decodeAbiParameters(); init_encodeAbiParameters(); init_encodeFunctionData(); -init_slice(); -init_fromHex(); init_toHex(); -init_keccak256(); -init_formatEther(); -// ../viem/src/_esm/utils/unit/parseEther.js +// ../viem/src/utils/unit/parseEther.ts init_Value(); function parseEther2(ether, unit = "wei") { return fromEther(ether, unit); } -// ../viem/src/_esm/accounts/generatePrivateKey.js +// ../viem/src/accounts/generatePrivateKey.ts init_secp256k1(); init_toHex(); function generatePrivateKey() { return toHex(secp256k1.utils.randomPrivateKey()); } -// ../viem/src/_esm/accounts/privateKeyToAccount.js +// ../viem/src/accounts/privateKeyToAccount.ts init_secp256k1(); init_toHex(); -// ../viem/src/_esm/accounts/toAccount.js +// ../viem/src/accounts/toAccount.ts init_address(); init_isAddress(); function toAccount(source) { @@ -18926,15 +17721,19 @@ function toAccount(source) { }; } -// ../viem/src/_esm/accounts/utils/sign.js +// ../viem/src/accounts/utils/sign.ts init_secp256k1(); init_toBytes(); init_toHex(); -var extraEntropy2 = false; -async function sign({ hash: hash3, privateKey, to = "object" }) { +var extraEntropy = false; +async function sign({ + hash: hash3, + privateKey, + to = "object" +}) { const { r, s, recovery } = secp256k1.sign(hash3.slice(2), privateKey.slice(2), { lowS: true, - extraEntropy: isHex(extraEntropy2, { strict: false }) ? hexToBytes(extraEntropy2) : extraEntropy2 + extraEntropy: isHex(extraEntropy, { strict: false }) ? hexToBytes(extraEntropy) : extraEntropy }); const signature = { r: numberToHex(r, { size: 32 }), @@ -18949,8 +17748,8 @@ async function sign({ hash: hash3, privateKey, to = "object" }) { })(); } -// ../viem/src/_esm/accounts/utils/signAuthorization.js -async function signAuthorization2(parameters) { +// ../viem/src/accounts/utils/signAuthorization.ts +async function signAuthorization(parameters) { const { chainId, nonce, privateKey, to = "object" } = parameters; const address = parameters.contractAddress ?? parameters.address; const signature = await sign({ @@ -18968,18 +17767,21 @@ async function signAuthorization2(parameters) { return signature; } -// ../viem/src/_esm/accounts/utils/signMessage.js -async function signMessage2({ message, privateKey }) { +// ../viem/src/accounts/utils/signMessage.ts +async function signMessage({ + message, + privateKey +}) { return await sign({ hash: hashMessage2(message), privateKey, to: "hex" }); } -// ../viem/src/_esm/accounts/utils/signTransaction.js +// ../viem/src/accounts/utils/signTransaction.ts init_keccak256(); -// ../viem/src/_esm/utils/transaction/serializeTransaction.js +// ../viem/src/utils/transaction/serializeTransaction.ts init_transaction(); -// ../viem/src/_esm/utils/authorization/serializeAuthorizationList.js +// ../viem/src/utils/authorization/serializeAuthorizationList.ts init_toHex(); function serializeAuthorizationList2(authorizationList) { if (!authorizationList || authorizationList.length === 0) @@ -18998,10 +17800,10 @@ function serializeAuthorizationList2(authorizationList) { return serializedAuthorizationList; } -// ../viem/src/_esm/utils/transaction/serializeTransaction.js +// ../viem/src/utils/transaction/serializeTransaction.ts init_toHex(); -// ../viem/src/_esm/utils/transaction/assertTransaction.js +// ../viem/src/utils/transaction/assertTransaction.ts init_number(); init_address(); init_base(); @@ -19078,7 +17880,7 @@ function assertTransactionLegacy3(transaction) { throw new FeeCapTooHighError({ maxFeePerGas: gasPrice }); } -// ../viem/src/_esm/utils/transaction/serializeAccessList.js +// ../viem/src/utils/transaction/serializeAccessList.ts init_address(); init_transaction(); init_isAddress(); @@ -19101,7 +17903,7 @@ function serializeAccessList3(accessList) { return serializedAccessList; } -// ../viem/src/_esm/utils/transaction/serializeTransaction.js +// ../viem/src/utils/transaction/serializeTransaction.ts function serializeTransaction3(transaction, signature) { const type = getTransactionType(transaction); if (type === "eip1559") @@ -19115,7 +17917,18 @@ function serializeTransaction3(transaction, signature) { return serializeTransactionLegacy(transaction, signature); } function serializeTransactionEIP7702(transaction, signature) { - const { authorizationList, chainId, gas, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, accessList, data } = transaction; + const { + authorizationList, + chainId, + gas, + nonce, + to, + value, + maxFeePerGas, + maxPriorityFeePerGas, + accessList, + data + } = transaction; assertTransactionEIP7702(transaction); const serializedAccessList = serializeAccessList3(accessList); const serializedAuthorizationList = serializeAuthorizationList2(authorizationList); @@ -19137,7 +17950,18 @@ function serializeTransactionEIP7702(transaction, signature) { ]); } function serializeTransactionEIP4844(transaction, signature) { - const { chainId, gas, nonce, to, value, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, accessList, data } = transaction; + const { + chainId, + gas, + nonce, + to, + value, + maxFeePerBlobGas, + maxFeePerGas, + maxPriorityFeePerGas, + accessList, + data + } = transaction; assertTransactionEIP4844(transaction); let blobVersionedHashes = transaction.blobVersionedHashes; let sidecars = transaction.sidecars; @@ -19188,7 +18012,17 @@ function serializeTransactionEIP4844(transaction, signature) { ]); } function serializeTransactionEIP1559(transaction, signature) { - const { chainId, gas, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, accessList, data } = transaction; + const { + chainId, + gas, + nonce, + to, + value, + maxFeePerGas, + maxPriorityFeePerGas, + accessList, + data + } = transaction; assertTransactionEIP15593(transaction); const serializedAccessList = serializeAccessList3(accessList); const serializedTransaction = [ @@ -19295,9 +18129,13 @@ function toYParitySignatureArray(transaction, signature_) { return [yParity_, r === "0x00" ? "0x" : r, s === "0x00" ? "0x" : s]; } -// ../viem/src/_esm/accounts/utils/signTransaction.js -async function signTransaction2(parameters) { - const { privateKey, transaction, serializer = serializeTransaction3 } = parameters; +// ../viem/src/accounts/utils/signTransaction.ts +async function signTransaction(parameters) { + const { + privateKey, + transaction, + serializer = serializeTransaction3 + } = parameters; const signableTransaction = (() => { if (transaction.type === "eip4844") return { @@ -19313,8 +18151,8 @@ async function signTransaction2(parameters) { return await serializer(transaction, signature); } -// ../viem/src/_esm/accounts/utils/signTypedData.js -async function signTypedData2(parameters) { +// ../viem/src/accounts/utils/signTypedData.ts +async function signTypedData(parameters) { const { privateKey, ...typedData } = parameters; return await sign({ hash: hashTypedData2(typedData), @@ -19323,7 +18161,7 @@ async function signTypedData2(parameters) { }); } -// ../viem/src/_esm/accounts/privateKeyToAccount.js +// ../viem/src/accounts/privateKeyToAccount.ts function privateKeyToAccount(privateKey, options = {}) { const { nonceManager: nonceManager3 } = options; const publicKey = toHex(secp256k1.getPublicKey(privateKey.slice(2), false)); @@ -19335,16 +18173,16 @@ function privateKeyToAccount(privateKey, options = {}) { return sign({ hash: hash3, privateKey, to: "hex" }); }, async signAuthorization(authorization) { - return signAuthorization2({ ...authorization, privateKey }); + return signAuthorization({ ...authorization, privateKey }); }, async signMessage({ message }) { - return signMessage2({ message, privateKey }); + return signMessage({ message, privateKey }); }, async signTransaction(transaction, { serializer } = {}) { - return signTransaction2({ privateKey, transaction, serializer }); + return signTransaction({ privateKey, transaction, serializer }); }, async signTypedData(typedData) { - return signTypedData2({ ...typedData, privateKey }); + return signTypedData({ ...typedData, privateKey }); } }); return { @@ -19353,5414 +18191,592 @@ function privateKeyToAccount(privateKey, options = {}) { source: "privateKey" }; } -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/core/Base64.js -var encoder5 = /* @__PURE__ */ new TextEncoder; -var integerToCharacter = /* @__PURE__ */ Object.fromEntries(Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").map((a, i) => [i, a.charCodeAt(0)])); -var characterToInteger = { - ...Object.fromEntries(Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").map((a, i) => [a.charCodeAt(0), i])), - [61]: 0, - [45]: 62, - [95]: 63 +// ../viem/src/eip8130/accounts/toEoaAccount.ts +init_base(); + +// ../viem/src/eip8130/constants.ts +var aaTransactionType = "0x79"; +var aaPayerType = "0x7a"; +var k1AuthCost = 5100n; +var txValueCost = 6000n; +var delegationCost = 4600n; +var nonceFreeCost = 13000n; +var nonceFreeDefaultExpiryWindow = 15000n; +var accountChangeType = { + delegation: "0x01", + create: "0x02", + config: "0x03" }; -function toBytes6(value) { - const base64 = value.replace(/=+$/, ""); - const size7 = base64.length; - const decoded = new Uint8Array(size7 + 3); - encoder5.encodeInto(base64 + "===", decoded); - for (let i = 0, j = 0;i < base64.length; i += 4, j += 3) { - const x = (characterToInteger[decoded[i]] << 18) + (characterToInteger[decoded[i + 1]] << 12) + (characterToInteger[decoded[i + 2]] << 6) + characterToInteger[decoded[i + 3]]; - decoded[j] = x >> 16; - decoded[j + 1] = x >> 8 & 255; - decoded[j + 2] = x & 255; - } - const decodedSize = (size7 >> 2) * 3 + (size7 % 4 && size7 % 4 - 1); - return new Uint8Array(decoded.buffer, 0, decodedSize); -} - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/webauthn/Authentication.js -init_Bytes(); -init_Errors(); -init_Hex(); +var changeType = { + authorizeActor: 0, + revokeActor: 1, + incrementLocalEpoch: 2, + lock: 3, + unlock: 4 +}; +var nonceKeyMax = 2n ** 256n - 1n; +var k1Authenticator = "0x0000000000000000000000000000000000000001"; +var k1AuthDataLength = 65; +var openPayer = "0x00"; -// ../viem/node_modules/.pnpm/@noble+curves@1.9.1/node_modules/@noble/curves/esm/nist.js -init_sha2(); -init__shortw_utils(); -init_modular(); -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -var Fp256 = Field(BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff")); -var p256_a = Fp256.create(BigInt("-3")); -var p256_b = BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"); -var p256 = createCurve({ - a: p256_a, - b: p256_b, - Fp: Fp256, - n: BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), - Gx: BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"), - Gy: BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"), - h: BigInt(1), - lowS: false -}, sha256); -var Fp384 = Field(BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff")); -var p384_a = Fp384.create(BigInt("-3")); -var p384_b = BigInt("0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"); -var p384 = createCurve({ - a: p384_a, - b: p384_b, - Fp: Fp384, - n: BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"), - Gx: BigInt("0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"), - Gy: BigInt("0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"), - h: BigInt(1), - lowS: false -}, sha384); -var Fp521 = Field(BigInt("0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); -var p521_a = Fp521.create(BigInt("-3")); -var p521_b = BigInt("0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00"); -var p521 = createCurve({ - a: p521_a, - b: p521_b, - Fp: Fp521, - n: BigInt("0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409"), - Gx: BigInt("0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66"), - Gy: BigInt("0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"), - h: BigInt(1), - lowS: false, - allowedPrivateKeyLengths: [130, 131, 132] -}, sha512); - -// ../viem/node_modules/.pnpm/@noble+curves@1.9.1/node_modules/@noble/curves/esm/p256.js -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -var p2562 = p256; -var secp256r1 = p256; - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/webauthn/Registration.js -init_Bytes(); -init_Errors(); - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/core/P256.js -init_Bytes(); -init_Hex(); -function getPublicKey(options) { - const { privateKey } = options; - const point = secp256r1.ProjectivePoint.fromPrivateKey(typeof privateKey === "string" ? privateKey.slice(2) : fromBytes(privateKey).slice(2)); - return from4(point); -} -function sign3(options) { - const { extraEntropy: extraEntropy3 = extraEntropy, hash: hash3, payload, privateKey } = options; - const { r, s, recovery } = secp256r1.sign(payload instanceof Uint8Array ? payload : fromHex(payload), privateKey instanceof Uint8Array ? privateKey : fromHex(privateKey), { - extraEntropy: typeof extraEntropy3 === "boolean" ? extraEntropy3 : from3(extraEntropy3).slice(2), - lowS: true, - ...hash3 ? { prehash: true } : {} - }); - return { - r, - s, - yParity: recovery - }; -} - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/webauthn/Registration.js -var createChallenge = Uint8Array.from([ - 105, - 171, - 180, - 181, - 160, - 222, - 75, - 198, - 42, - 42, - 32, - 31, - 141, - 37, - 186, - 233 -]); -async function create2(options) { - const { createFn = (opts) => window.navigator.credentials.create(opts), ...rest } = options; - const creationOptions = "publicKey" in rest ? rest : getOptions(rest); - try { - const credential = await createFn(creationOptions); - if (!credential) - throw new CreateFailedError; - const response = credential.response; - const attestationObject = response.attestationObject; - const clientDataJSON = response.clientDataJSON; - const id = credential.id; - const publicKey = await parseCredentialPublicKey(response, attestationObject); - return { - attestationObject, - clientDataJSON, - id, - publicKey, - raw: credential - }; - } catch (error) { - throw new CreateFailedError({ - cause: error - }); - } -} -function getOptions(options) { - const { attestation = "none", authenticatorSelection = { - residentKey: "preferred", - requireResidentKey: false, - userVerification: "required" - }, challenge: challenge2 = createChallenge, excludeCredentialIds, extensions, name: name_, rp = { - id: window.location.hostname, - name: window.document.title - }, user } = options; - const name = user?.name ?? name_; - return { - publicKey: { - attestation, - authenticatorSelection, - challenge: typeof challenge2 === "string" ? fromHex(challenge2) : challenge2, - ...excludeCredentialIds ? { - excludeCredentials: excludeCredentialIds?.map((id) => ({ - id: toBytes6(id), - type: "public-key" - })) - } : {}, - pubKeyCredParams: [ - { - type: "public-key", - alg: -7 - } - ], - rp, - user: { - id: user?.id ?? keccak2563(fromString(name), { as: "Bytes" }), - name, - displayName: user?.displayName ?? name - }, - ...extensions && { extensions } - } - }; -} -class CreateFailedError extends BaseError3 { - constructor({ cause } = {}) { - super("Failed to create credential.", { - cause - }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "Registration.CreateFailedError" - }); - } -} - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/core/internal/webauthn.js -function parseAsn1Signature(bytes) { - const sig = p2562.Signature.fromDER(bytes).normalizeS(); - return { r: sig.r, s: sig.s }; -} -async function parseCredentialPublicKey(response, attestationObject) { - try { - const publicKeyBuffer = response.getPublicKey(); - if (!publicKeyBuffer) - throw new CreateFailedError; - const publicKeyBytes = new Uint8Array(publicKeyBuffer); - const cryptoKey = await crypto.subtle.importKey("spki", new Uint8Array(publicKeyBytes), { - name: "ECDSA", - namedCurve: "P-256", - hash: "SHA-256" - }, true, ["verify"]); - const publicKey = new Uint8Array(await crypto.subtle.exportKey("raw", cryptoKey)); - return from4(publicKey); - } catch (error) { - if (error.message !== "Permission denied to access object") - throw error; - const data = new Uint8Array(attestationObject ?? response.attestationObject); - const coordinateLength = 32; - const cborPrefix = 88; - const findStart = (key) => { - const coordinate = new Uint8Array([key, cborPrefix, coordinateLength]); - for (let i = 0;i < data.length - coordinate.length; i++) - if (coordinate.every((byte, j) => data[i + j] === byte)) - return i + coordinate.length; - throw new CreateFailedError; - }; - const xStart = findStart(33); - const yStart = findStart(34); - return from4(new Uint8Array([ - 4, - ...data.slice(xStart, xStart + coordinateLength), - ...data.slice(yStart, yStart + coordinateLength) - ])); - } -} - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/webauthn/Authentication.js -function getOptions2(options) { - const { credentialId, challenge: challenge2, extensions, rpId = window.location.hostname, userVerification = "required" } = options; - return { - publicKey: { - ...credentialId ? { - allowCredentials: Array.isArray(credentialId) ? credentialId.map((id) => ({ - id: toBytes6(id), - type: "public-key" - })) : [ - { - id: toBytes6(credentialId), - type: "public-key" - } - ] - } : {}, - challenge: fromHex(challenge2), - ...extensions && { extensions }, - rpId, - userVerification - } - }; -} -async function sign4(options) { - const { getFn = (opts) => window.navigator.credentials.get(opts), ...rest } = options; - const requestOptions = "publicKey" in rest ? rest : getOptions2(rest); - try { - const credential = await getFn(requestOptions); - if (!credential) - throw new SignFailedError; - const response = credential.response; - const clientDataJSONBytes = new Uint8Array(response.clientDataJSON); - const authenticatorDataBytes = new Uint8Array(response.authenticatorData); - const signatureBytes = new Uint8Array(response.signature); - const id = credential.id; - const clientDataJSON = String.fromCharCode(...clientDataJSONBytes); - const challengeIndex = clientDataJSON.indexOf('"challenge"'); - const typeIndex = clientDataJSON.indexOf('"type"'); - const signature = parseAsn1Signature(signatureBytes); - return { - id, - metadata: { - authenticatorData: fromBytes(authenticatorDataBytes), - clientDataJSON, - challengeIndex, - typeIndex, - userVerificationRequired: requestOptions.publicKey.userVerification === "required" - }, - signature, - raw: credential - }; - } catch (error) { - throw new SignFailedError({ - cause: error - }); - } -} - -class SignFailedError extends BaseError3 { - constructor({ cause } = {}) { - super("Failed to request credential.", { - cause - }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "Authentication.SignFailedError" - }); - } -} - -// ../viem/node_modules/.pnpm/ox@0.14.34_typescript@5.9.3_zod@4.4.3/node_modules/ox/_esm/core/WebAuthnP256.js -async function createCredential(options) { - return create2(options); -} -async function sign5(options) { - return sign4(options); -} - -// ../viem/src/_esm/account-abstraction/accounts/createWebAuthnCredential.js -async function createWebAuthnCredential(parameters) { - const credential = await createCredential(parameters); - return { - id: credential.id, - publicKey: toHex2(credential.publicKey, { includePrefix: false }), - raw: credential.raw - }; -} -// ../viem/src/_esm/account-abstraction/accounts/toWebAuthnAccount.js -function toWebAuthnAccount(parameters) { - const { getFn, rpId } = parameters; - const { id, publicKey } = parameters.credential; - return { - id, - publicKey, - async sign({ hash: hash3 }) { - const { metadata, raw, signature } = await sign5({ - credentialId: id, - getFn, - challenge: hash3, - rpId - }); - return { - signature: toHex3(signature), - raw, - webauthn: metadata - }; - }, - async signMessage({ message }) { - return this.sign({ hash: hashMessage2(message) }); - }, - async signTypedData(parameters2) { - return this.sign({ hash: hashTypedData2(parameters2) }); - }, - type: "webAuthn" - }; -} -// ../viem/src/_esm/account-abstraction/actions/bundler/estimateUserOperationGas.js -init_stateOverride2(); - -// ../viem/src/_esm/account-abstraction/utils/errors/getUserOperationError.js -init_base(); -init_contract(); -init_decodeErrorResult(); - -// ../viem/src/_esm/account-abstraction/errors/bundler.js -init_base(); - -class AccountNotDeployedError extends BaseError2 { - constructor({ cause }) { - super("Smart Account is not deployed.", { - cause, - metaMessages: [ - "This could arise when:", - "- No `factory`/`factoryData` or `initCode` properties are provided for Smart Account deployment.", - "- An incorrect `sender` address is provided." - ], - name: "AccountNotDeployedError" - }); - } -} -Object.defineProperty(AccountNotDeployedError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa20/ -}); - -class ExecutionRevertedError3 extends BaseError2 { - constructor({ cause, data, message } = {}) { - const reason = message?.replace("execution reverted: ", "")?.replace("execution reverted", ""); - super(`Execution reverted ${reason ? `with reason: ${reason}` : "for an unknown reason"}.`, { - cause, - name: "ExecutionRevertedError" - }); - Object.defineProperty(this, "data", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - this.data = data; - } -} -Object.defineProperty(ExecutionRevertedError3, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32521 -}); -Object.defineProperty(ExecutionRevertedError3, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /execution reverted/ -}); - -class FailedToSendToBeneficiaryError extends BaseError2 { - constructor({ cause }) { - super("Failed to send funds to beneficiary.", { - cause, - name: "FailedToSendToBeneficiaryError" - }); - } -} -Object.defineProperty(FailedToSendToBeneficiaryError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa91/ -}); - -class GasValuesOverflowError extends BaseError2 { - constructor({ cause }) { - super("Gas value overflowed.", { - cause, - metaMessages: [ - "This could arise when:", - "- one of the gas values exceeded 2**120 (uint120)" - ].filter(Boolean), - name: "GasValuesOverflowError" - }); - } -} -Object.defineProperty(GasValuesOverflowError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa94/ -}); - -class HandleOpsOutOfGasError extends BaseError2 { - constructor({ cause }) { - super("The `handleOps` function was called by the Bundler with a gas limit too low.", { - cause, - name: "HandleOpsOutOfGasError" - }); - } -} -Object.defineProperty(HandleOpsOutOfGasError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa95/ -}); - -class InitCodeFailedError extends BaseError2 { - constructor({ cause, factory, factoryData, initCode }) { - super("Failed to simulate deployment for Smart Account.", { - cause, - metaMessages: [ - "This could arise when:", - "- Invalid `factory`/`factoryData` or `initCode` properties are present", - "- Smart Account deployment execution ran out of gas (low `verificationGasLimit` value)", - `- Smart Account deployment execution reverted with an error -`, - factory && `factory: ${factory}`, - factoryData && `factoryData: ${factoryData}`, - initCode && `initCode: ${initCode}` - ].filter(Boolean), - name: "InitCodeFailedError" - }); - } -} -Object.defineProperty(InitCodeFailedError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa13/ -}); - -class InitCodeMustCreateSenderError extends BaseError2 { - constructor({ cause, factory, factoryData, initCode }) { - super("Smart Account initialization implementation did not create an account.", { - cause, - metaMessages: [ - "This could arise when:", - "- `factory`/`factoryData` or `initCode` properties are invalid", - `- Smart Account initialization implementation is incorrect -`, - factory && `factory: ${factory}`, - factoryData && `factoryData: ${factoryData}`, - initCode && `initCode: ${initCode}` - ].filter(Boolean), - name: "InitCodeMustCreateSenderError" - }); - } -} -Object.defineProperty(InitCodeMustCreateSenderError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa15/ -}); - -class InitCodeMustReturnSenderError extends BaseError2 { - constructor({ cause, factory, factoryData, initCode, sender }) { - super("Smart Account initialization implementation does not return the expected sender.", { - cause, - metaMessages: [ - "This could arise when:", - `Smart Account initialization implementation does not return a sender address -`, - factory && `factory: ${factory}`, - factoryData && `factoryData: ${factoryData}`, - initCode && `initCode: ${initCode}`, - sender && `sender: ${sender}` - ].filter(Boolean), - name: "InitCodeMustReturnSenderError" - }); - } -} -Object.defineProperty(InitCodeMustReturnSenderError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa14/ -}); - -class InsufficientPrefundError extends BaseError2 { - constructor({ cause }) { - super("Smart Account does not have sufficient funds to execute the User Operation.", { - cause, - metaMessages: [ - "This could arise when:", - "- the Smart Account does not have sufficient funds to cover the required prefund, or", - "- a Paymaster was not provided" - ].filter(Boolean), - name: "InsufficientPrefundError" - }); - } -} -Object.defineProperty(InsufficientPrefundError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa21/ -}); - -class InternalCallOnlyError extends BaseError2 { - constructor({ cause }) { - super("Bundler attempted to call an invalid function on the EntryPoint.", { - cause, - name: "InternalCallOnlyError" - }); - } -} -Object.defineProperty(InternalCallOnlyError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa92/ -}); - -class InvalidAggregatorError extends BaseError2 { - constructor({ cause }) { - super("Bundler used an invalid aggregator for handling aggregated User Operations.", { - cause, - name: "InvalidAggregatorError" - }); - } -} -Object.defineProperty(InvalidAggregatorError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa96/ -}); - -class InvalidAccountNonceError extends BaseError2 { - constructor({ cause, nonce }) { - super("Invalid Smart Account nonce used for User Operation.", { - cause, - metaMessages: [nonce && `nonce: ${nonce}`].filter(Boolean), - name: "InvalidAccountNonceError" - }); - } -} -Object.defineProperty(InvalidAccountNonceError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa25/ -}); - -class InvalidBeneficiaryError extends BaseError2 { - constructor({ cause }) { - super("Bundler has not set a beneficiary address.", { - cause, - name: "InvalidBeneficiaryError" - }); - } -} -Object.defineProperty(InvalidBeneficiaryError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa90/ -}); - -class InvalidFieldsError extends BaseError2 { - constructor({ cause }) { - super("Invalid fields set on User Operation.", { - cause, - name: "InvalidFieldsError" - }); - } -} -Object.defineProperty(InvalidFieldsError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32602 -}); - -class InvalidPaymasterAndDataError extends BaseError2 { - constructor({ cause, paymasterAndData }) { - super("Paymaster properties provided are invalid.", { - cause, - metaMessages: [ - "This could arise when:", - "- the `paymasterAndData` property is of an incorrect length\n", - paymasterAndData && `paymasterAndData: ${paymasterAndData}` - ].filter(Boolean), - name: "InvalidPaymasterAndDataError" - }); - } -} -Object.defineProperty(InvalidPaymasterAndDataError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa93/ -}); - -class PaymasterDepositTooLowError extends BaseError2 { - constructor({ cause }) { - super("Paymaster deposit for the User Operation is too low.", { - cause, - metaMessages: [ - "This could arise when:", - "- the Paymaster has deposited less than the expected amount via the `deposit` function" - ].filter(Boolean), - name: "PaymasterDepositTooLowError" - }); - } -} -Object.defineProperty(PaymasterDepositTooLowError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32508 -}); -Object.defineProperty(PaymasterDepositTooLowError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa31/ -}); - -class PaymasterFunctionRevertedError extends BaseError2 { - constructor({ cause }) { - super("The `validatePaymasterUserOp` function on the Paymaster reverted.", { - cause, - name: "PaymasterFunctionRevertedError" - }); - } -} -Object.defineProperty(PaymasterFunctionRevertedError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa33/ -}); - -class PaymasterNotDeployedError extends BaseError2 { - constructor({ cause }) { - super("The Paymaster contract has not been deployed.", { - cause, - name: "PaymasterNotDeployedError" - }); - } -} -Object.defineProperty(PaymasterNotDeployedError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa30/ -}); - -class PaymasterRateLimitError extends BaseError2 { - constructor({ cause }) { - super("UserOperation rejected because paymaster (or signature aggregator) is throttled/banned.", { - cause, - name: "PaymasterRateLimitError" - }); - } -} -Object.defineProperty(PaymasterRateLimitError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32504 -}); - -class PaymasterStakeTooLowError extends BaseError2 { - constructor({ cause }) { - super("UserOperation rejected because paymaster (or signature aggregator) stake or unstake-delay is too low.", { - cause, - name: "PaymasterStakeTooLowError" - }); - } -} -Object.defineProperty(PaymasterStakeTooLowError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32505 -}); - -class PaymasterPostOpFunctionRevertedError extends BaseError2 { - constructor({ cause }) { - super("Paymaster `postOp` function reverted.", { - cause, - name: "PaymasterPostOpFunctionRevertedError" - }); - } -} -Object.defineProperty(PaymasterPostOpFunctionRevertedError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa50/ -}); - -class SenderAlreadyConstructedError extends BaseError2 { - constructor({ cause, factory, factoryData, initCode }) { - super("Smart Account has already been deployed.", { - cause, - metaMessages: [ - "Remove the following properties and try again:", - factory && "`factory`", - factoryData && "`factoryData`", - initCode && "`initCode`" - ].filter(Boolean), - name: "SenderAlreadyConstructedError" - }); - } -} -Object.defineProperty(SenderAlreadyConstructedError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa10/ -}); - -class SignatureCheckFailedError extends BaseError2 { - constructor({ cause }) { - super("UserOperation rejected because account signature check failed (or paymaster signature, if the paymaster uses its data as signature).", { - cause, - name: "SignatureCheckFailedError" - }); - } -} -Object.defineProperty(SignatureCheckFailedError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32507 -}); - -class SmartAccountFunctionRevertedError extends BaseError2 { - constructor({ cause }) { - super("The `validateUserOp` function on the Smart Account reverted.", { - cause, - name: "SmartAccountFunctionRevertedError" - }); - } -} -Object.defineProperty(SmartAccountFunctionRevertedError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa23/ -}); - -class UnsupportedSignatureAggregatorError extends BaseError2 { - constructor({ cause }) { - super("UserOperation rejected because account specified unsupported signature aggregator.", { - cause, - name: "UnsupportedSignatureAggregatorError" - }); - } -} -Object.defineProperty(UnsupportedSignatureAggregatorError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32506 -}); - -class UserOperationExpiredError extends BaseError2 { - constructor({ cause }) { - super("User Operation expired.", { - cause, - metaMessages: [ - "This could arise when:", - "- the `validAfter` or `validUntil` values returned from `validateUserOp` on the Smart Account are not satisfied" - ].filter(Boolean), - name: "UserOperationExpiredError" - }); - } -} -Object.defineProperty(UserOperationExpiredError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa22/ -}); - -class UserOperationPaymasterExpiredError extends BaseError2 { - constructor({ cause }) { - super("Paymaster for User Operation expired.", { - cause, - metaMessages: [ - "This could arise when:", - "- the `validAfter` or `validUntil` values returned from `validatePaymasterUserOp` on the Paymaster are not satisfied" - ].filter(Boolean), - name: "UserOperationPaymasterExpiredError" - }); - } -} -Object.defineProperty(UserOperationPaymasterExpiredError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa32/ -}); - -class UserOperationSignatureError extends BaseError2 { - constructor({ cause }) { - super("Signature provided for the User Operation is invalid.", { - cause, - metaMessages: [ - "This could arise when:", - "- the `signature` for the User Operation is incorrectly computed, and unable to be verified by the Smart Account" - ].filter(Boolean), - name: "UserOperationSignatureError" - }); - } -} -Object.defineProperty(UserOperationSignatureError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa24/ -}); - -class UserOperationPaymasterSignatureError extends BaseError2 { - constructor({ cause }) { - super("Signature provided for the User Operation is invalid.", { - cause, - metaMessages: [ - "This could arise when:", - "- the `signature` for the User Operation is incorrectly computed, and unable to be verified by the Paymaster" - ].filter(Boolean), - name: "UserOperationPaymasterSignatureError" - }); - } -} -Object.defineProperty(UserOperationPaymasterSignatureError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa34/ -}); - -class UserOperationRejectedByEntryPointError extends BaseError2 { - constructor({ cause }) { - super("User Operation rejected by EntryPoint's `simulateValidation` during account creation or validation.", { - cause, - name: "UserOperationRejectedByEntryPointError" - }); - } -} -Object.defineProperty(UserOperationRejectedByEntryPointError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32500 -}); - -class UserOperationRejectedByPaymasterError extends BaseError2 { - constructor({ cause }) { - super("User Operation rejected by Paymaster's `validatePaymasterUserOp`.", { - cause, - name: "UserOperationRejectedByPaymasterError" - }); - } -} -Object.defineProperty(UserOperationRejectedByPaymasterError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32501 -}); - -class UserOperationRejectedByOpCodeError extends BaseError2 { - constructor({ cause }) { - super("User Operation rejected with op code validation error.", { - cause, - name: "UserOperationRejectedByOpCodeError" - }); - } -} -Object.defineProperty(UserOperationRejectedByOpCodeError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32502 -}); - -class UserOperationOutOfTimeRangeError extends BaseError2 { - constructor({ cause }) { - super("UserOperation out of time-range: either wallet or paymaster returned a time-range, and it is already expired (or will expire soon).", { - cause, - name: "UserOperationOutOfTimeRangeError" - }); - } -} -Object.defineProperty(UserOperationOutOfTimeRangeError, "code", { - enumerable: true, - configurable: true, - writable: true, - value: -32503 -}); - -class UnknownBundlerError extends BaseError2 { - constructor({ cause }) { - super(`An error occurred while executing user operation: ${cause?.shortMessage}`, { - cause, - name: "UnknownBundlerError" - }); - } -} - -class VerificationGasLimitExceededError extends BaseError2 { - constructor({ cause }) { - super("User Operation verification gas limit exceeded.", { - cause, - metaMessages: [ - "This could arise when:", - "- the gas used for verification exceeded the `verificationGasLimit`" - ].filter(Boolean), - name: "VerificationGasLimitExceededError" - }); - } -} -Object.defineProperty(VerificationGasLimitExceededError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa40/ -}); - -class VerificationGasLimitTooLowError extends BaseError2 { - constructor({ cause }) { - super("User Operation verification gas limit is too low.", { - cause, - metaMessages: [ - "This could arise when:", - "- the `verificationGasLimit` is too low to verify the User Operation" - ].filter(Boolean), - name: "VerificationGasLimitTooLowError" - }); - } -} -Object.defineProperty(VerificationGasLimitTooLowError, "message", { - enumerable: true, - configurable: true, - writable: true, - value: /aa41/ -}); - -// ../viem/src/_esm/account-abstraction/errors/userOperation.js -init_base(); -init_transaction(); -class UserOperationExecutionError extends BaseError2 { - constructor(cause, { callData, callGasLimit, docsPath: docsPath8, factory, factoryData, initCode, maxFeePerGas, maxPriorityFeePerGas, nonce, paymaster, paymasterAndData, paymasterData, paymasterPostOpGasLimit, paymasterVerificationGasLimit, preVerificationGas, sender, signature, verificationGasLimit }) { - const prettyArgs = prettyPrint({ - callData, - callGasLimit, - factory, - factoryData, - initCode, - maxFeePerGas: typeof maxFeePerGas !== "undefined" && `${formatGwei2(maxFeePerGas)} gwei`, - maxPriorityFeePerGas: typeof maxPriorityFeePerGas !== "undefined" && `${formatGwei2(maxPriorityFeePerGas)} gwei`, - nonce, - paymaster, - paymasterAndData, - paymasterData, - paymasterPostOpGasLimit, - paymasterVerificationGasLimit, - preVerificationGas, - sender, - signature, - verificationGasLimit - }); - super(cause.shortMessage, { - cause, - docsPath: docsPath8, - metaMessages: [ - ...cause.metaMessages ? [...cause.metaMessages, " "] : [], - "Request Arguments:", - prettyArgs - ].filter(Boolean), - name: "UserOperationExecutionError" - }); - Object.defineProperty(this, "cause", { - enumerable: true, - configurable: true, - writable: true, - value: undefined - }); - this.cause = cause; - } -} - -class UserOperationReceiptNotFoundError extends BaseError2 { - constructor({ hash: hash3 }) { - super(`User Operation receipt with hash "${hash3}" could not be found. The User Operation may not have been processed yet.`, { name: "UserOperationReceiptNotFoundError" }); - } -} - -class UserOperationNotFoundError extends BaseError2 { - constructor({ hash: hash3 }) { - super(`User Operation with hash "${hash3}" could not be found.`, { - name: "UserOperationNotFoundError" - }); - } -} - -class WaitForUserOperationReceiptTimeoutError extends BaseError2 { - constructor({ hash: hash3 }) { - super(`Timed out while waiting for User Operation with hash "${hash3}" to be confirmed.`, { name: "WaitForUserOperationReceiptTimeoutError" }); - } -} - -// ../viem/src/_esm/account-abstraction/utils/errors/getBundlerError.js -var bundlerErrors = [ - ExecutionRevertedError3, - InvalidFieldsError, - PaymasterDepositTooLowError, - PaymasterRateLimitError, - PaymasterStakeTooLowError, - SignatureCheckFailedError, - UnsupportedSignatureAggregatorError, - UserOperationOutOfTimeRangeError, - UserOperationRejectedByEntryPointError, - UserOperationRejectedByPaymasterError, - UserOperationRejectedByOpCodeError -]; -function getBundlerError(err, args) { - const message = (err.details || "").toLowerCase(); - if (AccountNotDeployedError.message.test(message)) - return new AccountNotDeployedError({ - cause: err - }); - if (FailedToSendToBeneficiaryError.message.test(message)) - return new FailedToSendToBeneficiaryError({ - cause: err - }); - if (GasValuesOverflowError.message.test(message)) - return new GasValuesOverflowError({ - cause: err - }); - if (HandleOpsOutOfGasError.message.test(message)) - return new HandleOpsOutOfGasError({ - cause: err - }); - if (InitCodeFailedError.message.test(message)) - return new InitCodeFailedError({ - cause: err, - factory: args.factory, - factoryData: args.factoryData, - initCode: args.initCode - }); - if (InitCodeMustCreateSenderError.message.test(message)) - return new InitCodeMustCreateSenderError({ - cause: err, - factory: args.factory, - factoryData: args.factoryData, - initCode: args.initCode - }); - if (InitCodeMustReturnSenderError.message.test(message)) - return new InitCodeMustReturnSenderError({ - cause: err, - factory: args.factory, - factoryData: args.factoryData, - initCode: args.initCode, - sender: args.sender - }); - if (InsufficientPrefundError.message.test(message)) - return new InsufficientPrefundError({ - cause: err - }); - if (InternalCallOnlyError.message.test(message)) - return new InternalCallOnlyError({ - cause: err - }); - if (InvalidAccountNonceError.message.test(message)) - return new InvalidAccountNonceError({ - cause: err, - nonce: args.nonce - }); - if (InvalidAggregatorError.message.test(message)) - return new InvalidAggregatorError({ - cause: err - }); - if (InvalidBeneficiaryError.message.test(message)) - return new InvalidBeneficiaryError({ - cause: err - }); - if (InvalidPaymasterAndDataError.message.test(message)) - return new InvalidPaymasterAndDataError({ - cause: err - }); - if (PaymasterDepositTooLowError.message.test(message)) - return new PaymasterDepositTooLowError({ - cause: err - }); - if (PaymasterFunctionRevertedError.message.test(message)) - return new PaymasterFunctionRevertedError({ - cause: err - }); - if (PaymasterNotDeployedError.message.test(message)) - return new PaymasterNotDeployedError({ - cause: err - }); - if (PaymasterPostOpFunctionRevertedError.message.test(message)) - return new PaymasterPostOpFunctionRevertedError({ - cause: err - }); - if (SmartAccountFunctionRevertedError.message.test(message)) - return new SmartAccountFunctionRevertedError({ - cause: err - }); - if (SenderAlreadyConstructedError.message.test(message)) - return new SenderAlreadyConstructedError({ - cause: err, - factory: args.factory, - factoryData: args.factoryData, - initCode: args.initCode - }); - if (UserOperationExpiredError.message.test(message)) - return new UserOperationExpiredError({ - cause: err - }); - if (UserOperationPaymasterExpiredError.message.test(message)) - return new UserOperationPaymasterExpiredError({ - cause: err - }); - if (UserOperationPaymasterSignatureError.message.test(message)) - return new UserOperationPaymasterSignatureError({ - cause: err - }); - if (UserOperationSignatureError.message.test(message)) - return new UserOperationSignatureError({ - cause: err - }); - if (VerificationGasLimitExceededError.message.test(message)) - return new VerificationGasLimitExceededError({ - cause: err - }); - if (VerificationGasLimitTooLowError.message.test(message)) - return new VerificationGasLimitTooLowError({ - cause: err - }); - const error = err.walk((e) => bundlerErrors.some((error2) => error2.code === e.code)); - if (error) { - if (error.code === ExecutionRevertedError3.code) - return new ExecutionRevertedError3({ - cause: err, - data: error.data, - message: error.details - }); - if (error.code === InvalidFieldsError.code) - return new InvalidFieldsError({ - cause: err - }); - if (error.code === PaymasterDepositTooLowError.code) - return new PaymasterDepositTooLowError({ - cause: err - }); - if (error.code === PaymasterRateLimitError.code) - return new PaymasterRateLimitError({ - cause: err - }); - if (error.code === PaymasterStakeTooLowError.code) - return new PaymasterStakeTooLowError({ - cause: err - }); - if (error.code === SignatureCheckFailedError.code) - return new SignatureCheckFailedError({ - cause: err - }); - if (error.code === UnsupportedSignatureAggregatorError.code) - return new UnsupportedSignatureAggregatorError({ - cause: err - }); - if (error.code === UserOperationOutOfTimeRangeError.code) - return new UserOperationOutOfTimeRangeError({ - cause: err - }); - if (error.code === UserOperationRejectedByEntryPointError.code) - return new UserOperationRejectedByEntryPointError({ - cause: err - }); - if (error.code === UserOperationRejectedByPaymasterError.code) - return new UserOperationRejectedByPaymasterError({ - cause: err - }); - if (error.code === UserOperationRejectedByOpCodeError.code) - return new UserOperationRejectedByOpCodeError({ - cause: err - }); - } - return new UnknownBundlerError({ - cause: err - }); -} - -// ../viem/src/_esm/account-abstraction/utils/errors/getUserOperationError.js -function getUserOperationError(err, { calls, docsPath: docsPath8, ...args }) { - const cause = (() => { - const cause2 = getBundlerError(err, args); - if (calls && cause2 instanceof ExecutionRevertedError3) { - const revertData = getRevertData(cause2); - const contractCalls = calls?.filter((call2) => call2.abi); - if (revertData && contractCalls.length > 0) - return getContractError4({ calls: contractCalls, revertData }); - } - return cause2; - })(); - return new UserOperationExecutionError(cause, { - docsPath: docsPath8, - ...args - }); -} -function getRevertData(error) { - let revertData; - error.walk((e) => { - const error2 = e; - if (typeof error2.data === "string" || typeof error2.data?.revertData === "string" || !(error2 instanceof BaseError2) && typeof error2.message === "string") { - const match = (error2.data?.revertData || error2.data || error2.message).match?.(/(0x[A-Za-z0-9]*)/); - if (match) { - revertData = match[1]; - return true; - } - } - return false; - }); - return revertData; -} -function getContractError4(parameters) { - const { calls, revertData } = parameters; - const { abi: abi2, functionName, args, to } = (() => { - const contractCalls = calls?.filter((call2) => Boolean(call2.abi)); - if (contractCalls.length === 1) - return contractCalls[0]; - const compatContractCalls = contractCalls.filter((call2) => { - try { - return Boolean(decodeErrorResult({ - abi: call2.abi, - data: revertData - })); - } catch { - return false; - } - }); - if (compatContractCalls.length === 1) - return compatContractCalls[0]; - return { - abi: [], - functionName: contractCalls.reduce((acc, call2) => `${acc ? `${acc} | ` : ""}${call2.functionName}`, ""), - args: undefined, - to: undefined - }; - })(); - const cause = (() => { - if (revertData === "0x") - return new ContractFunctionZeroDataError({ functionName }); - return new ContractFunctionRevertedError({ - abi: abi2, - data: revertData, - functionName - }); - })(); - return new ContractFunctionExecutionError(cause, { - abi: abi2, - args, - contractAddress: to, - functionName - }); -} - -// ../viem/src/_esm/account-abstraction/utils/formatters/userOperationGas.js -function formatUserOperationGas(parameters) { - const gas = {}; - if (parameters.callGasLimit) - gas.callGasLimit = BigInt(parameters.callGasLimit); - if (parameters.preVerificationGas) - gas.preVerificationGas = BigInt(parameters.preVerificationGas); - if (parameters.verificationGasLimit) - gas.verificationGasLimit = BigInt(parameters.verificationGasLimit); - if (parameters.paymasterPostOpGasLimit) - gas.paymasterPostOpGasLimit = BigInt(parameters.paymasterPostOpGasLimit); - if (parameters.paymasterVerificationGasLimit) - gas.paymasterVerificationGasLimit = BigInt(parameters.paymasterVerificationGasLimit); - return gas; -} - -// ../viem/src/_esm/account-abstraction/utils/formatters/userOperationRequest.js -init_toHex(); -function formatUserOperationRequest(request) { - const rpcRequest = {}; - if (typeof request.callData !== "undefined") - rpcRequest.callData = request.callData; - if (typeof request.callGasLimit !== "undefined") - rpcRequest.callGasLimit = numberToHex(request.callGasLimit); - if (typeof request.factory !== "undefined") - rpcRequest.factory = request.factory; - if (typeof request.factoryData !== "undefined") - rpcRequest.factoryData = request.factoryData; - if (typeof request.initCode !== "undefined") - rpcRequest.initCode = request.initCode; - if (typeof request.maxFeePerGas !== "undefined") - rpcRequest.maxFeePerGas = numberToHex(request.maxFeePerGas); - if (typeof request.maxPriorityFeePerGas !== "undefined") - rpcRequest.maxPriorityFeePerGas = numberToHex(request.maxPriorityFeePerGas); - if (typeof request.nonce !== "undefined") - rpcRequest.nonce = numberToHex(request.nonce); - if (typeof request.paymaster !== "undefined") - rpcRequest.paymaster = request.paymaster; - if (typeof request.paymasterAndData !== "undefined") - rpcRequest.paymasterAndData = request.paymasterAndData || "0x"; - if (typeof request.paymasterData !== "undefined") - rpcRequest.paymasterData = request.paymasterData; - if (typeof request.paymasterPostOpGasLimit !== "undefined") - rpcRequest.paymasterPostOpGasLimit = numberToHex(request.paymasterPostOpGasLimit); - if (typeof request.paymasterSignature !== "undefined") - rpcRequest.paymasterSignature = request.paymasterSignature; - if (typeof request.paymasterVerificationGasLimit !== "undefined") - rpcRequest.paymasterVerificationGasLimit = numberToHex(request.paymasterVerificationGasLimit); - if (typeof request.preVerificationGas !== "undefined") - rpcRequest.preVerificationGas = numberToHex(request.preVerificationGas); - if (typeof request.sender !== "undefined") - rpcRequest.sender = request.sender; - if (typeof request.signature !== "undefined") - rpcRequest.signature = request.signature; - if (typeof request.verificationGasLimit !== "undefined") - rpcRequest.verificationGasLimit = numberToHex(request.verificationGasLimit); - if (typeof request.authorization !== "undefined") - rpcRequest.eip7702Auth = formatAuthorization(request.authorization); - return rpcRequest; -} -function formatAuthorization(authorization) { - return { - address: authorization.address, - chainId: numberToHex(authorization.chainId), - nonce: numberToHex(authorization.nonce), - r: authorization.r ? numberToHex(BigInt(authorization.r), { size: 32 }) : pad("0x", { size: 32 }), - s: authorization.s ? numberToHex(BigInt(authorization.s), { size: 32 }) : pad("0x", { size: 32 }), - yParity: typeof authorization.yParity !== "undefined" ? numberToHex(authorization.yParity, { size: 1 }) : pad("0x", { size: 32 }) - }; -} -// ../viem/src/_esm/account-abstraction/actions/bundler/prepareUserOperation.js -init_encodeFunctionData(); - -// ../viem/src/_esm/account-abstraction/actions/paymaster/getPaymasterData.js -init_fromHex(); -init_toHex(); -async function getPaymasterData(client, parameters) { - const { chainId, entryPointAddress, context, ...userOperation } = parameters; - const request = formatUserOperationRequest(userOperation); - const { paymasterPostOpGasLimit, paymasterVerificationGasLimit, ...rest } = await client.request({ - method: "pm_getPaymasterData", - params: [ - { - ...request, - callGasLimit: request.callGasLimit ?? "0x0", - verificationGasLimit: request.verificationGasLimit ?? "0x0", - preVerificationGas: request.preVerificationGas ?? "0x0" - }, - entryPointAddress, - numberToHex(chainId), - context - ] - }); - return { - ...rest, - ...paymasterPostOpGasLimit && { - paymasterPostOpGasLimit: hexToBigInt(paymasterPostOpGasLimit) - }, - ...paymasterVerificationGasLimit && { - paymasterVerificationGasLimit: hexToBigInt(paymasterVerificationGasLimit) - } - }; -} - -// ../viem/src/_esm/account-abstraction/actions/paymaster/getPaymasterStubData.js -init_fromHex(); -init_toHex(); -async function getPaymasterStubData(client, parameters) { - const { chainId, entryPointAddress, context, ...userOperation } = parameters; - const request = formatUserOperationRequest(userOperation); - const { paymasterPostOpGasLimit, paymasterVerificationGasLimit, ...rest } = await client.request({ - method: "pm_getPaymasterStubData", - params: [ - { - ...request, - callGasLimit: request.callGasLimit ?? "0x0", - verificationGasLimit: request.verificationGasLimit ?? "0x0", - preVerificationGas: request.preVerificationGas ?? "0x0" - }, - entryPointAddress, - numberToHex(chainId), - context - ] - }); - return { - ...rest, - ...paymasterPostOpGasLimit && { - paymasterPostOpGasLimit: hexToBigInt(paymasterPostOpGasLimit) - }, - ...paymasterVerificationGasLimit && { - paymasterVerificationGasLimit: hexToBigInt(paymasterVerificationGasLimit) - } - }; -} - -// ../viem/src/_esm/account-abstraction/actions/bundler/prepareUserOperation.js -var defaultParameters3 = [ - "factory", - "fees", - "gas", - "paymaster", - "nonce", - "signature", - "authorization" -]; -async function prepareUserOperation(client, parameters_) { - const parameters = parameters_; - const { account: account_ = client.account, dataSuffix = typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value, parameters: properties = defaultParameters3, stateOverride } = parameters; - if (!account_) - throw new AccountNotFoundError; - const account = parseAccount(account_); - const bundlerClient = client; - const paymaster = parameters.paymaster ?? bundlerClient?.paymaster; - const paymasterAddress = typeof paymaster === "string" ? paymaster : undefined; - const { getPaymasterStubData: getPaymasterStubData2, getPaymasterData: getPaymasterData2 } = (() => { - if (paymaster === true) - return { - getPaymasterStubData: (parameters2) => getAction(bundlerClient, getPaymasterStubData, "getPaymasterStubData")(parameters2), - getPaymasterData: (parameters2) => getAction(bundlerClient, getPaymasterData, "getPaymasterData")(parameters2) - }; - if (typeof paymaster === "object") { - const { getPaymasterStubData: getPaymasterStubData3, getPaymasterData: getPaymasterData3 } = paymaster; - return { - getPaymasterStubData: getPaymasterData3 && getPaymasterStubData3 ? getPaymasterStubData3 : getPaymasterData3, - getPaymasterData: getPaymasterData3 && getPaymasterStubData3 ? getPaymasterData3 : undefined - }; - } - return { - getPaymasterStubData: undefined, - getPaymasterData: undefined - }; - })(); - const paymasterContext = parameters.paymasterContext ? parameters.paymasterContext : bundlerClient?.paymasterContext; - let request = { - ...parameters, - paymaster: paymasterAddress, - sender: account.address - }; - const [callData, factory, fees, nonce, authorization] = await Promise.all([ - (async () => { - if (parameters.calls) - return account.encodeCalls(parameters.calls.map((call_) => { - const call3 = call_; - if (call3.abi) - return { - data: encodeFunctionData(call3), - to: call3.to, - value: call3.value - }; - return call3; - })); - return parameters.callData; - })(), - (async () => { - if (!properties.includes("factory")) - return; - if (parameters.initCode) - return { initCode: parameters.initCode }; - if (parameters.factory && parameters.factoryData) { - return { - factory: parameters.factory, - factoryData: parameters.factoryData - }; - } - const { factory: factory2, factoryData } = await account.getFactoryArgs(); - if (account.entryPoint.version === "0.6") - return { - initCode: factory2 && factoryData ? concat([factory2, factoryData]) : undefined - }; - return { - factory: factory2, - factoryData - }; - })(), - (async () => { - if (!properties.includes("fees")) - return; - if (typeof parameters.maxFeePerGas === "bigint" && typeof parameters.maxPriorityFeePerGas === "bigint") - return request; - if (bundlerClient?.userOperation?.estimateFeesPerGas) { - const fees2 = await bundlerClient.userOperation.estimateFeesPerGas({ - account, - bundlerClient, - userOperation: request - }); - return { - ...request, - ...fees2 - }; - } - try { - const client_ = bundlerClient.client ?? client; - const fees2 = await getAction(client_, estimateFeesPerGas, "estimateFeesPerGas")({ - chain: client_.chain, - type: "eip1559" - }); - return { - maxFeePerGas: typeof parameters.maxFeePerGas === "bigint" ? parameters.maxFeePerGas : BigInt(2n * fees2.maxFeePerGas), - maxPriorityFeePerGas: typeof parameters.maxPriorityFeePerGas === "bigint" ? parameters.maxPriorityFeePerGas : BigInt(2n * fees2.maxPriorityFeePerGas) - }; - } catch { - return; - } - })(), - (async () => { - if (!properties.includes("nonce")) - return; - if (typeof parameters.nonce === "bigint") - return parameters.nonce; - return account.getNonce(); - })(), - (async () => { - if (!properties.includes("authorization")) - return; - if (typeof parameters.authorization === "object") - return parameters.authorization; - if (account.authorization && !await account.isDeployed()) { - const authorization2 = await prepareAuthorization(account.client, account.authorization); - return { - ...authorization2, - r: "0xfffffffffffffffffffffffffffffff000000000000000000000000000000000", - s: "0x7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - yParity: 1 - }; - } - return; - })() - ]); - if (typeof callData !== "undefined") - request.callData = dataSuffix ? concat([callData, dataSuffix]) : callData; - if (typeof factory !== "undefined") - request = { ...request, ...factory }; - if (typeof fees !== "undefined") - request = { ...request, ...fees }; - if (typeof nonce !== "undefined") - request.nonce = nonce; - if (typeof authorization !== "undefined") - request.authorization = authorization; - if (properties.includes("signature")) { - if (typeof parameters.signature !== "undefined") - request.signature = parameters.signature; - else - request.signature = await account.getStubSignature(request); - } - if (account.entryPoint.version === "0.6" && !request.initCode) - request.initCode = "0x"; - let chainId; - async function getChainId3() { - if (chainId) - return chainId; - if (client.chain) - return client.chain.id; - const chainId_ = await getAction(client, getChainId, "getChainId")({}); - chainId = chainId_; - return chainId; - } - let isPaymasterPopulated = false; - if (properties.includes("paymaster") && getPaymasterStubData2 && !paymasterAddress && !parameters.paymasterAndData) { - const { isFinal = false, sponsor: _, ...paymasterArgs } = await getPaymasterStubData2({ - chainId: await getChainId3(), - entryPointAddress: account.entryPoint.address, - context: paymasterContext, - ...request - }); - isPaymasterPopulated = isFinal; - request = { - ...request, - ...paymasterArgs - }; - } - if (account.entryPoint.version === "0.6" && !request.paymasterAndData) - request.paymasterAndData = "0x"; - if (properties.includes("gas")) { - if (account.userOperation?.estimateGas) { - const gas = await account.userOperation.estimateGas(request); - request = { - ...request, - ...gas - }; - } - if (typeof request.callGasLimit === "undefined" || typeof request.preVerificationGas === "undefined" || typeof request.verificationGasLimit === "undefined" || request.paymaster && typeof request.paymasterPostOpGasLimit === "undefined" || request.paymaster && typeof request.paymasterVerificationGasLimit === "undefined") { - const gas = await getAction(bundlerClient, estimateUserOperationGas, "estimateUserOperationGas")({ - account, - callGasLimit: 0n, - preVerificationGas: 0n, - verificationGasLimit: 0n, - stateOverride, - ...request.paymaster ? { - paymasterPostOpGasLimit: 0n, - paymasterVerificationGasLimit: 0n - } : {}, - ...request - }); - request = { - ...request, - callGasLimit: request.callGasLimit ?? gas.callGasLimit, - preVerificationGas: request.preVerificationGas ?? gas.preVerificationGas, - verificationGasLimit: request.verificationGasLimit ?? gas.verificationGasLimit, - paymasterPostOpGasLimit: request.paymasterPostOpGasLimit ?? gas.paymasterPostOpGasLimit, - paymasterVerificationGasLimit: request.paymasterVerificationGasLimit ?? gas.paymasterVerificationGasLimit - }; - } - } - if (properties.includes("paymaster") && getPaymasterData2 && !paymasterAddress && !parameters.paymasterAndData && !isPaymasterPopulated) { - const paymaster2 = await getPaymasterData2({ - chainId: await getChainId3(), - entryPointAddress: account.entryPoint.address, - context: paymasterContext, - ...request - }); - request = { - ...request, - ...paymaster2 - }; - } - delete request.calls; - delete request.parameters; - delete request.paymasterContext; - if (typeof request.paymaster !== "string") - delete request.paymaster; - return request; -} - -// ../viem/src/_esm/account-abstraction/actions/bundler/estimateUserOperationGas.js -async function estimateUserOperationGas(client, parameters) { - const { account: account_ = client.account, entryPointAddress, stateOverride } = parameters; - if (!account_ && !parameters.sender) - throw new AccountNotFoundError; - const account = account_ ? parseAccount(account_) : undefined; - const rpcStateOverride = serializeStateOverride(stateOverride); - const request = account ? await getAction(client, prepareUserOperation, "prepareUserOperation")({ - ...parameters, - parameters: [ - "authorization", - "factory", - "fees", - "nonce", - "paymaster", - "signature" - ] - }) : parameters; - try { - const params = [ - formatUserOperationRequest(request), - entryPointAddress ?? account?.entryPoint?.address - ]; - const result = await client.request({ - method: "eth_estimateUserOperationGas", - params: rpcStateOverride ? [...params, rpcStateOverride] : [...params] - }); - return formatUserOperationGas(result); - } catch (error) { - const calls = parameters.calls; - throw getUserOperationError(error, { - ...request, - ...calls ? { calls } : {} - }); - } -} - -// ../viem/src/_esm/account-abstraction/actions/bundler/getSupportedEntryPoints.js -function getSupportedEntryPoints(client) { - return client.request({ method: "eth_supportedEntryPoints" }); -} - -// ../viem/src/_esm/account-abstraction/utils/formatters/userOperation.js -function formatUserOperation(parameters) { - const userOperation = { ...parameters }; - if (parameters.callGasLimit) - userOperation.callGasLimit = BigInt(parameters.callGasLimit); - if (parameters.maxFeePerGas) - userOperation.maxFeePerGas = BigInt(parameters.maxFeePerGas); - if (parameters.maxPriorityFeePerGas) - userOperation.maxPriorityFeePerGas = BigInt(parameters.maxPriorityFeePerGas); - if (parameters.nonce) - userOperation.nonce = BigInt(parameters.nonce); - if (parameters.paymasterPostOpGasLimit) - userOperation.paymasterPostOpGasLimit = BigInt(parameters.paymasterPostOpGasLimit); - if (parameters.paymasterVerificationGasLimit) - userOperation.paymasterVerificationGasLimit = BigInt(parameters.paymasterVerificationGasLimit); - if (parameters.preVerificationGas) - userOperation.preVerificationGas = BigInt(parameters.preVerificationGas); - if (parameters.verificationGasLimit) - userOperation.verificationGasLimit = BigInt(parameters.verificationGasLimit); - return userOperation; -} - -// ../viem/src/_esm/account-abstraction/actions/bundler/getUserOperation.js -async function getUserOperation(client, { hash: hash3 }) { - const result = await client.request({ - method: "eth_getUserOperationByHash", - params: [hash3] - }, { dedupe: true }); - if (!result) - throw new UserOperationNotFoundError({ hash: hash3 }); - const { blockHash, blockNumber, entryPoint, transactionHash, userOperation } = result; - return { - blockHash, - blockNumber: BigInt(blockNumber), - entryPoint, - transactionHash, - userOperation: formatUserOperation(userOperation) - }; -} - -// ../viem/src/_esm/account-abstraction/utils/formatters/userOperationReceipt.js -function formatUserOperationReceipt(parameters) { - const receipt = { ...parameters }; - if (parameters.actualGasCost) - receipt.actualGasCost = BigInt(parameters.actualGasCost); - if (parameters.actualGasUsed) - receipt.actualGasUsed = BigInt(parameters.actualGasUsed); - if (parameters.logs) - receipt.logs = parameters.logs.map((log) => formatLog(log)); - if (parameters.receipt) - receipt.receipt = formatTransactionReceipt(receipt.receipt); - return receipt; -} - -// ../viem/src/_esm/account-abstraction/actions/bundler/getUserOperationReceipt.js -async function getUserOperationReceipt(client, { hash: hash3 }) { - const receipt = await client.request({ - method: "eth_getUserOperationReceipt", - params: [hash3] - }, { dedupe: true }); - if (!receipt) - throw new UserOperationReceiptNotFoundError({ hash: hash3 }); - return formatUserOperationReceipt(receipt); -} -// ../viem/src/_esm/account-abstraction/actions/bundler/sendUserOperation.js -async function sendUserOperation(client, parameters) { - const { account: account_ = client.account, entryPointAddress } = parameters; - if (!account_ && !parameters.sender) - throw new AccountNotFoundError; - const account = account_ ? parseAccount(account_) : undefined; - const request = account ? await getAction(client, prepareUserOperation, "prepareUserOperation")(parameters) : parameters; - const signature = parameters.signature || await account?.signUserOperation?.(request); - const rpcParameters = formatUserOperationRequest({ - ...request, - signature - }); - try { - return await client.request({ - method: "eth_sendUserOperation", - params: [ - rpcParameters, - entryPointAddress ?? account?.entryPoint?.address - ] - }, { retryCount: 0 }); - } catch (error) { - const calls = parameters.calls; - throw getUserOperationError(error, { - ...request, - ...calls ? { calls } : {}, - signature - }); - } -} -// ../viem/src/_esm/account-abstraction/actions/bundler/waitForUserOperationReceipt.js -function waitForUserOperationReceipt(client, parameters) { - const { hash: hash3, pollingInterval = client.pollingInterval, retryCount, timeout = 120000 } = parameters; - let count = 0; - const observerId = stringify([ - "waitForUserOperationReceipt", - client.uid, - hash3 - ]); - return new Promise((resolve, reject) => { - const unobserve = observe(observerId, { resolve, reject }, (emit) => { - const done = (fn) => { - unpoll(); - fn(); - unobserve(); - }; - const timeoutId = timeout ? setTimeout(() => done(() => emit.reject(new WaitForUserOperationReceiptTimeoutError({ hash: hash3 }))), timeout) : undefined; - const unpoll = poll(async () => { - if (retryCount && count >= retryCount) { - clearTimeout(timeoutId); - done(() => emit.reject(new WaitForUserOperationReceiptTimeoutError({ hash: hash3 }))); - } - try { - const receipt = await getAction(client, getUserOperationReceipt, "getUserOperationReceipt")({ hash: hash3 }); - clearTimeout(timeoutId); - done(() => emit.resolve(receipt)); - } catch (err) { - const error = err; - if (error.name !== "UserOperationReceiptNotFoundError") { - clearTimeout(timeoutId); - done(() => emit.reject(error)); - } - } - count++; - }, { - emitOnBegin: true, - interval: pollingInterval - }); - return unpoll; - }); - }); -} - -// ../viem/src/_esm/account-abstraction/clients/decorators/bundler.js -function bundlerActions(client) { - return { - estimateUserOperationGas: (parameters) => estimateUserOperationGas(client, parameters), - getChainId: () => getChainId(client), - getSupportedEntryPoints: () => getSupportedEntryPoints(client), - getUserOperation: (parameters) => getUserOperation(client, parameters), - getUserOperationReceipt: (parameters) => getUserOperationReceipt(client, parameters), - prepareUserOperation: (parameters) => prepareUserOperation(client, parameters), - sendUserOperation: (parameters) => sendUserOperation(client, parameters), - waitForUserOperationReceipt: (parameters) => waitForUserOperationReceipt(client, parameters) - }; -} - -// ../viem/src/_esm/account-abstraction/clients/createBundlerClient.js -function createBundlerClient(parameters) { - const { client: client_, dataSuffix, key = "bundler", name = "Bundler Client", paymaster, paymasterContext, transport, userOperation } = parameters; - const client = Object.assign(createClient({ - ...parameters, - chain: parameters.chain ?? client_?.chain, - key, - name, - transport, - type: "bundlerClient" - }), { - client: client_, - dataSuffix: dataSuffix ?? client_?.dataSuffix, - paymaster, - paymasterContext, - userOperation - }); - return client.extend(bundlerActions); -} -// ../viem/src/_esm/account-abstraction/constants/abis.js -var entryPoint07Abi = [ - { - inputs: [ - { name: "success", type: "bool" }, - { name: "ret", type: "bytes" } - ], - name: "DelegateAndRevert", - type: "error" - }, - { - inputs: [ - { name: "opIndex", type: "uint256" }, - { name: "reason", type: "string" } - ], - name: "FailedOp", - type: "error" - }, - { - inputs: [ - { name: "opIndex", type: "uint256" }, - { name: "reason", type: "string" }, - { name: "inner", type: "bytes" } - ], - name: "FailedOpWithRevert", - type: "error" - }, - { - inputs: [{ name: "returnData", type: "bytes" }], - name: "PostOpReverted", - type: "error" - }, - { inputs: [], name: "ReentrancyGuardReentrantCall", type: "error" }, - { - inputs: [{ name: "sender", type: "address" }], - name: "SenderAddressResult", - type: "error" - }, - { - inputs: [{ name: "aggregator", type: "address" }], - name: "SignatureValidationFailed", - type: "error" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "userOpHash", - type: "bytes32" - }, - { - indexed: true, - name: "sender", - type: "address" - }, - { - indexed: false, - name: "factory", - type: "address" - }, - { - indexed: false, - name: "paymaster", - type: "address" - } - ], - name: "AccountDeployed", - type: "event" - }, - { anonymous: false, inputs: [], name: "BeforeExecution", type: "event" }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "account", - type: "address" - }, - { - indexed: false, - name: "totalDeposit", - type: "uint256" - } - ], - name: "Deposited", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "userOpHash", - type: "bytes32" - }, - { - indexed: true, - name: "sender", - type: "address" - }, - { - indexed: false, - name: "nonce", - type: "uint256" - }, - { - indexed: false, - name: "revertReason", - type: "bytes" - } - ], - name: "PostOpRevertReason", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "aggregator", - type: "address" - } - ], - name: "SignatureAggregatorChanged", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "account", - type: "address" - }, - { - indexed: false, - name: "totalStaked", - type: "uint256" - }, - { - indexed: false, - name: "unstakeDelaySec", - type: "uint256" - } - ], - name: "StakeLocked", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "account", - type: "address" - }, - { - indexed: false, - name: "withdrawTime", - type: "uint256" - } - ], - name: "StakeUnlocked", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "account", - type: "address" - }, - { - indexed: false, - name: "withdrawAddress", - type: "address" - }, - { - indexed: false, - name: "amount", - type: "uint256" - } - ], - name: "StakeWithdrawn", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "userOpHash", - type: "bytes32" - }, - { - indexed: true, - name: "sender", - type: "address" - }, - { - indexed: true, - name: "paymaster", - type: "address" - }, - { - indexed: false, - name: "nonce", - type: "uint256" - }, - { indexed: false, name: "success", type: "bool" }, - { - indexed: false, - name: "actualGasCost", - type: "uint256" - }, - { - indexed: false, - name: "actualGasUsed", - type: "uint256" - } - ], - name: "UserOperationEvent", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "userOpHash", - type: "bytes32" - }, - { - indexed: true, - name: "sender", - type: "address" - }, - { - indexed: false, - name: "nonce", - type: "uint256" - } - ], - name: "UserOperationPrefundTooLow", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "userOpHash", - type: "bytes32" - }, - { - indexed: true, - name: "sender", - type: "address" - }, - { - indexed: false, - name: "nonce", - type: "uint256" - }, - { - indexed: false, - name: "revertReason", - type: "bytes" - } - ], - name: "UserOperationRevertReason", - type: "event" - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - name: "account", - type: "address" - }, - { - indexed: false, - name: "withdrawAddress", - type: "address" - }, - { - indexed: false, - name: "amount", - type: "uint256" - } - ], - name: "Withdrawn", - type: "event" - }, - { - inputs: [{ name: "unstakeDelaySec", type: "uint32" }], - name: "addStake", - outputs: [], - stateMutability: "payable", - type: "function" - }, - { - inputs: [{ name: "account", type: "address" }], - name: "balanceOf", - outputs: [{ name: "", type: "uint256" }], - stateMutability: "view", - type: "function" - }, - { - inputs: [ - { name: "target", type: "address" }, - { name: "data", type: "bytes" } - ], - name: "delegateAndRevert", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [{ name: "account", type: "address" }], - name: "depositTo", - outputs: [], - stateMutability: "payable", - type: "function" - }, - { - inputs: [{ name: "", type: "address" }], - name: "deposits", - outputs: [ - { name: "deposit", type: "uint256" }, - { name: "staked", type: "bool" }, - { name: "stake", type: "uint112" }, - { name: "unstakeDelaySec", type: "uint32" }, - { name: "withdrawTime", type: "uint48" } - ], - stateMutability: "view", - type: "function" - }, - { - inputs: [{ name: "account", type: "address" }], - name: "getDepositInfo", - outputs: [ - { - components: [ - { name: "deposit", type: "uint256" }, - { name: "staked", type: "bool" }, - { name: "stake", type: "uint112" }, - { name: "unstakeDelaySec", type: "uint32" }, - { name: "withdrawTime", type: "uint48" } - ], - name: "info", - type: "tuple" - } - ], - stateMutability: "view", - type: "function" - }, - { - inputs: [ - { name: "sender", type: "address" }, - { name: "key", type: "uint192" } - ], - name: "getNonce", - outputs: [{ name: "nonce", type: "uint256" }], - stateMutability: "view", - type: "function" - }, - { - inputs: [{ name: "initCode", type: "bytes" }], - name: "getSenderAddress", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { - components: [ - { name: "sender", type: "address" }, - { name: "nonce", type: "uint256" }, - { name: "initCode", type: "bytes" }, - { name: "callData", type: "bytes" }, - { - name: "accountGasLimits", - type: "bytes32" - }, - { - name: "preVerificationGas", - type: "uint256" - }, - { name: "gasFees", type: "bytes32" }, - { name: "paymasterAndData", type: "bytes" }, - { name: "signature", type: "bytes" } - ], - name: "userOp", - type: "tuple" - } - ], - name: "getUserOpHash", - outputs: [{ name: "", type: "bytes32" }], - stateMutability: "view", - type: "function" - }, - { - inputs: [ - { - components: [ - { - components: [ - { name: "sender", type: "address" }, - { name: "nonce", type: "uint256" }, - { name: "initCode", type: "bytes" }, - { name: "callData", type: "bytes" }, - { - name: "accountGasLimits", - type: "bytes32" - }, - { - name: "preVerificationGas", - type: "uint256" - }, - { name: "gasFees", type: "bytes32" }, - { - name: "paymasterAndData", - type: "bytes" - }, - { name: "signature", type: "bytes" } - ], - name: "userOps", - type: "tuple[]" - }, - { - name: "aggregator", - type: "address" - }, - { name: "signature", type: "bytes" } - ], - name: "opsPerAggregator", - type: "tuple[]" - }, - { name: "beneficiary", type: "address" } - ], - name: "handleAggregatedOps", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { - components: [ - { name: "sender", type: "address" }, - { name: "nonce", type: "uint256" }, - { name: "initCode", type: "bytes" }, - { name: "callData", type: "bytes" }, - { - name: "accountGasLimits", - type: "bytes32" - }, - { - name: "preVerificationGas", - type: "uint256" - }, - { name: "gasFees", type: "bytes32" }, - { name: "paymasterAndData", type: "bytes" }, - { name: "signature", type: "bytes" } - ], - name: "ops", - type: "tuple[]" - }, - { name: "beneficiary", type: "address" } - ], - name: "handleOps", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [{ name: "key", type: "uint192" }], - name: "incrementNonce", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { name: "callData", type: "bytes" }, - { - components: [ - { - components: [ - { name: "sender", type: "address" }, - { name: "nonce", type: "uint256" }, - { - name: "verificationGasLimit", - type: "uint256" - }, - { - name: "callGasLimit", - type: "uint256" - }, - { - name: "paymasterVerificationGasLimit", - type: "uint256" - }, - { - name: "paymasterPostOpGasLimit", - type: "uint256" - }, - { - name: "preVerificationGas", - type: "uint256" - }, - { name: "paymaster", type: "address" }, - { - name: "maxFeePerGas", - type: "uint256" - }, - { - name: "maxPriorityFeePerGas", - type: "uint256" - } - ], - name: "mUserOp", - type: "tuple" - }, - { name: "userOpHash", type: "bytes32" }, - { name: "prefund", type: "uint256" }, - { name: "contextOffset", type: "uint256" }, - { name: "preOpGas", type: "uint256" } - ], - name: "opInfo", - type: "tuple" - }, - { name: "context", type: "bytes" } - ], - name: "innerHandleOp", - outputs: [{ name: "actualGasCost", type: "uint256" }], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { name: "", type: "address" }, - { name: "", type: "uint192" } - ], - name: "nonceSequenceNumber", - outputs: [{ name: "", type: "uint256" }], - stateMutability: "view", - type: "function" - }, - { - inputs: [{ name: "interfaceId", type: "bytes4" }], - name: "supportsInterface", - outputs: [{ name: "", type: "bool" }], - stateMutability: "view", - type: "function" - }, - { - inputs: [], - name: "unlockStake", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { - name: "withdrawAddress", - type: "address" - } - ], - name: "withdrawStake", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { - name: "withdrawAddress", - type: "address" - }, - { name: "withdrawAmount", type: "uint256" } - ], - name: "withdrawTo", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { stateMutability: "payable", type: "receive" } -]; -// ../viem/src/_esm/account-abstraction/constants/address.js -var entryPoint07Address = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; -// ../viem/src/_esm/eip8130/abis.js -init_exports(); -var keystoreAbi = parseAbi([ - "struct InitialActor { bytes32 actorId; address authenticator; uint16 scope; bytes policyData; }", - "struct ActorConfig { address authenticator; uint48 expiry; uint16 scope; }", - "struct Actor { bytes32 actorId; ActorConfig config; bytes policyData; }", - "struct AccountChange { uint8 changeType; bytes payload; }", - "struct SignedAccountChanges { uint8 channel; uint64 sequence; AccountChange[] changes; bytes signature; }", - "struct ChangeSequences { uint64 multichain; uint32 localEpoch; uint32 localSequence; }", - "event ActorAuthorized(address indexed account, bytes32 indexed actorId, bytes actorData)", - "event ActorRevoked(address indexed account, bytes32 indexed actorId)", - "event AccountCreated(address indexed account, bytes32 userSalt, bytes32 codeHash)", - "event AccountImported(address indexed account)", - "event DelegationApplied(address indexed account, address target)", - "event AccountLocked(address indexed account, uint16 unlockDelay)", - "event AccountUnlockInitiated(address indexed account, uint40 unlocksAt)", - "function createAccount(bytes32 userSalt, bytes bytecode, InitialActor[] initialActors) returns (address)", - "function computeAddress(bytes32 userSalt, bytes bytecode, InitialActor[] initialActors) view returns (address)", - "function importAccount()", - "function computeImportDigest(address account, InitialActor[] initialActors) pure returns (bytes32)", - "function applySignedAccountChanges(address account, SignedAccountChanges s)", - "function validateSignature(address account, bytes32 hash, bytes auth) view returns (bytes32 actorId, uint16 scope)", - "function authenticateActor(address account, bytes32 hash, bytes auth) view returns (bytes32 actorId, uint16 scope)", - "function getActorConfig(address account, bytes32 actorId) view returns (ActorConfig)", - "function getActorWithPolicy(address account, bytes32 actorId) view returns (ActorConfig config, address policyManager, bytes32 policyCommitment)", - "function getPolicyCommitment(address account, bytes32 actorId) view returns (bytes32)", - "function getPolicyManager(address account, bytes32 actorId) view returns (address)", - "function getChangeSequences(address account) view returns (ChangeSequences)", - "function isLocked(address account) view returns (bool)", - "function getLockStatus(address account) view returns (bool locked, bool hasInitiatedUnlock, uint40 unlocksAt, uint16 unlockDelay)" -]); -var erc4337AccountAbi = parseAbi([ - "struct Call { address target; uint256 value; bytes data; }", - "struct PackedUserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; bytes32 accountGasLimits; uint256 preVerificationGas; bytes32 gasFees; bytes paymasterAndData; bytes signature; }", - "event CallerAuthorized(address indexed caller)", - "event CallerRevoked(address indexed caller)", - "function executeBatch(Call[] calls)", - "function authorizeCaller(address caller)", - "function revokeCaller(address caller)", - "function isAuthorizedCaller(address caller) view returns (bool)", - "function validateUserOp(PackedUserOperation userOp, bytes32 userOpHash, uint256 missingAccountFunds) returns (uint256 validationData)", - "function isValidSignature(bytes32 hash, bytes signature) view returns (bytes4)" -]); -var authenticatorAbi = parseAbi([ - "function authenticate(bytes32 hash, bytes data) view returns (bytes32 actorId)" -]); -var transactionContextAbi = parseAbi([ - "function getTransactionSender() view returns (address)", - "function getTransactionPayer() view returns (address)", - "function getTransactionSenderActorId() view returns (bytes32)" -]); -var nonceManagerAbi = parseAbi([ - "function getNonce(address account, uint256 nonceKey) view returns (uint64)" -]); -// ../viem/src/_esm/eip8130/accounts/toAccount.js -init_base(); -init_fromHex(); -init_toHex(); - -// ../viem/src/_esm/eip8130/constants.js -var aaTransactionType = "0x79"; -var aaPayerType = "0x7a"; -var aaBaseCost = 15000n; -var nonceFreeCost = 13000n; -var nonceKeyFirstUseCost = 22100n; -var nonceKeyExistingCost = 5000n; -var replayIdType = "0x7901"; -var nonceFreeExpiryWindow = 30000n; -var nonceFreeMaxExpiryWindow = 20000n; -var replayBufferCapacity = 300000n; -var accountChangeType = { - create: "0x", - config: "0x01", - delegation: "0x02" -}; -var changeType = { - authorizeActor: 0, - revokeActor: 1, - incrementLocalEpoch: 2, - lock: 3, - unlock: 4 -}; -var unsequencedLocalHalf = 0xffffffffn; -var actorScope = { - operator: 1, - selfPayer: 2, - sponsorPayer: 4, - policy: 8, - nonce: 16 -}; -var scopeUnrestricted = 0; -var accountStateFlags = { - revokeDefaultEoa: 1, - locked: 2, - unlockInitiated: 4 -}; -var policyDataLength = 52; -var nonceKeyMax = 2n ** 256n - 1n; -var ecrecoverAuthenticator = "0x0000000000000000000000000000000000000001"; -var revokedAuthenticator = "0xffffffffffffffffffffffffffffffffffffffff"; -var trustedExecutorAuthenticator = "0xbe114b191a3ac7519670cac0c5e74aac1d819a13"; -var externalPolicyAuthenticator = "0x8a22e6B3c724A7D0C3aCA1f7EbD089CfbD96B392"; -var canonicalAuthenticators = { - k1: "0x0000000000000000000000000000000000000001", - p256: "0x8130C89F65750431b564A4730397552a11CeA256", - passkey: "0x813007b6b1b48E75D91dEc5927ab515d12a0F1d0", - delegate: "0x81301AA52202f8C6b79Cde660440E3c6A7c5ade1" -}; -var canonicalAuthDataLength = { - [canonicalAuthenticators.k1.toLowerCase()]: 65, - [canonicalAuthenticators.p256.toLowerCase()]: 128, - [canonicalAuthenticators.passkey.toLowerCase()]: 256 -}; -var nonceManagerAddress = "0x813000000000000000000000000000000000aa01"; -var txContextAddress = "0x813000000000000000000000000000000000aa02"; -var keystoreAddress = "0x813012Bd8D971928475235BBac6F0488c4A100AC"; -var defaultAccountAddress = "0x81309c54D6Bc190FbBc0FA9f296ea4C6A539ADEf"; -var deploymentHeaderSize = 14; -var maxCodeSize = 24576; - -// ../viem/src/_esm/eip8130/deployments.js -var canonicalEip8130Deployment = { - accounts: { - upgradeable: undefined, - default: "0x81309c54D6Bc190FbBc0FA9f296ea4C6A539ADEf", - defaultHighRate: "0x813002fFdd25C81CeF79781702176D453AF0Fa57" - }, - authenticators: { - k1: "0x0000000000000000000000000000000000000001", - p256: "0x8130C89F65750431b564A4730397552a11CeA256", - webAuthn: "0x813007b6b1b48E75D91dEc5927ab515d12a0F1d0", - delegate: "0x81301AA52202f8C6b79Cde660440E3c6A7c5ade1", - alwaysValid: "0xA550545Da91720c23483c5B3493412A02D1cF9F9" - }, - policies: { - manager: "0x8130E47Bc12CfDD6d2d2178B35Def9A51cae0aC1", - sessionPolicy: "0x8130A0D85473CeF9e888B4228F729b48F0c45E55" - } -}; -var baseSepoliaDeployment = { - ...canonicalEip8130Deployment -}; -var vibenetDevnetDeployment = { - ...canonicalEip8130Deployment -}; -var eip8130Deployments = { - 84532: baseSepoliaDeployment, - 84538453: vibenetDevnetDeployment -}; -function getEip8130Deployment(chainId) { - return eip8130Deployments[chainId]; -} - -// ../viem/src/_esm/eip8130/keys.js -init_base(); -init_pad(); -init_size(); - -// ../viem/src/_esm/eip8130/utils/actorId.js -init_base(); -init_pad(); -init_size(); -init_keccak256(); -function actorIdFromAddress(address) { - return pad(address, { dir: "left", size: 32 }); -} -function actorIdFromPublicKey(publicKey) { - if (typeof publicKey === "string") { - if (size2(publicKey) !== 64) - throw new BaseError2(`Public key must be 64 bytes (x || y); got ${size2(publicKey)} bytes.`); - return keccak256(publicKey); - } - const { x, y } = publicKey; - if (size2(x) !== 32 || size2(y) !== 32) - throw new BaseError2("Public key coordinates `x` and `y` must be 32 bytes."); - return keccak256(concatHex([x, y])); -} - -// ../viem/src/_esm/eip8130/keys.js -var key = { - k1(address) { - return { - actorId: actorIdFromAddress(address), - authenticator: ecrecoverAuthenticator - }; - }, - p256(publicKey, options = {}) { - return { - actorId: actorIdFromPublicKey(publicKey), - authenticator: options.authenticator ?? canonicalAuthenticators.p256 - }; - }, - webAuthn(publicKey, options = {}) { - return { - actorId: actorIdFromPublicKey(publicKey), - authenticator: options.authenticator ?? canonicalAuthenticators.passkey - }; - }, - passkey(publicKey, options = {}) { - return { - actorId: actorIdFromPublicKey(publicKey), - authenticator: options.authenticator ?? canonicalAuthenticators.passkey - }; - }, - delegate(delegatedAccount, options = {}) { - return { - actorId: actorIdFromAddress(delegatedAccount), - authenticator: options.authenticator ?? canonicalAuthenticators.delegate - }; - }, - trustedExecutor(caller) { - return key.k1(caller); - }, - externalPull(caller) { - return { - actorId: actorIdFromAddress(caller), - authenticator: externalPolicyAuthenticator - }; - } -}; -function toScope(...flags) { - return flags.reduce((acc, flag) => acc | flag, 0); -} -function canUseSequencedNonce(scope) { - const s = scope ?? scopeUnrestricted; - return s === scopeUnrestricted || (s & actorScope.nonce) !== 0; -} -function isNoncelessOnly(scope) { - return !canUseSequencedNonce(scope); -} -function encodePolicyData(policy) { - if (policy.type === 0) - throw new BaseError2("`policy.type` must be non-zero (0 = no policy)."); - if (size2(policy.commitment) !== 32) - throw new BaseError2("`policy.commitment` must be 32 bytes."); - return concatHex([pad(policy.manager, { size: 20 }), policy.commitment]); -} -function authorizeActor(actor, options = {}) { - const change = { - changeType: 0, - actorId: actor.actorId, - authenticator: actor.authenticator - }; - let scope = options.scope ?? 0; - if (options.expiry) - change.expiry = options.expiry; - if (options.policy) { - if (scope === 0) - throw new BaseError2("A policy-bearing actor MUST have a restricted (non-admin) scope (e.g. `actorScope.policy`)."); - scope |= actorScope.policy; - change.policyData = encodePolicyData(options.policy); - } - if (scope) - change.scope = scope; - return change; -} -function revokeActor(actor) { - const actorId = typeof actor === "string" ? actor : actor.actorId; - return { changeType: 1, actorId }; -} -function incrementLocalEpoch() { - return { changeType: 2 }; -} - -// ../viem/src/_esm/eip8130/utils/computeAddress.js -init_base(); -// ../viem/src/_esm/utils/data/isBytes.js -function isBytes5(value) { - if (!value) - return false; - if (typeof value !== "object") - return false; - if (!("BYTES_PER_ELEMENT" in value)) - return false; - return value.BYTES_PER_ELEMENT === 1 && value.constructor.name === "Uint8Array"; -} - -// ../viem/src/_esm/utils/address/getContractAddress.js -init_pad(); -init_slice(); -init_toBytes(); -init_keccak256(); -init_getAddress(); -function getCreate2Address3(opts) { - const from16 = toBytes(getAddress(opts.from)); - const salt = pad(isBytes5(opts.salt) ? opts.salt : toBytes(opts.salt), { - size: 32 - }); - const bytecodeHash = (() => { - if ("bytecodeHash" in opts) { - if (isBytes5(opts.bytecodeHash)) - return opts.bytecodeHash; - return toBytes(opts.bytecodeHash); - } - return keccak256(opts.bytecode, "bytes"); - })(); - return getAddress(slice(keccak256(concat([toBytes("0xff"), from16, salt, bytecodeHash])), 12)); -} - -// ../viem/src/_esm/eip8130/utils/computeAddress.js -init_size(); -init_fromHex(); -init_toHex(); -init_keccak256(); -function deploymentHeader(codeSize) { - const hi = codeSize >> 8 & 255; - const lo = codeSize & 255; - return bytesToHex(Uint8Array.from([ - 97, - hi, - lo, - 96, - 14, - 96, - 0, - 57, - 97, - hi, - lo, - 96, - 0, - 243 - ])); -} -function computeAddress(parameters) { - const { userSalt, code, initialActors } = parameters; - const codeSize = size2(code); - if (codeSize === 0) - throw new BaseError2("`code` must not be empty."); - if (codeSize > maxCodeSize) - throw new BaseError2(`\`code\` exceeds the maximum code size (${maxCodeSize} bytes): got ${codeSize} bytes.`); - if (initialActors.length === 0) - throw new BaseError2("`initialActors` must not be empty."); - for (let i = 1;i < initialActors.length; i++) { - if (hexToBigInt(initialActors[i].actorId) <= hexToBigInt(initialActors[i - 1].actorId)) - throw new BaseError2("`initialActors` must be sorted by `actorId` in strictly ascending order (no duplicates)."); - } - const actorsCommitment = keccak256(concatHex(initialActors.map((actor) => keccak256(concatHex([ - actor.actorId, - actor.authenticator, - toHex(actor.scope ?? 0, { size: 2 }), - actor.policyData ?? "0x" - ]))))); - const effectiveSalt = keccak256(concatHex([userSalt, actorsCommitment])); - const deploymentCode = concatHex([deploymentHeader(codeSize), code]); - return getCreate2Address3({ - from: keystoreAddress, - salt: effectiveSalt, - bytecode: deploymentCode - }); -} - -// ../viem/src/_esm/eip8130/utils/proxy.js -function erc1167Bytecode(implementation) { - return concatHex([ - "0x363d3d373d3d3d363d73", - implementation, - "0x5af43d82803e903d91602b57fd5bf3" - ]); -} -function upgradeableProxyBytecode(implementation) { - return concatHex([ - "0x7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", - "0x5480156100", - "0x2c", - "0x576100", - "0x4356", - "0x5b5073", - implementation, - "0x5b363d3d373d3d3d363d855af43d82803e903d91605b57fd5bf3" - ]); -} - -// ../viem/src/_esm/eip8130/utils/signActorChanges.js -init_base(); - -// ../viem/src/_esm/eip8130/utils/hashActorChanges.js -init_encodeAbiParameters(); -init_toHex(); -init_keccak256(); - -// ../viem/src/_esm/eip8130/utils/actorChangeData.js -init_decodeAbiParameters(); -init_encodeAbiParameters(); -var authorizePayloadParameters = [ - { name: "actorId", type: "bytes32" }, - { - name: "config", - type: "tuple", - components: [ - { name: "authenticator", type: "address" }, - { name: "expiry", type: "uint48" }, - { name: "scope", type: "uint16" } - ] - }, - { name: "policyData", type: "bytes" } -]; -var revokePayloadParameters = [{ name: "actorId", type: "bytes32" }]; -var lockPayloadParameters = [{ name: "unlockDelay", type: "uint16" }]; -function encodeChangePayload(change) { - if (change.changeType === changeType.authorizeActor) - return encodeAbiParameters(authorizePayloadParameters, [ - change.actorId, - { - authenticator: change.authenticator, - expiry: Number(change.expiry ?? 0n), - scope: change.scope ?? 0 - }, - change.policyData ?? "0x" - ]); - if (change.changeType === changeType.revokeActor) - return encodeAbiParameters(revokePayloadParameters, [change.actorId]); - if (change.changeType === changeType.lock) - return encodeAbiParameters(lockPayloadParameters, [change.unlockDelay]); - return "0x"; -} -function decodeAuthorizeActorPayload(payload) { - const [actorId, config, policyData] = decodeAbiParameters(authorizePayloadParameters, payload); - return { - actorId, - authenticator: config.authenticator, - scope: config.scope, - expiry: BigInt(config.expiry), - policyData - }; -} - -// ../viem/src/_esm/eip8130/utils/hashActorChanges.js -var accountChangeTypehash = keccak256(stringToHex("AccountChange(uint8 changeType,bytes payload)")); -var signedAccountChangesTypehash = keccak256(stringToHex("SignedAccountChangeBatch(address account,uint256 chainId,uint64 sequence,AccountChange[] changes)AccountChange(uint8 changeType,bytes payload)")); -function hashAccountChanges(parameters) { - const { account, chainId, sequence, changes } = parameters; - const changeHashes = changes.map((change) => keccak256(encodeAbiParameters([{ type: "bytes32" }, { type: "uint8" }, { type: "bytes32" }], [ - accountChangeTypehash, - change.changeType, - keccak256(encodeChangePayload(change)) - ]))); - const changesHash = keccak256(concatHex(changeHashes)); - return keccak256(encodeAbiParameters([ - { type: "bytes32" }, - { type: "address" }, - { type: "uint256" }, - { type: "uint64" }, - { type: "bytes32" } - ], [ - signedAccountChangesTypehash, - account, - BigInt(chainId), - BigInt(sequence), - changesHash - ])); -} - -// ../viem/src/_esm/eip8130/utils/signActorChanges.js -async function signAccountChanges(parameters) { - const { signer, chainId, sequence, changes } = parameters; - const channel = parameters.channel ?? "local"; - const authenticator = parameters.authenticator ?? signer.authenticator ?? ecrecoverAuthenticator; - const account = parameters.account ?? signer.address; - if (!signer.sign) - throw new BaseError2("`signer` does not support raw signing."); - const digest = hashAccountChanges({ - account, - chainId: channel === "local" ? chainId : 0, - sequence, - changes - }); - const signature = concatHex([ - authenticator, - await signer.sign({ hash: digest }) - ]); - return { type: "config", channel, sequence, changes, signature }; -} - -// ../viem/src/_esm/eip8130/utils/signMessage.js -init_encodeAbiParameters(); -init_pad(); -init_size(); -init_slice(); -init_fromHex(); -init_toHex(); -init_keccak256(); - -// ../viem/src/_esm/constants/bytes.js -var erc6492MagicBytes = "0x6492649264926492649264926492649264926492649264926492649264926492"; - -// ../viem/src/_esm/utils/signature/serializeErc6492Signature.js -init_encodeAbiParameters(); -init_toBytes(); -function serializeErc6492Signature3(parameters) { - const { address, data, signature, to = "hex" } = parameters; - const signature_ = concatHex([ - encodeAbiParameters([{ type: "address" }, { type: "bytes" }, { type: "bytes" }], [address, data, signature]), - erc6492MagicBytes - ]); - if (to === "hex") - return signature_; - return hexToBytes(signature_); -} - -// ../viem/src/_esm/eip8130/utils/keystoreCalls.js -init_encodeFunctionData(); -function toInitialActors(actors) { - return actors.map((actor) => ({ - actorId: actor.actorId, - authenticator: actor.authenticator, - scope: actor.scope ?? 0, - policyData: actor.policyData ?? "0x" - })); -} -function toAbiChanges(changes) { - return changes.map((change) => ({ - changeType: change.changeType, - payload: encodeChangePayload(change) - })); -} -function encodeCreateAccountData(parameters) { - const { userSalt, code, initialActors } = parameters; - return encodeFunctionData({ - abi: keystoreAbi, - functionName: "createAccount", - args: [userSalt, code, toInitialActors(initialActors)] - }); -} -function toFactoryArgs(parameters) { - return { - factory: keystoreAddress, - factoryData: encodeCreateAccountData(parameters) - }; -} -function encodeApplySignedAccountChangesData(parameters) { - const { account, channel, sequence, changes, signature } = parameters; - return encodeFunctionData({ - abi: keystoreAbi, - functionName: "applySignedAccountChanges", - args: [ - account, - { - channel: channel === "multichain" ? 1 : 0, - sequence, - changes: toAbiChanges(changes), - signature - } - ] - }); -} - -// ../viem/src/_esm/eip8130/utils/signMessage.js -var signedMessageTypehash = keccak256(stringToHex("SignedMessageEnvelope(address account,uint256 chainId,bytes32 hash)")); -var signatureType = { - local: 1, - multichain: 2 -}; -var multichainId = 0n; -function replaySafeHash(parameters) { - const { account, chainId, hash: hash3 } = parameters; - return keccak256(encodeAbiParameters([ - { type: "bytes32" }, - { type: "address" }, - { type: "uint256" }, - { type: "bytes32" } - ], [signedMessageTypehash, account, BigInt(chainId), hash3])); -} -function getSignatureEnvelopeHash(parameters) { - const { account, hash: hash3, sigType = "multichain", chainId } = parameters; - if (sigType === "local" && chainId === undefined) - throw new Error("`chainId` is required for a `local` signature envelope."); - return replaySafeHash({ - account, - chainId: sigType === "multichain" ? multichainId : chainId, - hash: hash3 - }); -} -function wrapSignatureEnvelope(parameters) { - const { sigType, authenticator, signature } = parameters; - return concatHex([ - numberToHex(signatureType[sigType], { size: 1 }), - pad(authenticator, { size: 20 }), - signature - ]); -} -function parseSignatureEnvelope(envelope) { - if (size2(envelope) < 21) - throw new Error("Signature envelope must be at least 21 bytes (`sigType || authenticator`)."); - const typeByte = hexToNumber(slice(envelope, 0, 1)); - const sigType = Object.keys(signatureType).find((k) => signatureType[k] === typeByte); - if (!sigType) - throw new Error(`Unknown signature envelope type byte: ${typeByte}.`); - return { - sigType, - authenticator: slice(envelope, 1, 21), - signature: slice(envelope, 21) - }; -} -async function signMessageEnvelope(parameters) { - const { signer, account, sigType = "multichain", chainId, message, hash: hash_ } = parameters; - if (!signer.sign) - throw new Error("`signer` does not support raw signing (`sign`)."); - const authenticator = parameters.authenticator ?? signer.authenticator ?? ecrecoverAuthenticator; - const hash3 = hash_ ?? hashMessage2(message); - const digest = getSignatureEnvelopeHash({ account, hash: hash3, sigType, chainId }); - const signature = await signer.sign({ hash: digest }); - return wrapSignatureEnvelope({ sigType, authenticator, signature }); -} -async function signTypedDataEnvelope(parameters) { - const { signer, account, sigType = "multichain", chainId, ...typedData } = parameters; - const authenticator = parameters.authenticator ?? signer.authenticator ?? ecrecoverAuthenticator; - const hash3 = hashTypedData2(typedData); - return signMessageEnvelope({ - signer, - account, - authenticator, - sigType, - chainId, - hash: hash3 - }); -} -function wrapCounterfactualSignature(parameters) { - const { signature, userSalt, code, initialActors } = parameters; - const { factory, factoryData } = toFactoryArgs({ - userSalt, - code, - initialActors - }); - return serializeErc6492Signature3({ - address: factory, - data: factoryData, - signature - }); -} - -// ../viem/src/_esm/eip8130/utils/signTransaction.js -init_base(); - -// ../viem/src/_esm/eip8130/utils/hashTransaction.js -init_toBytes(); -init_keccak256(); - -// ../viem/src/_esm/eip8130/utils/serializeTransaction.js -init_toHex(); - -// ../viem/src/_esm/eip8130/utils/assertTransaction.js -init_base(); -init_chain(); -function assertTransaction(transaction) { - const { chainId, nonceKey, nonceSequence, validBefore, payer, payerAuth, calls } = transaction; - if (chainId <= 0) - throw new InvalidChainIdError({ chainId }); - if (calls) { - for (const phase of calls) - for (const call3 of phase) - if (call3.value && call3.value !== 0n) - throw new BaseError2("EIP-8130 calls cannot carry `value` on the wire. Route value-bearing calls through the account wallet (e.g. `encodeWalletCalls` / `sendTransaction`)."); - } - if (typeof nonceKey === "bigint" && nonceKey === nonceKeyMax) { - if (nonceSequence !== undefined && nonceSequence !== 0n) - throw new BaseError2("`nonceSequence` must be `0n` when `nonceKey` is `nonceKeyMax` (nonce-free mode)."); - if (!validBefore || validBefore === 0n) - throw new BaseError2("`validBefore` must be non-zero when `nonceKey` is `nonceKeyMax` (nonce-free mode)."); - } - if (!payer && payerAuth && payerAuth !== "0x") - throw new BaseError2("`payerAuth` must be empty for self-pay transactions (no `payer` set)."); -} - -// ../viem/src/_esm/eip8130/utils/serializeTransaction.js -function toCallsList(calls) { - return (calls ?? []).map((phase) => phase.map((call3) => [call3.to, call3.data ?? "0x"])); -} -function toChange(change) { - return [ - change.changeType ? numberToHex(change.changeType) : "0x", - encodeChangePayload(change) - ]; -} -function toAccountChangesList(accountChanges) { - return (accountChanges ?? []).map((entry) => { - if (entry.type === "create") - return [ - accountChangeType.create, - entry.userSalt, - entry.code, - entry.initialActors.map((actor) => [ - actor.actorId, - actor.authenticator, - actor.scope ? numberToHex(actor.scope) : "0x", - actor.policyData ?? "0x" - ]) - ]; - if (entry.type === "config") - return [ - accountChangeType.config, - entry.channel === "multichain" ? "0x01" : "0x", - entry.sequence ? numberToHex(entry.sequence) : "0x", - entry.changes.map(toChange), - entry.signature - ]; - return [accountChangeType.delegation, entry.target]; - }); -} -function toTransactionBody(transaction) { - const { chainId, from: from16, nonceKey, nonceSequence, validAfter, validBefore, maxPriorityFeePerGas, maxFeePerGas, gas, accountChanges, calls, metadata } = transaction; - return [ - numberToHex(chainId), - from16 ?? "0x", - nonceKey ? numberToHex(nonceKey) : "0x", - nonceSequence ? numberToHex(nonceSequence) : "0x", - validAfter ? numberToHex(validAfter) : "0x", - validBefore ? numberToHex(validBefore) : "0x", - maxPriorityFeePerGas ? numberToHex(maxPriorityFeePerGas) : "0x", - maxFeePerGas ? numberToHex(maxFeePerGas) : "0x", - gas ? numberToHex(gas) : "0x", - toAccountChangesList(accountChanges), - toCallsList(calls), - metadata ?? "0x" - ]; -} -function serializeTransaction4(transaction) { - assertTransaction(transaction); - const { payer, senderAuth, payerAuth } = transaction; - return concatHex([ - aaTransactionType, - toRlp([ - ...toTransactionBody(transaction), - payer ?? "0x", - senderAuth ?? "0x", - payerAuth ?? "0x" - ]) - ]); -} - -// ../viem/src/_esm/eip8130/utils/hashTransaction.js -function getSenderSignatureHash(parameters) { - const { to = "hex", payer } = parameters; - const hash3 = keccak256(concatHex([ - aaTransactionType, - toRlp([...toTransactionBody(parameters), payer ?? "0x"]) - ])); - if (to === "bytes") - return hexToBytes(hash3); - return hash3; -} -function getPayerSignatureHash(parameters) { - const { to = "hex", payer } = parameters; - const hash3 = keccak256(concatHex([ - aaPayerType, - toRlp([...toTransactionBody(parameters), payer ?? "0x"]) - ])); - if (to === "bytes") - return hexToBytes(hash3); - return hash3; -} - -// ../viem/src/_esm/eip8130/utils/signTransaction.js -async function signTransaction5(parameters) { - const { account, payer } = parameters; - const transaction = { ...parameters.transaction }; - if (!transaction.senderAuth) { - if (!account?.sign) - throw new BaseError2("A sender `account` with raw signing support, or a preset `transaction.senderAuth`, is required."); - const authenticator = parameters.authenticator ?? account.authenticator ?? ecrecoverAuthenticator; - const senderHash = getSenderSignatureHash(transaction); - const signature = await account.sign({ hash: senderHash }); - transaction.senderAuth = transaction.from ? concatHex([authenticator, signature]) : signature; - } - if (payer && !transaction.payer) - transaction.payer = payer.address ?? payer.account.address; - if (transaction.payer && !transaction.payerAuth) { - if (!payer?.account.sign) - throw new BaseError2("A `payer` signer with raw signing support, or a preset `transaction.payerAuth`, is required for sponsored transactions."); - const authenticator = payer.authenticator ?? payer.account.authenticator ?? ecrecoverAuthenticator; - const from16 = transaction.from ?? account?.address; - const payerHash = getPayerSignatureHash({ ...transaction, from: from16 }); - const signature = await payer.account.sign({ hash: payerHash }); - transaction.payerAuth = concatHex([authenticator, signature]); - } - return serializeTransaction4(transaction); -} - -// ../viem/src/_esm/eip8130/accounts/toAccount.js -function toAccount3(parameters) { - const { signer, authenticator = ecrecoverAuthenticator, scope } = parameters; - const isAddressOnly = parameters.userSalt === undefined; - const address = (() => { - if (parameters.address) - return parameters.address; - if (isAddressOnly) - throw new BaseError2("Provide `address` or `userSalt + code + initialActors` to derive the account address."); - return computeAddress({ - userSalt: parameters.userSalt, - code: parameters.code, - initialActors: parameters.initialActors - }); - })(); - const initialActors = parameters.initialActors ?? []; - const isK1Authenticator = authenticator === ecrecoverAuthenticator || authenticator === canonicalAuthenticators.k1; - const actorId = parameters.actorId ?? (isK1Authenticator ? key.k1(signer.address).actorId : undefined); - const signerPublicKey = signer.publicKey; - const publicKey = typeof signerPublicKey === "string" ? signerPublicKey : "0x"; - return { - address, - signer, - initialActors, - scope, - actorId, - type: "local", - source: "eip8130", - publicKey, - async signMessage({ message }) { - return signMessageEnvelope({ - signer, - account: address, - authenticator, - message - }); - }, - async signTypedData(typedData) { - return signTypedDataEnvelope({ - signer, - account: address, - authenticator, - ...typedData - }); - }, - create() { - if (isAddressOnly) - throw new BaseError2("`create()` is not available for address-only (delegated EOA) accounts. " + "Include `account.delegate(impl)` in `accountChanges` instead."); - return { - type: "create", - userSalt: parameters.userSalt, - code: parameters.code, - initialActors: parameters.initialActors - }; - }, - async change(changes, options = {}) { - return signAccountChanges({ - signer, - account: address, - channel: options.channel ?? "local", - chainId: options.chainId ?? 0, - sequence: options.sequence ?? 0n, - changes, - authenticator - }); - }, - delegate(target) { - return { type: "delegation", target }; - }, - async signTransaction(transaction, options = {}) { - if (!signer.sign) - throw new BaseError2("`signer` does not support raw signing."); - return signTransaction5({ - transaction: { ...transaction, from: transaction.from ?? address }, - account: signer, - authenticator, - payer: options.payer - }); - } - }; -} -function newSmartAccount(parameters) { - const { signer, implementation, proxy = "upgradeable", admins = [], extraActors = [] } = parameters; - const primaryActor = "publicKey" in signer && signer.publicKey && typeof signer.publicKey !== "string" ? signer.authenticator === canonicalAuthenticators.passkey ? key.webAuthn(signer.publicKey) : key.p256(signer.publicKey) : key.k1(signer.address); - const adminActors = admins.map((a) => ({ - actorId: a.actorId, - authenticator: a.authenticator - })); - const allActors = [ - primaryActor, - ...adminActors, - ...extraActors - ].sort((a, b) => { - const ai = hexToBigInt(a.actorId); - const bi = hexToBigInt(b.actorId); - return ai < bi ? -1 : ai > bi ? 1 : 0; - }); - for (let i = 1;i < allActors.length; i++) - if (allActors[i].actorId === allActors[i - 1].actorId) - throw new BaseError2(`Duplicate initial actor id \`${allActors[i].actorId}\` (signer, admins, and extraActors must be distinct).`); - const salt = parameters.salt ?? randomBytes32(); - const code = parameters.code ?? (() => { - if (proxy === "erc1167") - return erc1167Bytecode(implementation ?? canonicalEip8130Deployment.accounts.default); - const impl = implementation ?? canonicalEip8130Deployment.accounts.upgradeable; - if (!impl) - throw new BaseError2("No canonical `CoinbaseSmartWalletV2` is deployed against the Keystore " + 'yet, so `proxy: "upgradeable"` requires an explicit `implementation` ' + "— a CoinbaseSmartWalletV2 you deployed (see " + "https://github.com/base/smart-wallet-v2). Alternatively pass " + '`proxy: "erc1167"` for an immutable DefaultAccount-backed account.'); - return upgradeableProxyBytecode(impl); - })(); - const inner = toAccount3({ - signer, - userSalt: salt, - code, - initialActors: allActors, - authenticator: signer.authenticator, - scope: primaryActor.scope ?? scopeUnrestricted - }); - return { ...inner, createChange: inner.create() }; -} -function toEoaAccount(signer, parameters = {}) { - if (!signer.address) - throw new BaseError2("`signer.address` is required. Use `privateKeyToAccount(pk)` or equivalent."); - const address = signer.address; - const scope = parameters.scope ?? scopeUnrestricted; - return { - address, - signer, - scope, - delegate(target) { - return { type: "delegation", target }; - }, - async change(changes, options = {}) { - return signAccountChanges({ - signer, - account: address, - channel: options.channel ?? "local", - chainId: options.chainId ?? 0, - sequence: options.sequence ?? 0n, - changes, - authenticator: ecrecoverAuthenticator - }); - }, - async signTransaction(transaction, options = {}) { - if (!signer.sign) - throw new BaseError2("`signer` does not support raw signing."); - return signTransaction5({ - transaction, - account: signer, - authenticator: ecrecoverAuthenticator, - payer: options.payer - }); - } - }; -} -function toDelegateSigner(parameters) { - const { delegateAccount, nestedSigner, nestedAuthenticator = ecrecoverAuthenticator, authenticator = canonicalAuthenticators.delegate } = parameters; - if (!nestedSigner.sign) - throw new BaseError2("`nestedSigner` must support raw signing."); - return { - address: nestedSigner.address, - authenticator, - async sign({ hash: hash3 }) { - const nestedSignature = await nestedSigner.sign({ hash: hash3 }); - return concatHex([delegateAccount, nestedAuthenticator, nestedSignature]); - } - }; -} -function delegateAuthSize(nestedDataLength = 65) { - return 20 + 20 + 20 + nestedDataLength; -} -function randomBytes32() { - const buf = new Uint8Array(32); - globalThis.crypto.getRandomValues(buf); - return bytesToHex(buf); -} -// ../viem/src/_esm/account-abstraction/accounts/toSmartAccount.js -init_exports(); - -// ../viem/src/_esm/utils/nonceManager.js -init_lru(); -function createNonceManager4(parameters) { - const { source } = parameters; - const deltaMap = new Map; - const nonceMap = new LruMap(8192); - const promiseMap = new Map; - const getKey = ({ address, chainId }) => `${address}.${chainId}`; - const resetCache = (key2) => { - deltaMap.delete(key2); - promiseMap.delete(key2); - }; - return { - async consume({ address, chainId, client }) { - const key2 = getKey({ address, chainId }); - const promise = this.get({ address, chainId, client }); - this.increment({ address, chainId }); - const nonce = await promise; - await source.set({ address, chainId }, nonce); - nonceMap.set(key2, nonce); - return nonce; - }, - async increment({ address, chainId }) { - const key2 = getKey({ address, chainId }); - const delta = deltaMap.get(key2) ?? 0; - deltaMap.set(key2, delta + 1); - }, - async get({ address, chainId, client }) { - const key2 = getKey({ address, chainId }); - let promise = promiseMap.get(key2); - if (!promise) { - promise = (async () => { - try { - const nonce = await source.get({ address, chainId, client }); - const previousNonce = nonceMap.get(key2) ?? 0; - if (previousNonce > 0 && nonce <= previousNonce) - return previousNonce + 1; - nonceMap.delete(key2); - return nonce; - } finally { - resetCache(key2); - } - })(); - promiseMap.set(key2, promise); - } - const delta = deltaMap.get(key2) ?? 0; - return delta + await promise; - }, - reset({ address, chainId }) { - const key2 = getKey({ address, chainId }); - nonceMap.delete(key2); - resetCache(key2); - } - }; -} -function jsonRpc() { - return { - async get(parameters) { - const { address, client } = parameters; - return getTransactionCount(client, { - address, - blockTag: "pending" - }); - }, - set() {} - }; -} -var nonceManager4 = /* @__PURE__ */ createNonceManager4({ - source: jsonRpc() -}); - -// ../viem/src/_esm/account-abstraction/accounts/toSmartAccount.js -async function toSmartAccount2(implementation) { - const { extend, nonceKeyManager = createNonceManager4({ - source: { - get() { - return Date.now(); - }, - set() {} - } - }), ...rest } = implementation; - let deployed = false; - const address = await implementation.getAddress(); - return { - ...extend, - ...rest, - address, - async getFactoryArgs() { - if ("isDeployed" in this && await this.isDeployed()) - return { factory: undefined, factoryData: undefined }; - return implementation.getFactoryArgs(); - }, - async getNonce(parameters) { - const key2 = parameters?.key ?? BigInt(await nonceKeyManager.consume({ - address, - chainId: implementation.client.chain.id, - client: implementation.client - })); - if (implementation.getNonce) - return await implementation.getNonce({ ...parameters, key: key2 }); - const nonce = await readContract(implementation.client, { - abi: parseAbi([ - "function getNonce(address, uint192) pure returns (uint256)" - ]), - address: implementation.entryPoint.address, - functionName: "getNonce", - args: [address, key2] - }); - return nonce; - }, - async isDeployed() { - if (deployed) - return true; - const code = await getAction(implementation.client, getCode, "getCode")({ - address - }); - deployed = Boolean(code); - return deployed; - }, - ...implementation.sign ? { - async sign(parameters) { - const [{ factory, factoryData }, signature] = await Promise.all([ - this.getFactoryArgs(), - implementation.sign(parameters) - ]); - if (factory && factoryData) - return serializeErc6492Signature3({ - address: factory, - data: factoryData, - signature - }); - return signature; - } - } : {}, - async signMessage(parameters) { - const [{ factory, factoryData }, signature] = await Promise.all([ - this.getFactoryArgs(), - implementation.signMessage(parameters) - ]); - if (factory && factoryData && factory !== "0x7702") - return serializeErc6492Signature3({ - address: factory, - data: factoryData, - signature - }); - return signature; - }, - async signTypedData(parameters) { - const [{ factory, factoryData }, signature] = await Promise.all([ - this.getFactoryArgs(), - implementation.signTypedData(parameters) - ]); - if (factory && factoryData && factory !== "0x7702") - return serializeErc6492Signature3({ - address: factory, - data: factoryData, - signature - }); - return signature; - }, - type: "smart" - }; -} - -// ../viem/src/_esm/account-abstraction/utils/userOperation/getUserOperationHash.js -init_encodeAbiParameters(); -init_keccak256(); - -// ../viem/src/_esm/account-abstraction/utils/userOperation/getInitCode.js -function getInitCode2(userOperation, options = {}) { - const { forHash } = options; - const { authorization, factory, factoryData } = userOperation; - if (forHash && (factory === "0x7702" || factory === "0x7702000000000000000000000000000000000000")) { - if (!authorization) - return "0x7702000000000000000000000000000000000000"; - return concat([authorization.address, factoryData ?? "0x"]); - } - if (!factory) - return "0x"; - return concat([factory, factoryData ?? "0x"]); -} - -// ../viem/src/_esm/account-abstraction/utils/userOperation/toPackedUserOperation.js -init_pad(); -init_size(); -var paymasterSignatureMagic = "0x22e325a297439656"; -function toPackedUserOperation2(userOperation, options = {}) { - const { callGasLimit, callData, maxPriorityFeePerGas, maxFeePerGas, paymaster, paymasterData, paymasterPostOpGasLimit, paymasterSignature, paymasterVerificationGasLimit, sender, signature = "0x", verificationGasLimit } = userOperation; - const accountGasLimits = concat([ - pad(numberToHex(verificationGasLimit || 0n), { size: 16 }), - pad(numberToHex(callGasLimit || 0n), { size: 16 }) - ]); - const initCode = getInitCode2(userOperation, options); - const gasFees = concat([ - pad(numberToHex(maxPriorityFeePerGas || 0n), { size: 16 }), - pad(numberToHex(maxFeePerGas || 0n), { size: 16 }) - ]); - const nonce = userOperation.nonce ?? 0n; - const paymasterAndData = paymaster ? concat([ - paymaster, - pad(numberToHex(paymasterVerificationGasLimit || 0n), { - size: 16 - }), - pad(numberToHex(paymasterPostOpGasLimit || 0n), { - size: 16 - }), - paymasterData || "0x", - ...paymasterSignature ? options.forHash ? [paymasterSignatureMagic] : [ - paymasterSignature, - pad(numberToHex(size2(paymasterSignature)), { size: 2 }), - paymasterSignatureMagic - ] : [] - ]) : "0x"; - const preVerificationGas = userOperation.preVerificationGas ?? 0n; - return { - accountGasLimits, - callData, - initCode, - gasFees, - nonce, - paymasterAndData, - preVerificationGas, - sender, - signature - }; -} - -// ../viem/src/_esm/account-abstraction/utils/userOperation/getUserOperationTypedData.js -var types = { - PackedUserOperation: [ - { type: "address", name: "sender" }, - { type: "uint256", name: "nonce" }, - { type: "bytes", name: "initCode" }, - { type: "bytes", name: "callData" }, - { type: "bytes32", name: "accountGasLimits" }, - { type: "uint256", name: "preVerificationGas" }, - { type: "bytes32", name: "gasFees" }, - { type: "bytes", name: "paymasterAndData" } - ] -}; -function getUserOperationTypedData2(parameters) { - const { chainId, entryPointAddress, userOperation } = parameters; - const packedUserOp = toPackedUserOperation2(userOperation, { forHash: true }); - return { - types, - primaryType: "PackedUserOperation", - domain: { - name: "ERC4337", - version: "1", - chainId, - verifyingContract: entryPointAddress - }, - message: packedUserOp - }; -} - -// ../viem/src/_esm/account-abstraction/utils/userOperation/getUserOperationHash.js -function getUserOperationHash2(parameters) { - const { chainId, entryPointAddress, entryPointVersion } = parameters; - const userOperation = parameters.userOperation; - const { authorization, callData = "0x", callGasLimit, maxFeePerGas, maxPriorityFeePerGas, nonce, paymasterAndData = "0x", preVerificationGas, sender, verificationGasLimit } = userOperation; - if (entryPointVersion === "0.8" || entryPointVersion === "0.9") - return hashTypedData2(getUserOperationTypedData2({ - chainId, - entryPointAddress, - userOperation - })); - const packedUserOp = (() => { - if (entryPointVersion === "0.6") { - const factory = userOperation.initCode?.slice(0, 42); - const factoryData = userOperation.initCode?.slice(42); - const initCode = getInitCode2({ - authorization, - factory, - factoryData - }, { forHash: true }); - return encodeAbiParameters([ - { type: "address" }, - { type: "uint256" }, - { type: "bytes32" }, - { type: "bytes32" }, - { type: "uint256" }, - { type: "uint256" }, - { type: "uint256" }, - { type: "uint256" }, - { type: "uint256" }, - { type: "bytes32" } - ], [ - sender, - nonce, - keccak256(initCode), - keccak256(callData), - callGasLimit, - verificationGasLimit, - preVerificationGas, - maxFeePerGas, - maxPriorityFeePerGas, - keccak256(paymasterAndData) - ]); - } - if (entryPointVersion === "0.7") { - const packedUserOp2 = toPackedUserOperation2(userOperation, { - forHash: true - }); - return encodeAbiParameters([ - { type: "address" }, - { type: "uint256" }, - { type: "bytes32" }, - { type: "bytes32" }, - { type: "bytes32" }, - { type: "uint256" }, - { type: "bytes32" }, - { type: "bytes32" } - ], [ - packedUserOp2.sender, - packedUserOp2.nonce, - keccak256(packedUserOp2.initCode), - keccak256(packedUserOp2.callData), - packedUserOp2.accountGasLimits, - packedUserOp2.preVerificationGas, - packedUserOp2.gasFees, - keccak256(packedUserOp2.paymasterAndData) - ]); - } - throw new Error(`entryPointVersion "${entryPointVersion}" not supported.`); - })(); - return keccak256(encodeAbiParameters([{ type: "bytes32" }, { type: "address" }, { type: "uint256" }], [keccak256(packedUserOp), entryPointAddress, BigInt(chainId)])); -} - -// ../viem/src/_esm/eip8130/accounts/toSmartAccount.js -init_base(); -init_decodeFunctionData(); -init_encodeFunctionData(); -async function toSmartAccount3(parameters) { - const { client, entryPoint: entryPoint_ = { - abi: entryPoint07Abi, - address: entryPoint07Address, - version: "0.7" - }, getNonce, authenticator = ecrecoverAuthenticator } = parameters; - const entryPoint = { - abi: entryPoint_.abi, - address: entryPoint_.address, - version: entryPoint_.version - }; - const owner = parseAccount(parameters.owner); - const stubData = parameters.stubData ?? "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; - const sign6 = parameters.sign ?? (async (hash3) => { - if (!owner.sign) - throw new BaseError2("`owner` must be a local account exposing `sign`, or pass a custom `sign` function. EIP-8130 validates the raw `userOpHash` (no EIP-191 prefix)."); - return owner.sign({ hash: hash3 }); - }); - const code = parameters.code ?? (parameters.implementation ? erc1167Bytecode(parameters.implementation) : undefined); - function getCreateParameters() { - if (!parameters.userSalt || !parameters.initialActors) - throw new BaseError2("`userSalt` and `initialActors` are required to derive factory args / address."); - if (!code) - throw new BaseError2("Provide `implementation` (wallet impl address) or `code` (deployment bytecode)."); - return { - userSalt: parameters.userSalt, - code, - initialActors: parameters.initialActors - }; - } - return toSmartAccount2({ - client, - entryPoint, - getNonce, - extend: { abi: erc4337AccountAbi }, - async decodeCalls(data) { - const result = decodeFunctionData({ abi: erc4337AccountAbi, data }); - if (result.functionName === "executeBatch") - return result.args[0].map((call3) => ({ - to: call3.target, - value: call3.value, - data: call3.data - })); - throw new BaseError2(`unable to decode calls for "${result.functionName}"`); - }, - async encodeCalls(calls) { - return encodeFunctionData({ - abi: erc4337AccountAbi, - functionName: "executeBatch", - args: [ - calls.map((call3) => ({ - target: call3.to, - value: call3.value ?? 0n, - data: call3.data ?? "0x" - })) - ] - }); - }, - async getAddress() { - if (parameters.address) - return parameters.address; - return computeAddress(getCreateParameters()); - }, - async getFactoryArgs() { - return toFactoryArgs(getCreateParameters()); - }, - async getStubSignature() { - return concatHex([authenticator, stubData]); - }, - async signMessage(parameters_) { - const address = await this.getAddress(); - const digest = getSignatureEnvelopeHash({ - account: address, - hash: hashMessage2(parameters_.message) - }); - return wrapSignatureEnvelope({ - sigType: "multichain", - authenticator, - signature: await sign6(digest) - }); - }, - async signTypedData(parameters_) { - const address = await this.getAddress(); - const digest = getSignatureEnvelopeHash({ - account: address, - hash: hashTypedData2(parameters_) - }); - return wrapSignatureEnvelope({ - sigType: "multichain", - authenticator, - signature: await sign6(digest) - }); - }, - async signUserOperation(parameters_) { - const { chainId = client.chain.id, ...userOperation } = parameters_; - const address = await this.getAddress(); - const userOpHash = getUserOperationHash2({ - chainId, - entryPointAddress: entryPoint.address, - entryPointVersion: entryPoint.version, - userOperation: { - ...userOperation, - sender: address - } - }); - return concatHex([authenticator, await sign6(userOpHash)]); - } - }); -} -// ../viem/src/_esm/eip8130/actions/estimateGas.js -init_base(); -init_fromHex(); -init_toHex(); - -// ../viem/src/_esm/eip8130/utils/toPhases.js -function toPhases(calls) { - if (!calls || calls.length === 0) - return []; - if (Array.isArray(calls[0])) - return calls; - return [calls]; -} - -// ../viem/src/_esm/eip8130/actions/estimateGas.js -var maxAuthSize = 8192; -async function estimateGas3(client, parameters) { - const { from: from16, sender, to, data, value, senderAuth: senderAuthExplicit, senderAuthAuthenticator, senderAuthSize, senderActorId, accountChanges, calls, nonceKey = 0n, nonceSequence = 0, payer, payerAuth: payerAuthExplicit, payerAuthAuthenticator, payerAuthSize, dataSuffix: dataSuffixParam, blockNumber, blockTag = "pending" } = parameters; - const dataSuffix = dataSuffixParam ?? (typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value); - const account_ = sender ?? from16; - if (!account_) - throw new BaseError2("`sender` (or `from`) is required for an EIP-8130 gas estimate: the sender drives actor/policy resolution."); - if (sender && from16 && sender !== from16) - throw new BaseError2(`\`sender\` (${sender}) and \`from\` (${from16}) must agree when both are set.`); - for (const size7 of [senderAuthSize, payerAuthSize]) - if (size7 !== undefined && (size7 < 0 || size7 > maxAuthSize)) - throw new BaseError2(`auth size ${size7} out of range (0..=${maxAuthSize}).`); - const senderAuth = buildAuthBlob(senderAuthExplicit, senderAuthAuthenticator, senderAuthSize); - const payerAuth = buildAuthBlob(payerAuthExplicit, payerAuthAuthenticator, payerAuthSize); - const useFullBody = accountChanges !== undefined || calls !== undefined; - let request; - if (useFullBody) { - request = { - type: aaTransactionType, - sender: account_, - nonceKey: Number(nonceKey), - nonceSequence, - validAfter: 0, - validBefore: 0, - maxFeePerGas: numberToHex(1000000000n), - maxPriorityFeePerGas: numberToHex(1000000n), - gasLimit: 30000000, - accountChanges: (accountChanges ?? []).map(serializeAccountChange), - calls: (calls !== undefined ? toPhases(calls) : [[{ to: account_, value: 0n, data: "0x" }]]).map((phase) => phase.map((c) => ({ - to: c.to, - value: numberToHex(c.value ?? 0n), - data: c.data ?? "0x" - }))), - metadata: dataSuffix ?? "0x", - payer: payer ?? null - }; - if (senderAuth !== undefined) - request.senderAuth = senderAuth; - if (payerAuth !== undefined) - request.payerAuth = payerAuth; - if (senderActorId !== undefined) - request.senderActorId = senderActorId; - } else { - request = { - type: aaTransactionType, - sender: account_ - }; - if (to !== undefined) - request.to = to; - if (data !== undefined) - request.data = data; - if (value !== undefined) - request.value = numberToHex(value); - if (payer !== undefined) - request.payer = payer; - if (senderAuth !== undefined) - request.senderAuth = senderAuth; - if (payerAuth !== undefined) - request.payerAuth = payerAuth; - if (senderActorId !== undefined) - request.senderActorId = senderActorId; - } - const block = blockNumber !== undefined ? numberToHex(blockNumber) : blockTag; - const gas = await client.request({ method: "eth_estimateGas", params: [request, block] }); - return hexToBigInt(gas); -} -function buildAuthBlob(explicit, authenticator, size7) { - if (explicit !== undefined) - return explicit; - if (authenticator === undefined) { - if (size7 === undefined) - return; - return filler(size7); - } - const dataLength = size7 ?? canonicalAuthDataLength[authenticator.toLowerCase()]; - if (dataLength === undefined) - throw new BaseError2(`No default auth-payload length is known for authenticator ${authenticator}. Pass an explicit auth size.`); - return concatHex([authenticator, filler(dataLength)]); -} -function filler(length) { - return `0x${"ff".repeat(length)}`; -} -function serializeAccountChange(change) { - if (change.type === "create") { - return { - type: "create", - userSalt: change.userSalt, - code: change.code, - initialActors: change.initialActors.map((a) => ({ - actorId: a.actorId, - authenticator: a.authenticator, - scope: a.scope ?? 0, - policyData: a.policyData ?? "0x" - })) - }; - } - if (change.type === "delegation") { - return { type: "delegation", target: change.target }; - } - const changeTypeName = { - [changeType.authorizeActor]: "AuthorizeActor", - [changeType.revokeActor]: "RevokeActor", - [changeType.incrementLocalEpoch]: "IncrementLocalEpoch", - [changeType.lock]: "Lock", - [changeType.unlock]: "Unlock" - }; - return { - type: "configChange", - channel: change.channel === "multichain" ? "Multichain" : "Local", - sequence: Number(change.sequence), - changes: change.changes.map((c) => ({ - changeType: changeTypeName[c.changeType], - payload: encodeChangePayload(c) - })), - signature: change.signature - }; -} -// ../viem/src/_esm/eip8130/actions/getActorConfig.js -async function getActorConfig(client, parameters) { - const { account, actorId } = parameters; - const config = await readContract(client, { - address: keystoreAddress, - abi: keystoreAbi, - functionName: "getActorConfig", - args: [account, actorId] - }); - return { - authenticator: config.authenticator, - scope: config.scope, - expiry: config.expiry, - hasPolicy: (config.scope & actorScope.policy) !== 0 - }; -} -// ../viem/src/_esm/eip8130/actions/getConfigSequence.js -async function getConfigSequence(client, parameters) { - const { account } = parameters; - const result = await readContract(client, { - address: keystoreAddress, - abi: keystoreAbi, - functionName: "getChangeSequences", - args: [account] - }); - const local = BigInt(result.localEpoch) << 32n | BigInt(result.localSequence); - return { - local, - multichain: result.multichain, - localEpoch: result.localEpoch, - localSequence: result.localSequence - }; -} -function unsequencedLocalSequence(localEpoch) { - return BigInt(localEpoch) << 32n | unsequencedLocalHalf; -} -// ../viem/src/_esm/eip8130/actions/getLockStatus.js -async function getLockStatus(client, parameters) { - const { account } = parameters; - const [locked, hasInitiatedUnlock, unlocksAt, unlockDelay] = await readContract(client, { - address: keystoreAddress, - abi: keystoreAbi, - functionName: "getLockStatus", - args: [account] - }); - return { locked, hasInitiatedUnlock, unlocksAt, unlockDelay }; -} -// ../viem/src/_esm/eip8130/actions/getPolicy.js -async function getPolicy(client, parameters) { - const { account, actorId } = parameters; - const [, policyManager, policyCommitment] = await readContract(client, { - address: keystoreAddress, - abi: keystoreAbi, - functionName: "getActorWithPolicy", - args: [account, actorId] - }); - return { target: policyManager, commitment: policyCommitment }; -} -// ../viem/src/_esm/eip8130/policies.js -init_exports(); +// ../viem/src/eip8130/utils/signTransaction.ts init_base(); -init_encodeAbiParameters(); -init_encodeFunctionData(); + +// ../viem/src/eip8130/utils/hashTransaction.ts +init_toBytes(); init_keccak256(); -var policyManagerAbi = parseAbi([ - "struct PolicyBinding { address account; address policy; bytes policyConfig; uint40 validAfter; uint40 validUntil; uint256 salt; }", - "event PolicyExecuted(address indexed account, address indexed policy, bytes32 indexed commitment, address caller)", - "event ExecutionSkipped(address indexed account, address indexed policy, bytes32 indexed actorId)", - "function commitmentOf(PolicyBinding binding) pure returns (bytes32)", - "function execute(PolicyBinding binding, bytes executionData)", - "function executeFor(PolicyBinding binding, bytes executionData)", - "function executeForMany(PolicyBinding[] bindings, bytes[] executionData) returns (bool[] results)" -]); -var sessionPolicyAbi = parseAbi([ - "struct TokenLimit { address token; uint256 limit; uint40 period; }", - "struct SelectorRule { bytes4 selector; address[] recipients; }", - "struct CallScope { address target; SelectorRule[] selectorRules; }", - "struct Config { TokenLimit[] tokenLimits; CallScope[] callScopes; }", - "struct Action { address target; uint256 value; bytes data; }", - "struct PeriodUsage { uint48 start; uint48 end; uint160 spend; }", - "function isTargetAllowed(Config config, address target) pure returns (bool allowed, bool anySelector)", - "function getSelectorRule(Config config, address target, bytes4 selector) pure returns (bool allowed, bool recipientBound)", - "function isRecipientAllowed(Config config, address target, bytes4 selector, address recipient) pure returns (bool)", - "function getTokenLimit(Config config, address token) pure returns (bool set, uint160 allowance, uint40 period)", - "function getCurrentSpend(bytes32 commitment, TokenLimit limit) view returns (PeriodUsage)" -]); -var commitmentParameters = [ - { type: "address" }, - { type: "address" }, - { type: "bytes32" }, - { type: "uint40" }, - { type: "uint40" }, - { type: "uint256" } -]; -function commitmentOf(binding) { - return keccak256(encodeAbiParameters(commitmentParameters, [ - binding.account, - binding.policy, - keccak256(binding.policyConfig), - Number(binding.validAfter), - Number(binding.validUntil), - binding.salt - ])); -} -function toBindingArgs(binding) { - return { - account: binding.account, - policy: binding.policy, - policyConfig: binding.policyConfig, - validAfter: Number(binding.validAfter), - validUntil: Number(binding.validUntil), - salt: binding.salt - }; -} -function defineSessionPolicy(parameters) { - const { account, policyConfig, policy = baseSepoliaDeployment.policies.sessionPolicy, manager = baseSepoliaDeployment.policies.manager, validAfter = 0n, validUntil = 0n, salt = 0n, policyType = 1 } = parameters; - if (policyType === 0) - throw new BaseError2("`policyType` must be non-zero (0 = no policy)."); - const binding = { - account, - policy, - policyConfig, - validAfter, - validUntil, - salt - }; - const commitment = commitmentOf(binding); - return { - manager, - policy, - binding, - commitment, - actorPolicy: { type: policyType, manager, commitment }, - executeCall(executionDataOrAction) { - const executionData = typeof executionDataOrAction === "string" ? executionDataOrAction : encodeSessionPolicyAction(executionDataOrAction); - return { - to: manager, - value: 0n, - data: encodeFunctionData({ - abi: policyManagerAbi, - functionName: "execute", - args: [toBindingArgs(binding), executionData] - }) - }; - }, - executeForCall(executionDataOrAction) { - const executionData = typeof executionDataOrAction === "string" ? executionDataOrAction : encodeSessionPolicyAction(executionDataOrAction); - return { - to: manager, - value: 0n, - data: encodeFunctionData({ - abi: policyManagerAbi, - functionName: "executeFor", - args: [toBindingArgs(binding), executionData] - }) - }; - } - }; -} -var sessionPolicyAddress = baseSepoliaDeployment.policies.sessionPolicy; -var sessionConfigParameters = [ - { - type: "tuple", - components: [ - { - name: "tokenLimits", - type: "tuple[]", - components: [ - { name: "token", type: "address" }, - { name: "limit", type: "uint256" }, - { name: "period", type: "uint40" } - ] - }, - { - name: "callScopes", - type: "tuple[]", - components: [ - { name: "target", type: "address" }, - { - name: "selectorRules", - type: "tuple[]", - components: [ - { name: "selector", type: "bytes4" }, - { name: "recipients", type: "address[]" } - ] - } - ] - } - ] - } -]; -var sessionActionParameters = [ + +// ../viem/src/eip8130/utils/serializeTransaction.ts +init_toHex(); + +// ../viem/src/eip8130/utils/actorChangeData.ts +init_encodeAbiParameters(); +var authorizePayloadParameters = [ + { name: "actorId", type: "bytes32" }, { + name: "config", type: "tuple", components: [ - { name: "target", type: "address" }, - { name: "value", type: "uint256" }, - { name: "data", type: "bytes" } + { name: "authenticator", type: "address" }, + { name: "expiry", type: "uint48" }, + { name: "scope", type: "uint16" } ] - } + }, + { name: "policyData", type: "bytes" } ]; -function encodeSessionPolicyConfig(config) { - return encodeAbiParameters(sessionConfigParameters, [ - { - tokenLimits: (config.tokenLimits ?? []).map((t) => ({ - token: t.token, - limit: t.limit, - period: Number(t.period ?? 0n) - })), - callScopes: (config.callScopes ?? []).map((s) => ({ - target: s.target, - selectorRules: (s.selectorRules ?? []).map((r) => ({ - selector: r.selector, - recipients: r.recipients ?? [] - })) - })) - } - ]); -} -function encodeSessionPolicyAction(action) { - return encodeAbiParameters(sessionActionParameters, [ - { - target: action.target, - value: action.value ?? 0n, - data: action.data ?? "0x" - } - ]); -} - -// ../viem/src/_esm/eip8130/actions/getSessionSpend.js -async function getSessionSpend(client, parameters) { - const { commitment, tokenLimit, sessionPolicy = sessionPolicyAddress } = parameters; - const read = getAction(client, readContract, "readContract"); - const allowance = tokenLimit.limit; - const period = Number(tokenLimit.period ?? 0n); - const usage = await read({ - address: sessionPolicy, - abi: sessionPolicyAbi, - functionName: "getCurrentSpend", - args: [ - commitment, +var revokePayloadParameters = [{ name: "actorId", type: "bytes32" }]; +var lockPayloadParameters = [{ name: "unlockDelay", type: "uint16" }]; +function encodeChangePayload(change) { + if (change.changeType === changeType.authorizeActor) + return encodeAbiParameters(authorizePayloadParameters, [ + change.actorId, { - token: tokenLimit.token, - limit: tokenLimit.limit, - period - } - ] - }); - const spent = usage.spend; - const remaining = allowance > spent ? allowance - spent : 0n; - return { - allowance, - period, - spent, - remaining, - periodStart: usage.start, - periodEnd: usage.end - }; -} -// ../viem/src/_esm/eip8130/actions/getTransaction.js -async function getTransaction3(client, parameters) { - const { hash: hash3 } = parameters; - const raw = await client.request({ method: "eth_getTransactionByHash", params: [hash3] }); - if (!raw || raw.type !== aaTransactionType) - throw new Error(`getTransaction: expected type ${aaTransactionType} but got type ${raw?.type ?? "null"} for hash ${hash3}`); - const body = raw.tx; - return { - type: aaTransactionType, - hash: hash3, - from: raw.from ?? body.sender, - chainId: body.chainId, - nonceKey: body.nonceKey, - nonceSequence: body.nonceSequence, - validAfter: body.validAfter, - validBefore: body.validBefore, - maxFeePerGas: BigInt(body.maxFeePerGas), - maxPriorityFeePerGas: BigInt(body.maxPriorityFeePerGas), - gas: BigInt(body.gasLimit), - calls: body.calls, - accountChanges: body.accountChanges, - metadata: body.metadata, - payer: body.payer, - senderAuth: raw.senderAuth, - payerAuth: raw.payerAuth, - gasPrice: raw.gasPrice ? BigInt(raw.gasPrice) : null, - blockHash: raw.blockHash ?? null, - blockNumber: raw.blockNumber ? BigInt(raw.blockNumber) : null, - transactionIndex: raw.transactionIndex ? Number(raw.transactionIndex) : null - }; -} -// ../viem/src/_esm/eip8130/actions/getTransactionCount.js -init_fromHex(); -init_toHex(); -async function getTransactionCount3(client, parameters) { - const { address, nonceKey = 0n, blockNumber, blockTag = "pending" } = parameters; - if (nonceKey === nonceKeyMax) - throw new Error("nonceKey NONCE_KEY_MAX selects the expiring-nonce channel, which has no per-channel counter. Use an `expiry` instead of reading a sequence number."); - const block = blockNumber !== undefined ? numberToHex(blockNumber) : blockTag; - const params = nonceKey === 0n ? [address, block] : [address, block, numberToHex(nonceKey)]; - const count = await client.request({ method: "eth_getTransactionCount", params }); - return hexToBigInt(count); -} -// ../viem/src/_esm/eip8130/actions/getTransactionReceipt.js -function parseReceiptFields(receipt) { - if (!receipt) - return {}; - return { - payer: receipt.payer, - phaseStatuses: receipt.phaseStatuses, - metadata: receipt.metadata - }; -} -function allPhasesSucceeded(fields) { - const phases = fields.phaseStatuses; - if (!phases) - return true; - return phases.every((s) => s === "0x1" || s === "0x01"); -} -async function getTransactionReceipt3(client, parameters) { - const { hash: hash3 } = parameters; - const receipt = await client.request({ method: "eth_getTransactionReceipt", params: [hash3] }); - if (!receipt) - return null; - return { ...receipt, eip8130: parseReceiptFields(receipt) }; -} -// ../viem/src/_esm/eip8130/actions/isActor.js -async function isActor(client, parameters) { - const { account, actorId } = parameters; - const { authenticator } = await getActorConfig(client, { - account, - actorId - }); - return authenticator !== zeroAddress; -} -// ../viem/src/_esm/eip8130/actions/isLocked.js -async function isLocked(client, parameters) { - const { account } = parameters; - return readContract(client, { - address: keystoreAddress, - abi: keystoreAbi, - functionName: "isLocked", - args: [account] - }); + authenticator: change.authenticator, + expiry: Number(change.expiry ?? 0n), + scope: change.scope ?? 0 + }, + change.policyData ?? "0x" + ]); + if (change.changeType === changeType.revokeActor) + return encodeAbiParameters(revokePayloadParameters, [change.actorId]); + if (change.changeType === changeType.lock) + return encodeAbiParameters(lockPayloadParameters, [change.unlockDelay]); + return "0x"; } -// ../viem/src/_esm/eip8130/actions/sendTransaction.js -init_base(); -// ../viem/src/_esm/eip8130/errors.js +// ../viem/src/eip8130/utils/assertTransaction.ts init_base(); - -class NonceScopeError extends BaseError2 { - constructor({ scope, nonceKey }) { - super(`Restricted signing actor scope \`0x${scope.toString(16)}\` lacks \`SCOPE_NONCE\`, so it may only send nonce-free (expiring) transactions${nonceKey !== undefined ? ` — received \`nonceKey\` ${nonceKey}.` : "."}`, { - metaMessages: [ - "Only a restricted (non-admin) actor without the `SCOPE_NONCE` bit is confined to nonce-free mode; admin (scope 0) and `SCOPE_NONCE` actors may use ordered nonces too.", - "Omit `nonceKey` to let the library select the default nonce mode automatically, or pass `...nonce.nonceless({ expiresIn })` for nonce-free." - ] - }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "NonceScopeError" - }); - } -} - -class ScopeMismatchError extends BaseError2 { - constructor({ declared, onChain }) { - super(`Declared signing scope \`0x${declared.toString(16)}\` does not match on-chain actor scope \`0x${onChain.toString(16)}\`.`, { - metaMessages: [ - "Omit `scope` on the account handle and let prepare read `getActorConfig` — the chain is authoritative for nonce-mode selection.", - "If you pass `scope`, it must equal the authorized on-chain value." - ] - }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "ScopeMismatchError" - }); +init_chain(); +init_size(); +function assertTransaction(transaction) { + const { + accountChanges, + chainId, + nonceKey, + nonceSequence, + validBefore, + payer, + payerAuth + } = transaction; + if (chainId <= 0) + throw new InvalidChainIdError({ chainId }); + if (typeof nonceKey === "bigint" && nonceKey === nonceKeyMax) { + if (nonceSequence !== undefined && nonceSequence !== 0n) + throw new BaseError2("`nonceSequence` must be `0n` when `nonceKey` is `nonceKeyMax` (nonce-free mode)."); + if (!validBefore || validBefore === 0n) + throw new BaseError2("`validBefore` must be non-zero when `nonceKey` is `nonceKeyMax` (nonce-free mode)."); } -} - -class TransactionExpiredError extends BaseError2 { - constructor({ hash: hash3, validBefore, blockTimestamp }) { - super(`Transaction \`${hash3}\` expired before landing: \`validBefore\` ${validBefore} (unix ms) passed (latest block timestamp ${blockTimestamp}s).`, { - metaMessages: [ - "Nonce-free (expiring) transactions are only valid until their `validBefore`; once the block timestamp passes it the tx is dropped and can never be mined.", - "Resubmit with a fresh `validBefore` (e.g. `nonce.nonceless({ expiresIn })`)." - ] - }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "TransactionExpiredError" - }); + if (accountChanges && accountChanges.filter((entry) => entry.type === "delegation").length > 1) + throw new BaseError2("At most one `delegation` account change is allowed."); + if (!payer && payerAuth && payerAuth !== "0x") + throw new BaseError2("`payerAuth` must be empty for self-pay transactions (no `payer` set)."); + if (payer === openPayer && payerAuth && payerAuth !== "0x") { + if (size2(payerAuth) !== 65) + throw new BaseError2("`payerAuth` must be a raw 65-byte signature in open payer mode (`payer: openPayer`)."); } } -class ActorNotBoundError extends BaseError2 { - constructor({ account, actorId }) { - super(`Signing actor \`${actorId}\` is not bound on account \`${account}\`.`, { - metaMessages: [ - "Check actorId derivation (`key.k1` / `key.p256` / …) and that authorize used the same actorId + authenticator.", - "If the public RPC shows the actor bound but broadcast still fails, that is builder lag — not this error." - ] - }); - Object.defineProperty(this, "name", { - enumerable: true, - configurable: true, - writable: true, - value: "ActorNotBoundError" - }); - } +// ../viem/src/eip8130/utils/serializeTransaction.ts +function toCallsList(calls) { + return (calls ?? []).map((phase) => phase.map((call2) => [ + call2.to, + call2.value ? numberToHex(call2.value) : "0x", + call2.data ?? "0x" + ])); } - -// ../viem/src/_esm/eip8130/utils/encodeWalletCalls.js -init_encodeFunctionData(); -var defaultEncodeExecute = ({ account, calls }) => ({ - to: account, - data: encodeFunctionData({ - abi: erc4337AccountAbi, - functionName: "executeBatch", - args: [ - calls.map((call3) => ({ - target: call3.to, - value: call3.value, - data: call3.data - })) - ] - }) -}); -function encodeWalletCalls(parameters) { - const { account, calls, encodeExecute = defaultEncodeExecute } = parameters; - return calls.map((phase) => { - const hasValue = phase.some((call3) => call3.value && call3.value !== 0n); - if (!hasValue) - return phase.map((call3) => ({ to: call3.to, data: call3.data ?? "0x" })); - const normalized = phase.map((call3) => ({ - to: call3.to, - value: call3.value ?? 0n, - data: call3.data ?? "0x" - })); - return [encodeExecute({ account, calls: normalized })]; - }); +function toChange(change) { + return [ + change.changeType ? numberToHex(change.changeType) : "0x", + encodeChangePayload(change) + ]; } - -// ../viem/src/_esm/eip8130/actions/sendTransaction.js -async function resolveSigningScope(client, account) { - const { actorId, scope: declared } = account; - if (!actorId) - return declared; - const bound = await isActor(client, { - account: account.address, - actorId - }); - if (!bound) - return declared; - const { scope: onChain } = await getActorConfig(client, { - account: account.address, - actorId +function toAccountChangesList(accountChanges) { + return (accountChanges ?? []).map((entry) => { + if (entry.type === "create") + return [ + accountChangeType.create, + entry.userSalt, + entry.code, + entry.initialActors.map((actor) => [ + actor.actorId, + actor.authenticator, + actor.scope ? numberToHex(actor.scope) : "0x", + actor.policyData ?? "0x" + ]) + ]; + if (entry.type === "config") + return [ + accountChangeType.config, + entry.channel === "multichain" ? "0x01" : "0x", + entry.sequence ? numberToHex(entry.sequence) : "0x", + entry.changes.map(toChange), + entry.signature + ]; + return [accountChangeType.delegation, entry.target]; }); - if (declared !== undefined && declared !== onChain) - throw new ScopeMismatchError({ declared, onChain }); - return onChain; } -async function prepareTransactionRequest3(client, parameters) { - const { account, calls, accountChanges, payer, gas } = parameters; - const chainId = client.chain?.id; - if (!chainId) - throw new BaseError2("`client` must be configured with a `chain`."); - const dataSuffix = parameters.dataSuffix ?? (typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value); - const scope = await resolveSigningScope(client, account); - const noncelessOnly = scope !== undefined && isNoncelessOnly(scope); - let nonceKey = parameters.nonceKey; - if (noncelessOnly) { - if (nonceKey !== undefined && nonceKey !== nonceKeyMax) - throw new NonceScopeError({ scope, nonceKey }); - nonceKey = nonceKeyMax; - } else { - nonceKey ??= 0n; - } - let validBefore = parameters.validBefore; - let { maxFeePerGas, maxPriorityFeePerGas } = parameters; - if (maxFeePerGas === undefined || maxPriorityFeePerGas === undefined) { - const fees = await getAction(client, estimateFeesPerGas, "estimateFeesPerGas")({ chain: client.chain }); - maxFeePerGas ??= fees.maxFeePerGas; - maxPriorityFeePerGas ??= fees.maxPriorityFeePerGas; - } - let nonceSequence = parameters.nonceSequence; - if (nonceKey === nonceKeyMax) { - if (!validBefore || validBefore === 0n) - validBefore = (parameters.now ?? BigInt(Date.now())) + (parameters.expiryWindow ?? nonceFreeMaxExpiryWindow); - nonceSequence ??= 0n; - } else if (nonceSequence === undefined) { - nonceSequence = await getAction(client, getTransactionCount3, "getTransactionCount")({ address: account.address, nonceKey }); - } - return { +function toTransactionBody(transaction) { + const { chainId, - from: account.address, + from: from16, nonceKey, nonceSequence, - maxFeePerGas, + validAfter, + validBefore, maxPriorityFeePerGas, + maxFeePerGas, gas, - validBefore, - ...parameters.validAfter !== undefined ? { validAfter: parameters.validAfter } : {}, accountChanges, - calls, - ...dataSuffix ? { metadata: dataSuffix } : {}, - payer: payer?.address ?? payer?.account.address - }; + calls, + metadata + } = transaction; + return [ + numberToHex(chainId), + from16 ?? "0x", + nonceKey ? numberToHex(nonceKey) : "0x", + nonceSequence ? numberToHex(nonceSequence) : "0x", + validAfter ? numberToHex(validAfter) : "0x", + validBefore ? numberToHex(validBefore) : "0x", + maxPriorityFeePerGas ? numberToHex(maxPriorityFeePerGas) : "0x", + maxFeePerGas ? numberToHex(maxFeePerGas) : "0x", + gas ? numberToHex(gas) : "0x", + toAccountChangesList(accountChanges), + toCallsList(calls), + metadata ?? "0x" + ]; } -async function prepareAndSign(client, parameters) { - const { account, calls, payer, encodeExecute, onTransaction, ...rest } = parameters; - const transaction = await prepareTransactionRequest3(client, { - ...rest, - account, - calls: encodeWalletCalls({ - account: account.address, - calls: toPhases(calls), - encodeExecute - }), - payer - }); - onTransaction?.(transaction); - return account.signTransaction(transaction, { payer }); +function serializeTransaction4(transaction) { + assertTransaction(transaction); + const { payer, senderAuth, payerAuth } = transaction; + return concatHex([ + aaTransactionType, + toRlp([ + ...toTransactionBody(transaction), + payer ?? "0x", + senderAuth ?? "0x", + payerAuth ?? "0x" + ]) + ]); } -async function sendTransaction3(client, parameters) { - const serializedTransaction = await prepareAndSign(client, parameters); - return getAction(client, sendRawTransaction, "sendRawTransaction")({ serializedTransaction }); + +// ../viem/src/eip8130/utils/hashTransaction.ts +function getSenderSignatureHash(parameters) { + const { to = "hex", payer } = parameters; + const hash3 = keccak256(concatHex([ + aaTransactionType, + toRlp([...toTransactionBody(parameters), payer ?? "0x"]) + ])); + if (to === "bytes") + return hexToBytes(hash3); + return hash3; } -async function sendTransactionSync3(client, parameters) { - const { throwOnReceiptRevert, timeout, ...rest } = parameters; - const serializedTransaction = await prepareAndSign(client, rest); - const receipt = await getAction(client, sendRawTransactionSync, "sendRawTransactionSync")({ serializedTransaction, throwOnReceiptRevert, timeout }); - return { ...receipt, eip8130: parseReceiptFields(receipt) }; +function getPayerSignatureHash(parameters) { + const { to = "hex", payer } = parameters; + const hash3 = keccak256(concatHex([ + aaPayerType, + toRlp([...toTransactionBody(parameters), payer ?? "0x"]) + ])); + if (to === "bytes") + return hexToBytes(hash3); + return hash3; } -// ../viem/src/_esm/eip8130/actions/validateSignature.js -async function validateSignature(client, parameters) { - const { account, signature } = parameters; - const hash3 = parameters.hash ?? (parameters.message !== undefined ? hashMessage2(parameters.message) : hashTypedData2(parameters.typedData)); - try { - const [actorId, scope] = await readContract(client, { - address: keystoreAddress, - abi: keystoreAbi, - functionName: "validateSignature", - args: [account, hash3, signature] - }); - return { valid: true, actorId, scope }; - } catch { - return { - valid: false, - actorId: "0x0000000000000000000000000000000000000000000000000000000000000000", - scope: 0 - }; - } + +// ../viem/src/eip8130/utils/recoverSender.ts +async function recoverSenderAddress(parameters) { + const { transaction } = parameters; + if (transaction.from) + return transaction.from; + if (!transaction.senderAuth || transaction.senderAuth === "0x") + throw new Error("Cannot recover sender: transaction has neither `from` nor `senderAuth`."); + const hash3 = getSenderSignatureHash({ ...transaction, from: undefined }); + return recoverAddress({ hash: hash3, signature: transaction.senderAuth }); } -// ../viem/src/_esm/eip8130/actions/waitForTransactionReceipt.js -async function waitForTransactionReceipt3(client, parameters) { - const { hash: hash3, pollingInterval = 500, timeout = 60000 } = parameters; - const deadline = Date.now() + timeout; - const suppliedValidBefore = parameters.validBefore !== undefined && BigInt(parameters.validBefore) > 0n; - let validBefore = suppliedValidBefore ? BigInt(parameters.validBefore) : undefined; - while (Date.now() < deadline) { - const receipt = await getTransactionReceipt3(client, { hash: hash3 }); - if (receipt !== null) - return receipt; - if (validBefore === undefined) { - try { - const tx = await getTransaction3(client, { hash: hash3 }); - if (tx.validBefore > 0) - validBefore = BigInt(tx.validBefore); - } catch {} + +// ../viem/src/eip8130/utils/signTransaction.ts +async function signTransaction3(parameters) { + const { account, payer } = parameters; + const transaction = { ...parameters.transaction }; + if (!transaction.senderAuth) { + if (!account?.sign) + throw new BaseError2("A sender `account` with raw signing support, or a preset `transaction.senderAuth`, is required."); + const authenticator = parameters.authenticator ?? account.authenticator ?? k1Authenticator; + const senderHash = getSenderSignatureHash(transaction); + const signature = await account.sign({ hash: senderHash }); + transaction.senderAuth = transaction.from ? concatHex([authenticator, signature]) : signature; + } + if (payer && !transaction.payer) + transaction.payer = payer.address ?? payer.account.address; + if (transaction.payer && !transaction.payerAuth && payer) { + if (!payer.account.sign) + throw new BaseError2("A `payer` signer with raw signing support, or a preset `transaction.payerAuth`, is required for sponsored transactions."); + const from16 = transaction.from ?? account?.address ?? await recoverSenderAddress({ transaction }); + const openMode = transaction.payer === openPayer; + if (openMode) { + const authenticator = payer.authenticator ?? payer.account.authenticator; + if (authenticator && authenticator.toLowerCase() !== k1Authenticator) + throw new BaseError2(`Open payer mode requires a secp256k1 payer signer (the payer is recovered from a raw signature), but the payer uses authenticator ${authenticator}. Name the payer address instead.`); } - if (validBefore !== undefined) { - const blockTimestamp = await getLatestBlockTimestamp(client); - if (blockTimestamp !== undefined && blockTimestamp * 1000n > validBefore) - throw new TransactionExpiredError({ - hash: hash3, - validBefore, - blockTimestamp - }); + const payerHash = getPayerSignatureHash({ ...transaction, from: from16 }); + const signature = await payer.account.sign({ hash: payerHash }); + if (openMode) + transaction.payerAuth = signature; + else { + const authenticator = payer.authenticator ?? payer.account.authenticator ?? k1Authenticator; + transaction.payerAuth = concatHex([authenticator, signature]); } - await new Promise((resolve) => setTimeout(resolve, pollingInterval)); - } - throw new Error(`waitForTransactionReceipt: timed out after ${timeout}ms waiting for ${hash3}`); -} -async function getLatestBlockTimestamp(client) { - try { - const block = await client.request({ method: "eth_getBlockByNumber", params: ["latest", false] }); - return block?.timestamp ? BigInt(block.timestamp) : undefined; - } catch { - return; } + return serializeTransaction4(transaction); } -// ../viem/src/_esm/eip8130/capabilities.js -init_toHex(); -var supportedPermissionTypes = [ - "native-token-transfer", - "erc20-token-transfer", - "contract-call" -]; -var supportedPolicyTypes = ["token-allowance", "rate-limit"]; -var supportedSignerTypes = ["account", "key"]; -var supportedSubAccountKeyTypes = [ - "address", - "p256", - "webcrypto-p256", - "webauthn-p256" -]; -function eip8130Capabilities(parameters = {}) { - const { paymasterService, signerTypes = supportedSignerTypes, permissionTypes = supportedPermissionTypes, policyTypes = supportedPolicyTypes, subAccountKeyTypes = supportedSubAccountKeyTypes } = parameters; + +// ../viem/src/eip8130/accounts/toEoaAccount.ts +function toEoaAccount(signer) { + if (!signer.address) + throw new BaseError2("`signer.address` is required. Use `privateKeyToAccount(pk)` or equivalent."); + const address = signer.address; + const local = signer; + const publicKey = typeof local.publicKey === "string" ? local.publicKey : "0x"; return { - atomic: { status: "supported" }, - permissions: { - supported: true, - signerTypes, - permissionTypes, - policyTypes + address, + signer, + type: "local", + source: "eip8130", + publicKey, + async signMessage({ message }) { + if (!local.signMessage) + throw new BaseError2("`signer` does not support `signMessage`."); + return local.signMessage({ message }); }, - unstable_addSubAccount: { - supported: true, - keyTypes: subAccountKeyTypes + async signTypedData(typedData) { + if (!local.signTypedData) + throw new BaseError2("`signer` does not support `signTypedData`."); + return local.signTypedData(typedData); }, - ...paymasterService !== undefined ? { paymasterService: { supported: paymasterService } } : {} - }; -} -function eip8130CapabilitiesByChain(chainIds, parameters = {}) { - const capabilities = eip8130Capabilities(parameters); - const record = {}; - for (const chainId of chainIds) { - const key2 = typeof chainId === "number" ? numberToHex(chainId) : chainId; - record[key2] = capabilities; - } - return record; -} -// ../viem/src/_esm/eip8130/chainConfig.js -init_base(); -var eip8130ChainConfig = { - formatters: { - transactionReceipt: defineTransactionReceipt({ - format(receipt) { - return { - ...formatTransactionReceipt(receipt), - eip8130: parseReceiptFields(receipt) - }; - } - }) - }, - prepareTransactionRequest: [ - async (request, { client }) => { - const req = request; - if (req.account?.source !== "eip8130" || !req.calls) - return request; - if (req.payer) - throw new BaseError2("Sponsored EIP-8130 transactions are not supported through core `sendTransaction`. " + "Use `client.eip8130.sendTransaction` (local payer signer) or " + "`client.eip8168.sendTransaction` (ERC-8168 payer service)."); - const account = req.account; - const calls = encodeWalletCalls({ - account: account.address, - calls: toPhases(req.calls), - encodeExecute: req.encodeExecute - }); - const dataSuffix = req.metadata ?? req.dataSuffix ?? (typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value); - const gas = req.gas ?? await estimateGas3(client, { - sender: account.address, - accountChanges: req.accountChanges, - calls, - nonceKey: req.nonceKey, - senderActorId: req.senderActorId ?? account.actorId, - senderAuthAuthenticator: req.senderAuthAuthenticator, - dataSuffix - }); - const body = await prepareTransactionRequest3(client, { - account, - calls, - accountChanges: req.accountChanges, - gas, - nonceKey: req.nonceKey, - nonceSequence: req.nonceSequence, - validAfter: req.validAfter, - validBefore: req.validBefore, - maxFeePerGas: req.maxFeePerGas, - maxPriorityFeePerGas: req.maxPriorityFeePerGas, - dataSuffix - }); - return { - ...request, - ...body, - nonce: Number(body.nonceSequence) - }; + delegate(target) { + return { type: "delegation", target }; }, - { runAt: ["beforeFillTransaction"] } - ] -}; -// ../viem/src/_esm/eip8130/chains.js -var eip8130ChainIds = new Set; -function register8130Chains(...chainIds) { - for (const id of chainIds) - eip8130ChainIds.add(id); -} -function unregister8130Chains(...chainIds) { - for (const id of chainIds) - eip8130ChainIds.delete(id); -} -function is8130Enabled(chain, parameters = {}) { - const id = typeof chain === "number" ? chain : chain.id; - const set = parameters.chainIds ? parameters.chainIds instanceof Set ? parameters.chainIds : new Set(parameters.chainIds) : eip8130ChainIds; - return set.has(id); -} -// ../viem/src/_esm/eip8130/decorators/eip8130Actions.js -function eip8130Actions() { - return (client) => ({ - eip8130: { - sendTransaction: (parameters) => sendTransaction3(client, parameters), - sendTransactionSync: (parameters) => sendTransactionSync3(client, parameters), - prepareTransactionRequest: (parameters) => prepareTransactionRequest3(client, parameters), - estimateGas: (parameters) => estimateGas3(client, parameters), - waitForTransactionReceipt: (parameters) => waitForTransactionReceipt3(client, parameters), - getTransaction: (parameters) => getTransaction3(client, parameters), - getTransactionCount: (parameters) => getTransactionCount3(client, parameters), - getConfigSequence: (parameters) => getConfigSequence(client, parameters), - getActorConfig: (parameters) => getActorConfig(client, parameters), - getPolicy: (parameters) => getPolicy(client, parameters), - isActor: (parameters) => isActor(client, parameters), - isLocked: (parameters) => isLocked(client, parameters), - getLockStatus: (parameters) => getLockStatus(client, parameters), - getSessionSpend: (parameters) => getSessionSpend(client, parameters), - validateSignature: (parameters) => validateSignature(client, parameters) + async signTransaction(transaction, options = {}) { + if (!signer.sign) + throw new BaseError2("`signer` does not support raw signing."); + return signTransaction3({ + transaction, + account: signer, + authenticator: k1Authenticator, + payer: options.payer + }); } - }); -} -// ../viem/src/_esm/eip8130/lock.js -init_base(); -var maxUnlockDelay = 65535; -function lockChange(parameters) { - const { unlockDelay } = parameters; - if (!Number.isInteger(unlockDelay) || unlockDelay < 1 || unlockDelay > maxUnlockDelay) - throw new BaseError2(`\`unlockDelay\` must be an integer in \`1 … ${maxUnlockDelay}\` (uint16 seconds). Received ${unlockDelay}.`); - return { changeType: changeType.lock, unlockDelay }; -} -function unlockChange() { - return { changeType: changeType.unlock }; + }; } -// ../viem/src/_esm/eip8130/nonce.js +// ../viem/src/eip8130/actions/estimateGas.ts init_base(); init_fromHex(); init_toHex(); -var nonce = { - sequential() { - return { nonceKey: 0n }; - }, - channel(key2) { - if (key2 < 0n || key2 > nonceKeyMax) - throw new BaseError2(`\`nonceKey\` must be in \`0 … NONCE_KEY_MAX\`. Received ${key2}.`); - if (key2 === nonceKeyMax) - throw new BaseError2("`NONCE_KEY_MAX` selects nonce-free mode, which has no counter. Use `nonce.nonceless({ validBefore })` instead."); - return { nonceKey: key2 }; - }, - randomChannel() { - const buffer2 = new Uint8Array(32); - globalThis.crypto.getRandomValues(buffer2); - const key2 = hexToBigInt(bytesToHex(buffer2)) % (nonceKeyMax - 1n) + 1n; - return { nonceKey: key2 }; - }, - nonceless(parameters) { - const { validBefore, expiresIn } = parameters; - const resolvedValidBefore = validBefore ?? (expiresIn !== undefined ? BigInt(Date.now() + expiresIn * 1000) : undefined); - if (resolvedValidBefore === undefined || resolvedValidBefore <= 0n) - throw new BaseError2("Nonce-free mode requires a non-zero `validBefore` (or `expiresIn`)."); + +// ../viem/src/eip8130/utils/rpcAccountChanges.ts +init_fromHex(); +init_toHex(); +var changeTypeNames = { + [changeType.authorizeActor]: "AuthorizeActor", + [changeType.revokeActor]: "RevokeActor", + [changeType.incrementLocalEpoch]: "IncrementLocalEpoch", + [changeType.lock]: "Lock", + [changeType.unlock]: "Unlock" +}; +var channelByte = { local: 0, multichain: 1 }; +var changeTypeByName = Object.fromEntries(Object.entries(changeTypeNames).map(([op, name]) => [name, Number(op)])); +function toQuantity(typeByte) { + return numberToHex(typeof typeByte === "number" ? typeByte : hexToNumber(typeByte)); +} +function toRpcAccountChange(change) { + if (change.type === "delegation") return { - nonceKey: nonceKeyMax, - nonceSequence: 0n, - validBefore: resolvedValidBefore + type: toQuantity(accountChangeType.delegation), + target: change.target + }; + if (change.type === "create") + return { + type: toQuantity(accountChangeType.create), + userSalt: change.userSalt, + code: change.code, + initialActors: change.initialActors.map((actor) => ({ + actorId: actor.actorId, + authenticator: actor.authenticator, + scope: numberToHex(actor.scope ?? 0), + policyData: actor.policyData ?? "0x" + })) }; - }, - forScope(scope, parameters = {}) { - if (isNoncelessOnly(scope)) - return nonce.nonceless(parameters.validBefore !== undefined ? { validBefore: parameters.validBefore } : { - expiresIn: parameters.expiresIn ?? Number(nonceFreeMaxExpiryWindow) / 1000 - }); - return nonce.channel(parameters.key ?? 0n); - } -}; -// ../viem/src/_esm/eip8130/permissions.js -init_base(); -init_decodeAbiParameters(); -init_encodeAbiParameters(); -init_toFunctionSelector(); -var erc20TransferSelectors = [ - toFunctionSelector("transfer(address,uint256)"), - toFunctionSelector("transferFrom(address,address,uint256)") -]; -var selectorRegex = /^0x[0-9a-fA-F]{8}$/; -function toSelector(signatureOrSelector) { - if (selectorRegex.test(signatureOrSelector)) - return signatureOrSelector.toLowerCase(); - return toFunctionSelector(signatureOrSelector); -} -function spendFromPolicies(policies) { - let limit; - let period; - for (const policy of policies) { - if (typeof policy.type === "object") - throw new BaseError2("Cannot lower a custom ERC-7715 policy to a SessionPolicy. Build the `SessionPolicyConfig` explicitly."); - const type = policy.type; - switch (policy.type) { - case "token-allowance": - limit = policy.data.allowance; - break; - case "rate-limit": - period = BigInt(policy.data.interval); - break; - case "gas-limit": - break; - default: - throw new BaseError2(`Unsupported ERC-7715 policy type: "${type}".`); - } - } - return { limit, period }; -} -function toSessionPolicyConfig(permissions) { - const tokenLimits = []; - const callScopes = []; - for (const permission of permissions) { - if (typeof permission.type === "object") - throw new BaseError2("Cannot lower a custom ERC-7715 permission to a SessionPolicy. Build the `SessionPolicyConfig` explicitly."); - const type = permission.type; - switch (permission.type) { - case "native-token-transfer": { - const { limit, period } = spendFromPolicies(permission.policies); - if (limit === undefined) - throw new BaseError2("A `native-token-transfer` permission must include a `token-allowance` policy (an unbounded spend cannot be granted)."); - tokenLimits.push({ token: zeroAddress, limit, period }); - break; - } - case "erc20-token-transfer": { - const token2 = permission.data.address; - const { limit, period } = spendFromPolicies(permission.policies); - if (limit === undefined) - throw new BaseError2("An `erc20-token-transfer` permission must include a `token-allowance` policy (an unbounded spend cannot be granted)."); - tokenLimits.push({ token: token2, limit, period }); - callScopes.push({ - target: token2, - selectorRules: erc20TransferSelectors.map((selector) => ({ - selector - })) - }); - break; - } - case "contract-call": { - callScopes.push({ - target: permission.data.address, - selectorRules: permission.data.calls.map((call3) => ({ - selector: toSelector(call3) - })) - }); - break; - } - default: - throw new BaseError2(`Unsupported ERC-7715 permission type: "${type}".`); - } - } return { - tokenLimits: tokenLimits.length > 0 ? tokenLimits : undefined, - callScopes: callScopes.length > 0 ? callScopes : undefined + type: toQuantity(accountChangeType.config), + channel: toQuantity(channelByte[change.channel]), + sequence: numberToHex(change.sequence), + changes: change.changes.map((c) => ({ + changeType: toQuantity(c.changeType), + payload: encodeChangePayload(c) + })), + signature: change.signature }; } -function toSessionPolicy(parameters) { - const { permissions, expiry, ...rest } = parameters; - return defineSessionPolicy({ - ...rest, - policyConfig: encodeSessionPolicyConfig(toSessionPolicyConfig(permissions)), - validUntil: expiry === undefined ? undefined : BigInt(expiry) - }); + +// ../viem/src/eip8130/utils/toPhases.ts +function toPhases(calls) { + if (!calls || calls.length === 0) + return []; + if (Array.isArray(calls[0])) + return calls; + return [calls]; } -async function fulfillGrantPermissions(client, parameters) { - const { account, grantee, role = "session", permissions, expiry, assumeManagerRegistered = false, ...rest } = parameters; - const expiryBig = expiry === undefined ? undefined : BigInt(expiry); - const session = defineSessionPolicy({ - ...rest, - account, - policyConfig: encodeSessionPolicyConfig(toSessionPolicyConfig(permissions)), - validUntil: expiryBig - }); - const actor = role === "pull" ? key.externalPull(grantee) : key.k1(grantee); - const change = authorizeActor(actor, { - scope: actorScope.policy, - policy: session.actorPolicy, - expiry: expiryBig - }); - let managerChange; - if (!assumeManagerRegistered) { - const managerActor = key.k1(session.manager); - const { authenticator } = await getActorConfig(client, { - account, - actorId: managerActor.actorId - }); - const registered = authenticator.toLowerCase() === ecrecoverAuthenticator.toLowerCase(); - if (!registered) - managerChange = authorizeActor(managerActor, { - scope: actorScope.operator - }); + +// ../viem/src/eip8130/actions/estimateGas.ts +var maxAuthSize = 8192; +async function estimateGas2(client, parameters) { + const { + from: from16, + sender, + to, + data, + value, + senderAuth: senderAuthExplicit, + senderAuthAuthenticator, + senderAuthSize, + senderActorId, + accountChanges, + calls, + nonceKey = 0n, + validAfter, + validBefore, + payer, + payerAuth: payerAuthExplicit, + payerAuthAuthenticator, + payerAuthSize, + dataSuffix: dataSuffixParam, + blockNumber, + blockTag = "pending" + } = parameters; + const dataSuffix = dataSuffixParam ?? (typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value); + const account_ = sender ?? from16; + if (!account_) + throw new BaseError2("`sender` (or `from`) is required for an EIP-8130 gas estimate: the sender drives actor/policy resolution."); + if (sender && from16 && sender !== from16) + throw new BaseError2(`\`sender\` (${sender}) and \`from\` (${from16}) must agree when both are set.`); + for (const size7 of [senderAuthSize, payerAuthSize]) + if (size7 !== undefined && (size7 < 0 || size7 > maxAuthSize)) + throw new BaseError2(`auth size ${size7} out of range (0..=${maxAuthSize}).`); + const senderAuth = buildAuthBlob(senderAuthExplicit, senderAuthAuthenticator, senderAuthSize); + const payerAuth = payer === openPayer && payerAuthExplicit === undefined && payerAuthAuthenticator === undefined && payerAuthSize === undefined ? openPayerAuthStub : buildAuthBlob(payerAuthExplicit, payerAuthAuthenticator, payerAuthSize); + const useFullBody = accountChanges !== undefined || calls !== undefined; + const request = { + type: aaTransactionType, + sender: account_, + nonceKey: numberToHex(nonceKey) + }; + if (validAfter !== undefined) + request.validAfter = numberToHex(validAfter); + if (validBefore !== undefined) + request.validBefore = numberToHex(validBefore); + const phases = useFullBody ? calls !== undefined ? toPhases(calls) : [[{ to: account_, data: "0x" }]] : to !== undefined ? [[{ to, value, data }]] : undefined; + if (phases) + request.calls = phases.map((phase) => phase.map((c) => ({ + to: c.to, + value: numberToHex(c.value ?? 0n), + data: c.data ?? "0x" + }))); + if (useFullBody) { + request.accountChanges = (accountChanges ?? []).map(toRpcAccountChange); + request.metadata = dataSuffix ?? "0x"; + request.maxFeePerGas = numberToHex(1000000000n); + request.maxPriorityFeePerGas = numberToHex(1000000n); + } else if (dataSuffix !== undefined) + request.metadata = dataSuffix; + if (payer !== undefined) + request.payer = toRpcPayer(payer); + if (senderAuth !== undefined) + request.senderAuth = senderAuth; + if (payerAuth !== undefined) + request.payerAuth = payerAuth; + if (senderActorId !== undefined) + request.senderActorId = senderActorId; + const block = blockNumber !== undefined ? numberToHex(blockNumber) : blockTag; + const gas = await client.request({ method: "eth_estimateGas", params: [request, block] }); + return hexToBigInt(gas); +} +var openPayerAuthStub = "0xa0b37f8fba683cc68f6574cd43b39f0343a50008bf6ccea9d13231d9e7e2e1e411edc8d307254296264aebfc3dc76cd8b668373a072fd64665b50000e9fcce521c"; +function toRpcPayer(payer) { + return payer === openPayer ? zeroAddress : payer; +} +function buildAuthBlob(explicit, authenticator, size7) { + if (explicit !== undefined) + return explicit; + if (authenticator === undefined) { + if (size7 === undefined) + return; + return filler(size7); } - const changes = managerChange ? [managerChange, change] : [change]; - const permissionsContext = toPermissionsContext({ role, actor, session }); - return { actor, change, managerChange, changes, session, permissionsContext }; + const dataLength = size7 ?? (authenticator.toLowerCase() === k1Authenticator ? k1AuthDataLength : undefined); + if (dataLength === undefined) + throw new BaseError2(`No default auth-payload length is known for authenticator ${authenticator}. Pass an explicit auth size (see \`canonicalAuthDataLength\` in \`viem/experimental/keystore\`).`); + return concatHex([authenticator, filler(dataLength)]); +} +function filler(length) { + return `0x${"ff".repeat(length)}`; +} +// ../viem/src/eip8130/actions/getTransactionCount.ts +init_fromHex(); +init_toHex(); +async function getTransactionCount2(client, parameters) { + const { + address, + nonceKey = 0n, + blockNumber, + blockTag = "pending" + } = parameters; + if (nonceKey === nonceKeyMax) + throw new Error("nonceKey NONCE_KEY_MAX selects the expiring-nonce channel, which has no per-channel counter. Use an `expiry` instead of reading a sequence number."); + const block = blockNumber !== undefined ? numberToHex(blockNumber) : blockTag; + const params = nonceKey === 0n ? [address, block] : [address, block, numberToHex(nonceKey)]; + const count = await client.request({ method: "eth_getTransactionCount", params }); + return hexToBigInt(count); } -var grantRoleCode = { session: 0, pull: 1 }; -var grantRoleName = [ - "session", - "pull" -]; -var permissionsContextParameters = [ - { type: "address" }, - { type: "uint8" }, - { type: "bytes32" }, - { type: "address" }, - { type: "address" }, - { type: "address" }, - { type: "bytes" }, - { type: "uint40" }, - { type: "uint40" }, - { type: "uint256" } -]; -function toPermissionsContext(parameters) { - const { role, actor, session } = parameters; - const { binding } = session; - return encodeAbiParameters(permissionsContextParameters, [ - binding.account, - grantRoleCode[role], - actor.actorId, - actor.authenticator, - session.manager, - binding.policy, - binding.policyConfig, - Number(binding.validAfter), - Number(binding.validUntil), - binding.salt - ]); +// ../viem/src/eip8130/actions/getTransactionReceipt.ts +function parseReceiptFields(receipt) { + if (!receipt) + return {}; + return { + payer: receipt.payer, + phaseStatuses: receipt.phaseStatuses, + metadata: receipt.metadata + }; } -function parsePermissionsContext(context) { - const [account, roleCode, actorId, authenticator, manager, policy, policyConfig, validAfter, validUntil, salt] = decodeAbiParameters(permissionsContextParameters, context); - const role = grantRoleName[roleCode]; - if (!role) - throw new BaseError2(`Unknown permissionsContext role code: ${roleCode}.`); - const session = defineSessionPolicy({ - account, - policy, - manager, - policyConfig, - validAfter: BigInt(validAfter), - validUntil: BigInt(validUntil), - salt - }); - return { account, role, actor: { actorId, authenticator }, session }; +function allPhasesSucceeded(fields) { + const phases = fields.phaseStatuses; + if (!phases) + return true; + return phases.every((s) => s === "0x1" || s === "0x01"); } -function routePermissionedCalls(parameters) { - const { context, calls } = parameters; - const parsed = parsePermissionsContext(context); - const wrap3 = parsed.role === "pull" ? parsed.session.executeForCall : parsed.session.executeCall; - return { ...parsed, calls: calls.map((action) => wrap3(action)) }; +async function getTransactionReceipt2(client, parameters) { + const { hash: hash3 } = parameters; + const receipt = await client.request({ method: "eth_getTransactionReceipt", params: [hash3] }); + if (!receipt) + return null; + return { ...receipt, eip8130: parseReceiptFields(receipt) }; } -// ../viem/src/_esm/eip8130/subAccounts.js +// ../viem/src/eip8130/actions/sendTransaction.ts init_base(); -init_fromHex(); -init_toHex(); -function toKeyActor(k) { - switch (k.type) { - case "address": - return key.k1(k.publicKey); - case "p256": - case "webcrypto-p256": - return key.p256(k.publicKey); - case "webauthn-p256": - return key.webAuthn(k.publicKey); - default: - throw new BaseError2(`Unsupported sub-account key type: "${k.type}".`); - } -} -function randomBytes322() { - const buf = new Uint8Array(32); - globalThis.crypto.getRandomValues(buf); - return bytesToHex(buf); -} -function fulfillAddSubAccount(parameters) { - const { parent, signer, keys = [], keyScope, keyPolicy, proxy = "upgradeable", implementation } = parameters; - const parentActor = key.delegate(parent); - const restricted = keyScope !== undefined && keyScope !== scopeUnrestricted; - const keyActors = keys.map((k) => { - const actor = toKeyActor(k); - if (!restricted) - return actor; - return authorizeActor(actor, { - scope: keyScope, - ...keyPolicy ? { policy: keyPolicy } : {} - }); - }); - const initialActors = [parentActor, ...keyActors].sort((a, b) => { - const ai = hexToBigInt(a.actorId); - const bi = hexToBigInt(b.actorId); - return ai < bi ? -1 : ai > bi ? 1 : 0; - }); - for (let i = 1;i < initialActors.length; i++) - if (initialActors[i].actorId === initialActors[i - 1].actorId) - throw new BaseError2(`Duplicate initial actor id \`${initialActors[i].actorId}\` (parent delegate and requested keys must be distinct).`); - const salt = parameters.salt ?? randomBytes322(); - const code = parameters.code ?? (() => { - if (proxy === "erc1167") - return erc1167Bytecode(implementation ?? canonicalEip8130Deployment.accounts.default); - const impl = implementation ?? canonicalEip8130Deployment.accounts.upgradeable; - if (!impl) - throw new BaseError2("No canonical `CoinbaseSmartWalletV2` is deployed against the Keystore " + 'yet, so `proxy: "upgradeable"` requires an explicit `implementation`. ' + 'Pass `proxy: "erc1167"` for an immutable DefaultAccount-backed ' + "sub-account."); - return upgradeableProxyBytecode(impl); - })(); - const inner = toAccount3({ - signer, - userSalt: salt, - code, - initialActors, - authenticator: canonicalAuthenticators.delegate, - actorId: parentActor.actorId, - scope: scopeUnrestricted - }); +async function prepareTransactionRequest2(client, parameters) { + const { account, calls, accountChanges, payer, gas } = parameters; + const chainId = client.chain?.id; + if (!chainId) + throw new BaseError2("`client` must be configured with a `chain`."); + const dataSuffix = parameters.dataSuffix ?? (typeof client.dataSuffix === "string" ? client.dataSuffix : client.dataSuffix?.value); + const nonceKey = (account.resolveNonceKey ? await account.resolveNonceKey(client, { + nonceKey: parameters.nonceKey + }) : parameters.nonceKey) ?? 0n; + let validBefore = parameters.validBefore; + let { maxFeePerGas, maxPriorityFeePerGas } = parameters; + if (maxFeePerGas === undefined || maxPriorityFeePerGas === undefined) { + const fees = await getAction(client, estimateFeesPerGas, "estimateFeesPerGas")({ chain: client.chain }); + maxFeePerGas ??= fees.maxFeePerGas; + maxPriorityFeePerGas ??= fees.maxPriorityFeePerGas; + } + let nonceSequence = parameters.nonceSequence; + if (nonceKey === nonceKeyMax) { + if (!validBefore || validBefore === 0n) + validBefore = (parameters.now ?? BigInt(Date.now())) + (parameters.expiryWindow ?? nonceFreeDefaultExpiryWindow); + nonceSequence ??= 0n; + } else if (nonceSequence === undefined) { + nonceSequence = await getAction(client, getTransactionCount2, "getTransactionCount")({ address: account.address, nonceKey }); + } return { - ...inner, - createChange: inner.create(), - parentActor, - response: { address: inner.address } + chainId, + from: account.address, + nonceKey, + nonceSequence, + maxFeePerGas, + maxPriorityFeePerGas, + gas, + validBefore, + ...parameters.validAfter !== undefined ? { validAfter: parameters.validAfter } : {}, + accountChanges, + calls, + ...dataSuffix ? { metadata: dataSuffix } : {}, + payer: payer?.address ?? payer?.account.address }; } -// ../viem/src/_esm/eip8130/utils/parseTransaction.js -init_base(); -init_decodeAbiParameters(); -init_slice(); -init_fromHex(); - -// ../viem/src/_esm/utils/encoding/fromRlp.js -init_base(); -init_encoding(); -init_cursor2(); -init_toBytes(); -init_toHex(); -var rlpDepthLimit = 1024; -function fromRlp3(value, to = "hex") { - const bytes = (() => { - if (typeof value === "string") { - if (value.length > 3 && value.length % 2 !== 0) - throw new InvalidHexValueError(value); - return hexToBytes(value); - } - return value; - })(); - const cursor = createCursor(bytes, { - recursiveReadLimit: Number.POSITIVE_INFINITY +async function prepareAndSign(client, parameters) { + const { account, calls, payer, onTransaction, ...rest } = parameters; + const transaction = await prepareTransactionRequest2(client, { + ...rest, + account, + calls: toPhases(calls), + payer }); - const result = fromRlpCursor(cursor, to); - if (cursor.position < cursor.bytes.length) - throw new RlpTrailingBytesError({ - count: cursor.bytes.length - cursor.position - }); - return result; -} -function fromRlpCursor(cursor, to = "hex", recursiveDepth = 0) { - if (recursiveDepth >= rlpDepthLimit) - throw new RlpDepthLimitExceededError({ limit: rlpDepthLimit }); - if (cursor.bytes.length === 0) - return to === "hex" ? bytesToHex(cursor.bytes) : cursor.bytes; - const prefix = cursor.readByte(); - if (prefix < 128) - cursor.decrementPosition(1); - if (prefix < 192) { - const length2 = readLength(cursor, prefix, 128); - const bytes = cursor.readBytes(length2); - return to === "hex" ? bytesToHex(bytes) : bytes; - } - const length = readLength(cursor, prefix, 192); - return readList(cursor, length, to, recursiveDepth + 1); -} -function readLength(cursor, prefix, offset) { - if (offset === 128 && prefix < 128) - return 1; - if (prefix <= offset + 55) - return prefix - offset; - if (prefix === offset + 55 + 1) - return cursor.readUint8(); - if (prefix === offset + 55 + 2) - return cursor.readUint16(); - if (prefix === offset + 55 + 3) - return cursor.readUint24(); - if (prefix === offset + 55 + 4) - return cursor.readUint32(); - throw new BaseError2("Invalid RLP prefix"); -} -function readList(cursor, length, to, recursiveDepth) { - const position = cursor.position; - const value = []; - while (cursor.position - position < length) - value.push(fromRlpCursor(cursor, to, recursiveDepth)); - if (cursor.position - position !== length) - throw new RlpListBoundaryExceededError({ - consumed: cursor.position - position, - declared: length - }); - return value; -} - -// ../viem/src/_esm/eip8130/utils/parseTransaction.js -function toOptionalAddress(value) { - return value === "0x" ? undefined : value; -} -function toOptionalBigInt(value) { - return value === "0x" ? undefined : hexToBigInt(value); + onTransaction?.(transaction); + return account.signTransaction(transaction, { payer }); } -function parseCalls(value) { - const phases = value; - return phases.map((phase) => phase.map((call3) => { - const [to, data] = call3; - return { to, data: data === "0x" ? undefined : data }; - })); +async function sendTransaction(client, parameters) { + const serializedTransaction = await prepareAndSign(client, parameters); + return getAction(client, sendRawTransaction, "sendRawTransaction")({ serializedTransaction }); } -function parseActor(value) { - const [actorId, authenticator, scope, policyData] = value; - const actor = { actorId, authenticator }; - const scopeNum = !scope || scope === "0x" ? 0 : hexToNumber(scope); - if (scopeNum !== 0) - actor.scope = scopeNum; - if (policyData && policyData !== "0x") - actor.policyData = policyData; - return actor; -} -function parseChange(value) { - const [opByte, payload] = value; - const type = opByte === "0x" ? 0 : hexToNumber(opByte); - if (type === changeType.authorizeActor) { - const { actorId, authenticator, scope, expiry, policyData } = decodeAuthorizeActorPayload(payload); - const change = { - changeType: changeType.authorizeActor, - actorId, - authenticator - }; - if (scope !== 0) - change.scope = scope; - if (expiry !== 0n) - change.expiry = expiry; - if (policyData !== "0x") - change.policyData = policyData; - return change; - } - if (type === changeType.revokeActor) { - const [actorId] = decodeAbiParameters([{ type: "bytes32" }], payload); - return { changeType: changeType.revokeActor, actorId }; - } - if (type === changeType.lock) { - const [unlockDelay] = decodeAbiParameters([{ type: "uint16" }], payload); - return { changeType: changeType.lock, unlockDelay }; - } - if (type === changeType.unlock) - return { changeType: changeType.unlock }; - return { changeType: changeType.incrementLocalEpoch }; -} -function parseAccountChanges(value) { - const entries = value; - const result = []; - for (const entry of entries) { - const [type, ...body] = entry; - if (type === accountChangeType.create) { - const [userSalt, code, actors] = body; - result.push({ - type: "create", - userSalt, - code, - initialActors: actors.map(parseActor) +// ../viem/src/eip8168/client.ts +function payerClientFromRequest(request) { + return { + getTerms(params) { + return request({ + method: "payer_getTerms", + params: [params] }); - continue; - } - if (type === accountChangeType.config) { - const [channel, sequence, changes, signature] = body; - result.push({ - type: "config", - channel: channel === "0x01" ? "multichain" : "local", - sequence: sequence === "0x" ? 0n : hexToBigInt(sequence), - changes: changes.map(parseChange), - signature + }, + sendTransaction(params) { + return request({ + method: "payer_sendTransaction", + params: [params] + }); + }, + signTransaction(params) { + return request({ + method: "payer_signTransaction", + params: [params] + }); + }, + getSponsorshipBalance(params) { + return request({ + method: "payer_getSponsorshipBalance", + params: [params] }); - continue; - } - if (type === accountChangeType.delegation) { - const [target] = body; - result.push({ type: "delegation", target }); - continue; - } - throw new BaseError2(`Unknown account change entry type: "${type}".`); - } - return result; -} -function parseTransaction3(serialized) { - const type = sliceHex(serialized, 0, 1); - if (type !== aaTransactionType) - throw new BaseError2(`Serialized transaction type "${type}" is not an EIP-8130 transaction.`); - const fields = fromRlp3(sliceHex(serialized, 1), "hex"); - const [chainId, from16, nonceKey, nonceSequence, validAfter, validBefore, maxPriorityFeePerGas, maxFeePerGas, gas, accountChanges, calls, metadata, payer, senderAuth, payerAuth] = fields; - const transaction = { - chainId: hexToNumber(chainId) - }; - const fromAddress = toOptionalAddress(from16); - if (fromAddress) - transaction.from = fromAddress; - const nonceKeyValue = toOptionalBigInt(nonceKey); - if (nonceKeyValue !== undefined) - transaction.nonceKey = nonceKeyValue; - const nonceSequenceValue = toOptionalBigInt(nonceSequence); - if (nonceSequenceValue !== undefined) - transaction.nonceSequence = nonceSequenceValue; - const validAfterValue = toOptionalBigInt(validAfter); - if (validAfterValue !== undefined) - transaction.validAfter = validAfterValue; - const validBeforeValue = toOptionalBigInt(validBefore); - if (validBeforeValue !== undefined) - transaction.validBefore = validBeforeValue; - const maxPriorityFeePerGasValue = toOptionalBigInt(maxPriorityFeePerGas); - if (maxPriorityFeePerGasValue !== undefined) - transaction.maxPriorityFeePerGas = maxPriorityFeePerGasValue; - const maxFeePerGasValue = toOptionalBigInt(maxFeePerGas); - if (maxFeePerGasValue !== undefined) - transaction.maxFeePerGas = maxFeePerGasValue; - const gasValue = toOptionalBigInt(gas); - if (gasValue !== undefined) - transaction.gas = gasValue; - if (accountChanges.length > 0) - transaction.accountChanges = parseAccountChanges(accountChanges); - if (calls.length > 0) - transaction.calls = parseCalls(calls); - if (metadata !== "0x") - transaction.metadata = metadata; - const payerAddress = toOptionalAddress(payer); - if (payerAddress) - transaction.payer = payerAddress; - if (senderAuth !== "0x") - transaction.senderAuth = senderAuth; - if (payerAuth !== "0x") - transaction.payerAuth = payerAuth; - return transaction; -} -// ../viem/src/_esm/eip8130/utils/recoverSender.js -async function recoverSenderAddress(parameters) { - const { transaction } = parameters; - if (transaction.from) - return transaction.from; - if (!transaction.senderAuth || transaction.senderAuth === "0x") - throw new Error("Cannot recover sender: transaction has neither `from` nor `senderAuth`."); - const hash3 = getSenderSignatureHash({ ...transaction, from: undefined }); - return recoverAddress({ hash: hash3, signature: transaction.senderAuth }); -} -// ../viem/src/_esm/eip8130/utils/signedActorChangesSignature.js -init_encodeAbiParameters(); -init_toHex(); -init_keccak256(); -var signedActorChangesMagic = keccak256(stringToHex("ERC4337Account.signedActorChanges.v1")); -var signatureParameters = [ - { type: "bytes32" }, - { - type: "tuple[]", - components: [ - { - name: "changes", - type: "tuple[]", - components: [ - { name: "changeType", type: "uint8" }, - { name: "payload", type: "bytes" } - ] - }, - { name: "auth", type: "bytes" } - ] - }, - { name: "opAuth", type: "bytes" } -]; -function encodeSignedActorChangesSignature(changeSets, opAuth) { - return encodeAbiParameters(signatureParameters, [ - signedActorChangesMagic, - changeSets.map((set) => ({ - changes: set.changes.map((change) => ({ - changeType: change.changeType, - payload: encodeChangePayload(change) - })), - auth: set.auth - })), - opAuth - ]); -} -// ../viem/src/_esm/eip8130/utils/signers.js -init_encodeAbiParameters(); -init_size(); -init_slice(); -init_toHex(); -function publicKeyToXY(publicKey) { - if (typeof publicKey !== "string") - return publicKey; - const body = size2(publicKey) === 65 ? sliceHex(publicKey, 1) : publicKey; - if (size2(body) !== 64) - throw new Error("`publicKey` must be a 64-byte `x || y` hex (optionally 0x04-prefixed) or `{ x, y }`."); - return { x: sliceHex(body, 0, 32), y: sliceHex(body, 32, 64) }; -} -function toP256Signer(parameters) { - const { privateKey } = parameters; - const authenticator = parameters.authenticator ?? canonicalAuthenticators.p256; - const pub = getPublicKey({ privateKey }); - const x = numberToHex(pub.x, { size: 32 }); - const y = numberToHex(pub.y, { size: 32 }); - return { - address: parameters.address ?? zeroAddress, - authenticator, - publicKey: { x, y }, - async sign({ hash: hash3 }) { - const { r, s } = sign3({ payload: hash3, privateKey }); - return concatHex([ - numberToHex(r, { size: 32 }), - numberToHex(s, { size: 32 }), - x, - y, - "0x00" - ]); } }; } -var webAuthnAuthParameters = [ - { - type: "tuple", - components: [ - { name: "r", type: "bytes32" }, - { name: "s", type: "bytes32" }, - { name: "challengeIndex", type: "uint256" }, - { name: "typeIndex", type: "uint256" }, - { name: "authenticatorData", type: "bytes" }, - { name: "clientDataJSON", type: "string" } - ] - }, - { name: "x", type: "bytes32" }, - { name: "y", type: "bytes32" } -]; -function toWebAuthnSigner(source, parameters = {}) { - const authenticator = parameters.authenticator ?? canonicalAuthenticators.passkey; - const { x, y } = publicKeyToXY(source.publicKey); - return { - address: parameters.address ?? zeroAddress, - authenticator, - publicKey: { x, y }, - async sign({ hash: hash3 }) { - const { signature, webauthn } = await source.sign({ hash: hash3 }); - const r = sliceHex(signature, 0, 32); - const s = sliceHex(signature, 32, 64); - return encodeAbiParameters(webAuthnAuthParameters, [ - { - r, - s, - challengeIndex: BigInt(webauthn.challengeIndex), - typeIndex: BigInt(webauthn.typeIndex), - authenticatorData: webauthn.authenticatorData, - clientDataJSON: webauthn.clientDataJSON - }, - x, - y - ]); - } - }; +function createPayerClient(parameters) { + const { url, transport = http(url) } = parameters; + if (!url && !parameters.transport) + throw new Error("`url` or `transport` is required."); + const { request } = createClient({ + transport + }); + return payerClientFromRequest(request); } -// ../viem/src/_esm/eip8168/actions/sendSponsoredCalls.js -init_base(); -init_fromHex(); -init_toHex(); - -// ../viem/src/_esm/eip8168/utils/buildSponsoredCalls.js +// ../viem/src/eip8168/utils/buildSponsoredCalls.ts init_abis(); init_base(); init_encodeFunctionData(); -init_fromHex(); function encodeTokenTransfer(parameters) { return { to: parameters.token, @@ -24780,19 +18796,16 @@ function isDeclinedOffer(option) { function isSponsoredOffer(option) { return option.kind === "sponsored"; } -function isSelectableOffer(option) { - return isSponsoredOffer(option) || isTokenOffer(option); -} function selectPaymentOption(terms, parameters = {}) { - const { token: token2 } = parameters; + const { token } = parameters; const options = terms.options ?? []; const matchChoice = (offer) => { const choices = offer.tokens ?? []; - if (token2) - return choices.find((c) => c.token.toLowerCase() === token2.toLowerCase()); + if (token) + return choices.find((c) => c.token.toLowerCase() === token.toLowerCase()); return choices[0]; }; - if (token2) { + if (token) { for (const option of options) { if (!isTokenOffer(option)) continue; @@ -24800,7 +18813,7 @@ function selectPaymentOption(terms, parameters = {}) { if (tokenChoice) return { option, tokenChoice }; } - throw new BaseError2(`No token offer matches the requested token "${token2}".`); + throw new BaseError2(`No token offer matches the requested token "${token}".`); } const sponsored = options.find(isSponsoredOffer); if (sponsored) @@ -24814,58 +18827,7 @@ function selectPaymentOption(terms, parameters = {}) { } throw new BaseError2("Terms carry no selectable offer (only `sponsored_declined` entries, or an empty `options` array)."); } -function buildSponsoredCalls(parameters) { - const { terms, calls, token: token2 } = parameters; - const { option, tokenChoice } = selectPaymentOption(terms, { token: token2 }); - if (option.kind === "sponsored") - return { payer: option.payer, calls: [calls], option }; - if (!tokenChoice) - throw new BaseError2("Selected token offer resolved no `TokenChoice`."); - const feeRecipient = tokenChoice.feeRecipient ?? option.payer; - const paymentAmount = hexToBigInt(tokenChoice.paymentAmount); - const phase0 = [ - encodeTokenTransfer({ - token: tokenChoice.token, - to: feeRecipient, - amount: paymentAmount - }) - ]; - return { - payer: option.payer, - calls: [phase0, calls], - option, - tokenChoice, - feeRecipient, - paymentAmount - }; -} - -// ../viem/src/_esm/eip8168/constants.js -var payerRejectedCode = -32000; -var payerErrorCode = { - policyRejected: "POLICY_REJECTED", - senderIneligible: "SENDER_INELIGIBLE", - budgetExhausted: "BUDGET_EXHAUSTED", - senderLimitReached: "SENDER_LIMIT_REACHED", - gasExceedsLimit: "GAS_EXCEEDS_LIMIT", - temporarilyUnavailable: "TEMPORARILY_UNAVAILABLE", - invalidTransaction: "INVALID_TRANSACTION", - unsupportedToken: "UNSUPPORTED_TOKEN", - paymentInsufficient: "PAYMENT_INSUFFICIENT", - gasTooLow: "GAS_TOO_LOW", - expiryOutOfBounds: "EXPIRY_OUT_OF_BOUNDS", - payerBalanceInsufficient: "PAYER_BALANCE_INSUFFICIENT" -}; -var sponsorshipDeclineCode = { - policyRejected: "POLICY_REJECTED", - senderIneligible: "SENDER_INELIGIBLE", - budgetExhausted: "BUDGET_EXHAUSTED", - senderLimitReached: "SENDER_LIMIT_REACHED", - gasExceedsLimit: "GAS_EXCEEDS_LIMIT", - temporarilyUnavailable: "TEMPORARILY_UNAVAILABLE" -}; - -// ../viem/src/_esm/eip8168/utils/parsePayerError.js +// ../viem/src/eip8168/utils/parsePayerError.ts function parsePayerError(error) { const seen = new Set; let current = error; @@ -24881,328 +18843,37 @@ function parsePayerError(error) { } return; } - -// ../viem/src/_esm/eip8168/actions/sendSponsoredCalls.js -async function sendSponsoredCalls(client, parameters) { - const { account, payerClient, calls, accountChanges, mode = "send", token: token2, context, retries = 2, confirmRetry, onTransaction } = parameters; - const chainId = client.chain?.id; - if (!chainId) - throw new BaseError2("`client` must be configured with a `chain`."); - const terms = parameters.terms ?? await payerClient.getTerms({ - chainId: numberToHex(chainId), - from: account.address, - calls: calls.map((call3) => ({ to: call3.to, data: call3.data ?? "0x" })), - ...token2 ? { preferredTokens: [token2] } : {}, - ...context ? { context } : {} - }); - const built = buildSponsoredCalls({ terms, calls, token: token2 }); - const { option } = built; - if (mode === "sign" && !option.methods?.includes("payer_signTransaction")) - throw new BaseError2('Selected offer does not advertise `payer_signTransaction`; use `mode: "send"` or pick an offer whose `methods` includes it.'); - const gasEstimate = terms.gasEstimate; - const initialGas = parameters.gas ?? (gasEstimate ? hexToBigInt(gasEstimate.gasLimit) : undefined); - if (initialGas === undefined) - throw new BaseError2("Unable to determine `gas`: the terms carry no top-level `gasEstimate.gasLimit` and no `gas` override was provided."); - const maxFeePerGas = parameters.maxFeePerGas ?? (gasEstimate ? hexToBigInt(gasEstimate.maxFeePerGas) : undefined); - const maxPriorityFeePerGas = parameters.maxPriorityFeePerGas ?? (gasEstimate ? hexToBigInt(gasEstimate.maxPriorityFeePerGas) : undefined); - const maxGasLimit = option.conditions?.maxGasLimit ? hexToBigInt(option.conditions.maxGasLimit) : undefined; - const noncelessOnly = account.scope !== undefined && isNoncelessOnly(account.scope); - const computeValidBefore = () => { - if (parameters.validBefore !== undefined) - return parameters.validBefore; - if (noncelessOnly) - return BigInt(Date.now()) + nonceFreeMaxExpiryWindow; - const maxExpiry = option.conditions?.maxExpiry; - return maxExpiry !== undefined ? BigInt(Date.now()) + BigInt(maxExpiry) * 1000n : 0n; - }; - const transaction = await prepareTransactionRequest3(client, { - account, - calls: built.calls, - accountChanges, - gas: initialGas, - maxFeePerGas, - maxPriorityFeePerGas, - validBefore: computeValidBefore(), - nonceKey: parameters.nonceKey, - nonceSequence: parameters.nonceSequence - }); - transaction.payer = built.payer; - let phases = built.calls; - let gas = initialGas; - for (let attempt = 0;; attempt++) { - transaction.calls = phases; - transaction.gas = gas; - transaction.validBefore = computeValidBefore(); - transaction.payerAuth = "0x"; - onTransaction?.(transaction); - const signedTransaction = await account.signTransaction(transaction); - try { - if (mode === "sign") - return await payerClient.signTransaction({ signedTransaction, context }); - return await payerClient.sendTransaction({ signedTransaction, context }); - } catch (error) { - if (attempt >= retries) - throw error; - const rejected = parsePayerError(error); - if (!rejected) - throw error; - let request; - let nextPhases = phases; - let nextGas = gas; - if (rejected.code === "PAYMENT_INSUFFICIENT" && rejected.requote) { - const { token: t, paymentAmount, feeRecipient } = rejected.requote; - const to = feeRecipient ?? built.payer; - const amount = hexToBigInt(paymentAmount); - nextPhases = [[encodeTokenTransfer({ token: t, to, amount })], calls]; - request = { - kind: "requote", - reason: rejected, - attempt, - token: t, - paymentAmount: amount, - feeRecipient: to - }; - } else if (rejected.code === "GAS_TOO_LOW" && rejected.minGasLimit) { - const minGas = hexToBigInt(rejected.minGasLimit); - if (maxGasLimit !== undefined && minGas > maxGasLimit) - throw error; - if (minGas <= gas) - throw error; - nextGas = minGas; - request = { kind: "gas", reason: rejected, attempt, gasLimit: minGas }; - } - if (!request) - throw error; - const approved = confirmRetry ? await confirmRetry(request) : false; - if (!approved) - throw error; - phases = nextPhases; - gas = nextGas; - } - } -} -// ../viem/src/_esm/eip8168/client.js -function payerClientFromRequest(request) { - return { - getTerms(params) { - return request({ - method: "payer_getTerms", - params: [params] - }); - }, - sendTransaction(params) { - return request({ - method: "payer_sendTransaction", - params: [params] - }); - }, - signTransaction(params) { - return request({ - method: "payer_signTransaction", - params: [params] - }); - }, - getSponsorshipBalance(params) { - return request({ - method: "payer_getSponsorshipBalance", - params: [params] - }); - } - }; -} -function createPayerClient(parameters) { - const { url, transport = http(url) } = parameters; - if (!url && !parameters.transport) - throw new Error("`url` or `transport` is required."); - const { request } = createClient({ - transport - }); - return payerClientFromRequest(request); -} export { zeroAddress, - wrapSignatureEnvelope, - wrapCounterfactualSignature, - waitForTransactionReceipt3 as waitForTransactionReceipt, - vibenetDevnetDeployment, - validateSignature, - upgradeableProxyBytecode, - unsequencedLocalSequence, - unsequencedLocalHalf, - unregister8130Chains, - unlockChange, - txContextAddress, - trustedExecutorAuthenticator, - transactionContextAbi, - toWebAuthnSigner, - toWebAuthnAccount, - toTransactionBody, - toSmartAccount3 as toSmartAccount, - toSessionPolicyConfig, - toSessionPolicy, - toScope, - toPermissionsContext, - toP256Signer, + txValueCost, toHex, - toFactoryArgs, toEoaAccount, - toDelegateSigner, - toCallsList, - toAccountChangesList, - toAccount3 as toAccount, - supportedSubAccountKeyTypes, - supportedSignerTypes, - supportedPolicyTypes, - supportedPermissionTypes, - sponsorshipDeclineCode, - slice, - signedMessageTypehash, - signedActorChangesMagic, - signedAccountChangesTypehash, - signatureType, - signTypedDataEnvelope, - signTransaction5 as signTransaction, - signMessageEnvelope, - signAccountChanges, - sessionPolicyAddress, - sessionPolicyAbi, - serializeTransaction4 as serializeTransaction, - sendTransactionSync3 as sendTransactionSync, - sendTransaction3 as sendTransaction, - sendSponsoredCalls, + sendTransaction, selectPaymentOption, - scopeUnrestricted, - routePermissionedCalls, - revokedAuthenticator, - revokeActor, - replaySafeHash, - replayIdType, - replayBufferCapacity, - register8130Chains, - recoverSenderAddress, privateKeyToAccount, - prepareTransactionRequest3 as prepareTransactionRequest, - policyManagerAbi, - policyDataLength, - payerRejectedCode, - payerErrorCode, + prepareTransactionRequest2 as prepareTransactionRequest, parseUnits2 as parseUnits, - parseTransaction3 as parseTransaction, - parseSignatureEnvelope, parseReceiptFields, - parsePermissionsContext, parsePayerError, parseEther2 as parseEther, parseAbi, - nonceManagerAddress, - nonceManagerAbi, nonceKeyMax, - nonceKeyFirstUseCost, - nonceKeyExistingCost, - nonceFreeMaxExpiryWindow, - nonceFreeExpiryWindow, nonceFreeCost, - nonce, - newSmartAccount, - multichainId, - maxUnlockDelay, - maxCodeSize, - lockChange, - keystoreAddress, - keystoreAbi, - key, - keccak256, + k1Authenticator, + k1AuthCost, isTokenOffer, - isSponsoredOffer, - isSelectableOffer, - isNoncelessOnly, - isLocked, isDeclinedOffer, - isActor, - is8130Enabled, - incrementLocalEpoch, http, - hexToBigInt, - hashAccountChanges, - getTransactionReceipt3 as getTransactionReceipt, - getTransactionCount3 as getTransactionCount, - getTransaction3 as getTransaction, - getSignatureEnvelopeHash, - getSessionSpend, - getSenderSignatureHash, - getPolicy, - getPayerSignatureHash, - getLockStatus, - getEip8130Deployment, - getConfigSequence, - getActorConfig, + getTransactionReceipt2 as getTransactionReceipt, + getTransactionCount2 as getTransactionCount, generatePrivateKey, - fulfillGrantPermissions, - fulfillAddSubAccount, - formatEther2 as formatEther, - externalPolicyAuthenticator, - estimateGas3 as estimateGas, - erc4337AccountAbi, - erc1167Bytecode, - entryPoint07Address, - entryPoint07Abi, - encodeWalletCalls, + estimateGas2 as estimateGas, encodeTokenTransfer, - encodeSignedActorChangesSignature, - encodeSessionPolicyConfig, - encodeSessionPolicyAction, - encodePolicyData, encodeFunctionData, - encodeCreateAccountData, - encodeChangePayload, - encodeApplySignedAccountChangesData, encodeAbiParameters, - eip8130Deployments, - eip8130ChainIds, - eip8130ChainConfig, - eip8130CapabilitiesByChain, - eip8130Capabilities, - eip8130Actions, - ecrecoverAuthenticator, - deploymentHeaderSize, - deploymentHeader, - delegateAuthSize, - defineSessionPolicy, - defaultEncodeExecute, - defaultAccountAddress, - decodeAuthorizeActorPayload, + delegationCost, decodeAbiParameters, - custom, - createWebAuthnCredential, - createWalletClient, createPublicClient, createPayerClient, - createBundlerClient, - concatHex, - computeAddress, - commitmentOf, - changeType, - canonicalEip8130Deployment, - canonicalAuthenticators, - canonicalAuthDataLength, - canUseSequencedNonce, - buildSponsoredCalls, - baseSepoliaDeployment, - authorizeActor, - authenticatorAbi, - assertTransaction, - allPhasesSucceeded, - actorScope, - actorIdFromPublicKey, - actorIdFromAddress, - accountStateFlags, - accountChangeTypehash, - accountChangeType, - aaTransactionType, - aaPayerType, - aaBaseCost, - TransactionExpiredError, - ScopeMismatchError, - NonceScopeError, - ActorNotBoundError + allPhasesSucceeded }; From b1ccd7bcb74754bcd15a9a7e13477d0099fedc8d Mon Sep 17 00:00:00 2001 From: Chris Hunter Date: Tue, 29 Sep 2026 20:02:23 -0400 Subject: [PATCH 2/6] feat(vibenet): EOA-only account engine with optional code delegation Accounts are secp256k1 EOAs. The engine composes phased calls with an optional delegation change, nonce-free sends and an ERC-8168 payer (token payment priced from the offer rate), and reads the current delegation from eth_getCode. Legacy Keystore-era records are dropped on load. --- app/vibenet/demos/account/library/apps.ts | 41 - app/vibenet/demos/account/library/calls.ts | 22 +- app/vibenet/demos/account/library/chains.ts | 328 +-- .../demos/account/library/delegation.ts | 16 + app/vibenet/demos/account/library/derive.ts | 50 - .../demos/account/library/model.test.ts | 59 + app/vibenet/demos/account/library/model.ts | 377 +-- .../demos/account/library/payer.test.ts | 46 + app/vibenet/demos/account/library/payer.ts | 33 + app/vibenet/demos/account/library/policy.ts | 233 -- app/vibenet/demos/account/shared.ts | 27 +- .../demos/account/useAccountEngine.tsx | 2053 +++-------------- app/vibenet/demos/account/useAccounts.ts | 32 +- 13 files changed, 603 insertions(+), 2714 deletions(-) delete mode 100644 app/vibenet/demos/account/library/apps.ts create mode 100644 app/vibenet/demos/account/library/delegation.ts delete mode 100644 app/vibenet/demos/account/library/derive.ts create mode 100644 app/vibenet/demos/account/library/model.test.ts create mode 100644 app/vibenet/demos/account/library/payer.test.ts create mode 100644 app/vibenet/demos/account/library/payer.ts delete mode 100644 app/vibenet/demos/account/library/policy.ts diff --git a/app/vibenet/demos/account/library/apps.ts b/app/vibenet/demos/account/library/apps.ts deleted file mode 100644 index 28a07f52..00000000 --- a/app/vibenet/demos/account/library/apps.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Demo apps directory. Each app connects to the active account through a scoped -// grant it fully controls: a capped session key (subscriptions) or a delegated -// sub-account. Ported from base/vibenet `account/page.tsx` DEMO_APPS. The -// "Vibe'n" mini-game is intentionally omitted (it was unlisted upstream). - -import type { Address } from '@aa'; - -import type { PolicySpec } from './policy'; - -export type DemoApp = { - id: string; - name: string; - emoji: string; - grant: 'session' | 'subaccount'; - desc: string; - /** For session apps: how long the grant lives + its policy summary. */ - expiryId?: string; - policyLabel?: string; - /** Build the app's SessionPolicy spec (account address available for self-targets). */ - spec?: (account: Address) => PolicySpec; -}; - -export const DEMO_APPS: DemoApp[] = [ - { - id: 'monthly-vibes', - name: 'Subscriptions', - emoji: '🎧', - grant: 'session', - expiryId: 'none', - policyLabel: 'Spend limit', - spec: () => ({ limits: [{ token: 'stable', amount: '1', periodSecs: 30 }] }), - desc: 'An app that bills from a capped session key — at most 1 USDV every 30s, and only via the USDV transfer. No re-signing each cycle; cancel by revoking the key.', - }, - { - id: 'spending-account', - name: 'Spending Account', - emoji: '💳', - grant: 'subaccount', - desc: 'A separate account you also own — added with your main account as one owner and a fresh spare key as another. Spend from it day-to-day without risking the funds in your main account.', - }, -]; diff --git a/app/vibenet/demos/account/library/calls.ts b/app/vibenet/demos/account/library/calls.ts index 5875befd..067752ff 100644 --- a/app/vibenet/demos/account/library/calls.ts +++ b/app/vibenet/demos/account/library/calls.ts @@ -59,25 +59,27 @@ export function buildPhases(rows: CallRow[], fallback: Address) { return { phase0, phase1 }; } -/** Flat list of all calls regardless of phase (used for the ERC-4337 / payer path). */ +/** Flat list of all calls regardless of phase (the payer's `payer_getTerms` intent). */ export function buildCalls(rows: CallRow[], fallback: Address) { return rows.map((r) => rowToCall(r, fallback)); } /** - * Count call rows that transfer a non-zero native ETH value. Each such inner - * CALL needs the ~9k value-transfer surcharge (G_callvalue) and, for a - * not-yet-existent recipient, the ~25k new-account creation cost (G_newaccount) - * — gas the node's EIP-8130 `eth_estimateGas` - * omits (a phase whose inner CALL OOGs is still a valid inclusion, so the - * estimator converges below what the transfer actually needs to SUCCEED). The - * structural floor budgets these via `estimateTxGas`'s `valueCalls`. Rows whose - * value is empty, zero, or unparseable count as non-value-bearing. + * Count call rows that transfer a non-zero native ETH value to someone other + * than the sender. Each pays the intrinsic `TX_VALUE_COST`, and a transfer to a + * not-yet-existent recipient also pays the new-account creation cost, which the + * node's estimate can miss (a phase whose inner CALL OOGs is still a valid + * inclusion). The structural floor budgets these via `estimateTxGas`'s + * `valueCalls`. Rows whose value is empty, zero, or unparseable count as + * non-value-bearing; rows with an empty `to` default to the sender. */ -export function valueBearingCallCount(rows: CallRow[]): number { +export function valueBearingCallCount(rows: CallRow[], sender?: string): number { + const self = sender?.toLowerCase(); return rows.reduce((n, r) => { const v = r.value.trim(); if (!v) return n; + const to = r.to.trim().toLowerCase(); + if (self && (!to || to === self)) return n; try { return parseEther(v) > 0n ? n + 1 : n; } catch { diff --git a/app/vibenet/demos/account/library/chains.ts b/app/vibenet/demos/account/library/chains.ts index 420c546f..9205e1f9 100644 --- a/app/vibenet/demos/account/library/chains.ts +++ b/app/vibenet/demos/account/library/chains.ts @@ -1,115 +1,15 @@ -import { - type Address, - baseSepoliaDeployment, - type Eip8130Deployment, - vibenetDevnetDeployment, -} from "@aa"; +import { delegationCost, k1AuthCost, nonceFreeCost, txValueCost } from "@aa"; -import { isAddress } from "../../../library/format"; +// omni-ui has no account backend of its own; the payer resolves to vibenet's +// cross-origin route (see library/config.ts). +import { ACCOUNT_PAYER_URL } from "../../../library/config"; /** - * Last-known-good vibenet EIP-8130 system contracts — a STATIC FALLBACK only. - * - * vibenet is ephemeral: a reset redeploys the enshrined system contracts, and - * several land at NEW addresses (DefaultAccount, high-rate payer, - * DelegateAuthenticator, PolicyManager, SessionPolicy). The keystore - * (`keystoreAddress`) itself is fixed/enshrined and not part of this record — - * see `@aa`'s `keystoreAddress`. The account address is a CREATE2 of - * `keccak(0xff ‖ keystoreAddress ‖ salt ‖ keccak(proxyCode→DefaultAccount))`, - * so with stale addresses the client derives a `from` the node can't - * reproduce → "EIP-8130 validation failed: create address does not match the - * sender". - * - * Rather than re-hardcode after every reset, the demo resolves these at runtime - * from https://api.vibes.base.org/api/vibenet/contracts via {@link deploymentFromContracts}. - * This constant is used only until that fetch lands (or if it fails). The K1 - * authenticator (ecrecover precompile) and p256/webAuthn/alwaysValid - * authenticators are deterministic across resets; `accounts.upgradeable`/ - * `accounts.erc4337` are not deployed on the native vibenet path (unused here). - */ -const VIBENET_DEPLOYMENT = { - ...vibenetDevnetDeployment, - accounts: { - ...vibenetDevnetDeployment.accounts, - default: "0x813078f98b3eb214046C8Dc93A771ac9de5AaDEf", - defaultHighRate: "0x8130931874c894aC4963e128D6273AE520dAFa57", - }, - authenticators: { - ...vibenetDevnetDeployment.authenticators, - p256: "0x8130C89F65750431b564A4730397552a11CeA256", - webAuthn: "0x813007b6b1b48E75D91dEc5927ab515d12a0F1d0", - delegate: "0x8130b7D430D041ED4050935814D493299980aDE1", - }, - policies: { - manager: "0x813077055d1110F92191ccE13018f51820B40ac1", - sessionPolicy: "0x813070914C530d030f4Efd8Fa99C18e836435e55", - }, -} satisfies Eip8130Deployment; - -/** - * Build an {@link Eip8130Deployment} from the live `/api/vibenet/contracts` - * `eip8130` block so a devnet reset never requires a code change — the demo just - * refetches. Falls back to {@link VIBENET_DEPLOYMENT} per field for anything the - * API omits (K1 precompile; `upgradeable`/`erc4337`, unused on the native path), - * and returns `null` when the payload lacks the core address-derivation - * contracts (Keystore/AccountConfiguration + DefaultAccount) so callers keep the - * static set. The keystore address is validated but not stored — it's fixed - * upstream and no longer part of {@link Eip8130Deployment}. - */ -export function deploymentFromContracts( - contracts: Record | null | undefined, -): Eip8130Deployment | null { - const eip8130 = (contracts as { eip8130?: Record } | null) - ?.eip8130; - if (!eip8130 || typeof eip8130 !== "object") return null; - - // The AccountConfiguration contract was renamed `Keystore` upstream; accept - // either key so the resolver survives both the old and new payload shapes. - const keystore = eip8130.Keystore ?? eip8130.AccountConfiguration; - - // Core derivation inputs — without both, the live payload is unusable. - if (!isAddress(keystore) || !isAddress(eip8130.DefaultAccount)) return null; - - // Valid address by API key, else the static fallback. - const addr = (key: string, fallback: Address): Address => - isAddress(eip8130[key]) ? (eip8130[key] as Address) : fallback; - - const fb = VIBENET_DEPLOYMENT; - return { - accounts: { - upgradeable: fb.accounts.upgradeable, // not deployed on native vibenet - default: eip8130.DefaultAccount as Address, - defaultHighRate: addr("CanonicalHighRatePayerAccount", fb.accounts.defaultHighRate), - erc4337: fb.accounts.erc4337, // ERC-4337 path is Base Sepolia only - }, - authenticators: { - k1: fb.authenticators.k1, // ecrecover precompile — constant across resets - p256: addr("P256Authenticator", fb.authenticators.p256), - webAuthn: addr("WebAuthnAuthenticator", fb.authenticators.webAuthn), - delegate: addr("DelegateAuthenticator", fb.authenticators.delegate), - alwaysValid: addr("AlwaysValidAuthenticator", fb.authenticators.alwaysValid), - }, - policies: { - manager: addr("PolicyManager", fb.policies.manager), - sessionPolicy: addr("SessionPolicy", fb.policies.sessionPolicy), - }, - }; -} - -// omni-ui has no account backend of its own; these resolve to vibenet's -// cross-origin routes (see library/config.ts). Ported from same-origin paths. -import { - ACCOUNT_BUNDLER_URL, - ACCOUNT_PAYER_URL, -} from "../../../library/config"; - -/** - * How EIP-8130 accounts execute on a given chain: - * - `erc4337` — portable path via the ERC-4337 EntryPoint (works today). - * - `eip8130-native` — first-class `AA_TX_TYPE` transactions (once a chain ships - * EIP-8130 natively). The same account address works on both. + * How EIP-8130 accounts execute on a given chain. Only first-class + * `AA_TX_TYPE` transactions are supported now that the Keystore (and with it + * the ERC-4337 path through smart accounts) is disabled. */ -export type AaMode = "erc4337" | "eip8130-native"; +export type AaMode = "eip8130-native"; export type DemoChain = { id: number; @@ -120,34 +20,17 @@ export type DemoChain = { status: "live" | "preview"; rpcUrl?: string; blockExplorer?: string; - /** EIP-8130 system contracts used for address derivation + execution. */ - deployment: Eip8130Deployment; tagline: string; }; -export const BASE_SEPOLIA: DemoChain = { - id: 84532, - name: "Base Sepolia", - shortName: "base-sepolia", - mode: "erc4337", - status: "live", - rpcUrl: "https://sepolia.base.org", - blockExplorer: "https://sepolia.basescan.org", - deployment: baseSepoliaDeployment, - tagline: "ERC-4337 today. Live system contracts deployed.", -}; - export const VIBENET: DemoChain = { - // Base "vibenet" devnet running native EIP-8130 (Cobalt). Native AA_TX_TYPE - // flows (create, owner change, EOA delegation) are verified end-to-end here. + // Base "vibenet" devnet running native EIP-8130 (Cobalt) with the Keystore + // disabled: senders are secp256k1 EOAs with optional code delegation. id: 84538453, name: "Vibenet", shortName: "vibenet", mode: "eip8130-native", status: "preview", - // Enshrined 8130 system contracts as derived by the devnet execution client. - // vibenet is ephemeral — see VIBENET_DEPLOYMENT for the post-reset addresses. - deployment: VIBENET_DEPLOYMENT, tagline: "Native AA_TX_TYPE. First-class account abstraction transactions.", }; @@ -158,187 +41,76 @@ export function getDemoChain(shortName: string): DemoChain { } /** - * Canonical EIP-8130 system contracts. These deploy to the same addresses on - * every chain (deterministic deployment), which is exactly why an account's - * address is identical everywhere — derived from key(s) + salt + this config, - * never from a per-chain factory. - */ -export const CANON_DEPLOYMENT = baseSepoliaDeployment; - -export type DeployEstimate = { - /** Estimated gas to deploy the account + run one no-op call. */ - gas: number; - /** Rough end-to-end inclusion latency (ms) for a fresh account. */ - latencyMs: number; - /** Path the transaction takes to reach the chain. */ - path: string; -}; - -/** - * Illustrative deploy+call estimates. Not measured onchain — they model the - * structural difference between the two execution paths: - * - * - ERC-4337: a UserOperation is relayed wallet → bundler → EntryPoint, which - * adds per-op verification overhead, EntryPoint accounting, and large - * calldata, plus a bundler round-trip before inclusion. - * - Native EIP-8130: the account-abstraction transaction is a first-class tx - * type — no EntryPoint, no bundler hop, account creation handled inline. - */ -export function estimateDeployAndCall(mode: AaMode): DeployEstimate { - if (mode === "eip8130-native") - return { gas: 172_000, latencyMs: 2_000, path: "direct inclusion" }; - return { - gas: 286_000, - latencyMs: 6_000, - path: "wallet → bundler → EntryPoint", - }; -} - -export function pctCheaper(from: DeployEstimate, to: DeployEstimate): number { - return Math.round(((from.gas - to.gas) / from.gas) * 100); -} - -/** - * Structural gas floor for a single composed transaction. + * Structural gas floor for a single composed EOA transaction. * * This is NOT the expected gas usage — it's a conservative safe *minimum* used * as a fallback (when the node can't run `eth_estimateGas`) and as a floor * under {@link safeGasLimit} so a pathological node under-estimate (an inner * CALL that OOGs is still a valid 8130 inclusion) can't under-provision a tx. * - * The native constants are calibrated from observed on-chain usage on the - * vibenet devnet — with headroom, but no longer the 2–6× over-provisioning the - * old values produced: - * - a 2-call non-deploy native tx used ~34k gas - * - the account `create()` on first use added ~100k on top - * so base ≈ 20k, per-call ≈ 10k, deploy ≈ 100k in practice. We pad each ~1.3× - * to keep the floor safely above reality (per-call keeps extra headroom for a - * value-bearing inner CALL's 9k stipend, which the node estimate can miss). + * Calibrated from observed vibenet usage (a 2-call native tx used ~34k gas), + * padded ~1.3×. The protocol dispatches each call natively from the sender, so + * there is no account-contract routing overhead. */ export function estimateTxGas(params: { - mode: AaMode; - deploy: boolean; calls: number; - keyChanges: number; - // Number of calls routed through a PolicyManager (session-key sends). Each - // adds the PolicyManager.execute frame, policy validation, spend-tracking - // SSTOREs, and the callback into executeBatch on top of the inner call. - policyCalls?: number; - // Number of calls that transfer a non-zero native ETH value. Each needs the - // ~9k value stipend plus (for a not-yet-existent recipient) the ~25k - // new-account creation cost. The node's `eth_estimateGas` misses this — it - // converges to the tx-envelope cost, ignoring that the inner value transfer - // must actually succeed — so the floor must carry it or a send to a cold - // recipient OOG-reverts on-chain (unused gas is refunded, an OOG is not). + // Calls with a non-zero native value to someone other than the sender. Each + // pays the intrinsic TX_VALUE_COST, plus headroom for creating a cold + // recipient (G_newaccount) that the node estimate can miss. valueCalls?: number; + // A `delegation` account change (set or clear EIP-7702-style code). + delegation?: boolean; + // Nonce-free mode prices the replay ring buffer instead of a nonce slot. + nonceless?: boolean; + // A sponsoring payer adds its own K1 authentication. + payer?: boolean; + // A phase-0 ERC-20 transfer paying the payer (balance SSTOREs on top of the call). + tokenPayment?: boolean; // When true, this value is the SOLE gas source (the node's `eth_estimateGas` - // is unavailable, reverted, or the user chose "Send anyway"), so it is scaled - // up by {@link FALLBACK_SAFETY} to over-provision on purpose — unused gas is - // refunded, whereas an under-estimate causes an on-chain OOG revert. When - // false (the default) it is used only as a *floor* beneath a successful node - // estimate, so it must stay realistic-with-headroom or it would swamp the - // node's accurate estimate and permanently over-price every transaction. + // is unavailable or the user chose "Send anyway"), so it is doubled to + // over-provision on purpose — unused gas is refunded, whereas an + // under-estimate causes an on-chain OOG revert. When false (the default) it + // is only a *floor* beneath a successful node estimate and must stay + // realistic or it would permanently over-price every transaction. fallback?: boolean; }): number { const { - mode, - deploy, calls, - keyChanges, - policyCalls = 0, valueCalls = 0, + delegation = false, + nonceless = false, + payer = false, + tokenPayment = false, fallback = false, } = params; - // ERC-4337: EntryPoint overhead (unchanged — different execution path). - // EIP-8130 native: base covers intrinsic gas for authenticator dispatch, - // AccountConfiguration lookup, and RLP calldata. - const base = mode === "erc4337" ? 60_000 : 45_000; - // Native deploy covers account `create()` execution plus the AccountConfiguration - // setup the node charges as intrinsic. Kept generous: when a tx bundles staged - // config changes + a policy install, the node's `eth_estimateGas` can't - // simulate it and throws, so this structural floor is the ONLY gas source and - // must stay above the tx's real intrinsic (unused gas is refunded anyway). - const deployCost = deploy ? (mode === "erc4337" ? 250_000 : 160_000) : 0; - const perCall = mode === "erc4337" ? 30_000 : 22_000; - const perKeyChange = 26_000; - const wrap = calls > 1 ? 9_000 : 0; // executeBatch routing - // A policy-gated session call detours through PolicyManager.execute, which - // decodes + validates the binding, updates spend tracking (cold SSTORE on - // first use), and calls back into executeBatch. Budget generously: a - // successful transfer's storage writes cost well beyond a bare call, and the - // node's estimate can be low when the simulated inner call reverts (an 8130 - // reverting phase is still a valid inclusion), so the floor is the backstop. - const perPolicyCall = 55_000; - // Headroom for a value-bearing inner CALL the node estimate can't see: the 9k - // value-transfer surcharge (G_callvalue, which itself includes the 2,300 callee - // stipend) + 25k creation of a cold recipient account (G_newaccount). Additive - // on top of `perCall` (a value call is still a call). Both native and 4337 pay - // it — the EVM cost is the same regardless of execution path. - const perValueCall = 34_000; - // 2x safety multiplier, applied ONLY in fallback mode (see `fallback` above): - // when the node's `eth_estimateGas` is unavailable or reverts (staged config + - // policy bundles, cold-account creation on a value transfer to a fresh - // recipient, etc.) this structural value is the sole gas source, so over-budget - // on purpose — unused gas is refunded, and an underestimate causes an on-chain - // OOG revert (far worse than a temporarily higher limit). As a *floor* beneath - // a successful node estimate we must NOT double it, or it would always exceed - // the (buffered) real estimate and permanently over-price every transaction. + const base = 45_000; + const perCall = 22_000; + const perValueCall = Number(txValueCost) + 25_000; + // Delegation entry intrinsic plus headroom for writing the delegation code. + const delegationGas = delegation ? Number(delegationCost) + 25_000 : 0; + const nonceGas = nonceless ? Number(nonceFreeCost) : 0; + const payerGas = payer ? Number(k1AuthCost) + 3_000 : 0; + const tokenPaymentGas = tokenPayment ? 30_000 : 0; const FALLBACK_SAFETY = fallback ? 2 : 1; return ( FALLBACK_SAFETY * (base + - deployCost + calls * perCall + - keyChanges * perKeyChange + - policyCalls * perPolicyCall + valueCalls * perValueCall + - wrap) + delegationGas + + nonceGas + + payerGas + + tokenPaymentGas) ); } -/** Public Base Sepolia RPC (read path: gas, balance, receipts). */ -export const BASE_SEPOLIA_RPC = "https://sepolia.base.org"; - -/** Canonical Circle USDC on Base Sepolia (6 decimals) — the demo stablecoin. */ -export const BASE_SEPOLIA_USDC = - "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as const; - -/** Minimal viem `Chain` for Base Sepolia (read client + bundler client). */ -export const baseSepoliaChain = { - id: 84532, - name: "Base Sepolia", - nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, - rpcUrls: { default: { http: [BASE_SEPOLIA_RPC] } }, -} as const; - -/** Cross-origin vibenet route that proxies ERC-4337 JSON-RPC to the bundler. */ -export const BUNDLER_PROXY_PATH = ACCOUNT_BUNDLER_URL; - -/** Cross-origin vibenet route that runs the ERC-8168 payer. */ -export const PAYER_PROXY_PATH = ACCOUNT_PAYER_URL; - /** * ERC-8168 payer web service endpoint (native EIP-8130 gas sponsorship + USDV * token payment). * - * In omni-ui this is vibenet's cross-origin {@link PAYER_PROXY_PATH} — already - * an absolute URL, which viem's `http()` transport requires. Set - * `NEXT_PUBLIC_PAYER_URL` to point at a standalone `just payer` instead (e.g. - * for local `npm run dev` against a local payer). + * In omni-ui this is vibenet's cross-origin payer route — already an absolute + * URL, which viem's `http()` transport requires. Set `NEXT_PUBLIC_PAYER_URL` to + * point at a standalone `just payer` instead (e.g. for local `npm run dev` + * against a local payer). */ export const PAYER_URL = process.env.NEXT_PUBLIC_PAYER_URL ?? ACCOUNT_PAYER_URL; - -/** - * Whether the demo should attempt a paymaster-sponsored UserOperation (no - * account funding required). Set `NEXT_PUBLIC_BASE_SEPOLIA_SPONSOR=1` when the - * configured bundler endpoint also serves `pm_*` sponsorship. - */ -export const SPONSOR_BASE_SEPOLIA = - process.env.NEXT_PUBLIC_BASE_SEPOLIA_SPONSOR === "1"; - -export function basescanTx(hash: string): string { - return `https://sepolia.basescan.org/tx/${hash}`; -} -export function basescanAddress(addr: string): string { - return `https://sepolia.basescan.org/address/${addr}`; -} diff --git a/app/vibenet/demos/account/library/delegation.ts b/app/vibenet/demos/account/library/delegation.ts new file mode 100644 index 00000000..d23d70b8 --- /dev/null +++ b/app/vibenet/demos/account/library/delegation.ts @@ -0,0 +1,16 @@ +import type { Address, Hex } from '@aa'; + +/** EIP-7702 delegation designator prefix: code is `0xef0100 || target`. */ +const DELEGATION_PREFIX = '0xef0100'; + +/** + * The delegation target encoded in an account's code, `null` for an account + * with no code, or `undefined` when the code is something other than a + * delegation designator (a contract, not an EOA). + */ +export function parseDelegation(code: Hex | null | undefined): Address | null | undefined { + if (!code || code === '0x') return null; + const lower = code.toLowerCase(); + if (lower.length !== DELEGATION_PREFIX.length + 40 || !lower.startsWith(DELEGATION_PREFIX)) return undefined; + return `0x${code.slice(DELEGATION_PREFIX.length)}` as Address; +} diff --git a/app/vibenet/demos/account/library/derive.ts b/app/vibenet/demos/account/library/derive.ts deleted file mode 100644 index e4384492..00000000 --- a/app/vibenet/demos/account/library/derive.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Pure address/actor derivation helpers shared by the account engine and the -// account-creation modal. Extracted from useAccountEngine so the create flow can -// own its own form state without pulling in the whole engine. - -import { type Address, type Hex, keccak256, toHex } from '@aa'; - -import type { StoredActor } from './model'; -import { signerIdentity, type WalletSigner } from '../shared'; - -export const HEX32 = /^0x[0-9a-fA-F]{64}$/; - -export function randomHex32(): Hex { - const b = new Uint8Array(32); - crypto.getRandomValues(b); - return `0x${Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('')}` as Hex; -} - -export function normalizeSalt(field: string): Hex { - const v = field.trim(); - if (HEX32.test(v)) return v as Hex; - return keccak256(toHex(v || 'vibes')); -} - -export function actorPairs(actors: { actorId: Hex; authenticator: Address }[]) { - return actors.map((a) => ({ actorId: a.actorId, authenticator: a.authenticator })); -} - -export function sortActors(actors: T[]): T[] { - // Must match the vendor's exact ordering: `createAccount`/`computeAddress` - // require initialActors sorted by `actorId` as a BIGINT in strictly ascending - // order (no duplicates). A lexicographic string sort diverges from numeric - // ordering whenever actorIds differ in hex width or case (e.g. an unpadded or - // upper-cased id), which surfaces as "initialActors are not sorted". - return [...actors].sort((a, b) => { - const av = BigInt(a.actorId); - const bv = BigInt(b.actorId); - return av < bv ? -1 : av > bv ? 1 : 0; - }); -} - -export function toStoredActor(s: WalletSigner): StoredActor { - return { - signerId: s.id, - actorId: s.actorId, - authenticator: s.authenticator, - kind: s.kind, - label: s.label, - identity: signerIdentity(s), - }; -} diff --git a/app/vibenet/demos/account/library/model.test.ts b/app/vibenet/demos/account/library/model.test.ts new file mode 100644 index 00000000..33b8d592 --- /dev/null +++ b/app/vibenet/demos/account/library/model.test.ts @@ -0,0 +1,59 @@ +import { describe, expect, it } from 'vitest'; + +import { normalizePersistedState } from './model'; + +const KEY = `0x${'11'.repeat(32)}`; +const ADDRESS = '0x19E7E376E7C213B7E7e7e46cc70A5dD086DAff2A'; + +describe('normalizePersistedState', () => { + it('keeps EOA accounts backed by a stored K1 key', () => { + const state = normalizePersistedState({ + signers: [ + { id: 's1', kind: 'k1', label: 'K1 1', privateKey: KEY, address: ADDRESS, actorId: '0x01', authenticator: '0x01' }, + ], + accounts: [ + { + id: 'a1', + label: 'Default', + type: 'eoa', + address: ADDRESS.toLowerCase(), + owners: [{ signerId: 's1' }], + sessionKeys: [], + subAccounts: [], + createdAt: 5, + }, + ], + activeAccountId: 'a1', + activity: [{ id: 'e1', ts: 1, kind: 'session', title: 'Session key staged' }], + }); + expect(state.signers).toEqual([{ id: 's1', kind: 'k1', label: 'K1 1', privateKey: KEY, address: ADDRESS }]); + expect(state.accounts).toEqual([ + { id: 'a1', label: 'Default', type: 'eoa', signerId: 's1', address: ADDRESS, createdAt: 5 }, + ]); + expect(state.activeAccountId).toBe('a1'); + expect(state.activity[0].kind).toBe('transact'); + }); + + it('drops smart accounts, sub-accounts, and non-K1 keys without throwing', () => { + const state = normalizePersistedState({ + signers: [ + { id: 's1', kind: 'k1', label: 'K1 1', privateKey: KEY, address: ADDRESS }, + { id: 's2', kind: 'passkey', label: 'Passkey 1', credential: { id: 'c', publicKey: '0x' } }, + ], + accounts: [ + { id: 'smart', type: 'smart', address: '0x0000000000000000000000000000000000000abc' }, + { id: 'legacy', address: '0x0000000000000000000000000000000000000def' }, + { id: 'sub', type: 'eoa', parentId: 'smart', address: ADDRESS }, + ], + activeAccountId: 'smart', + }); + expect(state.signers.map((s) => s.id)).toEqual(['s1']); + expect(state.accounts).toEqual([]); + expect(state.activeAccountId).toBeNull(); + }); + + it('tolerates garbage', () => { + expect(normalizePersistedState(null)).toEqual({ signers: [], accounts: [], activeAccountId: null, activity: [] }); + expect(normalizePersistedState({ signers: 'x', accounts: [1, null] }).accounts).toEqual([]); + }); +}); diff --git a/app/vibenet/demos/account/library/model.ts b/app/vibenet/demos/account/library/model.ts index 9cdd08a2..a527b980 100644 --- a/app/vibenet/demos/account/library/model.ts +++ b/app/vibenet/demos/account/library/model.ts @@ -1,228 +1,16 @@ -// App-level account model for the EIP-8130 demo: session keys, policies, -// sub-accounts, and a session activity log. These wrap the canonical viem -// primitives (`authorizeActor` scope/expiry/policy, `key.delegate`) into -// shapes the UI can render. +// App-level account model for the EIP-8130 demo. With the Keystore disabled an +// account is a plain secp256k1 EOA: its key signs `sender_auth`, its address is +// the account, and it can optionally point its code at a delegation target. -import { actorScope, type AaAccountChangeConfig, type Address, type Hex } from "@aa"; +import type { Address, Hex } from "@aa"; -// --------------------------------------------------------------------------- -// Scopes — sourced directly from viem's `actorScope` bitmask so the values can -// never drift from the protocol (the bits were reshuffled upstream). The UI's -// `sender` is viem's `operator` (ungated initiation); "Send" is its label. -// --------------------------------------------------------------------------- - -export const SCOPE = { - sender: actorScope.operator, - policy: actorScope.policy, - nonce: actorScope.nonce, - selfPayer: actorScope.selfPayer, - sponsorPayer: actorScope.sponsorPayer, -} as const; - -const SCOPE_LABEL: Array<[number, string]> = [ - [SCOPE.sender, "Send"], - [SCOPE.policy, "Policy"], - [SCOPE.nonce, "Nonce"], - [SCOPE.selfPayer, "Pay Gas"], - [SCOPE.sponsorPayer, "Sponsor"], -]; - -/** Human-readable chips for a scope bitmask. `0` = unrestricted admin (full owner). */ -export function scopeChips(scope: number): string[] { - if (!scope) return ["Full control"]; - return SCOPE_LABEL.filter(([bit]) => (scope & bit) !== 0).map(([, l]) => l); -} - -// --------------------------------------------------------------------------- -// Presets surfaced in the "register session key" UI. -// --------------------------------------------------------------------------- - -export type ScopePreset = { - id: string; - label: string; - scope: number; - hint: string; -}; - -export const SESSION_SCOPE_PRESETS: ScopePreset[] = [ - { - id: "spend", - label: "Spend", - scope: SCOPE.sender, - hint: "Originate calls and move funds. Cannot change account config.", - }, - { - id: "self-pay", - label: "Pay gas", - scope: SCOPE.selfPayer, - hint: "Pay for the account's own transactions (payer == sender).", - }, - { - id: "sponsor", - label: "Sponsor", - scope: SCOPE.sponsorPayer, - hint: "Sponsor gas on behalf of another sender (payer != sender).", - }, -]; - -export type ExpiryPreset = { id: string; label: string; seconds: number }; - -export const EXPIRY_PRESETS: ExpiryPreset[] = [ - { id: "1h", label: "1 hour", seconds: 3600 }, - { id: "1d", label: "1 day", seconds: 86_400 }, - { id: "7d", label: "7 days", seconds: 604_800 }, - { id: "30d", label: "30 days", seconds: 2_592_000 }, - { id: "none", label: "No expiry", seconds: 0 }, -]; - -export type PolicyPreset = { - id: string; - /** Non-zero policy selector (`0` = no policy). */ - type: number; - label: string; - hint: string; -}; - -export const POLICY_PRESETS: PolicyPreset[] = [ - { - id: "none", - type: 0, - label: "No policy", - hint: "Scope only. No extra gate.", - }, - { - id: "limit", - // Policy presence is the `SCOPE.policy` bit on the actor's scope; `type` is a - // non-zero off-chain marker only (the protocol does not interpret it). Both - // presets resolve to the same SessionPolicy contract — they differ only in config. - type: 1, - label: "Spending limit", - hint: "Cap how much the key can move per period (recurring or one-time).", - }, - { - id: "allowlist", - type: 1, - label: "Target allowlist", - hint: "Restrict the contract(s) the key may call.", - }, -]; +import type { WalletSigner } from "../shared"; // --------------------------------------------------------------------------- -// App model types. +// Activity log. // --------------------------------------------------------------------------- -export type AppPolicy = { - /** Non-zero off-chain policy marker. Policy presence is the `SCOPE.policy` scope bit. */ - type: number; - label: string; - /** PolicyManager the gated actor is forced to call. */ - manager: Address; - /** SessionPolicy contract enforcing the binding. */ - policy: Address; - /** Committed `SessionPolicy` config bytes (re-derives the commitment + actions). */ - policyConfig: Hex; - /** - * Complete binding fields required by `PolicyManager.execute`: every execute - * carries the full committed binding (no install call), so re-deriving the - * session (see `sessionFor`) MUST re-pass these or the recomputed commitment - * won't match the account-authorized one and the manager reverts. - */ - validAfter?: bigint; - validUntil?: bigint; - salt?: bigint; - /** keccak256 of the account-authorized policy binding. */ - commitment: Hex; - /** Human-readable parameter summary (e.g. "≤ 100 USDV / 7d"). */ - params: string; - /** - * Per-token spend caps (for the session-key card's live "remaining" view). - * `token` is the SessionPolicy token key — the zero address for native ETH. - */ - limits?: { - token: Address; - symbol: string; - decimals: number; - /** Cap per rolling window, in token base units. */ - allowance: bigint; - /** Rolling window length in seconds (`0` = one-shot / no reset). */ - period: number; - }[]; -}; - -export type AppSessionKey = { - id: string; - /** Wallet signer backing this session key. */ - signerId: string; - label: string; - kind: "k1" | "p256" | "passkey"; - actorId: Hex; - authenticator: Address; - scope: number; - /** Unix seconds; `0n` = no expiry. */ - expiry: bigint; - /** Chain the key was authorized for (token addresses are chain-local). */ - chainId?: number; - policy?: AppPolicy; - createdAt: number; - serialized?: Hex; - /** - * Private key for app-scoped session keys that should NOT appear in the - * Demo keys list. When set, the key signs silently without any user prompt. - * Stored alongside the session key so no separate WalletSigner entry is - * needed in global state. - */ - privateKey?: Hex; - /** - * Owner-signed authorization captured at registration but NOT yet broadcast. - * When present, the session key is authorized lazily on its FIRST transaction - * (which the session key itself signs): the owner-signed config (actor) change - * rides `accountChanges`. The PolicyManager needs no install call because every - * `execute` carries the full committed binding. Cleared once that first tx (or - * a standalone "deploy now" tx) lands. Absent = already authorized onchain. - */ - pendingAuth?: { - /** Owner-signed actor change (authorize session key [+ trusted manager]). */ - change: AaAccountChangeConfig; - /** Config sequence the change advances to. */ - sequence: number; - /** Whether the change also registered the manager as a trusted executor. */ - registeredManager: boolean; - }; - /** - * Owner-signed `revokeActor(actorId)` captured but NOT yet broadcast. Mirrors - * the owner-change "sign then apply / ride the next tx" flow: pressing Revoke - * on a landed key signs the revoke (a config change on the per-chain LOCAL - * counter) and stages it here. It lands via "Apply now" (a no-op tx) or by - * riding the account's next session-key transaction; the key record is then - * removed. The PolicyManager is intentionally NOT revoked (other keys may - * share it). Only ever set on an on-chain key (never together with pendingAuth). - */ - pendingRevoke?: { - /** Owner-signed `revokeActor` change for this session key's actor. */ - change: AaAccountChangeConfig; - /** Local config sequence the change consumes. */ - sequence: number; - }; -}; - -export type AppSubAccount = { - id: string; - label: string; - salt: Hex; - address: Address; - /** Wallet signers that own the sub-account directly. */ - signerIds: string[]; - /** Parent address the sub-account delegates control to. */ - delegateTo: Address; - createdAt: number; -}; - -export type ActivityKind = - | "create" - | "transact" - | "session" - | "subaccount" - | "revoke"; +export type ActivityKind = "create" | "transact" | "delegate"; export type ActivityEntry = { id: string; @@ -252,19 +40,6 @@ export type ActivityEntry = { // Formatting helpers. // --------------------------------------------------------------------------- -/** Relative expiry label from an absolute unix-seconds expiry. */ -export function formatExpiry(expiry: bigint): string { - if (!expiry) return "No expiry"; - const secs = Number(expiry) - Math.floor(Date.now() / 1000); - if (secs <= 0) return "Expired"; - const d = Math.floor(secs / 86_400); - if (d >= 1) return `${d}d left`; - const h = Math.floor(secs / 3600); - if (h >= 1) return `${h}h left`; - const m = Math.max(1, Math.floor(secs / 60)); - return `${m}m left`; -} - export function formatTime(ts: number): string { return new Date(ts).toLocaleTimeString([], { hour: "2-digit", @@ -273,76 +48,19 @@ export function formatTime(ts: number): string { }); } -export const ACTIVITY_ICON: Record = { - create: "+", - transact: "→", - session: "◷", - subaccount: "⌂", - revoke: "×", -}; - // --------------------------------------------------------------------------- // Stored (locally-persisted) account model. // --------------------------------------------------------------------------- -export type SignerKind = "k1" | "p256" | "passkey"; - -/** An actor bound to an account, paired with the wallet signer that backs it. */ -export type StoredActor = { - signerId: string; - actorId: Hex; - authenticator: Address; - kind: SignerKind; - label: string; - /** Display identity (address / pubkey.x / credential id). */ - identity: string; - /** Permission bitmask; `0`/undefined = full control (owner). */ - scope?: number; -}; - -/** - * "smart" — counterfactual account deployed via `createAccount` (address is - * derived from keys + salt). "eoa" — an existing EOA that *is* the account; it - * delegates its code to the DefaultAccount implementation and its own - * secp256k1 key is the default owner. Absent = "smart" (legacy records). - */ -export type AccountType = "smart" | "eoa"; +export type SignerKind = "k1"; +/** An EOA account: the address of the wallet key `signerId`. */ export type StoredAccount = { id: string; label: string; - /** Account model. Absent on legacy records → treat as "smart". */ - type?: AccountType; - /** - * Set on sub-account records: the id of the parent account that controls this - * one via `key.delegate(parent)`. Key selection for a sub-account resolves to - * the parent's owner signers (the parent is the on-chain delegate owner). - */ - parentId?: string; - saltField: string; - salt: Hex; + type: "eoa"; + signerId: string; address: Address; - /** EOA-only: code-delegation target (DefaultAccount implementation). */ - delegate?: Address; - /** Actors bound into the address — immutable (changing them changes address). */ - initialActors: StoredActor[]; - /** Current applied owner set (initial + authorized − revoked). */ - owners: StoredActor[]; - /** Has a chain/offline tx carrying `account.create()` been signed. */ - deployed: boolean; - configSeq: number; - sessionKeys: AppSessionKey[]; - /** - * PolicyManager addresses already registered on-chain as trusted-executor - * actors. A policy-gated session key needs its manager registered once so - * `PolicyManager.execute -> account.executeBatch` is accepted; the manager is - * NEVER revoked when a session key is removed (other keys may share it, and - * re-registering an existing actor reverts). Tracked here so a subsequent - * authorize doesn't re-add a manager that's already present. Absent on legacy - * records → fall back to inferring from `sessionKeys`. - */ - trustedManagers?: Address[]; - subAccounts: AppSubAccount[]; createdAt: number; }; @@ -368,6 +86,79 @@ export function deserializeState(raw: string): T { return JSON.parse(raw, bnReviver) as T; } +// --------------------------------------------------------------------------- +// Legacy (Keystore-era) record migration. +// --------------------------------------------------------------------------- + +const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/; +const PRIVATE_KEY_RE = /^0x[0-9a-fA-F]{64}$/; +const ACTIVITY_KINDS: readonly ActivityKind[] = ["create", "transact", "delegate"]; + +function asRecord(value: unknown): Record | null { + return value && typeof value === "object" ? (value as Record) : null; +} + +/** + * Keep only what an EOA-only chain can use from a persisted store written by an + * older build: K1 keys, and EOA accounts backed by one of those keys (the key + * whose address is the account). Smart accounts, sub-accounts, and P-256 / + * passkey keys are dropped; session keys, owners, and salts are discarded. + */ +export function normalizePersistedState(raw: unknown): { + signers: WalletSigner[]; + accounts: StoredAccount[]; + activeAccountId: string | null; + activity: ActivityEntry[]; +} { + const state = asRecord(raw) ?? {}; + + const signers: WalletSigner[] = []; + for (const item of Array.isArray(state.signers) ? state.signers : []) { + const s = asRecord(item); + if (!s || s.kind !== "k1") continue; + if (typeof s.id !== "string" || typeof s.privateKey !== "string" || typeof s.address !== "string") continue; + if (!PRIVATE_KEY_RE.test(s.privateKey) || !ADDRESS_RE.test(s.address)) continue; + signers.push({ + id: s.id, + kind: "k1", + label: typeof s.label === "string" ? s.label : "K1", + privateKey: s.privateKey as Hex, + address: s.address as Address, + }); + } + const signerByAddress = new Map(signers.map((s) => [s.address.toLowerCase(), s])); + + const accounts: StoredAccount[] = []; + for (const item of Array.isArray(state.accounts) ? state.accounts : []) { + const a = asRecord(item); + if (!a || a.type !== "eoa" || a.parentId) continue; + if (typeof a.id !== "string" || typeof a.address !== "string") continue; + const signer = signerByAddress.get(a.address.toLowerCase()); + if (!signer) continue; + accounts.push({ + id: a.id, + label: typeof a.label === "string" ? a.label : "Account", + type: "eoa", + signerId: signer.id, + address: signer.address, + createdAt: typeof a.createdAt === "number" ? a.createdAt : Date.now(), + }); + } + + const storedActive = typeof state.activeAccountId === "string" ? state.activeAccountId : null; + const activeAccountId = accounts.some((a) => a.id === storedActive) ? storedActive : (accounts[0]?.id ?? null); + + const activity: ActivityEntry[] = []; + for (const item of Array.isArray(state.activity) ? state.activity : []) { + const e = asRecord(item); + if (!e || typeof e.id !== "string" || typeof e.title !== "string" || typeof e.ts !== "number") continue; + const kind = ACTIVITY_KINDS.includes(e.kind as ActivityKind) ? (e.kind as ActivityKind) : "transact"; + activity.push({ ...(e as ActivityEntry), kind }); + } + + return { signers, accounts, activeAccountId, activity }; +} + // --------------------------------------------------------------------------- // Balance formatting. // --------------------------------------------------------------------------- diff --git a/app/vibenet/demos/account/library/payer.test.ts b/app/vibenet/demos/account/library/payer.test.ts new file mode 100644 index 00000000..8c09d0bb --- /dev/null +++ b/app/vibenet/demos/account/library/payer.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest'; + +import { parseDelegation } from './delegation'; +import { parseTokenRate, requiredTokenAmount } from './payer'; + +describe('parseTokenRate', () => { + it('reads the WAD hex rate', () => { + expect(parseTokenRate('0x1dcd65000')).toBe(8_000_000_000n); + }); + + it('converts the legacy numerator/denominator shape to WAD', () => { + expect(parseTokenRate({ numerator: '0x2', denominator: '0xde0b6b3a7640000' })).toBe(2n); + expect(parseTokenRate({ numerator: '0x1', denominator: '0x0' })).toBeNull(); + }); + + it('rejects malformed input', () => { + expect(parseTokenRate(undefined)).toBeNull(); + expect(parseTokenRate('not-hex')).toBeNull(); + }); +}); + +describe('requiredTokenAmount', () => { + it('rounds up once after multiplying', () => { + // 100k gas at 2 gwei = 2e14 wei; at 2000 USDV (6 dp) per ETH that is 0.4 USDV. + expect(requiredTokenAmount(100_000n, 2_000_000_000n, 2_000_000_000n)).toBe(400_000n); + expect(requiredTokenAmount(1n, 1n, 1n)).toBe(1n); + expect(requiredTokenAmount(0n, 1n, 1n)).toBe(0n); + }); +}); + +describe('parseDelegation', () => { + const target = '0x1234567890abcdef1234567890abcdef12345678'; + + it('reads a 7702 delegation designator', () => { + expect(parseDelegation(`0xef0100${target.slice(2)}`)).toBe(target); + }); + + it('treats empty code as undelegated', () => { + expect(parseDelegation('0x')).toBeNull(); + expect(parseDelegation(null)).toBeNull(); + }); + + it('flags other code as not a delegation', () => { + expect(parseDelegation('0x6080604052')).toBeUndefined(); + }); +}); diff --git a/app/vibenet/demos/account/library/payer.ts b/app/vibenet/demos/account/library/payer.ts new file mode 100644 index 00000000..38c56cb2 --- /dev/null +++ b/app/vibenet/demos/account/library/payer.ts @@ -0,0 +1,33 @@ +// ERC-8168 token-offer math for the vibenet payer. A token offer's binding +// price is a WAD `rate` (token atomic units per 1e18 wei); the phase-0 transfer +// must cover ceil(gasLimit * maxFeePerGas * rate / 1e18) at the gas and fee the +// transaction is actually signed with, not only the quote's `gasEstimate`. + +const WAD = 10n ** 18n; + +/** + * Read a token choice's `rate` as a WAD bigint. Accepts the current hex + * quantity and the older `{ numerator, denominator }` (units per `denominator` + * wei) shape. `null` when absent or malformed. + */ +export function parseTokenRate(rate: unknown): bigint | null { + try { + if (typeof rate === 'string') return BigInt(rate); + if (rate && typeof rate === 'object') { + const { numerator, denominator } = rate as { numerator?: unknown; denominator?: unknown }; + if (typeof numerator !== 'string' || typeof denominator !== 'string') return null; + const d = BigInt(denominator); + return d === 0n ? null : (BigInt(numerator) * WAD) / d; + } + } catch { + return null; + } + return null; +} + +/** `mulDivUp(gasLimit * maxFeePerGas, rate, 1e18)`. */ +export function requiredTokenAmount(gasLimit: bigint, maxFeePerGas: bigint, rate: bigint): bigint { + const cost = gasLimit * maxFeePerGas; + if (cost === 0n || rate === 0n) return 0n; + return (cost * rate + WAD - 1n) / WAD; +} diff --git a/app/vibenet/demos/account/library/policy.ts b/app/vibenet/demos/account/library/policy.ts deleted file mode 100644 index 728821ec..00000000 --- a/app/vibenet/demos/account/library/policy.ts +++ /dev/null @@ -1,233 +0,0 @@ -// SessionPolicy + owner-scope helpers for the account demo. Ported from the -// module-scope policy code in base/vibenet `account/page.tsx`. Composes spend -// limits + target/selector allowlists into a single committed SessionPolicy -// binding (see the EIP-8130 SessionPolicy worked example). - -import { - type Address, - defineSessionPolicy, - type encodeSessionPolicyConfig, - type Hex, - parseEther, - parseUnits, -} from '@aa'; - -import { vibenetApi } from '../../../library/client'; -import { BASE_SEPOLIA_USDC } from './chains'; -import { SCOPE, scopeChips } from './model'; -import { short } from '../shared'; -import type { AppPolicy } from './model'; - -export const ZERO_ADDR = '0x0000000000000000000000000000000000000000' as Address; -export const TRANSFER_SELECTOR = '0xa9059cbb' as Hex; - -const ADDR_RE = /^0x[0-9a-fA-F]{40}$/; - -/** What a session key is restricted to — spend caps and/or a target allowlist. */ -export type PolicySpec = { - limits?: { - token: 'stable' | 'eth' | Address; - /** Decimals for a custom token (ignored for stable/eth). @default 18 */ - decimals?: number; - amount: string; - /** Recurring window (seconds); `0` = one-time cap. */ - periodSecs: number; - }[]; - scopes?: { target: string; selectors?: Hex[] }[]; -}; - -/** Spend-limit period choices (independent of the key's expiry). */ -export const PERIOD_PRESETS: { id: string; label: string; seconds: number }[] = [ - { id: 'day', label: 'per day', seconds: 86_400 }, - { id: 'week', label: 'per week', seconds: 604_800 }, - { id: 'month', label: 'per month', seconds: 2_592_000 }, - { id: 'once', label: 'one-time', seconds: 0 }, -]; - -/** Known ERC-20 selectors offered as quick toggles in the allowlist. */ -export const SELECTOR_PRESETS: { id: string; label: string; selector: Hex }[] = [ - { id: 'transfer', label: 'transfer', selector: TRANSFER_SELECTOR }, - { id: 'approve', label: 'approve', selector: '0x095ea7b3' }, - { id: 'transferFrom', label: 'transferFrom', selector: '0x23b872dd' }, -]; - -// Owner-key permission presets. `0` = full control; otherwise a scope bitmask. -export const OWNER_SCOPE_PRESETS: { id: string; scope: number; label: string }[] = [ - { id: 'full', scope: 0, label: 'Full control' }, - { id: 'send', scope: SCOPE.sender, label: 'Send only' }, - { id: 'send_pay', scope: SCOPE.sender | SCOPE.selfPayer, label: 'Send + pay gas' }, - { id: 'pay', scope: SCOPE.selfPayer, label: 'Pay gas only' }, - { id: 'sponsor', scope: SCOPE.sponsorPayer, label: 'Sponsor only' }, - { id: 'send_nonce', scope: SCOPE.sender | SCOPE.nonce, label: 'Send + sequenced nonce' }, -]; - -export function periodLabel(secs: number): string { - return PERIOD_PRESETS.find((p) => p.seconds === secs)?.label ?? `/ ${secs}s`; -} - -export function stableSymbol(networkShort: string): string { - return networkShort === 'vibenet' ? 'USDV' : 'USDC'; -} - -export function scopeLabel(scope: number): string { - if (!scope) return 'Full Control'; - return OWNER_SCOPE_PRESETS.find((p) => p.scope === scope)?.label ?? scopeChips(scope).join(' + '); -} - -// Editable rows backing the register-session-key form. -export type LimitDraft = { - id: string; - token: 'stable' | 'eth' | 'custom'; - custom: string; - amount: string; - periodId: string; -}; -export type ScopeDraft = { - id: string; - target: string; - all: boolean; - selectors: Hex[]; -}; - -export function newLimitDraft(): LimitDraft { - return { id: crypto.randomUUID(), token: 'stable', custom: '', amount: '100', periodId: 'month' }; -} -export function newScopeDraft(selectors: Hex[] = []): ScopeDraft { - return { id: crypto.randomUUID(), target: '', all: selectors.length === 0, selectors }; -} - -/** Resolve the chain stablecoin: USDV on vibenet, USDC on Base Sepolia. */ -export async function resolveStable( - networkShort: string, -): Promise<{ address: Address; symbol: string; decimals: number }> { - if (networkShort === 'vibenet') { - const status = await vibenetApi.faucet.status().catch(() => null); - const a = status?.usdv_address; - if (a && ADDR_RE.test(a)) return { address: a as Address, symbol: 'USDV', decimals: 6 }; - } - return { address: BASE_SEPOLIA_USDC as Address, symbol: 'USDC', decimals: 6 }; -} - -/** - * Build a committed SessionPolicy config + a human summary from a PolicySpec. - * Composes spend limits and target/selector scopes into one binding. - */ -export async function buildSessionConfig( - spec: PolicySpec, - networkShort: string, -): Promise<{ - config: Parameters[0]; - summary: string; - limits: { token: Address; symbol: string; decimals: number; allowance: bigint; period: number }[]; -}> { - const scopeMap = new Map | null>(); - const addScope = (target: string, selectors?: Hex[]) => { - const t = target.trim(); - if (!ADDR_RE.test(t)) throw new Error(`Invalid target address: ${target}`); - const key = t.toLowerCase(); - if (selectors?.length) { - const existing = scopeMap.get(key); - const set = existing instanceof Set ? existing : new Set(); - for (const s of selectors) set.add(s); - scopeMap.set(key, set); - } else if (!scopeMap.has(key)) { - scopeMap.set(key, null); - } - }; - for (const s of spec.scopes ?? []) addScope(s.target, s.selectors); - - const tokenLimits: { token: Address; limit: bigint; period: bigint }[] = []; - const limits: { - token: Address; - symbol: string; - decimals: number; - allowance: bigint; - period: number; - }[] = []; - const summaryParts: string[] = []; - let hasEthLimit = false; - for (const limit of spec.limits ?? []) { - const amount = limit.amount.trim(); - if (!/^\d*\.?\d+$/.test(amount)) throw new Error('Enter a valid limit amount.'); - const period = BigInt(limit.periodSecs); - if (limit.token === 'eth') { - hasEthLimit = true; - const allowance = parseEther(amount); - tokenLimits.push({ token: ZERO_ADDR, limit: allowance, period }); - limits.push({ token: ZERO_ADDR, symbol: 'ETH', decimals: 18, allowance, period: limit.periodSecs }); - summaryParts.push(`≤ ${amount} ETH ${periodLabel(limit.periodSecs)}`); - } else if (limit.token === 'stable') { - const stable = await resolveStable(networkShort); - const allowance = parseUnits(amount, stable.decimals); - tokenLimits.push({ token: stable.address, limit: allowance, period }); - limits.push({ - token: stable.address, - symbol: stable.symbol, - decimals: stable.decimals, - allowance, - period: limit.periodSecs, - }); - // Pin the stablecoin to `transfer` so the cap can't be sidestepped. - addScope(stable.address, [TRANSFER_SELECTOR]); - summaryParts.push(`≤ ${amount} ${stable.symbol} ${periodLabel(limit.periodSecs)}`); - } else { - if (!ADDR_RE.test(limit.token)) throw new Error(`Invalid token address: ${limit.token}`); - const decimals = limit.decimals ?? 18; - const allowance = parseUnits(amount, decimals); - tokenLimits.push({ token: limit.token, limit: allowance, period }); - limits.push({ - token: limit.token, - symbol: short(limit.token, 4, 4), - decimals, - allowance, - period: limit.periodSecs, - }); - addScope(limit.token, [TRANSFER_SELECTOR]); - summaryParts.push(`≤ ${amount} ${short(limit.token, 6, 4)} ${periodLabel(limit.periodSecs)}`); - } - } - - const callScopes = [...scopeMap.entries()].map(([target, sels]) => ({ - target: target as Address, - selectorRules: sels ? [...sels].map((selector) => ({ selector })) : [], - })); - if (callScopes.length === 0) throw new Error('Add a spend limit or at least one allowed target.'); - if (hasEthLimit && (spec.scopes ?? []).length === 0) - throw new Error('An ETH limit needs at least one allowed target to pay.'); - - const shownTargets = (spec.scopes ?? []).map((s) => short(s.target, 6, 4)); - if (shownTargets.length) summaryParts.push(`calls ${shownTargets.join(', ')}`); - - return { config: { tokenLimits, callScopes }, summary: summaryParts.join(' · '), limits }; -} - -/** - * Re-derive the viem SessionPolicy bundle for a stored AppPolicy. The binding - * fields (validAfter/validUntil/salt) MUST be re-passed: every `execute` carries - * the full committed binding, so an omitted field changes the recomputed - * commitment and the PolicyManager rejects the call. - */ -export function sessionFor(policy: AppPolicy, account: Address) { - return defineSessionPolicy({ - account, - policy: policy.policy, - policyConfig: policy.policyConfig, - manager: policy.manager, - validAfter: policy.validAfter, - validUntil: policy.validUntil, - salt: policy.salt, - }); -} - -/** Wrap raw calls so a policy-gated session key reaches them via the manager. */ -export function wrapSessionCalls( - calls: { to: Address; value: bigint; data: Hex }[], - policy: AppPolicy, - account: Address, -): { to: Address; value: bigint; data: Hex }[] { - const session = sessionFor(policy, account); - return calls.map((c) => { - const call = session.executeCall({ target: c.to, value: c.value, data: c.data }); - return { to: call.to, value: call.value ?? 0n, data: (call.data ?? '0x') as Hex }; - }); -} diff --git a/app/vibenet/demos/account/shared.ts b/app/vibenet/demos/account/shared.ts index 89de85e8..9c40eebe 100644 --- a/app/vibenet/demos/account/shared.ts +++ b/app/vibenet/demos/account/shared.ts @@ -5,17 +5,13 @@ import type { Address, Hex } from '@aa'; import type { AccountBalancesResponse } from '../../library/api-types'; import type { ActivityEntry, SignerKind, StoredAccount } from './library/model'; -/** An in-browser signer key held in the demo wallet. */ +/** An in-browser secp256k1 key held in the demo wallet. */ export type WalletSigner = { id: string; kind: SignerKind; label: string; - actorId: Hex; - authenticator: Address; - privateKey?: Hex; - address?: Address; - publicKey?: { x: Hex; y: Hex }; - credential?: { id: string; publicKey: Hex }; + privateKey: Hex; + address: Address; }; export type Balances = AccountBalancesResponse; @@ -32,17 +28,11 @@ export type Persisted = { genesisHash?: string; }; -/** - * Top-level choice in the create-account modal's "Account Type" selector. - * `default`/`passkey` are one-click flows (auto-pick or mint a key); `advanced` - * exposes the full smart-vs-EOA + keys + salt controls. - */ -export type CreateMode = 'default' | 'passkey' | 'advanced'; +/** How the create-account drawer sources the account's key. */ +export type CreateMode = 'generate' | 'existing' | 'import'; export const KIND_LABEL: Record = { k1: 'K1', - p256: 'P-256', - passkey: 'Passkey', }; /** Abbreviate a hash/address as `0x1234...abcd`. */ @@ -67,10 +57,3 @@ export function formatTokenAmount( const fraction = raw.slice(-decimals).replace(/0+$/, '').slice(0, 6); return `${groupedWhole}${fraction ? `.${fraction}` : ''}`; } - -/** Display identity for a signer: address (k1), pubkey.x (p256), or credential id. */ -export function signerIdentity(s: WalletSigner): string { - if (s.kind === 'k1') return s.address ?? '0x'; - if (s.publicKey) return s.publicKey.x; - return s.credential?.id ?? ''; -} diff --git a/app/vibenet/demos/account/useAccountEngine.tsx b/app/vibenet/demos/account/useAccountEngine.tsx index f637a127..40d8bbde 100644 --- a/app/vibenet/demos/account/useAccountEngine.tsx +++ b/app/vibenet/demos/account/useAccountEngine.tsx @@ -1,56 +1,35 @@ 'use client'; // The EIP-8130 account engine shared by every vibenet demo that transacts from -// local accounts (Account demo, B20, …): chain/network resolution, signer + -// account CRUD, owner / session-key / sub-account management, and the -// underlying native-8130 signing/broadcast primitives. Extracted from -// AccountDemo.tsx so other demos (B20) get the exact same create/delete/ -// details capability instead of a stripped-down local reimplementation. +// local accounts (Account demo, B20, …): chain/network resolution, key + +// account CRUD, and the native-8130 signing/broadcast primitives. An account +// is a secp256k1 EOA: its key is the account, and it can optionally carry +// EIP-7702-style code delegation set by a `delegation` account change. // -// Demo-specific UI (the Transact modal's calls builder, gas-mode picker, Apps -// directory orchestration) stays in each demo and calls into this engine's -// shared primitives (signComposed, pendingBundleFor, applyLandedBundle, -// broadcast8130) exactly as AccountDemo's own transact flow does — those -// primitives are used by both config-apply and transact sends, so they have to -// live in one place, not two. Error and config-sequence-recovery UI is owned by -// the Transact modal, not the engine, so nothing surfaces on the page behind it. +// Demo-specific UI (the Transact modal's calls builder and gas-mode picker) +// stays in each demo and calls into this engine's shared primitives +// (signComposed, broadcast8130, awaitInclusion). Error UI is owned by the +// Transact modal, not the engine, so nothing surfaces on the page behind it. import { type AaAccountChange, + type AaCall, type Address, - authorizeActor, - canonicalAuthenticators, - computeAddress, createPublicClient, - createWebAuthnCredential, - defineSessionPolicy, - delegateAuthSize, - ecrecoverAuthenticator, - type Eip8130Deployment, - encodeSessionPolicyConfig, encodeTokenTransfer, - encodeWalletCalls, estimateGas, generatePrivateKey, - getConfigSequence, getTransactionCount, getTransactionReceipt, type Hex, http, - key, + k1Authenticator, + parseReceiptFields, privateKeyToAccount, - revokeActor, - sessionPolicyAbi, type Signer, - toAccount, - toDelegateSigner, toEoaAccount, toHex, - toP256Signer, - toWebAuthnAccount, - parseReceiptFields, - toWebAuthnSigner, - upgradeableProxyBytecode, + type TransactionSerializable8130, } from '@aa'; import { createContext, @@ -64,6 +43,7 @@ import { } from 'react'; import { toast } from 'sonner'; +import { noncelessFields } from '../../library/aa'; import { vibenetApi } from '../../library/client'; import { ACCOUNT_RPC_URL, VIBENET_WS_URL } from '../../library/config'; import { type Inclusion, inclusionFromChain, type SendAnchor } from '../_shared/inclusion'; @@ -74,36 +54,13 @@ import { type ReceiptWatcher, } from '../_shared/receiptWatcher'; import { connectJsonRpcStream } from '../validity/lib/stream'; -import { type DemoChain, deploymentFromContracts, estimateTxGas, getDemoChain } from './library/chains'; +import { estimateTxGas, getDemoChain } from './library/chains'; import { buildPhases, type CallRow, newCallRow, safeGasLimit, valueBearingCallCount } from './library/calls'; +import { parseDelegation } from './library/delegation'; +import type { StoredAccount } from './library/model'; +import { requiredTokenAmount } from './library/payer'; import { type AaReceiptLike, aaReceiptSucceeded } from './library/receipt'; -import { - type AppPolicy, - type AppSessionKey, - type AppSubAccount, - formatExpiry, - SCOPE, - scopeChips, - type SignerKind, - type StoredAccount, - type StoredActor, -} from './library/model'; -import { - buildSessionConfig, - type PolicySpec, - resolveStable, - scopeLabel, - wrapSessionCalls, - ZERO_ADDR, -} from './library/policy'; -import { - type Balances, - KIND_LABEL, - type Persisted, - short, - type WalletSigner, -} from './shared'; -import { actorPairs, randomHex32, sortActors, toStoredActor } from './library/derive'; +import { type Balances, KIND_LABEL, type Persisted, type WalletSigner } from './shared'; import { useAccounts } from './useAccounts'; const fundAccount = (address: Address) => @@ -112,34 +69,6 @@ const fundAccount = (address: Address) => vibenetApi.faucet.dripUsdv({ address }), ]); -/** Fold a landed batch of session-key config changes into the key list: - * - a key whose staged REVOKE landed is removed entirely, and - * - a key whose staged AUTHORIZE landed has its `pendingAuth` cleared. - * `landedIds` are the session ids whose changes rode the confirmed tx. */ -function commitLandedSessions(a: StoredAccount, landedIds: Set): AppSessionKey[] { - return a.sessionKeys - .filter((sk) => !(landedIds.has(sk.id) && sk.pendingRevoke)) - .map((sk) => (landedIds.has(sk.id) && sk.pendingAuth ? { ...sk, pendingAuth: undefined } : sk)); -} - -/** Add a PolicyManager address to the trusted-executor set (dedup, case-insensitive). */ -function mergeManagerAddr(existing: readonly Address[] | undefined, add: Address): Address[] { - const list = existing ? [...existing] : []; - return list.some((m) => m.toLowerCase() === add.toLowerCase()) ? list : [...list, add]; -} - -/** After deferred session keys land, fold any managers they registered - * (`pendingAuth.registeredManager`) into `trustedManagers`, so a later authorize - * won't try to re-register an already-present manager (which reverts). The manager - * is intentionally never removed on revoke — other keys may share it. */ -function mergeLandedManagers(a: StoredAccount, landedIds: Set): Address[] | undefined { - let out = a.trustedManagers; - for (const sk of a.sessionKeys) - if (landedIds.has(sk.id) && sk.pendingAuth?.registeredManager && sk.policy?.manager) - out = mergeManagerAddr(out, sk.policy.manager); - return out; -} - /** Best-effort human reason from a viem/RPC error (unwraps the "Missing or invalid * parameters" boilerplate to the underlying details). */ function estimateFailureReason(err: unknown): string { @@ -165,15 +94,6 @@ function estimateFailureReason(err: unknown): string { return String(err); } -/** True when an error is an EIP-8130 config-change sequence mismatch: a staged - * change's sequence went stale (the on-chain counter advanced since it was signed) - * so it can never land as-is and must be re-signed at the current sequence — or - * dropped. */ -export function isSeqMismatch(err: unknown): boolean { - const s = `${estimateFailureReason(err)} ${err instanceof Error ? err.message : String(err)}`; - return /config change sequence mismatch/i.test(s); -} - /** Collapse a giant viem error dump to its `Details:` line (or first line) for display. */ export function conciseError(message: string): string { const detail = message.match(/Details:\s*([\s\S]*?)(?:\s*Version:\s|$)/); @@ -187,9 +107,8 @@ export function conciseError(message: string): string { /** True when a gas-estimate error means the node simply lacks the EIP-8130 * `eth_estimateGas` extension — the ONE case where silently falling back to the - * structural floor is still correct. Any OTHER estimate revert now indicates the - * tx would actually fail (the node can simulate session-key + policy bundles once - * `senderActorId` is supplied), so it must be surfaced rather than swallowed. */ + * structural floor is still correct. Any OTHER estimate revert indicates the + * tx would actually fail, so it must be surfaced rather than swallowed. */ function isUnsupportedRpcError(err: unknown): boolean { if (!err || typeof err !== 'object') return false; const e = err as { @@ -213,34 +132,6 @@ function isUnsupportedRpcError(err: unknown): boolean { ); } -// --------------------------------------------------------------------------- -// Module-scope helpers. -// --------------------------------------------------------------------------- - -function localConfigSequence(local: bigint, bootstrap: AaAccountChange | undefined): bigint { - return bootstrap?.type === 'create' ? 1n : local; -} - -// Build a viem-compatible Signer from a stored wallet signer. -async function buildSigner(s: WalletSigner): Promise { - if (s.kind === 'k1') return privateKeyToAccount(s.privateKey as Hex); - if (s.kind === 'p256') return toP256Signer({ privateKey: s.privateKey as Hex }); - return toWebAuthnSigner( - toWebAuthnAccount({ credential: s.credential as { id: string; publicKey: Hex } }), - ); -} - -// An owner change signed in its own wallet step, waiting to be carried on-chain -// (by "Apply now" or the next Transact). The config signature is captured once; -// the carrying tx adds only its own senderAuth. -type SignedOwnerChange = { - accountId: string; - change: AaAccountChange; - sequence: number; - resultingOwners: StoredActor[]; - summary: string[]; -}; - /** Thrown when a tx was broadcast but not confirmed before the timeout. */ export class TxPendingError extends Error { readonly txHash: Hex; @@ -260,13 +151,47 @@ export class EstimateRevertedError extends Error { } } -type PendingChangeItem = { - change: AaAccountChange; - sequence: number; - sessionId?: string; - resultingOwners?: StoredActor[]; +/** ERC-8168 payer for a composed transaction. */ +export type ComposePayer = { + address: Address; + /** + * Phase-0 ERC-20 payment to the payer. With a `rate` (WAD token units per + * wei) the amount is raised to cover the gas the transaction is signed with. + */ + tokenPayment?: { token: Address; to: Address; amount: bigint; rate?: bigint | null }; + /** + * Co-signs `payerAuth` inline with a key this browser holds (the B20 demo's + * own faucet-funded payer EOA). Without it the tx is serialized with an empty + * `payerAuth` for a hosted payer service to co-sign out of band. + */ + localSigner?: Signer; +}; + +export type ComposeOptions = { + rows: CallRow[]; + metadata?: Hex; + /** Set this EOA's code delegation to `target` (the zero address clears it). */ + delegateTo?: Address; + /** Send nonce-free (expiring) instead of on the sequential nonce, valid for this many seconds. */ + noncelessSeconds?: number; + payer?: ComposePayer; + /** Upper validity bound (unix ms); a nonce-free send keeps the earlier of this and its own window. */ + validBefore?: bigint; + fees?: { maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }; + /** Never sign with less gas than this (a payer's `minGasLimit`). */ + minGas?: bigint; + estimateRevert?: 'fallback' | 'throw' | 'force'; +}; + +export type ComposedTransaction = { + serialized: Hex; + transaction: TransactionSerializable8130; + /** The phase-0 token payment actually signed, when paying a payer in tokens. */ + paymentAmount?: bigint; }; +const DEFAULT_FEES = { maxFeePerGas: 1_000_000_000n, maxPriorityFeePerGas: 1_000_000n }; + // --------------------------------------------------------------------------- function useAccountEngineCore() { @@ -281,67 +206,22 @@ function useAccountEngineCore() { setActivity, networkShort, setNetworkShort, - genesisHash, setGenesisHash, hydrated, addAccount, deleteAccount, } = useAccounts(); - const [busy, setBusy] = useState(null); - - const [activeSignerId, setActiveSignerId] = useState(null); - + const [busy, setBusy] = useState(false); const [faucetBusy, setFaucetBusy] = useState(null); // Regenesis (devnet reset) detection. const [regenesisNotice, setRegenesisNotice] = useState(false); - // Owner-change staging (draft owners vs applied owners). - const [ownerDraft, setOwnerDraft] = useState([]); - const [scopeDraft, setScopeDraft] = useState>({}); - const [signedChange, setSignedChange] = useState(null); - const [applying, setApplying] = useState(false); - - // Session-key apply state (the authorize/revoke form lives in SessionKeyEditor). - const [skApplyingId, setSkApplyingId] = useState(null); - const [policyRemaining, setPolicyRemaining] = useState< - Record< - string, - Record - > - >({}); - - // EIP-8130 system-contract addresses, resolved live from the dataplane so a - // devnet reset (which redeploys them to new addresses) never needs a code - // change. `null` until the first fetch lands → the static fallback in - // chains.ts is used. See the fetch effect below. - const [liveDeployment, setLiveDeployment] = useState(null); - // Overlay the live deployment onto a demo chain (vibenet only — Base Sepolia - // is a persistent testnet whose canonical addresses don't move). - const resolveChain = useCallback( - (short: string): DemoChain => { - const base = getDemoChain(short); - return liveDeployment && base.shortName === 'vibenet' - ? { ...base, deployment: liveDeployment } - : base; - }, - [liveDeployment], - ); - - const chain = useMemo(() => resolveChain(networkShort), [resolveChain, networkShort]); - // Proxy code for a smart account. MUST target a DEPLOYED implementation: with a - // codeless impl, policy-gated session-key sends route PolicyManager.execute -> - // account.executeBatch into empty code — the tx "succeeds", the policy consumes - // its spend counter, `PolicyExecuted` fires, yet no funds move. - // - // `accounts.upgradeable` (UpgradeableAccount) was removed from the canonical - // eip-8130 deploy and is NOT deployed on the devnet, which caused exactly that - // failure. Use `accounts.default` (deployed DefaultAccount). - const code = useMemo(() => upgradeableProxyBytecode(chain.deployment.accounts.default), [chain]); + const chain = useMemo(() => getDemoChain(networkShort), [networkShort]); // A viem public client pointed at vibenet's cross-origin RPC route — reads - // nonces / receipts and broadcasts native 8130 txs, plus the genesis hash. + // nonces / code / receipts and broadcasts native 8130 txs, plus the genesis hash. const makeRpcClient = useCallback( () => createPublicClient({ @@ -356,6 +236,49 @@ function useAccountEngineCore() { [chain], ); + const acct = useMemo(() => accounts.find((a) => a.id === activeAccountId) ?? null, [accounts, activeAccountId]); + const addressBook = useMemo( + () => accounts.map((a) => ({ label: a.label, address: a.address })), + [accounts], + ); + + const signerForAccount = useCallback( + (a: StoredAccount): WalletSigner | null => signers.find((s) => s.id === a.signerId) ?? null, + [signers], + ); + const activeSigner = acct ? signerForAccount(acct) : null; + + // --- code delegation ----------------------------------------------------- + // The active account's delegation target, read from its code + // (`0xef0100 || target`). `undefined` while unknown; `null` when undelegated. + const [delegation, setDelegation] = useState<{ address: Address; target: Address | null } | null>(null); + const activeAddress = acct?.address; + const readDelegation = useCallback(async () => { + if (!activeAddress) return null; + try { + const code = (await makeRpcClient().request({ method: 'eth_getCode', params: [activeAddress, 'latest'] })) as Hex; + return { address: activeAddress, target: parseDelegation(code) ?? null }; + } catch (err) { + console.error('Failed to read account code for delegation', err); + return null; + } + }, [activeAddress, makeRpcClient]); + const refreshDelegation = useCallback(async () => { + const next = await readDelegation(); + if (next) setDelegation(next); + }, [readDelegation]); + useEffect(() => { + let cancelled = false; + readDelegation().then((next) => { + if (next && !cancelled) setDelegation(next); + }); + return () => { + cancelled = true; + }; + }, [readDelegation]); + const delegationTarget = + acct && delegation?.address.toLowerCase() === acct.address.toLowerCase() ? delegation.target : undefined; + // --- regenesis detection ---------------------------------------------- useEffect(() => { if (!hydrated) return; @@ -371,7 +294,8 @@ function useAccountEngineCore() { if (!hash || cancelled) return; setGenesisHash((prev) => { if (prev && prev !== hash) { - setAccounts((accts) => accts.map((a) => (a.deployed ? { ...a, deployed: false } : a))); + // A reset wipes all code, so every delegation is gone. + setDelegation((d) => (d ? { ...d, target: null } : d)); setRegenesisNotice(true); } return hash; @@ -383,239 +307,7 @@ function useAccountEngineCore() { cancelled = true; clearInterval(t); }; - }, [hydrated, makeRpcClient, setAccounts, setGenesisHash]); - - // --- live EIP-8130 deployment resolution ------------------------------ - // Fetch the system-contract addresses from the dataplane on mount and again - // whenever a reset is detected (`genesisHash` changes). This is what makes the - // demo survive an arbitrary devnet reset with no code change. Keeps the same - // object identity when addresses are unchanged so `chain`/`code`/rpc-client - // memos don't churn. - useEffect(() => { - const controller = new AbortController(); - vibenetApi - .contracts(controller.signal) - .then((contracts) => { - const next = deploymentFromContracts(contracts); - if (!next) return; // malformed payload → keep static fallback - setLiveDeployment((prev) => (prev && JSON.stringify(prev) === JSON.stringify(next) ? prev : next)); - }) - .catch(() => { - /* offline / aborted → keep last-known-good deployment */ - }); - return () => controller.abort(); - }, [genesisHash]); - - const acct = useMemo(() => accounts.find((a) => a.id === activeAccountId) ?? null, [accounts, activeAccountId]); - const addressBook = useMemo( - () => accounts.map((a) => ({ label: a.label, address: a.address })), - [accounts], - ); - - // Owner signers for the active account. A sub-account is controlled by its - // parent (via key.delegate), so key selection resolves to the parent's owner - // signers — plus any direct owners the sub holds itself (e.g. a minted spare key). - const ownerSigners = useMemo(() => { - if (!acct) return [] as WalletSigner[]; - const parent = acct.parentId ? (accounts.find((a) => a.id === acct.parentId) ?? null) : null; - const ownerIds = new Set(); - for (const o of acct.owners) if (o.signerId) ownerIds.add(o.signerId); - if (parent) for (const o of parent.owners) if (o.signerId) ownerIds.add(o.signerId); - return signers.filter((s) => ownerIds.has(s.id)); - }, [acct, accounts, signers]); - const activeSigner = ownerSigners.find((s) => s.id === activeSignerId) ?? ownerSigners[0] ?? null; - - // Session-key signers held in the wallet (scoped actors, not owners). - const sessionSigners = useMemo(() => { - if (!acct) return [] as WalletSigner[]; - const ownerIds = new Set(acct.owners.map((o) => o.signerId)); - const seen = new Set(); - return acct.sessionKeys - .map((sk) => signers.find((s) => s.id === sk.signerId)) - .filter((s): s is WalletSigner => { - if (!s || ownerIds.has(s.id) || seen.has(s.id)) return false; - seen.add(s.id); - return true; - }); - }, [acct, signers]); - - // Staged owner changes (draft vs applied owners). - const pendingAuthorize = useMemo(() => { - if (!acct) return [] as WalletSigner[]; - return signers.filter((s) => ownerDraft.includes(s.id) && !acct.owners.some((o) => o.signerId === s.id)); - }, [acct, signers, ownerDraft]); - const pendingRevoke = useMemo(() => { - if (!acct) return [] as StoredActor[]; - return acct.owners.filter((o) => !ownerDraft.includes(o.signerId)); - }, [acct, ownerDraft]); - const pendingScope = useMemo(() => { - if (!acct) return [] as (StoredActor & { fromScope: number; toScope: number })[]; - return acct.owners - .filter((o) => ownerDraft.includes(o.signerId)) - .map((o) => { - const fromScope = o.scope ?? 0; - const toScope = scopeDraft[o.signerId] ?? fromScope; - return { ...o, fromScope, toScope }; - }) - .filter((o) => o.toScope !== o.fromScope); - }, [acct, ownerDraft, scopeDraft]); - const keyChangeCount = pendingAuthorize.length + pendingRevoke.length + pendingScope.length; - - // Owners valid *after* the staged changes apply — the keys eligible to sign a - // tx that carries the change. - const postChangeOwnerSigners = useMemo(() => { - if (!acct) return [] as WalletSigner[]; - const revokedIds = new Set(pendingRevoke.map((o) => o.signerId)); - const kept = ownerSigners.filter((s) => !revokedIds.has(s.id)); - const keptIds = new Set(kept.map((s) => s.id)); - const added = pendingAuthorize.filter((s) => !keptIds.has(s.id)); - return [...kept, ...added]; - }, [acct, ownerSigners, pendingRevoke, pendingAuthorize]); - - // A current owner able to authorize config changes (must be valid *before* the - // change). Prefer the tx signer when it's already a current owner — callers - // that have a concept of a "tx signer" (e.g. AccountDemo's Transact flow) pass - // it in; engine-internal callers pass `null`. - const configChangeSignerFor = useCallback( - (txSigner: WalletSigner | null): WalletSigner | null => { - if (keyChangeCount === 0) return null; - if (txSigner && ownerSigners.some((s) => s.id === txSigner.id)) return txSigner; - return ownerSigners.find((s) => s.id === activeSignerId) ?? ownerSigners[0] ?? null; - }, - [keyChangeCount, ownerSigners, activeSignerId], - ); - const configChangeSigner = useMemo(() => configChangeSignerFor(null), [configChangeSignerFor]); - - // Which staged changes ride an outgoing tx. Owner sends never install a - // session policy; session sends carry that key's authorize+install (plus any - // lower-sequence prerequisites for continuity). - const pendingChanges = useMemo(() => { - if (!acct) return []; - const items: PendingChangeItem[] = []; - if (signedChange && signedChange.accountId === acct.id) - items.push({ - change: signedChange.change, - sequence: signedChange.sequence, - resultingOwners: signedChange.resultingOwners, - }); - for (const sk of acct.sessionKeys) { - if (sk.pendingAuth) - items.push({ change: sk.pendingAuth.change, sequence: sk.pendingAuth.sequence, sessionId: sk.id }); - // A staged revoke is a local-counter change too — carry it like an - // authorization so it rides a session send / apply-all. - if (sk.pendingRevoke) - items.push({ change: sk.pendingRevoke.change, sequence: sk.pendingRevoke.sequence, sessionId: sk.id }); - } - return items.sort((a, b) => a.sequence - b.sequence); - }, [acct, signedChange]); - - const pendingBundleFor = (opts: { mode: 'owner-send' | 'session-send' | 'apply-all'; sessionId?: string }): PendingChangeItem[] => { - if (opts.mode === 'apply-all') return pendingChanges; - if (opts.mode === 'owner-send') - return pendingChanges.filter( - (i) => !i.sessionId && !pendingChanges.some((s) => s.sessionId && s.sequence < i.sequence), - ); - const active = pendingChanges.find((i) => i.sessionId === opts.sessionId); - if (!active) return pendingChanges.filter((i) => !i.sessionId); - return pendingChanges.filter((i) => i.sequence <= active.sequence); - }; - - const pendingSessionChangeCount = () => - (acct?.sessionKeys ?? []).filter((sk) => sk.pendingAuth || sk.pendingRevoke).length; - - // Re-sync owner draft + config-related state when the active account changes. - // Form-local state (the transact modal, the session-key editor) resets in the - // component that owns it, since this core has no notion of those forms. - useEffect(() => { - setOwnerDraft(acct ? acct.owners.map((o) => o.signerId) : []); - setScopeDraft(acct ? Object.fromEntries(acct.owners.map((o) => [o.signerId, o.scope ?? 0])) : {}); - setActiveSignerId(acct ? (acct.owners[0]?.signerId ?? null) : null); - setSignedChange(null); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeAccountId]); - - // --- session-key live spend remaining ---------------------------------- - // Read each installed session key's per-token budget from the SessionPolicy - // (getTokenLimit → cap + window, getCurrentSpend → usage) for the card's - // "remaining" readout. Pending (not-yet-installed) keys are skipped. - const sessionPolicyKey = useMemo( - () => - (acct?.sessionKeys ?? []) - .map((sk) => `${sk.id}:${sk.policy?.commitment ?? ''}:${sk.pendingAuth ? 'p' : 'd'}`) - .join('|'), - [acct], - ); - useEffect(() => { - if (!acct) { - setPolicyRemaining({}); - return; - } - const keys = acct.sessionKeys.filter((sk) => !sk.pendingAuth && sk.policy?.commitment && sk.policy.policy); - if (keys.length === 0) { - setPolicyRemaining({}); - return; - } - let cancelled = false; - (async () => { - const client = makeRpcClient() as unknown as { - readContract: (args: unknown) => Promise; - }; - const nowSecs = BigInt(Math.floor(Date.now() / 1000)); - const stable = await resolveStable(chain.shortName).catch(() => null); - const out: Record< - string, - Record - > = {}; - for (const sk of keys) { - const policy = sk.policy!; - const meta = new Map(); - for (const lim of policy.limits ?? []) - meta.set(lim.token.toLowerCase(), { symbol: lim.symbol, decimals: lim.decimals }); - if (!meta.has(ZERO_ADDR.toLowerCase())) meta.set(ZERO_ADDR.toLowerCase(), { symbol: 'ETH', decimals: 18 }); - if (stable && !meta.has(stable.address.toLowerCase())) - meta.set(stable.address.toLowerCase(), { symbol: stable.symbol, decimals: stable.decimals }); - - const perToken: Record< - string, - { remaining: bigint; allowance: bigint; symbol: string; decimals: number; period: number } - > = {}; - for (const [token, info] of meta) { - try { - const [set, allowance, period] = (await client.readContract({ - address: policy.policy, - abi: sessionPolicyAbi, - functionName: 'getTokenLimit', - args: [policy.commitment, token as Address], - })) as [boolean, bigint, number]; - if (!set) continue; - const spend = (await client.readContract({ - address: policy.policy, - abi: sessionPolicyAbi, - functionName: 'getCurrentSpend', - args: [policy.commitment, token as Address], - })) as { end: bigint | number; spend: bigint | number }; - const end = BigInt(spend.end ?? 0); - const used = end !== 0n && nowSecs >= end ? 0n : BigInt(spend.spend ?? 0); - perToken[token] = { - remaining: allowance > used ? allowance - used : 0n, - allowance, - symbol: info.symbol, - decimals: info.decimals, - period: Number(period), - }; - } catch { - /* RPC/read failure — fall back to the static cap */ - } - } - if (Object.keys(perToken).length > 0) out[sk.id] = perToken; - } - if (!cancelled) setPolicyRemaining(out); - })(); - return () => { - cancelled = true; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sessionPolicyKey, chain.shortName]); + }, [hydrated, makeRpcClient, setGenesisHash]); // --- helpers ----------------------------------------------------------- // Entries that name a tx hash pick up its inclusion timing automatically, so @@ -626,14 +318,6 @@ function useAccountEngineCore() { ...prev, ]); - const updateAccount = useCallback( - (id: string, patch: Partial | ((a: StoredAccount) => StoredAccount)) => - setAccounts((prev) => - prev.map((a) => (a.id === id ? (typeof patch === 'function' ? patch(a) : { ...a, ...patch }) : a)), - ), - [setAccounts], - ); - const refreshVibenetBalances = async (): Promise => { if (!acct) return null; return vibenetApi.account.balances(acct.address, 'vibenet').catch(() => null); @@ -675,77 +359,45 @@ function useAccountEngineCore() { .catch(() => toast.error('Auto top-up failed — use Top Up to retry')); }; - const createSigner = async (kind: SignerKind): Promise => { - setBusy(kind); + const nextSignerLabel = () => `${KIND_LABEL.k1} ${signers.length + 1}`; + + const createSigner = (): WalletSigner => { + setBusy(true); try { - const n = signers.filter((s) => s.kind === kind).length + 1; - const label = `${KIND_LABEL[kind]} ${n}`; - let ws: WalletSigner; - if (kind === 'k1') { - const pk = generatePrivateKey(); - const owner = privateKeyToAccount(pk); - const a = key.k1(owner.address); - ws = { - id: crypto.randomUUID(), - kind, - label, - privateKey: pk, - address: owner.address, - actorId: a.actorId, - authenticator: a.authenticator, - }; - } else if (kind === 'p256') { - const pk = generatePrivateKey(); - const s = toP256Signer({ privateKey: pk }); - const a = key.p256(s.publicKey); - ws = { - id: crypto.randomUUID(), - kind, - label, - privateKey: pk, - publicKey: s.publicKey, - actorId: a.actorId, - authenticator: a.authenticator, - }; - } else { - const credential = await createWebAuthnCredential({ name: label }); - const a = key.passkey(credential.publicKey); - ws = { - id: crypto.randomUUID(), - kind, - label, - credential: { id: credential.id, publicKey: credential.publicKey }, - actorId: a.actorId, - authenticator: a.authenticator, - }; - } - if (signers.some((s) => s.actorId === ws.actorId)) { - toast.error('That key is already in your wallet (same actor). Skipped.'); - return null; - } + const privateKey = generatePrivateKey(); + const ws: WalletSigner = { + id: crypto.randomUUID(), + kind: 'k1', + label: nextSignerLabel(), + privateKey, + address: privateKeyToAccount(privateKey).address, + }; setSigners((prev) => [...prev, ws]); return ws; - } catch (err) { - const e = err as { message?: string; name?: string }; - toast.error(e.name === 'NotAllowedError' ? 'Passkey prompt was dismissed.' : (e.message ?? String(err))); - return null; } finally { - setBusy(null); + setBusy(false); } }; - // Signer ids referenced by any account — as an owner, a session key, or a - // sub-account owner. Keys outside this set are unused and safe to delete. - const usedSignerIds = useMemo(() => { - const ids = new Set(); - for (const a of accounts) { - for (const o of a.owners) ids.add(o.signerId); - for (const o of a.initialActors) ids.add(o.signerId); - for (const sk of a.sessionKeys) ids.add(sk.signerId); - for (const sub of a.subAccounts) for (const id of sub.signerIds) ids.add(id); - } - return ids; - }, [accounts]); + // Adds an existing private key to the wallet, reusing the stored key when the + // same address is already held. Throws on a malformed key. + const importSigner = (privateKey: Hex): WalletSigner => { + const address = privateKeyToAccount(privateKey).address; + const existing = signers.find((s) => s.address.toLowerCase() === address.toLowerCase()); + if (existing) return existing; + const ws: WalletSigner = { + id: crypto.randomUUID(), + kind: 'k1', + label: nextSignerLabel(), + privateKey, + address, + }; + setSigners((prev) => [...prev, ws]); + return ws; + }; + + // Signer ids backing an account. Keys outside this set are unused and safe to delete. + const usedSignerIds = useMemo(() => new Set(accounts.map((a) => a.signerId)), [accounts]); // Drop an unused wallet key. The create modal owns its own selection state, so // it clears any reference to a just-deleted key itself. @@ -757,61 +409,6 @@ function useAccountEngineCore() { [usedSignerIds, setSigners], ); - // --- 8130 account handle + first-deploy change ------------------------- - const nativeAccountFor = (a: StoredAccount, signer: Signer, authenticator: Address) => { - const isDefaultEoaActor = - a.type === 'eoa' && - authenticator === ecrecoverAuthenticator && - !!signer.address && - signer.address.toLowerCase() === a.address.toLowerCase(); - if (isDefaultEoaActor) return toEoaAccount(signer); - if (a.type === 'eoa') { - return toAccount({ signer, address: a.address as Address, authenticator }); - } - // Sub-account controlled by a parent via `key.delegate(parent)`. When the - // selected signer is NOT one of the sub's own direct owners (e.g. a minted - // spare key), it must be a PARENT admin owner vouching through the - // DelegateAuthenticator. Wrap it so the senderAuth is the delegate blob - // (DELEGATE || parent || nestedAuthenticator || nestedSignature) instead of a - // plain [ecrecover||sig], which the node rejects with "actor is not bound" - // (the parent's k1 actorId is not an actor on the sub — only the delegate is). - if (a.parentId) { - const parent = accounts.find((p) => p.id === a.parentId) ?? null; - const selfActorId = key.k1(signer.address as Address).actorId.toLowerCase(); - const isDirectOwner = a.initialActors.some( - (o) => - o.actorId.toLowerCase() === selfActorId && - (o.authenticator ?? ecrecoverAuthenticator).toLowerCase() === ecrecoverAuthenticator.toLowerCase(), - ); - if (parent && !isDirectOwner) { - const delegateSigner = toDelegateSigner({ - delegateAccount: parent.address as Address, - nestedSigner: signer, - nestedAuthenticator: authenticator, - }); - return toAccount({ - signer: delegateSigner, - authenticator: delegateSigner.authenticator, - userSalt: a.salt, - code, - initialActors: sortActors(actorPairs(a.initialActors)), - }); - } - } - return toAccount({ - signer, - userSalt: a.salt, - code, - initialActors: sortActors(actorPairs(a.initialActors)), - authenticator, - }); - }; - - const firstDeployChange = (a: StoredAccount, account: ReturnType): AaAccountChange => - a.type === 'eoa' - ? account.delegate(a.delegate ?? chain.deployment.accounts.default) - : (account as ReturnType).create(); - // Inclusion timing per broadcast hash, in chain time: which block (and which // 200 ms slot) each transaction landed in, and how many blocks after the // newest head this page had seen when it broadcast. Written by @@ -894,309 +491,160 @@ function useAccountEngineCore() { return txHash; }; + // Record the newest head this page has seen as the anchor a broadcast's + // inclusion is measured from. Anchors outlive a pending timeout (a retry + // re-awaits the same hash), so abandoned ones are swept here instead. + const anchorSend = (txHash: Hex, anchor: SendAnchor | null) => { + const now = Date.now(); + for (const [hash, mark] of sendAnchors.current) if (now - mark.at > 300_000) sendAnchors.current.delete(hash); + sendAnchors.current.set(txHash, { anchor, at: now }); + }; + const latestAnchor = (): SendAnchor | null => { + const latest = ensureWatcher().latestHead(); + return latest ? { number: latest.number, timestampMs: latest.timestampMs } : null; + }; + // Broadcast a signed 8130 tx and wait for inclusion. Throws TxPendingError on // timeout (submitted but unconfirmed), a plain Error if any phase reverts. const broadcast8130 = async (signedTx: Hex, onStatus?: (s: 'submitting' | 'confirming') => void): Promise => { const client = makeRpcClient(); - const w = ensureWatcher(); onStatus?.('submitting'); - // The newest block this page has seen is the anchor the inclusion is - // measured from, on the chain's clock: read it before the send leaves. - const latest = w.latestHead(); - const anchor: SendAnchor | null = latest ? { number: latest.number, timestampMs: latest.timestampMs } : null; + // Read the anchor before the send leaves. + const anchor = latestAnchor(); const txHash = (await client.request({ method: 'eth_sendRawTransaction', params: [signedTx], })) as Hex; - // Anchors outlive a pending timeout (the batch retry re-awaits the same - // hash), so abandoned ones are swept here instead. - const now = Date.now(); - for (const [hash, mark] of sendAnchors.current) if (now - mark.at > 300_000) sendAnchors.current.delete(hash); - sendAnchors.current.set(txHash, { anchor, at: now }); + anchorSend(txHash, anchor); onStatus?.('confirming'); return awaitInclusion(txHash); }; - // Live EIP-8130 state used while preparing a transaction. This is the only - // source of truth for deployment and config sequences; the persisted - // `deployed` / `configSeq` fields are display caches and are never consulted - // while signing. - // - // Reads the account's two config-change counters: - // - `multichain` (configChainId 0) — carries OWNER (actor) changes, so they - // sequence independently of session-key authorizes. - // - `local` (per-chain) — carries session-key authorizes. - // Keeping them on separate counters means a pending session key can't shift an - // owner change's sequence (or vice versa) — the classic "config change sequence - // mismatch". Never guess a live sequence (a wrong value reverts on-chain): on a - // read failure we THROW so the caller aborts signing instead of using a guess. - const fetchOnChainAccountState = async ( - address: Address, - ): Promise<{ deployed: boolean; local: bigint; multichain: bigint }> => { - try { - const client = makeRpcClient(); - const [codeAt, { local, multichain }] = await Promise.all([ - client.request({ - method: 'eth_getCode', - params: [address as `0x${string}`, 'latest'], - }), - getConfigSequence(client, { account: address }), - ]); - return { deployed: !!codeAt && codeAt !== '0x', local, multichain }; - } catch (err) { - const reason = (err as { message?: string })?.message ?? String(err); - throw new Error( - `Couldn't read the on-chain EIP-8130 state for ${address}: ${reason}. Not signing with cached state.`, - ); - } + // Wait for a tx a hosted payer broadcast (`payer_sendTransaction`), measured + // from the head seen when the request left. + const awaitRelayed = async (txHash: Hex, anchor: SendAnchor | null): Promise => { + anchorSend(txHash, anchor); + return awaitInclusion(txHash); }; - // Compose + sign a native EIP-8130 transaction: first-use deploy change, - // any pre-signed owner/session config changes (carried in sequence order), - // optional payer pre-calls, and the user calls (wrapped through the - // PolicyManager when a session key signs — every execute carries the full - // committed binding, so there is no separate install phase). Returns the - // signed tx + the config sequence it advances to. - const signComposed = async ( - a: StoredAccount, - signerWS: WalletSigner, - rows: CallRow[], - presignedChanges: AaAccountChange[], - changeSeq: number | null, - meta: Hex | undefined, - sessionPolicy?: AppPolicy, - // `localSigner` co-signs `payerAuth` inline with a key this browser holds - // (the B20 demo's own faucet-funded payer EOA, which accepts an arbitrary - // B20 stablecoin as the fee). Without it the tx is serialized with an empty - // `payerAuth` for a hosted payer service to co-sign out of band. - payerOpt?: { address: Address; phase0?: { to: Address; data: Hex }[]; localSigner?: Signer }, - // Set by callers that run several transactions back to back. The public RPC - // is served by replicas whose heads can differ, so re-reading the nonce (or - // probing for code) between two sends can answer from a replica that hasn't - // seen the previous one yet. Such a caller reads both once up front and - // pins them here instead. - seqOpt?: { - nonceSequence?: bigint; - nonceKey?: bigint; - validBefore?: bigint; - assumeDeployed?: boolean; - estimateRevert?: 'fallback' | 'throw' | 'force'; - maxFeePerGas?: bigint; - maxPriorityFeePerGas?: bigint; - }, - ): Promise<{ serialized: Hex; nextSeq: number }> => { - const signer = await buildSigner(signerWS); - const account = nativeAccountFor(a, signer, signerWS.authenticator); - const chainId = chain.id || 84532; - const accountChanges: AaAccountChange[] = []; - const nextSeq = changeSeq ?? 0; - - // Sub-account signed via the parent's delegate actor? Then the acting actor - // (for estimation) is the delegate, not the parent owner's own k1 actor — and - // its senderAuth is the longer delegate blob. Detect it the same way - // nativeAccountFor does (parent owner, not a direct sub owner). - const parentAcct = a.parentId ? (accounts.find((p) => p.id === a.parentId) ?? null) : null; - const isDirectSubOwner = - !!a.parentId && - a.initialActors.some( - (o) => - o.actorId.toLowerCase() === signerWS.actorId.toLowerCase() && - (o.authenticator ?? ecrecoverAuthenticator).toLowerCase() === ecrecoverAuthenticator.toLowerCase(), - ); - const isDelegateSub = !!parentAcct && !isDirectSubOwner; - - // Resolve deployment + both config counters once at the composition - // boundary. Lower-level signing never consults the persisted account flags. - // A caller running several transactions back to back pins the deployment - // state instead: an earlier transaction in that run already deployed the - // account, and a code probe can still lag it and wrongly re-attach the - // create change. - const effectivelyDeployed = - seqOpt?.assumeDeployed ?? (await fetchOnChainAccountState(account.address as Address)).deployed; - const bootstrapChange = effectivelyDeployed ? undefined : firstDeployChange(a, account); - if (bootstrapChange) accountChanges.push(bootstrapChange); - if (effectivelyDeployed !== a.deployed) updateAccount(a.id, { deployed: effectivelyDeployed }); - accountChanges.push(...presignedChanges); + // Compose and sign one EOA transaction: + // phases `[payerPayment?, userPhase0?, userPhase1]`, an optional delegation + // change, sequential or nonce-free replay protection, and an optional payer. + // Gas comes from the node's 8130 `eth_estimateGas` (priced with the exact + // auth shapes), floored by the structural estimate. + const signComposed = async (a: StoredAccount, opts: ComposeOptions): Promise => { + const signerWS = signerForAccount(a); + if (!signerWS) throw new Error(`No local key found for ${a.label}.`); + const account = toEoaAccount(privateKeyToAccount(signerWS.privateKey)); + const client = makeRpcClient(); + const { rows, metadata, payer } = opts; + const accountChanges: AaAccountChange[] = opts.delegateTo ? [account.delegate(opts.delegateTo)] : []; const { phase0: userPhase0, phase1: userPhase1 } = buildPhases(rows, account.address); - const phases: { to: Address; value?: bigint; data?: Hex }[][] = []; - if (sessionPolicy) { - // A gated session key may only reach the PolicyManager, so wrap every user - // call as `PolicyManager.execute` (each execute carries the full committed - // binding — no install phase). Any payer USDV payment is also wrapped. - const sessionPhase0: { to: Address; value?: bigint; data?: Hex }[] = []; - if (payerOpt?.phase0 && payerOpt.phase0.length > 0) - sessionPhase0.push( - ...wrapSessionCalls( - payerOpt.phase0.map((c) => ({ to: c.to, value: 0n, data: c.data })), - sessionPolicy, - account.address, - ), - ); - if (sessionPhase0.length > 0) phases.push(sessionPhase0); - phases.push(wrapSessionCalls([...userPhase0, ...userPhase1], sessionPolicy, account.address)); - } else { - // [payerPreCalls?, userPhase0?, userPhase1] - if (payerOpt?.phase0 && payerOpt.phase0.length > 0) - phases.push(payerOpt.phase0.map((c) => ({ to: c.to, value: 0n, data: c.data }))); - if (userPhase0.length > 0) phases.push(userPhase0); - phases.push(userPhase1); - } - - // Structural gas-floor accounting: wrapped session calls are "heavy" - // (PolicyManager frames + first-use SSTOREs); everything else plain. - const totalCalls = phases.reduce((n, p) => n + p.length, 0); - const heavyCallCount = sessionPolicy ? userPhase0.length + userPhase1.length : 0; - const plainCallCount = Math.max(totalCalls - heavyCallCount, 1); - const wire = encodeWalletCalls({ account: account.address, calls: phases }); + const userPhases: AaCall[][] = [...(userPhase0.length > 0 ? [userPhase0] : []), userPhase1]; + const phasesWith = (paymentAmount: bigint | undefined): AaCall[][] => { + const payment = payer?.tokenPayment; + if (!payment || paymentAmount === undefined) return userPhases; + const transfer = encodeTokenTransfer({ token: payment.token, to: payment.to, amount: paymentAmount }); + return [[{ to: transfer.to, data: transfer.data }], ...userPhases]; + }; - const nonceKey = seqOpt?.nonceKey ?? 0n; + const nonceless = opts.noncelessSeconds !== undefined ? noncelessFields(opts.noncelessSeconds) : null; + const nonceKey = nonceless?.nonceKey ?? 0n; const nonceSequence = - seqOpt?.nonceSequence ?? - (await getTransactionCount(makeRpcClient(), { - address: account.address as Address, - nonceKey, - })); - - // Authenticator hint so estimateGas shapes the senderAuth stub for the - // actual signer. A delegate-signed sub-account acts via the parent's delegate - // actor, whose senderAuth is the longer delegate blob — hint the delegate - // authenticator. - const senderAuthAuthenticator: Address = isDelegateSub - ? canonicalAuthenticators.delegate - : signerWS.kind === 'p256' - ? canonicalAuthenticators.p256 - : signerWS.kind === 'passkey' - ? canonicalAuthenticators.passkey - : canonicalAuthenticators.k1; - const senderActorId: Hex = - isDelegateSub && parentAcct ? key.delegate(parentAcct.address as Address).actorId : signerWS.actorId; - + nonceless?.nonceSequence ?? (await getTransactionCount(client, { address: account.address, nonceKey })); + const validBefore = + nonceless && opts.validBefore !== undefined + ? nonceless.validBefore < opts.validBefore + ? nonceless.validBefore + : opts.validBefore + : (nonceless?.validBefore ?? opts.validBefore); + const fees = opts.fees ?? DEFAULT_FEES; + + const totalCalls = userPhases.reduce((n, p) => n + p.length, 0); // Structural gas floor. `false` = realistic-with-headroom (a floor UNDER a - // successful node estimate). `true` = 2x over-provision (used when no node - // estimate is available, so a heavy policy/payer send can't under-provision - // and OOG-revert — unused gas is refunded). - const floorGas = (fallback = false) => - estimateTxGas({ - mode: chain.mode, - deploy: !effectivelyDeployed, - calls: plainCallCount, - keyChanges: accountChanges.filter((c) => c.type === 'config').length, - policyCalls: heavyCallCount, - // Value-bearing user calls carry the stipend + cold-account cost the node - // estimate misses (policy-wrapped sends still forward the ETH value). - valueCalls: valueBearingCallCount(rows), - fallback, - }); + // successful node estimate). `true` = 2x over-provision, used when no node + // estimate is available so a send can't under-provision and OOG-revert — + // unused gas is refunded. + const floorGas = (fallback: boolean) => + BigInt( + estimateTxGas({ + calls: totalCalls, + valueCalls: valueBearingCallCount(rows, account.address), + delegation: accountChanges.length > 0, + nonceless: !!nonceless, + payer: !!payer, + tokenPayment: !!payer?.tokenPayment, + fallback, + }), + ); + let gasLimit: bigint; - if (chain.mode === 'eip8130-native') { - try { - const estimated = await estimateGas(makeRpcClient(), { - sender: account.address as Address, - // Name the acting actor so the node can fully simulate the tx — - // policy-gated session keys (resolving the actor's scope + PolicyManager - // binding) and payer (ERC-8168) bundles. Without it the node falls back - // to the account's self actor and mis-prices or reverts those shapes, - // which under-provisions a session send and OOG-reverts on-chain. - senderActorId, - accountChanges, - calls: phases, - nonceSequence: Number(nonceSequence), - senderAuthAuthenticator, - // The delegate authenticator has no fixed default auth-payload length, - // so hand the estimator the exact senderAuth size (delegate blob). - ...(isDelegateSub ? { senderAuthSize: delegateAuthSize() } : {}), - ...(payerOpt ? { payer: payerOpt.address } : {}), - }); - gasLimit = safeGasLimit(estimated, floorGas(false)); - } catch (err) { - // With `senderActorId` supplied the node CAN simulate session-key/policy/ - // payer bundles, so a failed estimate now generally means the tx would - // actually revert. Only a few shapes are benign and fall back to the floor: - if (isUnsupportedRpcError(err)) { - // Node lacks the 8130 `eth_estimateGas` extension — floor is still correct. - gasLimit = BigInt(floorGas(true) || 200_000); - } else if (!effectivelyDeployed) { - // A tx carrying `create` can't be simulated (account doesn't exist yet; - // the node rejects with -32602) — but the create binds actors and lands. - gasLimit = BigInt(floorGas(true) || 200_000); - } else if (isDelegateSub) { - // Delegate sub-account: the nested (parent) vouch through the - // DelegateAuthenticator is a shape the node's estimator may not simulate, - // but a broadcast still lands — fall back to the generous floor. - gasLimit = BigInt(floorGas(true) || 200_000); - } else if (seqOpt?.estimateRevert === 'force') { - // User chose "Send anyway": price at a high ceiling so an under-estimate - // isn't the cause of a revert. If it still reverts, it's a genuine logic - // failure and the gas is spent (self-pay) / rejected (payer). - gasLimit = BigInt(Math.max(floorGas(true) * 2, 2_000_000)); - } else if (seqOpt?.estimateRevert === 'throw') { - // Genuine reverting estimate on a Transact send — surface it instead of - // broadcasting a doomed tx. The Transact view shows a "Send anyway" hatch. - throw new EstimateRevertedError(estimateFailureReason(err)); - } else { - // Non-transact caller (config apply flows) — keep the over-provisioned - // floor so a genuine revert surfaces via the normal on-chain error path. - gasLimit = BigInt(floorGas(true) || 200_000); - } + try { + const estimated = await estimateGas(client, { + sender: account.address, + accountChanges, + calls: phasesWith(payer?.tokenPayment?.amount), + nonceKey, + ...(validBefore !== undefined ? { validBefore } : {}), + senderAuthAuthenticator: k1Authenticator, + ...(payer ? { payer: payer.address, payerAuthAuthenticator: k1Authenticator } : {}), + ...(metadata ? { dataSuffix: metadata } : {}), + }); + gasLimit = safeGasLimit(estimated, Number(floorGas(false))); + } catch (err) { + if (isUnsupportedRpcError(err)) { + // Node lacks the 8130 `eth_estimateGas` extension — floor is still correct. + gasLimit = floorGas(true); + } else if (opts.estimateRevert === 'force') { + // User chose "Send anyway": price at a high ceiling so an under-estimate + // isn't the cause of a revert. If it still reverts, it's a genuine logic + // failure and the gas is spent (self-pay) / rejected (payer). + gasLimit = BigInt(Math.max(Number(floorGas(true)) * 2, 2_000_000)); + } else if (opts.estimateRevert === 'throw') { + throw new EstimateRevertedError(estimateFailureReason(err)); + } else { + gasLimit = floorGas(true); } - } else { - gasLimit = BigInt(floorGas(true) || 200_000); + } + if (opts.minGas !== undefined && gasLimit < opts.minGas) gasLimit = opts.minGas; + + // The binding price of a token offer is its rate at the signed gas and fee. + let paymentAmount = payer?.tokenPayment?.amount; + const rate = payer?.tokenPayment?.rate; + if (paymentAmount !== undefined && rate) { + const required = requiredTokenAmount(gasLimit, fees.maxFeePerGas, rate); + if (required > paymentAmount) paymentAmount = required; } + const transaction: TransactionSerializable8130 = { + chainId: chain.id || 84538453, + from: account.address, + nonceKey, + nonceSequence, + ...(validBefore !== undefined ? { validBefore } : {}), + maxFeePerGas: fees.maxFeePerGas, + maxPriorityFeePerGas: fees.maxPriorityFeePerGas, + gas: gasLimit, + ...(accountChanges.length > 0 ? { accountChanges } : {}), + calls: phasesWith(paymentAmount), + ...(metadata ? { metadata } : {}), + ...(payer ? { payer: payer.address } : {}), + }; const serialized = await account.signTransaction( - { - chainId, - accountChanges, - calls: wire, - metadata: meta, - nonceKey, - nonceSequence, - ...(seqOpt?.validBefore !== undefined ? { validBefore: seqOpt.validBefore } : {}), - maxFeePerGas: seqOpt?.maxFeePerGas ?? 1_000_000_000n, - maxPriorityFeePerGas: seqOpt?.maxPriorityFeePerGas ?? 1_000_000n, - gas: gasLimit, - // A local payer signs `payerAuth` here, so don't stub it out. - ...(payerOpt ? { payer: payerOpt.address, ...(payerOpt.localSigner ? {} : { payerAuth: '0x' as Hex }) } : {}), - }, - payerOpt?.localSigner ? { payer: { account: payerOpt.localSigner, address: payerOpt.address } } : undefined, + transaction, + payer?.localSigner ? { payer: { account: payer.localSigner, address: payer.address } } : undefined, ); - return { serialized, nextSeq }; - }; - - // Apply the on-chain effects a landed tx carried: mark deployed, advance the - // config sequence, apply a bundled owner change, clear bundled keys' pendingAuth, - // remove keys whose staged revoke landed, and record any newly-trusted managers. - const applyLandedBundle = (a: StoredAccount, nextSeq: number, bundle: PendingChangeItem[]) => { - const ownerItem = bundle.find((i) => i.resultingOwners); - const bundledSessionIds = new Set(bundle.flatMap((i) => (i.sessionId ? [i.sessionId] : []))); - const newOwners = ownerItem?.resultingOwners ?? a.owners; - updateAccount(a.id, (acc) => ({ - ...acc, - deployed: true, - configSeq: nextSeq, - owners: ownerItem?.resultingOwners ?? acc.owners, - sessionKeys: commitLandedSessions(acc, bundledSessionIds), - trustedManagers: mergeLandedManagers(acc, bundledSessionIds), - })); - if (ownerItem) { - setSignedChange(null); - setOwnerDraft(newOwners.map((o) => o.signerId)); - setScopeDraft(Object.fromEntries(newOwners.map((o) => [o.signerId, o.scope ?? 0]))); - } + return { serialized, transaction, paymentAmount }; }; - // Shared owner-signed call path for account-backed demos outside the account - // transaction builder. It deliberately reuses the full compose/broadcast - // implementation so deployment reconciliation, sub-account delegation, gas - // estimation, and eligible staged account changes behave consistently. - // - // `calls` land as one atomic EIP-8130 transaction, so a demo can pair an - // approve with the call that spends it. `tokenGas` routes the transaction - // through a caller-supplied ERC-8168 payer: phase 0 pays that payer a flat - // fee in the given token and the payer's own ETH covers gas, which is how a - // demo lets you pay fees in a token you just created. Without it the account - // pays its own gas. + // Shared call path for account-backed demos outside the account transaction + // builder (B20). `calls` land as one atomic EIP-8130 transaction, so a demo + // can pair an approve with the call that spends it. `tokenGas` routes the + // transaction through a caller-supplied ERC-8168 payer: phase 0 pays that + // payer a flat fee in the given token and the payer's own ETH covers gas, + // which is how a demo lets you pay fees in a token you just created. Without + // it the account pays its own gas. const sendActiveCalls = async ({ calls, tokenGas, @@ -1209,912 +657,19 @@ function useAccountEngineCore() { }): Promise<{ hash: Hex; serialized: Hex; mode: 'self' | 'token'; inclusion?: Inclusion }> => { if (!acct) throw new Error('Select an account before you continue.'); if (!calls.length) throw new Error('No calls to send.'); - const signer = - postChangeOwnerSigners.find((s) => s.id === activeSignerId) ?? - postChangeOwnerSigners[0] ?? - activeSigner; - if (!signer) throw new Error('No local owner key found for this account.'); - - const bundle = pendingBundleFor({ mode: 'owner-send' }); - const presigned = bundle.map((item) => item.change); - const changeSeq = bundle.length ? bundle[bundle.length - 1].sequence : null; - const payerOpt = tokenGas - ? { - address: tokenGas.payer.address, - phase0: [ - (({ to, data }) => ({ to, data }))( - encodeTokenTransfer({ token: tokenGas.token, to: tokenGas.payer.address, amount: tokenGas.fee }), - ), - ], - localSigner: tokenGas.payer, - } - : undefined; - const { serialized, nextSeq } = await signComposed( - acct, - signer, - calls.map((call) => newCallRow({ to: call.to, data: call.data, value: call.value ?? '0' })), - presigned, - changeSeq, - metadata?.trim() ? toHex(metadata.trim()) : undefined, - undefined, - payerOpt, - ); - const hash = await broadcast8130(serialized); - applyLandedBundle(acct, nextSeq, bundle); - return { hash, serialized, mode: tokenGas ? 'token' : 'self', inclusion: inclusionFor(hash) }; - }; - - // Sign + broadcast from a specific stored account (not necessarily the active - // one). Validity's simulated makers are delegated sub-accounts; switching - // `activeAccountId` to send from them would steal the user's selection. - const signerForAccount = (account: StoredAccount): WalletSigner => { - const parent = account.parentId ? (accounts.find((item) => item.id === account.parentId) ?? null) : null; - const ownerIds = new Set(); - for (const owner of account.owners) if (owner.signerId) ownerIds.add(owner.signerId); - if (parent) for (const owner of parent.owners) if (owner.signerId) ownerIds.add(owner.signerId); - const candidates = signers.filter((signer) => ownerIds.has(signer.id)); - const spare = candidates.find( - (signer) => - signer.kind === 'k1' && - signer.privateKey && - account.owners.some((owner) => owner.signerId === signer.id), - ); - const signer = spare ?? candidates[0]; - if (!signer) throw new Error(`No local owner key found for ${account.label}.`); - return signer; - }; - - const signAccountCalls = async ({ - account, - calls, - seqOpt, - metadata, - }: { - account: StoredAccount; - calls: { to: Address; data: Hex; value?: string }[]; - seqOpt?: { - nonceSequence?: bigint; - nonceKey?: bigint; - validBefore?: bigint; - assumeDeployed?: boolean; - maxFeePerGas?: bigint; - maxPriorityFeePerGas?: bigint; - }; - metadata?: string; - }): Promise<{ serialized: Hex; nextSeq: number }> => { - if (!calls.length) throw new Error('No calls to send.'); - const signer = signerForAccount(account); - return signComposed( - account, - signer, - calls.map((call) => newCallRow({ to: call.to, data: call.data, value: call.value ?? '0' })), - [], - null, - metadata?.trim() ? toHex(metadata.trim()) : undefined, - undefined, - undefined, - seqOpt, - ); - }; - - const sendAccountCalls = async ({ - wait = true, - ...signArgs - }: Parameters[0] & { - wait?: boolean; - }): Promise<{ hash: Hex; serialized: Hex; nextSeq: number }> => { - const { account } = signArgs; - const { serialized, nextSeq } = await signAccountCalls(signArgs); - if (wait) { - const hash = await broadcast8130(serialized); - applyLandedBundle(account, nextSeq, []); - return { hash, serialized, nextSeq }; - } - const hash = (await makeRpcClient().request({ - method: 'eth_sendRawTransaction', - params: [serialized], - })) as Hex; - applyLandedBundle(account, nextSeq, []); - return { hash, serialized, nextSeq }; - }; - - /** - * Run several transactions from the active account back to back. - * - * Not a loop over `sendActiveCalls`: the reads that call depends on — the - * account's nonce and whether it has code — are answered by load-balanced RPC - * replicas whose heads can differ, so re-reading them between two sends can - * return a view that predates the previous one. That drops the second - * transaction as a duplicate nonce, or re-attaches the create change to an - * account that already exists. Both reads happen once here, and each batch - * gets its sequence counted from there. - * - * Pending owner/session changes ride the first batch only. Returns one result - * per batch; throws on the first failure, leaving earlier batches applied - * (callers should make each batch meaningful on its own). - */ - const sendActiveCallsBatches = async ({ - batches, - tokenGas, - onBatchStart, - onBatchResult, - }: { - batches: { calls: { to: Address; data: Hex }[] }[]; - tokenGas?: { token: Address; decimals: number; payer: Signer; fee: bigint }; - onBatchStart?: (index: number, total: number) => void; - onBatchResult?: (index: number, result: { hash: Hex; serialized: Hex; mode: 'self' | 'token' }) => void; - }): Promise<{ hash: Hex; serialized: Hex; mode: 'self' | 'token' }[]> => { - if (!acct) throw new Error('Select an account before you continue.'); - if (!batches.length) throw new Error('No calls to send.'); - const signer = - postChangeOwnerSigners.find((s) => s.id === activeSignerId) ?? - postChangeOwnerSigners[0] ?? - activeSigner; - if (!signer) throw new Error('No local owner key found for this account.'); - - const bundle = pendingBundleFor({ mode: 'owner-send' }); - const presigned = bundle.map((item) => item.change); - const changeSeq = bundle.length ? bundle[bundle.length - 1].sequence : null; - const payerOpt = tokenGas - ? { - address: tokenGas.payer.address, - phase0: [ - (({ to, data }) => ({ to, data }))( - encodeTokenTransfer({ token: tokenGas.token, to: tokenGas.payer.address, amount: tokenGas.fee }), - ), - ], - localSigner: tokenGas.payer, - } - : undefined; - - // Read the starting nonce a few times and keep the highest: a single read - // can land on a replica that is a block behind. - const address = acct.address as Address; - let startSequence = 0n; - for (let i = 0; i < 3; i += 1) { - const count = await getTransactionCount(makeRpcClient(), { address, nonceKey: 0n }).catch(() => null); - if (count !== null && count > startSequence) startSequence = count; - } - - // An account's code and the actors bound to it reach every replica a moment - // after the transaction that wrote them lands, so a batch prepared right - // behind the one that deployed the account is validated against a replica - // that has not seen it yet and is rejected with "actor is not bound" before - // it is ever broadcast. Wait for the state to catch up and prepare it again. - // A transaction that expired without landing is definitively dropped, so - // that one can go straight back out. Everything else — a revert, a rejected - // call, a broadcast whose receipt never arrived — is real and propagates. - const attemptBatch = async (send: () => Promise): Promise => { - for (let attempt = 0; ; attempt += 1) { - try { - return await send(); - } catch (error) { - if (attempt >= 3) throw error; - // Broadcast but not included in time. Give it a little longer, then - // ask the node whether it still holds the transaction: one it has - // dropped is never coming back, so the batch is signed and sent again - // on the same nonce. One it still holds must be left alone — a second - // copy would only collide with it. - if (error instanceof TxPendingError) { - const landed = await awaitInclusion(error.txHash, 15_000).catch((err) => { - if (err instanceof TxPendingError) return null; - throw err; - }); - if (landed) return landed; - const known = await makeRpcClient() - .request({ method: 'eth_getTransactionByHash', params: [error.txHash] }) - .catch(() => 'unreadable'); - if (known !== null) throw error; - continue; + const { serialized } = await signComposed(acct, { + rows: calls.map((call) => newCallRow({ to: call.to, data: call.data, value: call.value ?? '0' })), + metadata: metadata?.trim() ? toHex(metadata.trim()) : undefined, + payer: tokenGas + ? { + address: tokenGas.payer.address, + tokenPayment: { token: tokenGas.token, to: tokenGas.payer.address, amount: tokenGas.fee }, + localSigner: tokenGas.payer, } - const message = error instanceof Error ? error.message : String(error); - const expired = /expired before landing/i.test(message); - if (!expired && !/actor is not bound/i.test(message)) throw error; - await new Promise((resolve) => setTimeout(resolve, expired ? 1_000 : 5_000)); - } - } - }; - - const results: { hash: Hex; serialized: Hex; mode: 'self' | 'token' }[] = []; - const mode: 'self' | 'token' = tokenGas ? 'token' : 'self'; - for (const [index, batch] of batches.entries()) { - onBatchStart?.(index, batches.length); - const first = index === 0; - // Written by whichever signing attempt produced the transaction that - // landed — a retry re-signs, so these can't be read from the first one. - let landedSeq: number | null = null; - let landedSerialized: Hex = '0x'; - const hash = await attemptBatch(async () => { - const { serialized, nextSeq } = await signComposed( - acct, - signer, - batch.calls.map((call) => newCallRow({ ...call, value: '0' })), - first ? presigned : [], - first ? changeSeq : null, - undefined, - undefined, - payerOpt, - { nonceSequence: startSequence + BigInt(index), assumeDeployed: !first || undefined }, - ); - landedSeq = nextSeq; - landedSerialized = serialized; - return broadcast8130(serialized); - }); - if (first && landedSeq !== null) applyLandedBundle(acct, landedSeq, bundle); - const result = { hash, serialized: landedSerialized, mode }; - results.push(result); - onBatchResult?.(index, result); - } - return results; - }; - - // --- owner changes ----------------------------------------------------- - const invalidateSignedChange = () => setSignedChange(null); - const discardOwnerChanges = () => { - setSignedChange(null); - if (!acct) return; - setOwnerDraft(acct.owners.map((o) => o.signerId)); - setScopeDraft(Object.fromEntries(acct.owners.map((o) => [o.signerId, o.scope ?? 0]))); - }; - const stageAddOwner = (id: string) => { - setOwnerDraft((prev) => (prev.includes(id) ? prev : [...prev, id])); - invalidateSignedChange(); - }; - const stageRemoveOwner = (id: string, eoaSelf: boolean) => { - if ( - eoaSelf && - !window.confirm( - "Revoke the EOA's own key? The EOA will no longer be able to sign for this account — make sure another owner is authorized first.", - ) - ) - return; - setOwnerDraft((prev) => prev.filter((x) => x !== id)); - invalidateSignedChange(); - }; - const setOwnerScope = (id: string, scope: number) => { - setScopeDraft((prev) => ({ ...prev, [id]: scope })); - invalidateSignedChange(); - }; - const mintOwner = async (kind: SignerKind) => { - const s = await createSigner(kind); - if (s) { - setOwnerDraft((prev) => [...prev, s.id]); - invalidateSignedChange(); - } - }; - - const buildAuthorizeActions = (): { actorId: Hex; authenticator: Address; scope: number }[] => [ - ...pendingAuthorize.map((s) => ({ - actorId: s.actorId, - authenticator: s.authenticator, - scope: scopeDraft[s.id] ?? 0, - })), - ...pendingScope.map((o) => ({ actorId: o.actorId, authenticator: o.authenticator, scope: o.toScope })), - ]; - const applyOwnerUpdate = (a: StoredAccount): StoredActor[] => { - const kept = a.owners - .filter((o) => ownerDraft.includes(o.signerId)) - .map((o) => ({ ...o, scope: scopeDraft[o.signerId] ?? o.scope ?? 0 })); - const added = pendingAuthorize.map((s) => ({ ...toStoredActor(s), scope: scopeDraft[s.id] ?? 0 })); - return [...kept, ...added]; - }; - - // Sign the owner change on its own (a current owner authorizes it). Captures - // the signed blob; it then rides the next Transact or an explicit "Apply now". - // Returns true once a signed change is staged so callers can open the apply - // dialog only on success. - const signOwnerChange = async (): Promise => { - if (!acct || keyChangeCount === 0) return false; - const changeWS = configChangeSigner ?? activeSigner; - if (!changeWS) return false; - setApplying(true); - try { - const changeSigner = await buildSigner(changeWS); - const changeAccount = nativeAccountFor(acct, changeSigner, changeWS.authenticator); - // Owner (actor) changes live on the GLOBAL multichain config counter - // (configChainId 0) so they sequence independently of session-key - // authorizes (per-chain local counter) — a pending session key can't shift - // this sequence, and vice versa. - const chainId = 0; - // Neither create nor delegation consumes the multichain counter, so the - // network-returned value is always the sequence to sign. - const { multichain } = await fetchOnChainAccountState(changeAccount.address as Address); - const nextSeq = Number(multichain); - const change = await changeAccount.change( - [ - ...buildAuthorizeActions().map((s) => - s.scope - ? authorizeActor({ actorId: s.actorId, authenticator: s.authenticator }, { scope: s.scope }) - : authorizeActor({ actorId: s.actorId, authenticator: s.authenticator }), - ), - ...pendingRevoke.map((o) => revokeActor(o.actorId)), - ], - { channel: 'multichain', chainId, sequence: multichain }, - ); - setSignedChange({ - accountId: acct.id, - change, - sequence: nextSeq, - resultingOwners: applyOwnerUpdate(acct), - summary: [ - ...pendingAuthorize.map((s) => `authorize ${s.label}`), - ...pendingRevoke.map((o) => `revoke ${o.label}`), - ...pendingScope.map((o) => `scope ${o.label} → ${scopeLabel(o.toScope)}`), - ], - }); - return true; - } catch (err) { - const e = err as { message?: string; name?: string }; - toast.error(e.name === 'NotAllowedError' ? 'Signature was dismissed.' : (e.message ?? String(err))); - return false; - } finally { - setApplying(false); - } - }; - - // Apply an already-signed owner change now: a post-change owner signs a no-op - // tx that carries it. - const applyOwnerNow = async ( - onStatus?: (status: '' | 'submitting' | 'confirming') => void, - ): Promise<{ hash: Hex; label: string } | null> => { - if (!acct || !signedChange || signedChange.accountId !== acct.id) return null; - const txWS = postChangeOwnerSigners.find((s) => s.id === activeSignerId) ?? postChangeOwnerSigners[0] ?? activeSigner; - if (!txWS) return null; - const bundle = pendingBundleFor({ mode: 'owner-send' }); - if (!bundle.some((i) => !i.sessionId)) - throw new Error( - 'A pending session key is ahead in the config sequence. Apply or discard it first, then apply the owner change.', - ); - const presigned = bundle.map((i) => i.change); - const changeSeq = bundle.length ? bundle[bundle.length - 1].sequence : signedChange.sequence; - const summary = signedChange.summary; - setApplying(true); - try { - const { serialized, nextSeq } = await signComposed(acct, txWS, [newCallRow()], presigned, changeSeq, undefined, undefined, undefined); - const txHash = await broadcast8130(serialized, onStatus); - applyLandedBundle(acct, nextSeq, bundle); - pushActivity({ - kind: 'transact', - title: 'Key changes landed onchain', - txHash, - changes: summary, - network: chain.name, - mode: chain.mode, - serialized, - account: acct.address, - }); - return { hash: txHash, label: 'Owner change' }; - } finally { - setApplying(false); - onStatus?.(''); - } - }; - - // --- session keys ------------------------------------------------------ - // Mint the owner-signed authorization for a session key. `defer` captures it - // without broadcasting — the key authorizes on its first transaction (or via - // "Apply now"). Returns the stored key. - const doAuthorizeSession = async ( - target: WalletSigner, - opts: { - expirySecs: number; - policyLabel: string; - spec: PolicySpec; - label: string; - chainShort: string; - // `true` (default): capture the owner-signed authorization and install on - // the key's first use. `false`: sign an immediate authorize+install tx now - // (the caller broadcasts the returned `serialized`, then calls `commit()` - // to persist the key + `deployed` state ONLY once the tx has landed). - defer?: boolean; - }, - ): Promise<(AppSessionKey & { commit?: () => void }) | null> => { - const defer = opts.defer ?? true; - if (!acct || !activeSigner) return null; - const skChain = resolveChain(opts.chainShort); - const ownerSigner = await buildSigner(activeSigner); - const account = nativeAccountFor(acct, ownerSigner, activeSigner.authenticator); - // Every session key in this demo is policy-gated (an owner-signed authorize - // always binds a SessionPolicy via the PolicyManager — see below), so grant - // SCOPE.policy (key is constrained to its bound PolicyManager) plus SCOPE.nonce - // (the send path signs with the account's sequenced nonce key; without the - // nonce bit the node rejects the send with "actor scope insufficient"). This - // does NOT grant config-change rights (that's the admin scope 0, for owners). - const scope = SCOPE.policy | SCOPE.nonce; - const expiry = opts.expirySecs ? BigInt(Math.floor(Date.now() / 1000) + opts.expirySecs) : 0n; - - if (!skChain.deployment.policies) throw new Error(`Session policies are not available on ${skChain.name}.`); - const { config, summary, limits } = await buildSessionConfig(opts.spec, skChain.shortName); - const policyConfig = encodeSessionPolicyConfig(config); - const session = defineSessionPolicy({ - account: account.address, - policy: skChain.deployment.policies.sessionPolicy, - policyConfig, - manager: skChain.deployment.policies.manager, - validUntil: expiry, - }); - const actorPolicy = session.actorPolicy; - const policy: AppPolicy = { - type: session.actorPolicy.type, - label: opts.policyLabel, - manager: session.manager, - policy: session.policy, - policyConfig, - // Persist the full binding so every later execute (see `sessionFor`) - // recomputes the same commitment the account authorized. - validAfter: session.binding.validAfter, - validUntil: session.binding.validUntil, - salt: session.binding.salt, - commitment: session.commitment, - params: summary, - limits, - }; - - // Session-key authorizes live on the per-chain LOCAL config counter, - // independent of owner changes (multichain counter). Start from a fresh - // network read, then reserve positions for already-staged session changes. - const chainId = skChain.id || 84532; - const liveState = await fetchOnChainAccountState(account.address as Address); - const bootstrapChange = liveState.deployed ? undefined : firstDeployChange(acct, account); - const sequence = localConfigSequence(liveState.local, bootstrapChange) + BigInt(pendingSessionChangeCount()); - const nextSeq = Number(sequence); - - // Register the manager as a trusted-executor actor on first use so its - // executeBatch callback into the account succeeds (skip if already trusted). - const configChanges = [ - authorizeActor({ actorId: target.actorId, authenticator: target.authenticator }, { scope, expiry, policy: actorPolicy }), - ]; - let registeredManager = false; - // The manager is a one-time, account-level registration that outlives any - // single session key (it is never revoked — see revokeSessionKey). Re-adding - // an already-registered actor reverts, so skip if it's already trusted: tracked - // explicitly in `trustedManagers`, or (legacy records / pre-landing) inferred - // from a live session key sharing the same manager. - const managerLc = policy.manager.toLowerCase(); - const managerTrusted = - (acct.trustedManagers ?? []).some((m) => m.toLowerCase() === managerLc) || - acct.sessionKeys.some((sk) => sk.policy?.manager?.toLowerCase() === managerLc); - if (!managerTrusted) { - configChanges.unshift(authorizeActor(key.trustedExecutor(policy.manager), { scope: SCOPE.sender })); - registeredManager = true; - } - const accountChanges: AaAccountChange[] = []; - if (bootstrapChange) accountChanges.push(bootstrapChange); - const configChange = await account.change(configChanges, { chainId, sequence }); - accountChanges.push(configChange); - - // Defer: hold the owner-signed authorization on the key; it authorizes on the - // key's first transaction (or via "Apply now"). Nothing is broadcast now. - if (defer) { - const deferredKey: AppSessionKey = { - id: crypto.randomUUID(), - signerId: target.id, - label: opts.label, - kind: target.kind, - actorId: target.actorId, - authenticator: target.authenticator, - scope, - expiry, - chainId, - policy, - createdAt: Date.now(), - pendingAuth: { change: configChange, sequence: nextSeq, registeredManager }, - }; - updateAccount(acct.id, (a) => ({ ...a, sessionKeys: [...a.sessionKeys, deferredKey] })); - pushActivity({ - kind: 'session', - title: `Session key staged · ${opts.label}`, - detail: scopeChips(scope).join(' · '), - changes: [ - `authorize ${opts.label}`, - ...(registeredManager ? ['register manager as external caller'] : []), - `policy: ${policy.label}`, - 'authorizes on first use', - expiry ? formatExpiry(expiry) : 'no expiry', - ], - network: skChain.name, - mode: skChain.mode, - account: acct.address, - }); - return deferredKey; - } - - // Immediate: sign the authorize tx now (owner-signed). There is no install - // call — the policy binding is committed entirely by the actor change; the - // caller broadcasts `serialized`. - const nonceSeqSk = await getTransactionCount(makeRpcClient(), { - address: account.address as Address, - nonceKey: 0n, - }); - const skSenderAuthAuthenticator: Address = - activeSigner.kind === 'p256' - ? canonicalAuthenticators.p256 - : activeSigner.kind === 'passkey' - ? canonicalAuthenticators.passkey - : canonicalAuthenticators.k1; - let skGas = 400_000n; - if (chain.mode === 'eip8130-native') { - try { - const estimated = await estimateGas(makeRpcClient(), { - sender: account.address as Address, - // Owner signs this authorize tx, so name the owner's actor for full - // node simulation (resolves the new actor's scope + policy binding). - senderActorId: activeSigner.actorId, - accountChanges, - calls: [], - nonceSequence: Number(nonceSeqSk), - senderAuthAuthenticator: skSenderAuthAuthenticator, - }); - skGas = safeGasLimit( - estimated, - estimateTxGas({ - mode: chain.mode, - deploy: !!bootstrapChange, - calls: 0, - keyChanges: accountChanges.filter((c) => c.type === 'config').length, - }), - ); - } catch (err) { - if (isUnsupportedRpcError(err) || bootstrapChange?.type === 'create') skGas = 400_000n; - else throw err; - } - } - const serialized = await account.signTransaction({ - chainId, - accountChanges, - calls: [], - metadata: toHex(`authorize:${opts.label}`), - nonceKey: 0n, - nonceSequence: nonceSeqSk, - maxFeePerGas: 1_000_000_000n, - maxPriorityFeePerGas: 1_000_000n, - gas: skGas, + : undefined, }); - const sk: AppSessionKey = { - id: crypto.randomUUID(), - signerId: target.id, - label: opts.label, - kind: target.kind, - actorId: target.actorId, - authenticator: target.authenticator, - scope, - expiry, - chainId, - policy, - createdAt: Date.now(), - serialized, - }; - // Don't persist the key, flip `deployed`, or advance `configSeq` yet: the - // subscribed/"Deployed" UI is derived from this local state, so committing - // before the tx lands would leave the account looking subscribed/deployed - // even if the authorize+install reverts. The caller broadcasts `serialized` - // and calls `commit()` only after the tx has landed successfully. - const commit = () => { - updateAccount(acct.id, (a) => ({ - ...a, - deployed: true, - configSeq: nextSeq, - sessionKeys: [...a.sessionKeys, sk], - })); - pushActivity({ - kind: 'session', - title: `Session key authorized · ${opts.label}`, - detail: scopeChips(scope).join(' · '), - changes: [ - `authorize ${opts.label}`, - ...(registeredManager ? ['register manager as external caller'] : []), - `policy: ${policy.label}`, - `binding ${short(policy.commitment, 6, 4)}`, - expiry ? formatExpiry(expiry) : 'no expiry', - ], - network: skChain.name, - mode: skChain.mode, - serialized, - account: acct.address, - }); - }; - return { ...sk, commit }; - }; - - // Apply a staged session-key change now: an owner signs a no-op tx carrying its - // authorize + install (plus lower-sequence prerequisites) — or its staged revoke. - const applySessionKeyNow = async ( - skId: string, - onStatus?: (status: '' | 'submitting' | 'confirming') => void, - ): Promise<{ hash: Hex; label: string } | null> => { - if (!acct || !activeSigner) return null; - const sk = acct.sessionKeys.find((x) => x.id === skId); - if (!sk || (!sk.pendingAuth && !sk.pendingRevoke)) return null; - const isRevoke = !!sk.pendingRevoke && !sk.pendingAuth; - const txWS = postChangeOwnerSigners.find((s) => s.id === activeSignerId) ?? postChangeOwnerSigners[0] ?? activeSigner; - const bundle = pendingBundleFor({ mode: 'session-send', sessionId: sk.id }); - const presigned = bundle.map((i) => i.change); - const changeSeq = bundle.length ? bundle[bundle.length - 1].sequence : (sk.pendingAuth?.sequence ?? sk.pendingRevoke?.sequence ?? null); - setSkApplyingId(sk.id); - try { - const { serialized, nextSeq } = await signComposed(acct, txWS, [newCallRow()], presigned, changeSeq, undefined, undefined, undefined); - const txHash = await broadcast8130(serialized, onStatus); - applyLandedBundle(acct, nextSeq, bundle); - pushActivity({ - kind: isRevoke ? 'revoke' : 'session', - title: isRevoke ? `Session key revoked · ${sk.label}` : `Session key installed · ${sk.label}`, - detail: scopeChips(sk.scope).join(' · '), - changes: isRevoke - ? [`revoke ${sk.label}`, 'manager kept'] - : [`authorize ${sk.label}`, ...(sk.policy ? [`policy: ${sk.policy.label}`, 'install'] : [])], - network: chain.name, - mode: chain.mode, - txHash, - serialized, - account: acct.address, - }); - return { hash: txHash, label: `Session key: ${sk.label}` }; - } finally { - setSkApplyingId(null); - onStatus?.(''); - } - }; - - // Revoke a session key. A never-landed key (still staged for first use) or an - // undeployed account has no on-chain actor, so it's just discarded locally. An - // on-chain key is revoked by an owner-signed `revokeActor` config change on the - // per-chain LOCAL counter, STAGED (not broadcast): it rides the next session-key - // tx or an explicit "Apply now", and the key record is removed only once it - // lands. The PolicyManager is intentionally never revoked (other keys share it). - // Returns how the revoke resolved so callers can react: `'discarded'` (removed - // locally, nothing to apply), `'staged'` (an on-chain revoke is now pending and - // must be applied), `'noop'` (already staged), or `'error'`. - const revokeSessionKey = async (id: string): Promise<'discarded' | 'staged' | 'noop' | 'error'> => { - if (!acct) return 'error'; - const sk = acct.sessionKeys.find((x) => x.id === id); - if (!sk) return 'error'; - - const discard = () => { - updateAccount(acct.id, (a) => ({ ...a, sessionKeys: a.sessionKeys.filter((x) => x.id !== id) })); - pushActivity({ - kind: 'revoke', - title: `Session key discarded · ${sk.label}`, - detail: scopeChips(sk.scope).join(' · '), - account: acct.address, - }); - return 'discarded' as const; - }; - - // A staged authorization has never landed, so there is nothing on-chain to revoke. - if (sk.pendingAuth) return discard(); - - // Already staged — no-op (use "Apply now" to land it, or "Undo" to discard). - if (sk.pendingRevoke) return 'noop'; - - const changeWS = ownerSigners.find((s) => s.id === activeSignerId) ?? ownerSigners[0] ?? activeSigner; - if (!changeWS) { - toast.error('Select an owner key to sign the revoke.'); - return 'error'; - } - try { - const liveState = await fetchOnChainAccountState(acct.address); - if (!liveState.deployed) return discard(); - - const changeSigner = await buildSigner(changeWS); - const changeAccount = nativeAccountFor(acct, changeSigner, changeWS.authenticator); - // Session-key changes are on the per-chain LOCAL counter. Read it live and - // reserve positions for other already-staged session changes. - const chainId = chain.id || 84532; - const sequence = liveState.local + BigInt(pendingSessionChangeCount()); - const nextSeq = Number(sequence); - const change = await changeAccount.change([revokeActor(sk.actorId)], { chainId, sequence }); - updateAccount(acct.id, (a) => ({ - ...a, - sessionKeys: a.sessionKeys.map((x) => (x.id === id ? { ...x, pendingRevoke: { change, sequence: nextSeq } } : x)), - })); - pushActivity({ - kind: 'revoke', - title: `Session key revoke staged · ${sk.label}`, - detail: scopeChips(sk.scope).join(' · '), - changes: [`revoke ${sk.label}`, 'manager kept', 'applies on next tx'], - account: acct.address, - }); - return 'staged'; - } catch (err) { - const e = err as { message?: string; name?: string }; - toast.error(e.name === 'NotAllowedError' ? 'Signature was dismissed.' : (e.message ?? String(err))); - return 'error'; - } - }; - - // Discard a staged (signed-but-not-landed) revoke — the key stays active. - const undoStagedRevoke = (id: string) => { - if (!acct) return; - updateAccount(acct.id, (a) => ({ - ...a, - sessionKeys: a.sessionKeys.map((x) => (x.id === id ? { ...x, pendingRevoke: undefined } : x)), - })); - }; - - // --- config-sequence recovery ----------------------------------------- - // Re-sign every staged (not-yet-landed) session-key authorization at the current - // local sequence. Recovers from "config change sequence mismatch": the baked - // sequence went stale (the local counter advanced — e.g. another change landed). - // All pending keys share the per-chain local counter, so they re-sequence - // together (consecutive). Returns false if it couldn't run (no owner selected). - const resignPendingSessionKeys = async (): Promise => { - if (!acct) return false; - const pending = acct.sessionKeys.filter((sk) => sk.pendingAuth && sk.policy); - if (pending.length === 0) return true; - const signerWS = ownerSigners.find((s) => s.id === activeSignerId) ?? ownerSigners[0] ?? activeSigner; - if (!signerWS) { - toast.error('Select an owner key to re-sign the session-key authorization.'); - return false; - } - const ownerSigner = await buildSigner(signerWS); - const account = nativeAccountFor(acct, ownerSigner, signerWS.authenticator); - const liveState = await fetchOnChainAccountState(account.address as Address); - const bootstrapChange = liveState.deployed ? undefined : firstDeployChange(acct, account); - const base = localConfigSequence(liveState.local, bootstrapChange); - // Re-sign in current-sequence order so relative ordering is preserved. - const ordered = [...pending].sort((a, b) => (a.pendingAuth?.sequence ?? 0) - (b.pendingAuth?.sequence ?? 0)); - const updates = new Map>(); - // Managers registered within THIS batch — so two keys sharing one manager don't - // both try to register it (the second would revert). - const registeredInBatch = new Set(); - let offset = 0; - for (const sk of ordered) { - if (!sk.policy || !sk.pendingAuth) continue; - const skChainId = sk.chainId ?? (chain.id || 84532); - const sequence = base + BigInt(offset); - const seq = Number(sequence); - const managerLc = sk.policy.manager.toLowerCase(); - const managerTrusted = - (acct.trustedManagers ?? []).some((m) => m.toLowerCase() === managerLc) || - acct.sessionKeys.some((k) => !k.pendingAuth && k.policy?.manager?.toLowerCase() === managerLc) || - registeredInBatch.has(managerLc); - const session = defineSessionPolicy({ - account: account.address, - policy: sk.policy.policy, - policyConfig: sk.policy.policyConfig, - manager: sk.policy.manager, - validUntil: sk.expiry, - }); - const configChanges = [ - authorizeActor({ actorId: sk.actorId, authenticator: sk.authenticator }, { scope: sk.scope, expiry: sk.expiry, policy: session.actorPolicy }), - ]; - let registeredManager = false; - if (!managerTrusted) { - configChanges.unshift(authorizeActor(key.trustedExecutor(sk.policy.manager), { scope: SCOPE.sender })); - registeredManager = true; - registeredInBatch.add(managerLc); - } - const change = await account.change(configChanges, { chainId: skChainId, sequence }); - updates.set(sk.id, { change, sequence: seq, registeredManager }); - offset++; - } - updateAccount(acct.id, (a) => ({ - ...a, - sessionKeys: a.sessionKeys.map((sk) => { - const u = updates.get(sk.id); - return u ? { ...sk, pendingAuth: u } : sk; - }), - })); - return true; - }; - - // Drop staged (never-landed) session keys by id — they were never registered - // on-chain, so discarding them locally is all that's needed. - const dropPendingSessionKeys = (ids: string[]) => { - if (!acct || ids.length === 0) return; - const idSet = new Set(ids); - const dropped = acct.sessionKeys.filter((sk) => idSet.has(sk.id) && sk.pendingAuth); - if (dropped.length === 0) return; - updateAccount(acct.id, (a) => ({ - ...a, - sessionKeys: a.sessionKeys.filter((sk) => !(idSet.has(sk.id) && sk.pendingAuth)), - })); - for (const sk of dropped) - pushActivity({ - kind: 'revoke', - title: `Staged session key dropped · ${sk.label}`, - detail: scopeChips(sk.scope).join(' · '), - account: acct.address, - }); - }; - - // --- sub-accounts ------------------------------------------------------ - // Mint a dedicated app key (a K1 signer added to the demo key store). - const mintAppKey = (label: string): WalletSigner | null => { - const pk = generatePrivateKey(); - const owner = privateKeyToAccount(pk); - const a = key.k1(owner.address); - if (signers.some((s) => s.actorId === a.actorId)) return null; - const ws: WalletSigner = { - id: crypto.randomUUID(), - kind: 'k1', - label, - privateKey: pk, - address: owner.address, - actorId: a.actorId, - authenticator: a.authenticator, - }; - setSigners((prev) => [...prev, ws]); - return ws; - }; - - // Derive + store a delegated sub-account (its own address, controlled by this - // account via key.delegate). `withSpareKey` also mints a fresh owner key you - // hold, so you can spend from the sub-account without your main keys. - const doCreateSubAccount = ( - label: string, - opts?: { withSpareKey?: boolean; parent?: StoredAccount }, - ): { sub: AppSubAccount; account: StoredAccount } | null => { - const parent = opts?.parent ?? acct; - if (!parent) return null; - const subSalt = randomHex32() as Hex; - const actors = [key.delegate(parent.address)]; - const signerIds: string[] = []; - let spare: WalletSigner | null = null; - if (opts?.withSpareKey) { - spare = mintAppKey(`${label.trim() || 'Spending Account'} key`); - if (spare?.address) { - actors.push(key.k1(spare.address)); - signerIds.push(spare.id); - } - } - const initialActors = sortActors(actors); - const subAddress = computeAddress({ - userSalt: subSalt, - code, - initialActors, - }); - const sub: AppSubAccount = { - id: crypto.randomUUID(), - label: label.trim() || `Sub-account ${parent.subAccounts.length + 1}`, - salt: subSalt, - address: subAddress, - signerIds, - delegateTo: parent.address, - createdAt: Date.now(), - }; - // Selectable account record for the sub. The on-chain owner is the parent (via - // key.delegate) — captured as a StoredActor with no wallet signerId so it never - // resolves to a local key; `ownerSigners` instead pulls the parent's owner - // signers for a record with `parentId` set. A minted spare key is a real direct - // owner and stays selectable on its own. - const delegateActor: StoredActor = { - signerId: '', - actorId: key.delegate(parent.address).actorId, - authenticator: canonicalAuthenticators.delegate, - kind: 'k1', - label: `${parent.label} (delegate)`, - identity: parent.address, - scope: 0, - }; - const subStoredActors = sortActors([delegateActor, ...(spare ? [toStoredActor(spare)] : [])]); - const subRecord: StoredAccount = { - id: crypto.randomUUID(), - label: sub.label, - type: 'smart', - parentId: parent.id, - saltField: '', - salt: subSalt, - address: subAddress, - initialActors: subStoredActors, - owners: [...subStoredActors], - deployed: false, - configSeq: 0, - sessionKeys: [], - subAccounts: [], - createdAt: Date.now(), - }; - updateAccount(parent.id, (a) => ({ ...a, subAccounts: [...a.subAccounts, sub] })); - setAccounts((prev) => [...prev, subRecord]); - pushActivity({ - kind: 'subaccount', - title: `Sub-account created · ${sub.label}`, - detail: `Delegates to ${short(parent.address)}`, - changes: ['owner: this account', ...(spare ? [`owner: ${spare.label}`] : [])], - account: subAddress, - }); - autoFundNewAccount(subAddress); - return { sub, account: subRecord }; + const hash = await broadcast8130(serialized); + return { hash, serialized, mode: tokenGas ? 'token' : 'self', inclusion: inclusionFor(hash) }; }; return { @@ -2134,13 +689,11 @@ function useAccountEngineCore() { // Chain chain, - code, // Shared transient state busy, - activeSignerId, - setActiveSignerId, activeSigner, + signerForAccount, regenesisNotice, setRegenesisNotice, @@ -2148,58 +701,26 @@ function useAccountEngineCore() { faucetBusy, requestFaucet, - // Signer + account-building primitives (used by CreateAccountModal) + // Key + account-building primitives (used by CreateAccountModal) usedSignerIds, deleteSigner, createSigner, + importSigner, pushActivity, autoFundNewAccount, - // Owner-change staging + apply - ownerSigners, - sessionSigners, - pendingAuthorize, - pendingRevoke, - pendingScope, - keyChangeCount, - postChangeOwnerSigners, - ownerDraft, - scopeDraft, - applying, - stageAddOwner, - stageRemoveOwner, - setOwnerScope, - mintOwner, - signOwnerChange, - applyOwnerNow, - discardOwnerChanges, + // Code delegation of the active account + delegationTarget, + refreshDelegation, // Signing engine (also used by each surface's own Transact flow) + latestAnchor, broadcast8130, + awaitRelayed, + awaitInclusion, inclusionFor, signComposed, - signAccountCalls, sendActiveCalls, - sendAccountCalls, - sendActiveCallsBatches, - applyLandedBundle, - pendingBundleFor, - - // Config-sequence recovery primitives (the recovery prompt lives in the modal) - resignPendingSessionKeys, - dropPendingSessionKeys, - - // Session-key apply (the authorize/revoke form lives in SessionKeyEditor) - skApplyingId, - policyRemaining, - applySessionKeyNow, - revokeSessionKey, - undoStagedRevoke, - doAuthorizeSession, - - // Sub-accounts - doCreateSubAccount, - mintAppKey, }; } @@ -2218,4 +739,4 @@ export function useAccountEngine(): AccountEngineCore { return ctx; } -type AccountEngineCore = ReturnType; +export type AccountEngineCore = ReturnType; diff --git a/app/vibenet/demos/account/useAccounts.ts b/app/vibenet/demos/account/useAccounts.ts index 6e145de0..4c04e7eb 100644 --- a/app/vibenet/demos/account/useAccounts.ts +++ b/app/vibenet/demos/account/useAccounts.ts @@ -5,7 +5,7 @@ import { useCallback, useEffect, useState } from 'react'; import type { ActivityEntry, StoredAccount } from './library/model'; -import { deserializeState, serializeState } from './library/model'; +import { deserializeState, normalizePersistedState, serializeState } from './library/model'; import type { Persisted, WalletSigner } from './shared'; export const ACCOUNTS_STORAGE_KEY = 'vibenet.account.v2'; @@ -26,11 +26,14 @@ export function useAccounts() { try { const raw = localStorage.getItem(ACCOUNTS_STORAGE_KEY); if (raw) { - const s = deserializeState(raw); - setSigners(s.signers ?? []); - setAccounts(s.accounts ?? []); - setActiveAccountId(s.activeAccountId ?? null); - setActivity(s.activity ?? []); + const s = deserializeState>(raw); + // Records written before the Keystore was disabled (smart accounts, + // sub-accounts, passkeys) are dropped here; the next save rewrites them. + const normalized = normalizePersistedState(s); + setSigners(normalized.signers); + setAccounts(normalized.accounts); + setActiveAccountId(normalized.activeAccountId); + setActivity(normalized.activity); setGenesisHash(s.genesisHash ?? null); if (s.network) setNetworkShort(s.network); } @@ -66,22 +69,9 @@ export function useAccounts() { const deleteAccount = useCallback( (id: string) => { - const removed = accounts.filter((a) => a.id === id || a.parentId === id); - const removedIds = new Set(removed.map((a) => a.id)); - const removedAddresses = new Set(removed.map((a) => a.address.toLowerCase())); - const next = accounts - .filter((a) => !removedIds.has(a.id)) - .map((a) => ({ - ...a, - subAccounts: a.subAccounts.filter( - (subAccount) => !removedAddresses.has(subAccount.address.toLowerCase()), - ), - })); - + const next = accounts.filter((a) => a.id !== id); setAccounts(next); - if (activeAccountId && removedIds.has(activeAccountId)) { - setActiveAccountId(next.find((a) => !a.parentId)?.id ?? next[0]?.id ?? null); - } + if (activeAccountId === id) setActiveAccountId(next[0]?.id ?? null); }, [accounts, activeAccountId], ); From ee3a2ab03b9f9e43748ad0ce8710de24d64c30c9 Mon Sep 17 00:00:00 2001 From: Chris Hunter Date: Tue, 29 Sep 2026 20:02:23 -0400 Subject: [PATCH 3/6] feat(vibenet): rework account demo UI around EOA + delegation Create generates or imports a K1 key; Transact adds a Delegate Code control, a nonce-free option and payer rejection recovery (requote, min gas, USDV fallback). Removes session keys, owners, sub-accounts, passkeys and the apps directory; the explorer account view shows Overview / Delegation / Activity. --- app/vibenet/demos/account/AccountDemo.tsx | 177 +--- .../demos/account/components/ActivityLog.tsx | 4 +- .../demos/account/components/AppsView.tsx | 180 ---- .../account/components/CreateAccountModal.tsx | 499 +++------ .../account/components/SessionKeyEditor.tsx | 347 ------- .../account/components/TransactionModal.tsx | 979 +++++++----------- .../address/[addr]/OwnedAccountView.tsx | 434 +------- 7 files changed, 571 insertions(+), 2049 deletions(-) delete mode 100644 app/vibenet/demos/account/components/AppsView.tsx delete mode 100644 app/vibenet/demos/account/components/SessionKeyEditor.tsx diff --git a/app/vibenet/demos/account/AccountDemo.tsx b/app/vibenet/demos/account/AccountDemo.tsx index b73b484b..967ca3fc 100644 --- a/app/vibenet/demos/account/AccountDemo.tsx +++ b/app/vibenet/demos/account/AccountDemo.tsx @@ -1,10 +1,10 @@ 'use client'; -// Account demo (EIP-8130): in-browser signer keys, portable account creation -// (smart + EOA), balances/assets, native transact, session keys, and the apps -// directory. Account management (owners / session keys / sub-accounts / balances) -// now lives on the explorer address page (/vibenet/explorer/address/) when -// the address is a local account; this demo links there. +// Account demo (EIP-8130): in-browser K1 keys, EOA accounts, balances/assets, +// native transact (batched calls, nonce-free sends, payer-sponsored or +// token-paid gas) and optional EIP-7702-style code delegation. Per-account +// detail (balances, delegation, activity) lives on the explorer address page +// (/vibenet/explorer/address/) when the address is a local account. // // The shared account engine + transact dialog are consumed from context, so this // demo, B20, and the account page all behave identically. @@ -12,7 +12,6 @@ import { trackAccountAction } from '../../../analytics/events'; import { useState } from 'react'; import { AnimatePresence, motion } from 'motion/react'; -import { toast } from 'sonner'; import { Button } from '../../../components/ui/Button'; import { Modal } from '../../../components/ui/Modal'; @@ -21,12 +20,9 @@ import { AccountDemoShell } from '../_components/AccountDemoShell'; import { FeatureCard } from '../../components/FeatureCard'; import { FEATURES } from '../../data/features'; import { ActivityLog } from './components/ActivityLog'; -import { AppCard, AppCardPlaceholder, AppsNetworkNotice } from './components/AppsView'; import { FeatureGridCard, FeatureGridPlaceholder } from '../_shared/FeatureGridCard'; -import { TransactionModal, type ApplyTarget, type TransactPreset } from './components/TransactionModal'; -import { DEMO_APPS, type DemoApp } from './library/apps'; +import { TransactionModal, type TransactPreset } from './components/TransactionModal'; import { encodeUsdvTransfer, isAddressStr, newCallRow } from './library/calls'; -import { EXPIRY_PRESETS, type AppSessionKey, type AppSubAccount } from './library/model'; import { AccountEngineProvider, useAccountEngine } from './useAccountEngine'; import { vibenetApi } from '../../library/client'; import type { Address } from '@aa'; @@ -41,49 +37,20 @@ export function AccountDemo() { function AccountDemoInner() { const engine = useAccountEngine(); - const { - signers, - accounts, - activeAccountId, - activity, - networkShort, - setNetworkShort, - deleteAccount, + const { accounts, activeAccountId, activity, regenesisNotice, setRegenesisNotice, acct } = engine; - activeSigner, - - chain, - regenesisNotice, - setRegenesisNotice, - - acct, - - deleteSigner, - revokeSessionKey, - undoStagedRevoke, - doAuthorizeSession, - doCreateSubAccount, - mintAppKey, - } = engine; - - // Apps directory. - const [appBusy, setAppBusy] = useState(null); const [transactionRequest, setTransactionRequest] = useState<{ preset?: TransactPreset; - applyTarget?: ApplyTarget; contentKey: string; } | null>(null); - // Crossfade key for the dashboard (transact + apps). Capture it in the modal - // request so changing "From" doesn't remount the content behind an open dialog. + // Crossfade key for the dashboard. Capture it in the modal request so + // changing "From" doesn't remount the content behind an open dialog. const activeAccountKey = activeAccountId ?? 'empty'; const contentKey = transactionRequest?.contentKey ?? activeAccountKey; const openTransaction = (preset?: TransactPreset) => { setTransactionRequest({ preset, contentKey: activeAccountKey }); }; - const openApply = (applyTarget: ApplyTarget) => { - setTransactionRequest({ applyTarget, contentKey: activeAccountKey }); - }; const resolveUsdvAddress = async (): Promise
=> { const status = await vibenetApi.faucet.status().catch(() => null); @@ -120,77 +87,12 @@ function AccountDemoInner() { }); }; - // Session-app config changes use the same transaction review popup as every - // other account-demo send. A never-landed authorization is only local, so - // revoking it simply discards it without opening a transaction. - const unsubscribeApp = async (sk: AppSessionKey) => { - const outcome = await revokeSessionKey(sk.id); - if (outcome === 'staged' || outcome === 'noop') openApply({ session: sk.id }); - }; - - const sessionKeyFor = (name: string) => acct?.sessionKeys.find((sk) => sk.label === name); - const subAccountFor = (name: string) => acct?.subAccounts.find((sa) => sa.label === name); - - // "Delete Account" on a connected Spending Account app card. - const deleteVault = (sub: AppSubAccount) => { - const rec = accounts.find((a) => a.address.toLowerCase() === sub.address.toLowerCase()); - if (rec) deleteAccount(rec.id); - }; - - // Connect a session-key app: mint a dedicated key and stage its owner-signed - // authorization, then hand submission to the common transaction popup. - const connectSessionApp = async (app: DemoApp) => { - if (!acct || !activeSigner) return; - setAppBusy(app.id); - let mintedKeyId: string | null = null; - try { - const target = mintAppKey(app.name); - if (!target) { - toast.error("Couldn't mint an app key — try again."); - return; - } - mintedKeyId = target.id; - const expirySecs = EXPIRY_PRESETS.find((p) => p.id === app.expiryId)?.seconds ?? 0; - const sk = await doAuthorizeSession(target, { - expirySecs, - policyLabel: app.policyLabel ?? 'Policy', - spec: app.spec?.(acct.address) ?? {}, - label: app.name, - chainShort: chain.shortName, - }); - if (sk) { - mintedKeyId = null; - openApply({ session: sk.id }); - } - } catch (err) { - const e = err as { message?: string; name?: string }; - toast.error(e.name === 'NotAllowedError' ? 'Signature was dismissed.' : (e.message ?? String(err))); - } finally { - if (mintedKeyId) deleteSigner(mintedKeyId); - setAppBusy(null); - } - }; - - // Connect a sub-account app ("spending account"): derive a delegated account - // with a spare owner key you hold. - const connectVault = (app: DemoApp) => { - if (!acct) return; - setAppBusy(app.id); - try { - doCreateSubAccount(app.name, { withSpareKey: true }); - } catch (err) { - toast.error((err as { message?: string }).message ?? String(err)); - } finally { - setAppBusy(null); - } - }; - return ( <> } activityCount={activity.length} - activityEmptyMessage="No activity yet. Transactions and account changes will appear here." + activityEmptyMessage="No activity yet. Transactions and delegation changes will appear here." className="gap-10" > {FEATURES.map((feature) => ( @@ -212,9 +114,8 @@ function AccountDemoInner() { {renderSponsorship()} {renderBatchedCalls()} {renderGasToken()} - {renderOwners()} + {renderDelegation()} {renderTransact()} - {renderApps()} @@ -224,7 +125,6 @@ function AccountDemoInner() { key={activeAccountId ?? 'no-account'} onClose={() => setTransactionRequest(null)} preset={transactionRequest.preset} - applyTarget={transactionRequest.applyTarget} /> ) : null} @@ -239,45 +139,13 @@ function AccountDemoInner() { } > - The vibenet devnet has been regenesised — its onchain state was wiped. Your accounts and keys are still here - and their addresses are unchanged; they've been marked undeployed and will redeploy on their next - transaction. + The vibenet devnet has been regenesised — its onchain state was wiped, including any code delegation. Your + accounts and keys are still here and their addresses are unchanged; top up to transact again. ); - function renderApps() { - if (!acct) { - return DEMO_APPS.map((app) => ); - } - const native = chain.mode === 'eip8130-native'; - return ( - <> - {!native ? setNetworkShort('vibenet')} /> : null} - {DEMO_APPS.map((app) => ( - openApply({ session: sessionKey.id })} - undoSessionRevoke={undoStagedRevoke} - deleteVault={deleteVault} - /> - ))} - - ); - } - function renderTransact() { if (!acct) return ( @@ -346,29 +214,30 @@ function AccountDemoInner() { ); } - function renderOwners() { + function renderDelegation() { if (!acct) { return ( - + ); } return ( - - + } - title="Modify Owners" - description="Add or revoke owner keys and rotate signers — swap keys anytime without ever migrating accounts." + title="Code Delegation" + description="Point your EOA at a contract so it runs that code, or clear it again — set in the same transaction as your calls." > ); diff --git a/app/vibenet/demos/account/components/ActivityLog.tsx b/app/vibenet/demos/account/components/ActivityLog.tsx index 1f0f6fda..abcabdaf 100644 --- a/app/vibenet/demos/account/components/ActivityLog.tsx +++ b/app/vibenet/demos/account/components/ActivityLog.tsx @@ -101,7 +101,7 @@ export function ActivityLog({ activity, accounts }: { activity: ActivityEntry[]; href={`${VIBENET_EXPLORER_PATH}/address/${e.account}`} className="no-underline transition-colors hover:opacity-80" > - + ) : null} @@ -171,7 +171,7 @@ export function ActivityLog({ activity, accounts }: { activity: ActivityEntry[]; href={`${VIBENET_EXPLORER_PATH}/address/${e.account}`} className="no-underline" > - + ) : null} diff --git a/app/vibenet/demos/account/components/AppsView.tsx b/app/vibenet/demos/account/components/AppsView.tsx deleted file mode 100644 index b57f8062..00000000 --- a/app/vibenet/demos/account/components/AppsView.tsx +++ /dev/null @@ -1,180 +0,0 @@ -'use client'; - -import { Button } from '../../../../components/ui/Button'; -import { CopyableValue } from '../../../components/CopyableValue'; -import type { DemoApp } from '../library/apps'; -import { formatExpiry, type AppSessionKey, type AppSubAccount, type StoredAccount } from '../library/model'; -import { short, type WalletSigner } from '../shared'; -import { Badge } from '../../_shared/primitives'; -import { FeatureGridCard, FeatureGridPlaceholder } from '../../_shared/FeatureGridCard'; - -const CONNECTED_FOOTER = - 'border-t border-bds-gray-10 pt-3 dark:border-white/10'; - -// Banner shown above the app cards when the active network doesn't support -// native EIP-8130 grants yet — apps stay disabled until the user switches. -export function AppsNetworkNotice({ onSwitchToVibenet }: { onSwitchToVibenet: () => void }) { - return ( -
- - Vibenet Only - - Apps use native EIP-8130 grants. - - - -
- ); -} - -type AppCardProps = { - acct: StoredAccount; - native: boolean; - app: DemoApp; - appBusy: string | null; - activeSigner: WalletSigner | null; - signers: WalletSigner[]; - sessionKeyFor: (name: string) => AppSessionKey | undefined; - subAccountFor: (name: string) => AppSubAccount | undefined; - connectSessionApp: (app: DemoApp) => void; - connectVault: (app: DemoApp) => void; - unsubscribeApp: (sk: AppSessionKey) => void; - reviewSessionApp: (sk: AppSessionKey) => void; - undoSessionRevoke: (sessionKeyId: string) => void; - deleteVault: (sub: AppSubAccount) => void; -}; - -function AppIcon({ app }: { app: DemoApp }) { - if (app.id === 'monthly-vibes') { - return ( - - - - - ); - } - if (app.id === 'spending-account') { - return ( - - - - - ); - } - return {app.emoji}; -} - -// A single demo app: connects to the active account through a scoped grant it -// fully controls — a capped session key (subscriptions) or a delegated -// sub-account. Idle chrome matches the other Features tiles; once a grant is -// live the footer becomes a status row with a divider. -export function AppCard(p: AppCardProps) { - const { app } = p; - const sk = app.grant === 'session' ? p.sessionKeyFor(app.name) : undefined; - const sub = app.grant === 'subaccount' ? p.subAccountFor(app.name) : undefined; - const connecting = p.appBusy === app.id; - - let footer = null; - let connected = false; - if (app.id === 'monthly-vibes') { - if (sk) { - connected = true; - const pendingLabel = sk.pendingAuth ? 'Pending authorization' : sk.pendingRevoke ? 'Pending revoke' : null; - footer = ( - <> - {pendingLabel ?? 'Active'} - - {sk.policy?.params ?? 'capped'} · {formatExpiry(sk.expiry)} - - {pendingLabel ? ( - - ) : ( - - )} - {sk.pendingAuth ? ( - - ) : sk.pendingRevoke ? ( - - ) : null} - - ); - } else { - footer = ( - - ); - } - } else if (app.id === 'spending-account') { - if (sub) { - connected = true; - footer = ( - <> - - - - ); - } else { - footer = ( - - ); - } - } - - return ( - } - title={app.name} - description={app.desc} - footerClassName={connected ? CONNECTED_FOOTER : undefined} - > - {footer} - - ); -} - -export function AppCardPlaceholder({ app }: { app: DemoApp }) { - return ( - - ); -} diff --git a/app/vibenet/demos/account/components/CreateAccountModal.tsx b/app/vibenet/demos/account/components/CreateAccountModal.tsx index 37979974..66884152 100644 --- a/app/vibenet/demos/account/components/CreateAccountModal.tsx +++ b/app/vibenet/demos/account/components/CreateAccountModal.tsx @@ -1,15 +1,16 @@ 'use client'; -// The account-creation drawer. "Account Type" is the top-level choice: -// Default — one-click EOA off your first unused key (mints one if none) -// Passkey — one-click smart account owned by your first unused passkey -// Advanced — hand-pick smart/EOA + initial keys + salt -// Default/Passkey stay minimal (name only); Advanced reveals the full controls. +// The account-creation drawer. An account is a secp256k1 EOA — its key is the +// account. "Key" is the only real choice: +// New key — generate a fresh K1 key in this browser +// Unused key — reuse a K1 key already in the wallet that backs no account +// Import — paste an existing private key +// Code delegation is never set here; it's an explicit transaction afterwards. // // Owns its own form state; reads the shared store + account-building primitives // from the account-engine context. -import { type Address, computeAddress, type Hex } from '@aa'; +import { type Hex } from '@aa'; import { useEffect, useMemo, useState } from 'react'; import { Button } from '../../../../components/ui/Button'; @@ -17,14 +18,12 @@ import { cn } from '../../../../components/ui/cn'; import { Drawer } from '../../../../components/ui/Drawer'; import { Field } from '../../../../components/ui/Field'; import { Input } from '../../../../components/ui/Input'; -import { InputGroup } from '../../../../components/ui/InputGroup'; import { Radio } from '../../../../components/ui/Radio'; import { RadioGroup } from '../../../../components/ui/RadioGroup'; import { Text } from '../../../../components/ui/Text'; -import { KIND_LABEL, short, signerIdentity, type CreateMode, type WalletSigner } from '../shared'; import { CheckIcon, KindBadge, TrashIcon } from '../../_shared/primitives'; -import { actorPairs, normalizeSalt, randomHex32, sortActors, toStoredActor } from '../library/derive'; -import type { AccountType, SignerKind, StoredAccount } from '../library/model'; +import type { StoredAccount } from '../library/model'; +import { type CreateMode, short, type WalletSigner } from '../shared'; import { useAccountEngine } from '../useAccountEngine'; type CreateAccountModalProps = { @@ -32,81 +31,56 @@ type CreateAccountModalProps = { onClose: () => void; }; -const MODES: ReadonlyArray<{ value: CreateMode; title: string; description: string }> = [ - { value: 'default', title: 'Default', description: 'Simplest account setup' }, - { value: 'passkey', title: 'Passkey', description: 'Smart account · passkey' }, - { value: 'advanced', title: 'Advanced', description: 'Pick type, keys & salt' }, -]; - -const ACCOUNT_MODELS = [ - { value: 'smart' as const, title: 'Smart Account', description: 'Counterfactual · keys + salt → address' }, - { value: 'eoa' as const, title: 'EOA', description: 'Your EOA · delegates to DefaultAccount' }, -]; +const PRIVATE_KEY_RE = /^0x[0-9a-fA-F]{64}$/; export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { const { signers, accounts, addAccount, - chain, - code, busy, usedSignerIds, deleteSigner, createSigner, + importSigner, pushActivity, autoFundNewAccount, } = useAccountEngine(); - const [createMode, setCreateMode] = useState('default'); - const [modalType, setModalType] = useState('eoa'); + const [createMode, setCreateMode] = useState('generate'); const [modalLabel, setModalLabel] = useState(''); - const [modalSalt, setModalSalt] = useState(() => randomHex32()); - const [modalIds, setModalIds] = useState([]); - const [modalEoaId, setModalEoaId] = useState(null); + const [existingId, setExistingId] = useState(null); + const [importKey, setImportKey] = useState(''); + const [importError, setImportError] = useState(''); + + const unusedSigners = useMemo(() => signers.filter((s) => !usedSignerIds.has(s.id)), [signers, usedSignerIds]); - // Reset to the one-click default each time the drawer opens. + // Reset each time the drawer opens. useEffect(() => { if (!open) return; - setCreateMode('default'); - setModalType('eoa'); + setCreateMode('generate'); setModalLabel(''); - setModalSalt(randomHex32()); - setModalIds([]); - setModalEoaId(null); + setExistingId(null); + setImportKey(''); + setImportError(''); }, [open]); - const eoaSigners = useMemo(() => signers.filter((s) => s.kind === 'k1'), [signers]); - const defaultModeSigner = useMemo( - () => eoaSigners.find((s) => !usedSignerIds.has(s.id)) ?? null, - [eoaSigners, usedSignerIds], - ); - const passkeyModeSigner = useMemo( - () => signers.find((s) => s.kind === 'passkey' && !usedSignerIds.has(s.id)) ?? null, - [signers, usedSignerIds], + const modes = useMemo( + () => + [ + { value: 'generate' as const, title: 'New Key', description: 'Generate a K1 key' }, + ...(unusedSigners.length > 0 + ? [{ value: 'existing' as const, title: 'Unused Key', description: 'Reuse a key in your wallet' }] + : []), + { value: 'import' as const, title: 'Import', description: 'Paste a private key' }, + ] satisfies ReadonlyArray<{ value: CreateMode; title: string; description: string }>, + [unusedSigners.length], ); - const modalEoaSigner = useMemo(() => eoaSigners.find((s) => s.id === modalEoaId) ?? null, [eoaSigners, modalEoaId]); - const modalSigners = useMemo(() => signers.filter((s) => modalIds.includes(s.id)), [signers, modalIds]); - const modalSalt32 = useMemo(() => normalizeSalt(modalSalt), [modalSalt]); - const modalAddress = useMemo
(() => { - if (modalType === 'eoa') return modalEoaSigner?.address ?? null; - if (modalSigners.length === 0) return null; - const ids = new Set(modalSigners.map((s) => s.actorId)); - if (ids.size !== modalSigners.length) return null; - try { - return computeAddress({ userSalt: modalSalt32, code, initialActors: sortActors(actorPairs(modalSigners)) }); - } catch { - return null; - } - }, [modalType, modalEoaSigner, modalSigners, modalSalt32, code]); - const suggestedName = useMemo(() => { - if (createMode === 'default') return 'Default'; - if (createMode === 'passkey') return 'Passkey'; - return modalType === 'eoa' ? 'EOA' : 'Smart Account'; - }, [createMode, modalType]); + const existingSigner = unusedSigners.find((s) => s.id === existingId) ?? null; + const importValid = PRIVATE_KEY_RE.test(importKey.trim()); - // Keep the auto-suggested fallback name unique (Default, Default 2, …). A name + // Keep the auto-suggested fallback name unique (Account, Account 2, …). A name // the user typed by hand is respected as-is, collisions and all. const uniqueAccountName = (base: string): string => { const taken = new Set(accounts.map((a) => a.label)); @@ -117,114 +91,59 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { } }; - // Build + persist an EOA account: the signer's own K1 key IS the account and - // its default owner; it delegates to DefaultAccount on first use. const buildEoaAccount = (signer: WalletSigner, label: string) => { - if (!signer.address) return; - const selfActor = toStoredActor(signer); const account: StoredAccount = { id: crypto.randomUUID(), label, type: 'eoa', - saltField: '', - salt: `0x${'00'.repeat(32)}` as Hex, + signerId: signer.id, address: signer.address, - delegate: chain.deployment.accounts.default, - initialActors: [selfActor], - owners: [selfActor], - deployed: false, - configSeq: 0, - sessionKeys: [], - subAccounts: [], createdAt: Date.now(), }; addAccount(account); pushActivity({ kind: 'create', title: `EOA account · ${account.label}`, - detail: 'Delegates to DefaultAccount on first use', + detail: 'Stored locally · no code delegation', account: account.address, }); autoFundNewAccount(account.address); }; - // Build + persist a counterfactual smart account from its initial owner keys - // and salt. Returns false (no-op) if the keys collide or the address won't derive. - const buildSmartAccount = (chosen: WalletSigner[], salt32: Hex, saltField: string, label: string): boolean => { - if (chosen.length === 0) return false; - const ids = new Set(chosen.map((s) => s.actorId)); - if (ids.size !== chosen.length) return false; - let address: Address; - try { - address = computeAddress({ userSalt: salt32, code, initialActors: sortActors(actorPairs(chosen)) }); - } catch { - return false; - } - const initialActors = chosen.map(toStoredActor); - const account: StoredAccount = { - id: crypto.randomUUID(), - label, - type: 'smart', - saltField, - salt: salt32, - address, - initialActors, - owners: [...initialActors], - deployed: false, - configSeq: 0, - sessionKeys: [], - subAccounts: [], - createdAt: Date.now(), - }; - addAccount(account); - pushActivity({ - kind: 'create', - title: `Account created · ${account.label}`, - detail: 'Stored locally · deploys on first use', - changes: initialActors.map((a) => `${a.label} (${KIND_LABEL[a.kind]})`), - account: account.address, - }); - autoFundNewAccount(address); - return true; - }; - - const createAccount = async () => { - const name = modalLabel.trim() || uniqueAccountName(suggestedName); - - // Advanced: honour the hand-picked type, keys, and salt. - if (createMode === 'advanced') { - if (!modalAddress) return; - if (modalType === 'eoa') { - if (!modalEoaSigner) return; - buildEoaAccount(modalEoaSigner, name); - } else if (!buildSmartAccount(modalSigners, modalSalt32, modalSalt, name)) { + const createAccount = () => { + const name = modalLabel.trim() || uniqueAccountName('Account'); + let signer: WalletSigner | null = null; + if (createMode === 'generate') { + signer = createSigner(); + } else if (createMode === 'existing') { + signer = existingSigner; + } else { + if (!importValid) { + setImportError('Enter a 32-byte hex private key (0x + 64 hex characters).'); + return; + } + try { + signer = importSigner(importKey.trim() as Hex); + } catch { + setImportError('That is not a valid secp256k1 private key.'); + return; + } + if (accounts.some((a) => a.address.toLowerCase() === signer?.address.toLowerCase())) { + setImportError('An account for this key already exists.'); return; } - onClose(); - return; - } - - // Default: an EOA off your first unused K1 key (mint one if you have none). - if (createMode === 'default') { - const signer = defaultModeSigner ?? (await createSigner('k1')); - if (!signer) return; - buildEoaAccount(signer, name); - onClose(); - return; } - - // Passkey: a smart account owned by your first unused passkey (mint if none). - const signer = passkeyModeSigner ?? (await createSigner('passkey')); if (!signer) return; - const saltField = randomHex32(); - if (buildSmartAccount([signer], normalizeSalt(saltField), saltField, name)) onClose(); + buildEoaAccount(signer, name); + setImportKey(''); + onClose(); }; - const busyCreating = busy !== null; - const canCreate = createMode === 'advanced' ? Boolean(modalAddress) : true; + const canCreate = + createMode === 'generate' ? true : createMode === 'existing' ? Boolean(existingSigner) : importValid; const submit = () => { - if (canCreate && !busyCreating) void createAccount(); + if (canCreate && !busy) createAccount(); }; return ( @@ -241,10 +160,10 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { variant="primary" size="sm" onClick={submit} - disabled={!canCreate || busyCreating} + disabled={!canCreate || busy} className="disabled:cursor-not-allowed disabled:opacity-50" > - {busyCreating ? 'Creating…' : 'Create Account'} + {busy ? 'Creating…' : 'Create Account'} } @@ -253,7 +172,7 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { Name { if (e.key === 'Enter') { @@ -265,9 +184,13 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { - Account type - - {MODES.map((option) => ( + Key + + {modes.map((option) => ( {option.title} @@ -280,215 +203,101 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { - {createMode === 'advanced' ? ( - <> - - Account model - - {ACCOUNT_MODELS.map((option) => ( - - - {option.title} - - - {option.description} - - - ))} - - - - {modalType === 'smart' ? ( - <> - !usedSignerIds.has(s.id)} - onDelete={deleteSigner} - isOn={(s) => modalIds.includes(s.id)} - onToggle={(s) => - setModalIds((prev) => (prev.includes(s.id) ? prev.filter((x) => x !== s.id) : [...prev, s.id])) - } - onMint={async (kind) => { - const s = await createSigner(kind); - if (s) setModalIds((prev) => [...prev, s.id]); - }} - /> - - Salt - - - - - - - ) : ( - !usedSignerIds.has(s.id)} - onDelete={deleteSigner} - isOn={(s) => modalEoaId === s.id} - onToggle={(s) => setModalEoaId(modalEoaId === s.id ? null : s.id)} - onMint={async (kind) => { - const s = await createSigner(kind); - if (s) setModalEoaId(s.id); - }} - /> - )} - -
- Address - {modalAddress ? ( - {modalAddress} - ) : modalType === 'eoa' ? ( - Pick a K1 key - ) : modalSigners.length === 0 ? ( - Select at least one key - ) : ( - duplicate key — pick distinct actors - )} -
- - ) : null} + {createMode === 'existing' ? ( + existingId === s.id} + onToggle={(s) => setExistingId(existingId === s.id ? null : s.id)} + onDelete={(id) => { + deleteSigner(id); + if (existingId === id) setExistingId(null); + }} + /> + ) : createMode === 'import' ? ( + + Private key + { + setImportKey(v); + setImportError(''); + }} + /> + + {importError || 'Stored only in this browser. Use a throwaway devnet key, never a real wallet key.'} + + + ) : ( + + A new secp256k1 key is generated and kept in this browser. Its address is the account — no deployment, + no salt. Delegate code to it later from Transact if you want contract behavior. + + )} ); } type KeyPickerProps = { - heading: string; - empty: string; - hint?: string; signers: WalletSigner[]; - busy: SignerKind | null; - mintKinds: readonly SignerKind[]; isOn: (s: WalletSigner) => boolean; onToggle: (s: WalletSigner) => void; - onMint: (kind: SignerKind) => void; - /** A key is deletable when no account references it. */ - canDelete?: (s: WalletSigner) => boolean; - onDelete?: (id: string) => void; + onDelete: (id: string) => void; }; -function KeyPicker({ - heading, - empty, - hint, - signers, - busy, - mintKinds, - isOn, - onToggle, - onMint, - canDelete, - onDelete, -}: KeyPickerProps) { +function KeyPicker({ signers, isOn, onToggle, onDelete }: KeyPickerProps) { return (
- {heading} + Unused keys - {signers.length === 0 ? ( - - {empty} - - ) : ( -
    - {signers.map((s) => { - const on = isOn(s); - const deletable = Boolean(canDelete?.(s) && onDelete); - // A key that can't be deleted is bound to an existing account. - const inUse = Boolean(canDelete && !canDelete(s)); - return ( -
  • - - {deletable ? ( - - ) : inUse ? ( - - in use - - ) : null} -
  • - ); - })} -
- )} - {/* Mint controls sit at the foot of the list, styled like the "+ New - Account" affordance — one dashed button per available key kind. */} -
- {mintKinds.map((kind) => ( - - ))} -
- {hint ? ( - - {hint} - - ) : null} +
    + {signers.map((s) => { + const on = isOn(s); + return ( +
  • + + +
  • + ); + })} +
); } diff --git a/app/vibenet/demos/account/components/SessionKeyEditor.tsx b/app/vibenet/demos/account/components/SessionKeyEditor.tsx deleted file mode 100644 index 687d6f03..00000000 --- a/app/vibenet/demos/account/components/SessionKeyEditor.tsx +++ /dev/null @@ -1,347 +0,0 @@ -'use client'; - -// The "register a session key" form: signer + chain + expiry, spend limits, and -// a target allowlist. Owns its own draft state and turns it into an owner-signed -// authorization via the engine's `doAuthorizeSession` primitive. Extracted from -// ConfigView so both the account page and any future surface reuse it. - -import type { Address } from '@aa'; -import { useState } from 'react'; - -import { Button } from '../../../../components/ui/Button'; -import { cn } from '../../../../components/ui/cn'; -import { Field } from '../../../../components/ui/Field'; -import { CloseIcon } from '../../../../components/ui/icons'; -import { Input } from '../../../../components/ui/Input'; -import { Select } from '../../../../components/ui/Select'; -import { Text } from '../../../../components/ui/Text'; -import { getDemoChain, DEMO_CHAINS } from '../library/chains'; -import { EXPIRY_PRESETS } from '../library/model'; -import { - type LimitDraft, - newLimitDraft, - newScopeDraft, - PERIOD_PRESETS, - type PolicySpec, - type ScopeDraft, - SELECTOR_PRESETS, - stableSymbol, -} from '../library/policy'; -import { short } from '../shared'; -import { useAccountEngine } from '../useAccountEngine'; - -const ADDR_RE = /^0x[0-9a-fA-F]{40}$/; -const CHIP_CLS = - 'rounded-full border border-bds-gray-10 px-2.5 py-1 text-[12px] text-bds-gray-60 transition-colors hover:border-bds-gray-15 dark:border-white/10 dark:text-bds-gray-40'; -const CHIP_ON = 'border-base-blue bg-bds-blue-0 text-base-blue'; - -export function SessionKeyEditor({ - onClose, - onAuthorized, -}: { - onClose?: () => void; - onAuthorized?: (sessionKeyId: string) => void; -}) { - const { acct, signers, activeSigner, networkShort, doAuthorizeSession } = useAccountEngine(); - - const [skSignerId, setSkSignerId] = useState(''); - const [skExpiryId, setSkExpiryId] = useState('7d'); - const [skChainShort, setSkChainShort] = useState(networkShort); - const [skLimits, setSkLimits] = useState(() => [newLimitDraft()]); - const [skScopes, setSkScopes] = useState([]); - const [skBusy, setSkBusy] = useState(false); - const [error, setError] = useState(''); - - if (!acct) return null; - - const patchLimit = (id: string, patch: Partial) => - setSkLimits((ls) => ls.map((l) => (l.id === id ? { ...l, ...patch } : l))); - const addLimit = () => setSkLimits((ls) => [...ls, newLimitDraft()]); - const removeLimit = (id: string) => setSkLimits((ls) => ls.filter((l) => l.id !== id)); - const patchScope = (id: string, patch: Partial) => - setSkScopes((ss) => ss.map((s) => (s.id === id ? { ...s, ...patch } : s))); - const addScope = () => setSkScopes((ss) => [...ss, newScopeDraft()]); - const removeScope = (id: string) => setSkScopes((ss) => ss.filter((s) => s.id !== id)); - const toggleScopeSelector = (id: string, sel: `0x${string}`) => - setSkScopes((ss) => - ss.map((s) => { - if (s.id !== id) return s; - const selectors = s.selectors.includes(sel) ? s.selectors.filter((x) => x !== sel) : [...s.selectors, sel]; - return { ...s, selectors, all: selectors.length === 0 }; - }), - ); - const setScopeAll = (id: string) => - setSkScopes((ss) => ss.map((s) => (s.id === id ? { ...s, all: true, selectors: [] } : s))); - - const formPolicySpec = (): PolicySpec => ({ - limits: skLimits.map((l) => ({ - token: l.token === 'custom' ? (l.custom.trim() as Address) : l.token, - amount: l.amount, - periodSecs: PERIOD_PRESETS.find((p) => p.id === l.periodId)?.seconds ?? 0, - })), - scopes: skScopes - .filter((s) => s.target.trim()) - .map((s) => ({ target: s.target, selectors: s.all ? undefined : s.selectors })), - }); - const formPolicyLabel = (): string => { - const parts: string[] = []; - if (skLimits.length) parts.push('Spend limit'); - if (skScopes.some((s) => s.target.trim())) parts.push('Allowlist'); - return parts.join(' + ') || 'Policy'; - }; - const formPolicyEmpty = skLimits.length === 0 && !skScopes.some((s) => s.target.trim()); - - const registerSessionKey = async () => { - if (!activeSigner) return; - const target = signers.find((s) => s.id === skSignerId); - if (!target) { - setError('Pick a signer to authorize as a session key.'); - return; - } - if (acct.owners.some((o) => o.actorId === target.actorId)) { - setError(`${target.label} is already an owner of this account — pick a different signer.`); - return; - } - if (acct.sessionKeys.some((sk) => sk.actorId === target.actorId)) { - setError(`${target.label} is already an active session key — revoke it first to change its policy.`); - return; - } - if (formPolicyEmpty) { - setError('Add a spend limit or at least one allowed target.'); - return; - } - setSkBusy(true); - setError(''); - try { - const sessionKey = await doAuthorizeSession(target, { - expirySecs: EXPIRY_PRESETS.find((p) => p.id === skExpiryId)!.seconds, - policyLabel: formPolicyLabel(), - spec: formPolicySpec(), - label: target.label, - chainShort: skChainShort, - }); - if (!sessionKey) return; - setSkSignerId(''); - onClose?.(); - onAuthorized?.(sessionKey.id); - } catch (err) { - const e = err as { message?: string; name?: string }; - setError(e.name === 'NotAllowedError' ? 'Signature was dismissed.' : (e.message ?? String(err))); - } finally { - setSkBusy(false); - } - }; - - const impliedScopes: { key: string; label: string; note: string }[] = []; - for (const l of skLimits) { - if (l.token === 'stable') - impliedScopes.push({ - key: `implied-stable-${l.id}`, - label: `${stableSymbol(skChainShort)} contract`, - note: 'transfer · auto-pinned by spend limit', - }); - else if (l.token === 'custom' && ADDR_RE.test(l.custom.trim())) - impliedScopes.push({ - key: `implied-custom-${l.id}`, - label: short(l.custom.trim()), - note: 'transfer · auto-pinned by spend limit', - }); - } - - return ( -
- - Register a Session Key - -
- - Signer - ({ value: c.shortName, label: c.name }))} - /> - - - Expiry - patchLimit(l.id, { token: value as LimitDraft['token'] })} - options={[ - { value: 'stable', label: stableSymbol(skChainShort) }, - { value: 'eth', label: 'ETH' }, - { value: 'custom', label: 'Custom token...' }, - ]} - /> -
- {l.token === 'custom' ? ( - patchLimit(l.id, { custom })} - /> - ) : null} - patchLimit(l.id, { amount })} - /> -
- patchScope(s.id, { target })} - /> - -
-
- - {SELECTOR_PRESETS.map((sp) => ( - - ))} -
-
- ); - })} -
- -
- - - {error ?

{error}

: null} - -
-

- Send-only key on {getDemoChain(skChainShort).name}. - {skLimits.some((l) => l.token === 'eth') - ? ' An ETH limit needs at least one allowed target to pay.' - : ''} -

- {onClose ? ( - - ) : null} - -
- - ); -} diff --git a/app/vibenet/demos/account/components/TransactionModal.tsx b/app/vibenet/demos/account/components/TransactionModal.tsx index d5edd791..11368f3b 100644 --- a/app/vibenet/demos/account/components/TransactionModal.tsx +++ b/app/vibenet/demos/account/components/TransactionModal.tsx @@ -1,32 +1,32 @@ 'use client'; -// The shared "Create Transaction" dialog for EIP-8130 accounts: a single popup -// with three steps — build (calls + gas), review, and submitted (sign → -// broadcast → wait for inclusion). It also doubles as the apply surface for -// staged key changes: `openApply()` skips the builder, reviews the pending -// owner/session-key change, and on Send runs the engine's apply primitives -// through the same submitted/wait step. +// The shared "Create Transaction" dialog for EIP-8130 EOA accounts: a single +// popup with three steps — build (calls, code delegation, gas), review, and +// submitted (sign → broadcast → wait for inclusion). // -// Driven by declarative open/request props plus the account-engine context, so +// Driven by declarative open/preset props plus the account-engine context, so // every surface gets the same component without an imperative "modal hook". import { type Address, createPayerClient, - encodeTokenTransfer, generatePrivateKey, type Hex, isDeclinedOffer, isTokenOffer, + parsePayerError, parseUnits, + type PayerRejectedData, privateKeyToAccount, selectPaymentOption, toHex, + zeroAddress, } from '@aa'; import { useMemo, useState } from 'react'; import { toast } from 'sonner'; import { Button } from '../../../../components/ui/Button'; +import { Checkbox } from '../../../../components/ui/Checkbox'; import { cn } from '../../../../components/ui/cn'; import { Field } from '../../../../components/ui/Field'; import { CloseIcon } from '../../../../components/ui/icons'; @@ -45,7 +45,7 @@ import type { Inclusion } from '../../_shared/inclusion'; import { InclusionBadge, InclusionTagline } from '../../_shared/InclusionBadge'; import { Badge, CheckIcon, KindBadge } from '../../_shared/primitives'; import { ViewTransactionButton } from '../../_shared/ViewTransactionButton'; -import { DEMO_CHAINS, estimateTxGas, PAYER_URL } from '../library/chains'; +import { estimateTxGas, PAYER_URL } from '../library/chains'; import { buildCalls, type CallRow, @@ -57,22 +57,78 @@ import { USDV_DECIMALS, valueBearingCallCount, } from '../library/calls'; -import { formatExpiry, scopeChips, type SignerKind, type StoredAccount } from '../library/model'; -import { scopeLabel } from '../library/policy'; -import { formatTokenAmount, KIND_LABEL, short, type WalletSigner } from '../shared'; -import { conciseError, EstimateRevertedError, isSeqMismatch, TxPendingError, useAccountEngine } from '../useAccountEngine'; +import type { SignerKind, StoredAccount } from '../library/model'; +import { parseTokenRate } from '../library/payer'; +import { formatTokenAmount, short, type WalletSigner } from '../shared'; +import { + type ComposePayer, + conciseError, + EstimateRevertedError, + TxPendingError, + useAccountEngine, +} from '../useAccountEngine'; + +type GasMode = 'eth' | 'free' | 'usdv'; +type DelegateMode = 'none' | 'set' | 'clear'; -export type TransactPreset = { calls: CallRow[]; gasMode?: 'eth' | 'free' | 'usdv'; metadata?: string }; -/** Apply the staged owner change, or a specific session key's change. */ -export type ApplyTarget = 'owner' | { session: string }; +export type TransactPreset = { + calls?: CallRow[]; + gasMode?: GasMode; + metadata?: string; + /** Open with the "Delegate code" control set (target left for the user to fill in). */ + delegation?: 'set' | 'clear'; + nonceless?: boolean; +}; type TransactionModalProps = { onClose: () => void; preset?: TransactPreset; - applyTarget?: ApplyTarget; }; -export function TransactionModal({ onClose, preset, applyTarget }: TransactionModalProps) { +const NONCELESS_SECONDS = 15; + +// A payer rejection the dialog can recover from with one more signature. +type PayerRetry = + | { kind: 'requote'; amount: bigint } + | { kind: 'minGas'; gas: bigint } + | { kind: 'usdv' }; + +function payerRejectionMessage(rejected: PayerRejectedData): string { + const data = rejected as PayerRejectedData & { + shortfall?: { required?: Hex; available?: Hex }; + revert?: { phase?: number }; + }; + switch (rejected.code) { + case 'PAYMENT_INSUFFICIENT': + return rejected.requote + ? `The payer now needs ${formatTokenAmount(BigInt(rejected.requote.paymentAmount), USDV_DECIMALS)} USDV for this gas. Retry to sign the new amount.` + : 'This payer requires a USDV payment — switch gas to USDV.'; + case 'SENDER_BALANCE_INSUFFICIENT': + return data.shortfall?.required && data.shortfall.available + ? `Not enough USDV for gas: needs ${formatTokenAmount(BigInt(data.shortfall.required), USDV_DECIMALS)}, account has ${formatTokenAmount(BigInt(data.shortfall.available), USDV_DECIMALS)}. Top up and retry.` + : 'Not enough USDV for gas. Top up and retry.'; + case 'BUDGET_EXHAUSTED': + return 'Free sponsorship for this account is used up. Pay gas in USDV instead.'; + case 'EXECUTION_REVERTED': + return data.revert?.phase === 0 + ? 'The USDV gas payment would revert — check the account’s USDV balance.' + : 'The payer’s simulation says this transaction would revert.'; + case 'GAS_TOO_LOW': + return 'The payer needs a higher gas limit for these calls. Retry to re-sign with more gas.'; + default: + return rejected.reason ?? `Payer rejected the transaction (${rejected.code}).`; + } +} + +function retryFor(rejected: PayerRejectedData): PayerRetry | null { + if (rejected.code === 'PAYMENT_INSUFFICIENT' && rejected.requote) + return { kind: 'requote', amount: BigInt(rejected.requote.paymentAmount) }; + if (rejected.code === 'GAS_TOO_LOW' && rejected.minGasLimit) return { kind: 'minGas', gas: BigInt(rejected.minGasLimit) }; + if (rejected.code === 'BUDGET_EXHAUSTED') return { kind: 'usdv' }; + return null; +} + +export function TransactionModal({ onClose, preset }: TransactionModalProps) { const engine = useAccountEngine(); const { acct, @@ -80,79 +136,53 @@ export function TransactionModal({ onClose, preset, applyTarget }: TransactionMo activeAccountId, setActiveAccountId, addressBook, - networkShort, - setNetworkShort, chain, - activeSignerId, - setActiveSignerId, activeSigner, - ownerSigners, - sessionSigners, - postChangeOwnerSigners, - pendingAuthorize, - pendingRevoke, - pendingScope, - keyChangeCount, + delegationTarget, + refreshDelegation, + latestAnchor, broadcast8130, + awaitRelayed, inclusionFor, signComposed, - applyLandedBundle, - pendingBundleFor, pushActivity, - applyOwnerNow, - applySessionKeyNow, - signOwnerChange, - resignPendingSessionKeys, - dropPendingSessionKeys, - discardOwnerChanges, } = engine; - const [txSignerId, setTxSignerId] = useState(null); - const [calls, setCalls] = useState(() => preset?.calls ?? [newCallRow()]); + const [calls, setCalls] = useState( + () => + preset?.calls ?? + // A delegation-only transaction still needs a call; a self no-op is the cheapest. + [preset?.delegation && acct ? newCallRow({ to: acct.address }) : newCallRow()], + ); const [callsAdvanced, setCallsAdvanced] = useState(false); const [usdvRecipientDrafts, setUsdvRecipientDrafts] = useState>({}); const [usdvAmountDrafts, setUsdvAmountDrafts] = useState>({}); const [metaField, setMetaField] = useState(preset?.metadata ?? ''); - const [gasMode, setGasMode] = useState<'eth' | 'free' | 'usdv'>(preset?.gasMode ?? 'eth'); + const [gasMode, setGasMode] = useState(preset?.gasMode ?? 'eth'); + const [nonceless, setNonceless] = useState(preset?.nonceless ?? false); + const [delegateMode, setDelegateMode] = useState(preset?.delegation ?? 'none'); + const [delegateInput, setDelegateInput] = useState(''); const [signing, setSigning] = useState(false); const [copied, setCopied] = useState(null); const [submitStatus, setSubmitStatus] = useState<'' | 'submitting' | 'confirming'>(''); - const [configTx, setConfigTx] = useState<{ hash: Hex; label: string } | null>(null); const [estimateBlocked, setEstimateBlocked] = useState(null); - // Error + config-sequence-recovery UI is local to this dialog — nothing leaks - // onto the page behind it. `notice` is a transient status line (after a - // re-sign / drop); `seqRecovery` is the "config change sequence mismatch" - // prompt offering to re-sign at the current sequence or drop the change. + const [payerRetry, setPayerRetry] = useState(null); + // Error UI is local to this dialog — nothing leaks onto the page behind it. const [error, setError] = useState(''); - const [notice, setNotice] = useState(''); - const [seqRecovery, setSeqRecovery] = useState<{ - what: string; - resign: () => Promise | void; - drop: () => void; - busy?: boolean; - } | null>(null); const [txStep, setTxStep] = useState<'build' | 'review' | 'submitted'>( - applyTarget || preset ? 'review' : 'build', + preset?.calls && !preset.delegation ? 'review' : 'build', ); const [result, setResult] = useState(null); - const signableSigners = useMemo( - () => [...postChangeOwnerSigners, ...sessionSigners], - [postChangeOwnerSigners, sessionSigners], - ); - const txSigner = - signableSigners.find((s) => s.id === txSignerId) ?? - postChangeOwnerSigners.find((s) => s.id === activeSignerId) ?? - postChangeOwnerSigners[0] ?? - activeSigner; - const txIsSession = !!txSigner && sessionSigners.some((s) => s.id === txSigner.id); - const activeSessionKey = - txIsSession && txSigner ? (acct?.sessionKeys.find((sk) => sk.signerId === txSigner.id) ?? null) : null; - - // Session keys always use sponsorship without mutating the owner's last gas choice. - const effectiveGasMode = txIsSession ? 'free' : gasMode; - const callsValid = useMemo(() => calls.every(rowToValid), [calls]); + const delegateTo: Address | undefined = + delegateMode === 'set' && isAddressStr(delegateInput.trim()) && BigInt(delegateInput.trim()) !== 0n + ? (delegateInput.trim() as Address) + : delegateMode === 'clear' + ? zeroAddress + : undefined; + const delegateValid = delegateMode === 'none' || !!delegateTo; + const formValid = callsValid && delegateValid; const metadataHex = useMemo( () => (metaField.trim() ? (toHex(metaField.trim()) as Hex) : undefined), [metaField], @@ -160,13 +190,14 @@ export function TransactionModal({ onClose, preset, applyTarget }: TransactionMo const gasEstimate = useMemo(() => { if (!acct) return 0; return estimateTxGas({ - mode: chain.mode, - deploy: !acct.deployed, calls: calls.length, - keyChanges: keyChangeCount, - valueCalls: valueBearingCallCount(calls), + valueCalls: valueBearingCallCount(calls, acct.address), + delegation: delegateMode !== 'none', + nonceless, + payer: gasMode !== 'eth', + tokenPayment: gasMode === 'usdv', }); - }, [acct, chain.mode, calls, keyChangeCount]); + }, [acct, calls, delegateMode, nonceless, gasMode]); const clearResult = () => setResult(null); const copy = async (text: string, key: string) => { @@ -180,6 +211,12 @@ export function TransactionModal({ onClose, preset, applyTarget }: TransactionMo }; const copyRandomAddress = () => copy(privateKeyToAccount(generatePrivateKey()).address, 'randaddr'); + const delegationChange = delegateTo + ? delegateTo === zeroAddress + ? 'clear code delegation' + : `delegate → ${short(delegateTo)}` + : null; + const recordResult = ( a: StoredAccount, serialized: Hex, @@ -187,26 +224,23 @@ export function TransactionModal({ onClose, preset, applyTarget }: TransactionMo pending: boolean, by: WalletSigner, gasNote?: string, - extraChanges: string[] = [], ) => { setResult({ serialized, txHash, by: by.label, kind: by.kind, pending, gasNote, inclusion: inclusionFor(txHash) }); pushActivity({ - kind: a.deployed && !pending ? 'transact' : 'create', + kind: delegationChange ? 'delegate' : 'transact', txHash, title: pending ? 'Transaction pending · not yet included' - : a.deployed - ? `Transaction landed onchain${gasNote ? ' (payer gas)' : ''}` - : a.type === 'eoa' - ? 'EOA delegated + first action' - : 'Account deployed + first action', + : delegationChange + ? delegateTo === zeroAddress + ? 'Code delegation cleared' + : 'Code delegation set' + : `Transaction landed onchain${gasNote ? ' (payer gas)' : ''}`, changes: [ - ...(!a.deployed - ? [a.type === 'eoa' ? 'delegate → DefaultAccount' : `create · ${a.initialActors.length} keys`] - : []), + ...(delegationChange ? [delegationChange] : []), + ...(nonceless ? ['nonce-free'] : []), ...(pending ? ['⚠ pending — not yet included'] : []), ...(gasNote ? [gasNote] : []), - ...extraChanges, ], calls: calls.length, metadata: metaField.trim() || undefined, @@ -215,140 +249,53 @@ export function TransactionModal({ onClose, preset, applyTarget }: TransactionMo serialized, account: a.address, }); + if (delegationChange && !pending) void refreshDelegation(); }; - const sendExtraChanges = (): string[] => - txIsSession && txSigner - ? [`via session key · ${txSigner.label}`] - : [ - ...pendingAuthorize.map((s) => `authorize ${s.label}`), - ...pendingRevoke.map((o) => `revoke ${o.label}`), - ...pendingScope.map((o) => `scope ${o.label} → ${scopeLabel(o.toScope)}`), - ]; - const surfaceSendError = (message: string) => { setError(message); toast.error(message); }; - const clearNotices = () => { - setNotice(''); - setSeqRecovery(null); + const sendError = (err: unknown) => { + if (err instanceof EstimateRevertedError) setEstimateBlocked(err.reason); + const e = err as { message?: string; name?: string }; + surfaceSendError(conciseError(e.message ?? String(err))); }; - // Catch a "config change sequence mismatch" from a config-carrying broadcast - // and show a recovery prompt inside this dialog (re-sign at the current - // sequence, or drop the change), scoped to what the failed tx carried. Returns - // true once handled so the caller skips its generic error handling. - const handleSeqMismatch = (err: unknown, ctx: { sessionIds: string[]; hasOwner: boolean }): boolean => { - if (!isSeqMismatch(err)) return false; - if (!ctx.hasOwner && ctx.sessionIds.length === 0) return false; - const parts: string[] = []; - if (ctx.hasOwner) parts.push('owner change'); - if (ctx.sessionIds.length) - parts.push(`${ctx.sessionIds.length} session-key authorization${ctx.sessionIds.length === 1 ? '' : 's'}`); - setError(''); - setNotice(''); - setSeqRecovery({ - what: parts.join(' + ') || 'staged config change', - resign: async () => { - setSeqRecovery((r) => (r ? { ...r, busy: true } : r)); - setError(''); - try { - if (ctx.hasOwner) await signOwnerChange(); - if (ctx.sessionIds.length && !(await resignPendingSessionKeys())) { - setSeqRecovery((r) => (r ? { ...r, busy: false } : r)); - return; - } - setSeqRecovery(null); - setNotice('Re-signed at the current sequence — send again to apply it.'); - } catch (e) { - const m = e as { message?: string; name?: string }; - setSeqRecovery((r) => (r ? { ...r, busy: false } : r)); - setError(m.name === 'NotAllowedError' ? 'Signature was dismissed.' : (m.message ?? String(e))); - } - }, - drop: () => { - if (ctx.hasOwner) discardOwnerChanges(); - if (ctx.sessionIds.length) dropPendingSessionKeys(ctx.sessionIds); - setSeqRecovery(null); - setNotice('Dropped the out-of-sequence config change.'); - }, - }); - return true; + // Broadcast and wait, treating a timeout as "submitted but pending". + const broadcastOrPending = async (serialized: Hex): Promise<{ txHash: Hex; pending: boolean }> => { + try { + return { txHash: await broadcast8130(serialized, setSubmitStatus), pending: false }; + } catch (err) { + if (err instanceof TxPendingError) return { txHash: err.txHash, pending: true }; + throw err; + } }; // Transact: native offline sign, own ETH gas. - const doSignNative = async (forceEstimate = false) => { - if (!acct || !txSigner || !callsValid) return; - const sessionPolicy = activeSessionKey?.policy; - if (txIsSession && !acct.deployed && !activeSessionKey?.pendingAuth) { - surfaceSendError('Authorize this session key with an owner key first (Apply now).'); - return; - } - setSigning(true); - setError(''); - clearNotices(); - setEstimateBlocked(null); - let seqCtx: { sessionIds: string[]; hasOwner: boolean } = { sessionIds: [], hasOwner: false }; + const doSignNative = async (forceEstimate: boolean) => { + if (!acct || !activeSigner) return; try { - const bundle = pendingBundleFor( - txIsSession ? { mode: 'session-send', sessionId: activeSessionKey?.id } : { mode: 'owner-send' }, - ); - seqCtx = { - sessionIds: bundle.flatMap((i) => (i.sessionId ? [i.sessionId] : [])), - hasOwner: bundle.some((i) => i.resultingOwners), - }; - const presigned = bundle.map((i) => i.change); - const changeSeq = bundle.length ? bundle[bundle.length - 1].sequence : null; - const extra = sendExtraChanges(); - const { serialized, nextSeq } = await signComposed( - acct, - txSigner, - calls, - presigned, - changeSeq, - metadataHex, - sessionPolicy, - undefined, - { estimateRevert: forceEstimate ? 'force' : 'throw' }, - ); - let txHash: Hex; - let pending = false; - try { - txHash = await broadcast8130(serialized, setSubmitStatus); - } catch (err) { - if (err instanceof TxPendingError) { - txHash = err.txHash; - pending = true; - } else throw err; - } - if (!pending) applyLandedBundle(acct, nextSeq, bundle); - recordResult(acct, serialized, txHash, pending, txSigner, undefined, extra); + const { serialized } = await signComposed(acct, { + rows: calls, + metadata: metadataHex, + delegateTo, + noncelessSeconds: nonceless ? NONCELESS_SECONDS : undefined, + estimateRevert: forceEstimate ? 'force' : 'throw', + }); + const { txHash, pending } = await broadcastOrPending(serialized); + recordResult(acct, serialized, txHash, pending, activeSigner); } catch (err) { - if (handleSeqMismatch(err, seqCtx)) return; - if (err instanceof EstimateRevertedError) setEstimateBlocked(err.reason); - const e = err as { message?: string; name?: string }; - surfaceSendError(conciseError(e.name === 'NotAllowedError' ? 'Signature was dismissed.' : (e.message ?? String(err)))); - } finally { - setSigning(false); - setSubmitStatus(''); + sendError(err); } }; - // Transact: native sign co-signed by an ERC-8168 payer service. - const doSponsoredSign = async (forceEstimate = false) => { - if (!acct || !txSigner || !callsValid) return; - const sessionPolicy = activeSessionKey?.policy; - if (txIsSession && !acct.deployed && !activeSessionKey?.pendingAuth) { - surfaceSendError('Authorize this session key with an owner key first (Apply now).'); - return; - } - setSigning(true); - setError(''); - clearNotices(); - setEstimateBlocked(null); - let seqCtx: { sessionIds: string[]; hasOwner: boolean } = { sessionIds: [], hasOwner: false }; + // Transact: sign with an ERC-8168 payer named on the transaction. The payer + // either co-signs (`payer_signTransaction`) and this page broadcasts, or it + // co-signs and broadcasts itself (`payer_sendTransaction`). + const doSponsoredSign = async (mode: 'free' | 'usdv', forceEstimate: boolean, retry: PayerRetry | null) => { + if (!acct || !activeSigner) return; try { const payerClient = createPayerClient({ url: PAYER_URL }); const rpcCalls = buildCalls(calls, acct.address).map((c) => ({ to: c.to, value: toHex(c.value), data: c.data })); @@ -361,129 +308,105 @@ export function TransactionModal({ onClose, preset, applyTarget }: TransactionMo }); let selToken: Address | undefined; - if (effectiveGasMode === 'usdv') { + if (mode === 'usdv') { const tokenOffer = terms.options.find(isTokenOffer); selToken = tokenOffer?.tokens?.[0]?.token; if (!selToken) throw new Error('This payer does not accept USDV gas payment.'); } - const declinedFree = effectiveGasMode === 'free' ? terms.options.find(isDeclinedOffer) : undefined; + const declinedFree = mode === 'free' ? terms.options.find(isDeclinedOffer) : undefined; const { option, tokenChoice } = selectPaymentOption(terms, selToken ? { token: selToken } : {}); - let phase0: { to: Address; data: Hex }[] | undefined; - let gasNote: string; + let payer: ComposePayer; if (option.kind === 'token' && tokenChoice) { - const amount = BigInt(tokenChoice.paymentAmount); - const transfer = encodeTokenTransfer({ - token: tokenChoice.token, - to: tokenChoice.feeRecipient ?? option.payer, - amount, - }); - phase0 = [{ to: transfer.to, data: transfer.data }]; - const human = `${formatTokenAmount(amount, tokenChoice.decimals)} ${tokenChoice.symbol}`; - gasNote = - declinedFree && isDeclinedOffer(declinedFree) - ? `Free sponsorship spent — paid ${human} gas · co-signed by payer` - : `Paid ${human} gas · co-signed by payer`; + const quoted = BigInt(tokenChoice.paymentAmount); + payer = { + address: option.payer, + tokenPayment: { + token: tokenChoice.token, + to: tokenChoice.feeRecipient ?? option.payer, + amount: retry?.kind === 'requote' && retry.amount > quoted ? retry.amount : quoted, + rate: parseTokenRate(tokenChoice.rate), + }, + }; } else { - gasNote = 'Sponsored by vibenet payer · free grant'; + payer = { address: option.payer }; } - const bundle = pendingBundleFor( - txIsSession ? { mode: 'session-send', sessionId: activeSessionKey?.id } : { mode: 'owner-send' }, - ); - seqCtx = { - sessionIds: bundle.flatMap((i) => (i.sessionId ? [i.sessionId] : [])), - hasOwner: bundle.some((i) => i.resultingOwners), - }; - const presigned = bundle.map((i) => i.change); - const changeSeq = bundle.length ? bundle[bundle.length - 1].sequence : null; - const extra = sendExtraChanges(); - const { serialized, nextSeq } = await signComposed( - acct, - txSigner, - calls, - presigned, - changeSeq, - metadataHex, - sessionPolicy, - { address: option.payer, phase0 }, - { estimateRevert: forceEstimate ? 'force' : 'throw' }, - ); - const cosigned = await payerClient.signTransaction({ - signedTransaction: serialized, - context: { flow: 'transact' }, + // A payer requires an expiry; stay inside its `maxExpiry` (the engine + // clamps a nonce-free send to its own shorter window). + const maxExpiry = option.conditions?.maxExpiry ?? 60; + const validBefore = BigInt(Date.now() + Math.max(maxExpiry - 2, 1) * 1000); + const fees = terms.gasEstimate + ? { + maxFeePerGas: BigInt(terms.gasEstimate.maxFeePerGas), + maxPriorityFeePerGas: BigInt(terms.gasEstimate.maxPriorityFeePerGas), + } + : undefined; + + const { serialized, paymentAmount } = await signComposed(acct, { + rows: calls, + metadata: metadataHex, + delegateTo, + noncelessSeconds: nonceless ? NONCELESS_SECONDS : undefined, + payer, + validBefore, + fees, + minGas: retry?.kind === 'minGas' ? retry.gas : undefined, + estimateRevert: forceEstimate ? 'force' : 'throw', }); - const finalTx = (cosigned.signedTransaction ?? serialized) as Hex; + + const gasNote = + paymentAmount !== undefined && tokenChoice + ? `${declinedFree ? 'Free sponsorship spent — paid' : 'Paid'} ${formatTokenAmount(paymentAmount, tokenChoice.decimals)} ${tokenChoice.symbol} gas · co-signed by payer` + : 'Sponsored by vibenet payer · free grant'; let txHash: Hex; let pending = false; - try { - txHash = await broadcast8130(finalTx, setSubmitStatus); - } catch (err) { - if (err instanceof TxPendingError) { - txHash = err.txHash; + let finalTx = serialized; + if (option.methods?.includes('payer_signTransaction')) { + const cosigned = await payerClient.signTransaction({ signedTransaction: serialized, context: { flow: 'transact' } }); + finalTx = cosigned.signedTransaction; + ({ txHash, pending } = await broadcastOrPending(finalTx)); + } else { + setSubmitStatus('submitting'); + const anchor = latestAnchor(); + const sent = await payerClient.sendTransaction({ signedTransaction: serialized, context: { flow: 'transact' } }); + setSubmitStatus('confirming'); + txHash = sent.transactionHash; + try { + await awaitRelayed(txHash, anchor); + } catch (err) { + if (!(err instanceof TxPendingError)) throw err; pending = true; - } else throw err; + } } - if (!pending) applyLandedBundle(acct, nextSeq, bundle); - recordResult(acct, finalTx, txHash, pending, txSigner, gasNote, extra); + recordResult(acct, finalTx, txHash, pending, activeSigner, gasNote); } catch (err) { - if (handleSeqMismatch(err, seqCtx)) return; - if (err instanceof EstimateRevertedError) setEstimateBlocked(err.reason); - const e = err as { message?: string; name?: string }; - const msg = e.message ?? String(err); - surfaceSendError( - conciseError( - e.name === 'NotAllowedError' - ? 'Signature was dismissed.' - : /fetch|ECONNREFUSED|network/i.test(msg) - ? `Couldn't reach the payer service at ${PAYER_URL}.` - : msg, - ), - ); - } finally { - setSigning(false); - setSubmitStatus(''); + const rejected = parsePayerError(err); + if (rejected) { + setPayerRetry(retryFor(rejected)); + surfaceSendError(payerRejectionMessage(rejected)); + return; + } + const msg = (err as { message?: string })?.message ?? String(err); + if (/fetch|ECONNREFUSED|network/i.test(msg) && !(err instanceof EstimateRevertedError)) { + surfaceSendError(`Couldn't reach the payer service at ${PAYER_URL}.`); + return; + } + sendError(err); } }; - const confirmSend = async (forceEstimate = false) => { + const confirmSend = async (forceEstimate = false, retry: PayerRetry | null = null) => { + const mode = retry?.kind === 'usdv' ? 'usdv' : gasMode; + if (retry?.kind === 'usdv') setGasMode('usdv'); setError(''); - setTxStep('submitted'); - await (effectiveGasMode === 'eth' ? doSignNative(forceEstimate) : doSponsoredSign(forceEstimate)); - }; - - // Apply a staged config change (owner or session key) through this dialog's - // submitted/wait step. The engine's apply primitives broadcast + wait and - // return their result while this component owns all modal progress state. - const confirmApply = async () => { - if (!applyTarget) return; + setEstimateBlocked(null); + setPayerRetry(null); setTxStep('submitted'); setSigning(true); - setError(''); - clearNotices(); - // What the carrying tx bundles — so a sequence mismatch prompt names the - // right changes to re-sign or drop. - const seqCtx = - applyTarget === 'owner' - ? { sessionIds: [], hasOwner: true } - : (() => { - const bundle = pendingBundleFor({ mode: 'session-send', sessionId: applyTarget.session }); - return { - sessionIds: bundle.flatMap((i) => (i.sessionId ? [i.sessionId] : [])), - hasOwner: bundle.some((i) => i.resultingOwners), - }; - })(); try { - const tx = - applyTarget === 'owner' - ? await applyOwnerNow(setSubmitStatus) - : await applySessionKeyNow(applyTarget.session, setSubmitStatus); - setConfigTx(tx); - } catch (err) { - if (handleSeqMismatch(err, seqCtx)) return; - const e = err as { message?: string; name?: string }; - surfaceSendError(conciseError(e.name === 'NotAllowedError' ? 'Signature was dismissed.' : (e.message ?? String(err)))); + await (mode === 'eth' ? doSignNative(forceEstimate) : doSponsoredSign(mode, forceEstimate, retry)); } finally { setSigning(false); setSubmitStatus(''); @@ -516,93 +439,33 @@ export function TransactionModal({ onClose, preset, applyTarget }: TransactionMo }; const startSend = () => { - if (!callsValid || !txSigner) return; + if (!formValid || !activeSigner) return; setError(''); setResult(null); setTxStep('review'); }; - const selectSigner = (id: string) => { - setTxSignerId(id); - if (ownerSigners.some((s) => s.id === id)) setActiveSignerId(id); - }; - const closeModal = () => { if (signing) return; // never abandon an in-flight send onClose(); }; - // Success shown in the submitted step. Apply and normal-send results use the - // same presentational shape even though their execution paths differ. - const applyResult = - applyTarget && configTx && txSigner - ? { txHash: configTx.hash, by: txSigner.label, kind: txSigner.kind, inclusion: inclusionFor(configTx.hash) } - : null; - const submittedResult = applyTarget ? applyResult : result; - - const applyChanges = useMemo(() => { - if (applyTarget === 'owner') { - return [ - ...pendingAuthorize.map((s) => `Authorize ${s.label}`), - ...pendingRevoke.map((o) => `Revoke ${o.label}`), - ...pendingScope.map((o) => `${o.label} → ${scopeLabel(o.toScope)}`), - ]; - } - if (applyTarget && typeof applyTarget === 'object') { - const sk = acct?.sessionKeys.find((k) => k.id === applyTarget.session); - if (!sk) return []; - if (sk.pendingRevoke) return [`Revoke ${sk.label}`]; - return [ - `Authorize ${sk.label}`, - ...(sk.policy ? [`Policy · ${sk.policy.label}`] : []), - ...scopeChips(sk.scope), - formatExpiry(sk.expiry), - ]; - } - return []; - }, [applyTarget, acct, pendingAuthorize, pendingRevoke, pendingScope]); + const retryLabel = estimateBlocked + ? 'Send Anyway' + : payerRetry?.kind === 'requote' + ? 'Sign New Amount' + : payerRetry?.kind === 'usdv' + ? 'Pay in USDV' + : 'Retry'; return ( - - - - ) : notice ? ( - <> - - - - ) : error ? ( + signing ? null : error ? ( <> - ) : ( <> - {submittedResult?.txHash ? ( - - ) : null} + {result?.txHash ? : null} ) - ) : applyTarget ? ( - <> - - - ) : txStep === 'review' ? ( <> @@ -165,7 +162,7 @@ export function AccountSwitcher({ > {active ? ( - + {active.label} ) : ( @@ -188,12 +185,7 @@ export function AccountSwitcher({ className="flex max-h-[60vh] w-[max(340px,var(--anchor-width))] max-w-[calc(100vw-2rem)] origin-[var(--transform-origin)] flex-col gap-1 overflow-y-auto rounded-2xl border border-bds-gray-10 bg-background p-2 shadow-lg outline-none [transform:scale(1)] transition-[opacity,transform] duration-150 ease-out data-[ending-style]:opacity-0 data-[ending-style]:[transform:scale(0.97)] data-[starting-style]:opacity-0 data-[starting-style]:[transform:scale(0.97)] dark:border-white/10 dark:bg-[rgb(38,38,38)] motion-reduce:transition-none" > Accounts - {topLevel.map((parent) => ( -
- {row(parent, false)} - {accounts.filter((s) => s.parentId === parent.id).map((sub) => row(sub, true))} -
- ))} + {accounts.map((a) => row(a))} {onCreate ? ( = { k1: 'bg-bds-blue-0 text-bds-blue-70 dark:text-base-blue', - p256: 'bg-bds-purple-0 text-bds-purple-70', - passkey: 'bg-bds-teal-0 text-bds-teal-70', }; export function AccountAvatar({ @@ -159,7 +157,7 @@ export function AccountIdentity({ ); } -// Signer-kind chip (K1 / P-256 / passkey). +// Signer-kind chip (K1). export function KindBadge({ kind }: { kind: SignerKind }) { return ( import('./AccountDemo').then((m) => m.AccountDemo), { diff --git a/app/vibenet/demos/b20/B20Demo.tsx b/app/vibenet/demos/b20/B20Demo.tsx index 33a839b9..53318521 100644 --- a/app/vibenet/demos/b20/B20Demo.tsx +++ b/app/vibenet/demos/b20/B20Demo.tsx @@ -380,10 +380,10 @@ function B20DemoInner() { // The payer underwrites the gas in ETH, so it has to be funded before it // co-signs — the first token-paid send follows key creation closely. if (payer) await ensurePayerFunded(payer); - // Sign + broadcast through the shared account engine so account deploy, - // sub-account, gas-estimation, and staged-settings behavior stays in one - // implementation across demos. Logging via pushActivity puts this send in - // the same history the account demo reads, so both demos share one trail. + // Sign + broadcast through the shared account engine so gas estimation + // and payer co-signing stay in one implementation across demos. Logging + // via pushActivity puts this send in the same history the account demo + // reads, so both demos share one trail. const { hash, serialized, mode } = await engine.sendActiveCalls({ calls, metadata: label, diff --git a/app/vibenet/demos/catalogue.ts b/app/vibenet/demos/catalogue.ts index 7559df68..c973fdcc 100644 --- a/app/vibenet/demos/catalogue.ts +++ b/app/vibenet/demos/catalogue.ts @@ -37,10 +37,10 @@ export const DEMOS: DemoEntry[] = [ shortTitle: 'Account', icon: '/account-illo.svg', summary: - 'Create portable account-abstraction accounts from in-browser keys, fund them from the faucet, and inspect balances across networks.', + 'Send native account-abstraction transactions from in-browser EOA keys, fund them from the faucet, and inspect balances across networks.', points: [ - 'Smart & EOA accounts — deterministic addresses', - 'K1 / P-256 / passkey signers', + 'EOA accounts with optional code delegation', + 'Batched, nonce-free and sponsored sends', 'Transactions land in the next 200 ms block', ], available: true, diff --git a/app/vibenet/explorer/address/[addr]/page.tsx b/app/vibenet/explorer/address/[addr]/page.tsx index da2333ac..95300a01 100644 --- a/app/vibenet/explorer/address/[addr]/page.tsx +++ b/app/vibenet/explorer/address/[addr]/page.tsx @@ -17,7 +17,7 @@ import type { ExplorerAddressResponse } from '../../../library/api-types'; import { vibenetApi, VibenetApiError } from '../../../library/client'; import { PublicAddressView } from './PublicAddressView'; -// Owned management view: dynamic + client-only so `@aa`/WebAuthn/signing never +// Owned management view: dynamic + client-only so `@aa`/signing never // load on the public inspector path. const OwnedAccountView = dynamic(() => import('./OwnedAccountView').then((m) => m.OwnedAccountView), { ssr: false, From 83ef7e3acac0a5d707a8f99c082e0012a96b5dca Mon Sep 17 00:00:00 2001 From: Chris Hunter Date: Wed, 30 Sep 2026 07:52:44 -0400 Subject: [PATCH 5/6] refactor(vibenet): drop code delegation from the account demo for now --- app/vibenet/data/features.ts | 1 - app/vibenet/demos/account/AccountDemo.tsx | 38 +----- .../account/components/CreateAccountModal.tsx | 5 +- .../account/components/TransactionModal.tsx | 122 ++---------------- app/vibenet/demos/account/library/chains.ts | 10 +- .../demos/account/library/delegation.ts | 16 --- .../demos/account/library/model.test.ts | 7 +- app/vibenet/demos/account/library/model.ts | 8 +- .../demos/account/library/payer.test.ts | 18 --- .../demos/account/useAccountEngine.tsx | 60 ++------- app/vibenet/demos/catalogue.ts | 2 +- .../address/[addr]/OwnedAccountView.tsx | 73 +---------- vendor/aa/entry.mjs | 4 +- vendor/aa/index.d.ts | 5 +- vendor/aa/index.js | 2 - 15 files changed, 42 insertions(+), 329 deletions(-) delete mode 100644 app/vibenet/demos/account/library/delegation.ts diff --git a/app/vibenet/data/features.ts b/app/vibenet/data/features.ts index 437e38a0..0f2e5d6d 100644 --- a/app/vibenet/data/features.ts +++ b/app/vibenet/data/features.ts @@ -15,7 +15,6 @@ export const FEATURES: VibenetFeature[] = [ highlights: [ { title: 'Your EOA Is the Account', detail: 'Any secp256k1 key sends native AA transactions — nothing to deploy.' }, { title: 'Portable Everywhere', detail: 'Same key and address on any EVM chain.' }, - { title: 'Optional Code Delegation', detail: 'Point your EOA at contract code, or clear it, in any transaction.' }, { title: 'Nonce-Free Sends', detail: 'Short-lived transactions with no nonce to track or collide on.' }, { title: 'Sponsored & ERC-20 Gas', detail: 'Native payer support via the ERC-8168 payer service.' }, { title: 'Batch Everything', detail: 'Atomic, phased multicall with per-call value and top-level metadata.' }, diff --git a/app/vibenet/demos/account/AccountDemo.tsx b/app/vibenet/demos/account/AccountDemo.tsx index 967ca3fc..a2d681c6 100644 --- a/app/vibenet/demos/account/AccountDemo.tsx +++ b/app/vibenet/demos/account/AccountDemo.tsx @@ -2,8 +2,8 @@ // Account demo (EIP-8130): in-browser K1 keys, EOA accounts, balances/assets, // native transact (batched calls, nonce-free sends, payer-sponsored or -// token-paid gas) and optional EIP-7702-style code delegation. Per-account -// detail (balances, delegation, activity) lives on the explorer address page +// token-paid gas). Per-account detail (balances, activity) lives on the +// explorer address page // (/vibenet/explorer/address/) when the address is a local account. // // The shared account engine + transact dialog are consumed from context, so this @@ -92,7 +92,7 @@ function AccountDemoInner() { } activityCount={activity.length} - activityEmptyMessage="No activity yet. Transactions and delegation changes will appear here." + activityEmptyMessage="No activity yet. Transactions and account changes will appear here." className="gap-10" > {FEATURES.map((feature) => ( @@ -114,7 +114,6 @@ function AccountDemoInner() { {renderSponsorship()} {renderBatchedCalls()} {renderGasToken()} - {renderDelegation()} {renderTransact()} @@ -139,7 +138,7 @@ function AccountDemoInner() { } > - The vibenet devnet has been regenesised — its onchain state was wiped, including any code delegation. Your + The vibenet devnet has been regenesised — its onchain state was wiped. Your accounts and keys are still here and their addresses are unchanged; top up to transact again.
@@ -214,35 +213,6 @@ function AccountDemoInner() { ); } - function renderDelegation() { - if (!acct) { - return ( - - ); - } - return ( - - - - } - title="Code Delegation" - description="Point your EOA at a contract so it runs that code, or clear it again — set in the same transaction as your calls." - > - - - ); - } - function renderBatchedCalls() { if (!acct) { return ( diff --git a/app/vibenet/demos/account/components/CreateAccountModal.tsx b/app/vibenet/demos/account/components/CreateAccountModal.tsx index 66884152..b98c1945 100644 --- a/app/vibenet/demos/account/components/CreateAccountModal.tsx +++ b/app/vibenet/demos/account/components/CreateAccountModal.tsx @@ -5,7 +5,6 @@ // New key — generate a fresh K1 key in this browser // Unused key — reuse a K1 key already in the wallet that backs no account // Import — paste an existing private key -// Code delegation is never set here; it's an explicit transaction afterwards. // // Owns its own form state; reads the shared store + account-building primitives // from the account-engine context. @@ -104,7 +103,7 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { pushActivity({ kind: 'create', title: `EOA account · ${account.label}`, - detail: 'Stored locally · no code delegation', + detail: 'Stored locally · ready to transact', account: account.address, }); autoFundNewAccount(account.address); @@ -234,7 +233,7 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { ) : ( A new secp256k1 key is generated and kept in this browser. Its address is the account — no deployment, - no salt. Delegate code to it later from Transact if you want contract behavior. + no salt. )} diff --git a/app/vibenet/demos/account/components/TransactionModal.tsx b/app/vibenet/demos/account/components/TransactionModal.tsx index 11368f3b..74f5d8a7 100644 --- a/app/vibenet/demos/account/components/TransactionModal.tsx +++ b/app/vibenet/demos/account/components/TransactionModal.tsx @@ -1,7 +1,7 @@ 'use client'; // The shared "Create Transaction" dialog for EIP-8130 EOA accounts: a single -// popup with three steps — build (calls, code delegation, gas), review, and +// popup with three steps — build (calls, gas), review, and // submitted (sign → broadcast → wait for inclusion). // // Driven by declarative open/preset props plus the account-engine context, so @@ -20,7 +20,6 @@ import { privateKeyToAccount, selectPaymentOption, toHex, - zeroAddress, } from '@aa'; import { useMemo, useState } from 'react'; import { toast } from 'sonner'; @@ -69,14 +68,11 @@ import { } from '../useAccountEngine'; type GasMode = 'eth' | 'free' | 'usdv'; -type DelegateMode = 'none' | 'set' | 'clear'; export type TransactPreset = { calls?: CallRow[]; gasMode?: GasMode; metadata?: string; - /** Open with the "Delegate code" control set (target left for the user to fill in). */ - delegation?: 'set' | 'clear'; nonceless?: boolean; }; @@ -138,8 +134,6 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { addressBook, chain, activeSigner, - delegationTarget, - refreshDelegation, latestAnchor, broadcast8130, awaitRelayed, @@ -148,20 +142,13 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { pushActivity, } = engine; - const [calls, setCalls] = useState( - () => - preset?.calls ?? - // A delegation-only transaction still needs a call; a self no-op is the cheapest. - [preset?.delegation && acct ? newCallRow({ to: acct.address }) : newCallRow()], - ); + const [calls, setCalls] = useState(() => preset?.calls ?? [newCallRow()]); const [callsAdvanced, setCallsAdvanced] = useState(false); const [usdvRecipientDrafts, setUsdvRecipientDrafts] = useState>({}); const [usdvAmountDrafts, setUsdvAmountDrafts] = useState>({}); const [metaField, setMetaField] = useState(preset?.metadata ?? ''); const [gasMode, setGasMode] = useState(preset?.gasMode ?? 'eth'); const [nonceless, setNonceless] = useState(preset?.nonceless ?? false); - const [delegateMode, setDelegateMode] = useState(preset?.delegation ?? 'none'); - const [delegateInput, setDelegateInput] = useState(''); const [signing, setSigning] = useState(false); const [copied, setCopied] = useState(null); const [submitStatus, setSubmitStatus] = useState<'' | 'submitting' | 'confirming'>(''); @@ -170,19 +157,11 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { // Error UI is local to this dialog — nothing leaks onto the page behind it. const [error, setError] = useState(''); const [txStep, setTxStep] = useState<'build' | 'review' | 'submitted'>( - preset?.calls && !preset.delegation ? 'review' : 'build', + preset?.calls ? 'review' : 'build', ); const [result, setResult] = useState(null); const callsValid = useMemo(() => calls.every(rowToValid), [calls]); - const delegateTo: Address | undefined = - delegateMode === 'set' && isAddressStr(delegateInput.trim()) && BigInt(delegateInput.trim()) !== 0n - ? (delegateInput.trim() as Address) - : delegateMode === 'clear' - ? zeroAddress - : undefined; - const delegateValid = delegateMode === 'none' || !!delegateTo; - const formValid = callsValid && delegateValid; const metadataHex = useMemo( () => (metaField.trim() ? (toHex(metaField.trim()) as Hex) : undefined), [metaField], @@ -192,12 +171,11 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { return estimateTxGas({ calls: calls.length, valueCalls: valueBearingCallCount(calls, acct.address), - delegation: delegateMode !== 'none', nonceless, payer: gasMode !== 'eth', tokenPayment: gasMode === 'usdv', }); - }, [acct, calls, delegateMode, nonceless, gasMode]); + }, [acct, calls, nonceless, gasMode]); const clearResult = () => setResult(null); const copy = async (text: string, key: string) => { @@ -211,12 +189,6 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { }; const copyRandomAddress = () => copy(privateKeyToAccount(generatePrivateKey()).address, 'randaddr'); - const delegationChange = delegateTo - ? delegateTo === zeroAddress - ? 'clear code delegation' - : `delegate → ${short(delegateTo)}` - : null; - const recordResult = ( a: StoredAccount, serialized: Hex, @@ -227,17 +199,12 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { ) => { setResult({ serialized, txHash, by: by.label, kind: by.kind, pending, gasNote, inclusion: inclusionFor(txHash) }); pushActivity({ - kind: delegationChange ? 'delegate' : 'transact', + kind: 'transact', txHash, title: pending ? 'Transaction pending · not yet included' - : delegationChange - ? delegateTo === zeroAddress - ? 'Code delegation cleared' - : 'Code delegation set' - : `Transaction landed onchain${gasNote ? ' (payer gas)' : ''}`, + : `Transaction landed onchain${gasNote ? ' (payer gas)' : ''}`, changes: [ - ...(delegationChange ? [delegationChange] : []), ...(nonceless ? ['nonce-free'] : []), ...(pending ? ['⚠ pending — not yet included'] : []), ...(gasNote ? [gasNote] : []), @@ -249,7 +216,6 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { serialized, account: a.address, }); - if (delegationChange && !pending) void refreshDelegation(); }; const surfaceSendError = (message: string) => { @@ -280,7 +246,6 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { const { serialized } = await signComposed(acct, { rows: calls, metadata: metadataHex, - delegateTo, noncelessSeconds: nonceless ? NONCELESS_SECONDS : undefined, estimateRevert: forceEstimate ? 'force' : 'throw', }); @@ -346,7 +311,6 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { const { serialized, paymentAmount } = await signComposed(acct, { rows: calls, metadata: metadataHex, - delegateTo, noncelessSeconds: nonceless ? NONCELESS_SECONDS : undefined, payer, validBefore, @@ -439,7 +403,7 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { }; const startSend = () => { - if (!formValid || !activeSigner) return; + if (!callsValid || !activeSigner) return; setError(''); setResult(null); setTxStep('review'); @@ -507,7 +471,7 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { variant="primary" size="sm" onClick={() => confirmSend()} - disabled={signing || !formValid} + disabled={signing || !callsValid} className="disabled:cursor-not-allowed disabled:opacity-50" > Send @@ -521,7 +485,7 @@ export function TransactionModal({ onClose, preset }: TransactionModalProps) { - {target ? ( - - ) : null} - - - - ); -} diff --git a/vendor/aa/entry.mjs b/vendor/aa/entry.mjs index 015e724a..e64ca71a 100644 --- a/vendor/aa/entry.mjs +++ b/vendor/aa/entry.mjs @@ -30,11 +30,9 @@ export { privateKeyToAccount, } from '../../../viem/src/accounts/index.ts' -// EIP-8130 (native account abstraction) — secp256k1 EOA senders with optional -// code delegation. +// EIP-8130 (native account abstraction) — secp256k1 EOA senders. export { allPhasesSucceeded, - delegationCost, estimateGas, getTransactionCount, getTransactionReceipt, diff --git a/vendor/aa/index.d.ts b/vendor/aa/index.d.ts index 41094562..d861fc10 100644 --- a/vendor/aa/index.d.ts +++ b/vendor/aa/index.d.ts @@ -2,8 +2,8 @@ // Covers exactly the surface entry.mjs exports. Generated artifact pairing: // `bun run vendor/aa/build.mjs` rebuilds index.js from the sibling viem branch // (feat/aa-tx-split). The chain runs with the EIP-8130 Keystore disabled, so -// only the Keystore-free core is declared: secp256k1 EOA senders, optional -// `delegation` account changes, and ERC-8168 payers. +// only the Keystore-free core is declared: secp256k1 EOA senders and ERC-8168 +// payers. export type Hex = `0x${string}` export type Address = `0x${string}` @@ -130,7 +130,6 @@ export const k1Authenticator: Address export const nonceKeyMax: bigint export const k1AuthCost: bigint export const txValueCost: bigint -export const delegationCost: bigint export const nonceFreeCost: bigint /** Read the EIP-8130 nonce via `eth_getTransactionCount` (2D channel-nonce). */ diff --git a/vendor/aa/index.js b/vendor/aa/index.js index 2032306e..0ee1f3b8 100644 --- a/vendor/aa/index.js +++ b/vendor/aa/index.js @@ -18199,7 +18199,6 @@ var aaTransactionType = "0x79"; var aaPayerType = "0x7a"; var k1AuthCost = 5100n; var txValueCost = 6000n; -var delegationCost = 4600n; var nonceFreeCost = 13000n; var nonceFreeDefaultExpiryWindow = 15000n; var accountChangeType = { @@ -18871,7 +18870,6 @@ export { encodeTokenTransfer, encodeFunctionData, encodeAbiParameters, - delegationCost, decodeAbiParameters, createPublicClient, createPayerClient, From 898da315a497fd20e58e24465034ba57e5515e4d Mon Sep 17 00:00:00 2001 From: Chris Hunter Date: Fri, 2 Oct 2026 12:31:40 -0400 Subject: [PATCH 6/6] vibenet(account): drop private-key import; rename EOA feature card New accounts always get a browser-generated key (or reuse an unused one). The lone-option Key picker is hidden when there is nothing to reuse. --- app/vibenet/data/features.ts | 2 +- .../account/components/CreateAccountModal.tsx | 91 ++++--------------- app/vibenet/demos/account/shared.ts | 2 +- .../demos/account/useAccountEngine.tsx | 18 ---- 4 files changed, 21 insertions(+), 92 deletions(-) diff --git a/app/vibenet/data/features.ts b/app/vibenet/data/features.ts index 0f2e5d6d..e6efdca1 100644 --- a/app/vibenet/data/features.ts +++ b/app/vibenet/data/features.ts @@ -13,7 +13,7 @@ export const FEATURES: VibenetFeature[] = [ availabilityLabel: 'Base Denim', availabilityHref: {label: 'Base Denim', href: 'https://docs.base.org/upgrades/denim', external: true}, highlights: [ - { title: 'Your EOA Is the Account', detail: 'Any secp256k1 key sends native AA transactions — nothing to deploy.' }, + { title: 'Superpowered EOAs', detail: 'Any secp256k1 key sends native AA transactions — nothing to deploy.' }, { title: 'Portable Everywhere', detail: 'Same key and address on any EVM chain.' }, { title: 'Nonce-Free Sends', detail: 'Short-lived transactions with no nonce to track or collide on.' }, { title: 'Sponsored & ERC-20 Gas', detail: 'Native payer support via the ERC-8168 payer service.' }, diff --git a/app/vibenet/demos/account/components/CreateAccountModal.tsx b/app/vibenet/demos/account/components/CreateAccountModal.tsx index b98c1945..8d72eaeb 100644 --- a/app/vibenet/demos/account/components/CreateAccountModal.tsx +++ b/app/vibenet/demos/account/components/CreateAccountModal.tsx @@ -4,12 +4,10 @@ // account. "Key" is the only real choice: // New key — generate a fresh K1 key in this browser // Unused key — reuse a K1 key already in the wallet that backs no account -// Import — paste an existing private key // // Owns its own form state; reads the shared store + account-building primitives // from the account-engine context. -import { type Hex } from '@aa'; import { useEffect, useMemo, useState } from 'react'; import { Button } from '../../../../components/ui/Button'; @@ -30,8 +28,6 @@ type CreateAccountModalProps = { onClose: () => void; }; -const PRIVATE_KEY_RE = /^0x[0-9a-fA-F]{64}$/; - export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { const { signers, @@ -41,7 +37,6 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { usedSignerIds, deleteSigner, createSigner, - importSigner, pushActivity, autoFundNewAccount, } = useAccountEngine(); @@ -49,8 +44,6 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { const [createMode, setCreateMode] = useState('generate'); const [modalLabel, setModalLabel] = useState(''); const [existingId, setExistingId] = useState(null); - const [importKey, setImportKey] = useState(''); - const [importError, setImportError] = useState(''); const unusedSigners = useMemo(() => signers.filter((s) => !usedSignerIds.has(s.id)), [signers, usedSignerIds]); @@ -60,8 +53,6 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { setCreateMode('generate'); setModalLabel(''); setExistingId(null); - setImportKey(''); - setImportError(''); }, [open]); const modes = useMemo( @@ -71,13 +62,11 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { ...(unusedSigners.length > 0 ? [{ value: 'existing' as const, title: 'Unused Key', description: 'Reuse a key in your wallet' }] : []), - { value: 'import' as const, title: 'Import', description: 'Paste a private key' }, ] satisfies ReadonlyArray<{ value: CreateMode; title: string; description: string }>, [unusedSigners.length], ); const existingSigner = unusedSigners.find((s) => s.id === existingId) ?? null; - const importValid = PRIVATE_KEY_RE.test(importKey.trim()); // Keep the auto-suggested fallback name unique (Account, Account 2, …). A name // the user typed by hand is respected as-is, collisions and all. @@ -111,35 +100,13 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { const createAccount = () => { const name = modalLabel.trim() || uniqueAccountName('Account'); - let signer: WalletSigner | null = null; - if (createMode === 'generate') { - signer = createSigner(); - } else if (createMode === 'existing') { - signer = existingSigner; - } else { - if (!importValid) { - setImportError('Enter a 32-byte hex private key (0x + 64 hex characters).'); - return; - } - try { - signer = importSigner(importKey.trim() as Hex); - } catch { - setImportError('That is not a valid secp256k1 private key.'); - return; - } - if (accounts.some((a) => a.address.toLowerCase() === signer?.address.toLowerCase())) { - setImportError('An account for this key already exists.'); - return; - } - } + const signer = createMode === 'generate' ? createSigner() : existingSigner; if (!signer) return; buildEoaAccount(signer, name); - setImportKey(''); onClose(); }; - const canCreate = - createMode === 'generate' ? true : createMode === 'existing' ? Boolean(existingSigner) : importValid; + const canCreate = createMode === 'generate' || Boolean(existingSigner); const submit = () => { if (canCreate && !busy) createAccount(); @@ -182,25 +149,23 @@ export function CreateAccountModal({ open, onClose }: CreateAccountModalProps) { /> - - Key - - {modes.map((option) => ( - - - {option.title} - - - {option.description} - - - ))} - - + {modes.length > 1 ? ( + + Key + + {modes.map((option) => ( + + + {option.title} + + + {option.description} + + + ))} + + + ) : null} {createMode === 'existing' ? ( - ) : createMode === 'import' ? ( - - Private key - { - setImportKey(v); - setImportError(''); - }} - /> - - {importError || 'Stored only in this browser. Use a throwaway devnet key, never a real wallet key.'} - - ) : ( A new secp256k1 key is generated and kept in this browser. Its address is the account — no deployment, diff --git a/app/vibenet/demos/account/shared.ts b/app/vibenet/demos/account/shared.ts index 9c40eebe..eb4f5516 100644 --- a/app/vibenet/demos/account/shared.ts +++ b/app/vibenet/demos/account/shared.ts @@ -29,7 +29,7 @@ export type Persisted = { }; /** How the create-account drawer sources the account's key. */ -export type CreateMode = 'generate' | 'existing' | 'import'; +export type CreateMode = 'generate' | 'existing'; export const KIND_LABEL: Record = { k1: 'K1', diff --git a/app/vibenet/demos/account/useAccountEngine.tsx b/app/vibenet/demos/account/useAccountEngine.tsx index da3fc176..885a7bd0 100644 --- a/app/vibenet/demos/account/useAccountEngine.tsx +++ b/app/vibenet/demos/account/useAccountEngine.tsx @@ -343,23 +343,6 @@ function useAccountEngineCore() { } }; - // Adds an existing private key to the wallet, reusing the stored key when the - // same address is already held. Throws on a malformed key. - const importSigner = (privateKey: Hex): WalletSigner => { - const address = privateKeyToAccount(privateKey).address; - const existing = signers.find((s) => s.address.toLowerCase() === address.toLowerCase()); - if (existing) return existing; - const ws: WalletSigner = { - id: crypto.randomUUID(), - kind: 'k1', - label: nextSignerLabel(), - privateKey, - address, - }; - setSigners((prev) => [...prev, ws]); - return ws; - }; - // Signer ids backing an account. Keys outside this set are unused and safe to delete. const usedSignerIds = useMemo(() => new Set(accounts.map((a) => a.signerId)), [accounts]); @@ -665,7 +648,6 @@ function useAccountEngineCore() { usedSignerIds, deleteSigner, createSigner, - importSigner, pushActivity, autoFundNewAccount,