@valve-tech/wallet-adapter 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@valve-tech/wallet-adapter` are documented in
4
+ this file.
5
+
6
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
7
+ and this project adheres to [Semantic Versioning](https://semver.org/).
8
+
9
+ ## [Unreleased]
10
+
11
+ ### Added
12
+
13
+ - Initial implementation. Vocabulary lifted from a real-world dapp
14
+ (Provex) where SDK / UI / tx-tracker each redefined the same shapes
15
+ separately; this is the first upstream packaging.
16
+ - `WalletAdapter` interface plus `WalletSendTransactionRequest` and
17
+ `WalletReadContractRequest` request shapes.
18
+ - `WriteHookParams` — full lifecycle contract. Six named callbacks
19
+ (`onAwaitingSignature`, `onTransactionHash`, `onConfirmed`,
20
+ `onFailed`, `onDropped`, `onReplaced`) plus a complementary
21
+ single-callback `onPhase(event)` shape with a discriminated-union
22
+ payload. Fire-ers fire BOTH shapes for every transition.
23
+ - `WritePhase` (`'preparing' | 'awaiting-signature' | 'pending' |
24
+ 'confirmed' | 'failed' | 'dropped' | 'replaced'`) and
25
+ `WritePhaseEvent` discriminated union for `onPhase` consumers.
26
+ - `TX_STATUS` lifecycle const, `TrackedTxStatus` type, `TrackedTx`
27
+ shape, `TrackedTxGas`, `TxConfirmedCallback`.
28
+ - `TX_FLOW` extension point (ships empty), `TxFlow = string`.
29
+ - `STALE_TX_AGE_MS` / `CONFIRMED_DISPLAY_MS` / `FAILED_DISPLAY_MS`
30
+ display-window defaults.
31
+ - Unit tests covering the runtime constants and type-level shape
32
+ guarantees (status-value uniqueness, phase literal union, hook
33
+ parameter typing, `TrackedTx` pre-hash and post-hash construction).
34
+ - `sendTransactionWithHooks(options)` — wallet-side runtime helper.
35
+ Fires `onAwaitingSignature` + `onPhase('awaiting-signature')`
36
+ immediately before `sendTransaction`; fires per-call + global
37
+ `onTransactionHash` and `onPhase('pending', { hash })` after the
38
+ wallet returns; fires `onFailed` + `onPhase('failed', ...)` on any
39
+ thrown error before re-throwing.
40
+ - `awaitReceiptWithHooks(options)` — chain-side runtime helper.
41
+ Awaits `waitForTransactionReceipt`; fires `onConfirmed` +
42
+ `onPhase('confirmed', { hash, receipt })` on success; fires
43
+ `onFailed` with a `ContractRevertedError` + `onPhase('failed', ...)`
44
+ on `status: reverted`; fires `onFailed` with the original error +
45
+ `onPhase('failed', ...)` on any other receipt-await failure.
46
+ - `WalletRejectedError` — `Error` subclass thrown by
47
+ `sendTransactionWithHooks` on user rejection; preserves the original
48
+ error as `cause`.
49
+ - `ContractRevertedError` — `Error` subclass thrown by
50
+ `awaitReceiptWithHooks` on `status: reverted`; carries the `hash`
51
+ and full `receipt` so consumers can extract revert reasons / log
52
+ data without re-fetching.
53
+ - Runtime dependency on `@valve-tech/viem-errors` for the
54
+ three-signal rejection detection (EIP-1193 `code === 4001`, viem
55
+ class name, message regex — anywhere in the cause chain).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Valve Tech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # `@valve-tech/wallet-adapter`
2
+
3
+ Framework-agnostic vocabulary for EVM dapp wallet integration. Pure
4
+ types + a few `as const` lifecycle constants — no runtime
5
+ implementation, no opinion about which wallet library you use.
6
+
7
+ Five concerns under one package so SDK authors, UI authors, and apps
8
+ all agree on the same surface:
9
+
10
+ 1. **`WalletAdapter`** — the contract an SDK accepts in lieu of
11
+ coupling to wagmi / ethers / viem direct / a smart account.
12
+ 2. **`WriteHookParams`** — every phase a tracked tx can be in. Six
13
+ named hooks (`onAwaitingSignature`, `onTransactionHash`,
14
+ `onConfirmed`, `onFailed`, `onDropped`, `onReplaced`) plus a
15
+ complementary single-callback shape (`onPhase(event)`) with a
16
+ discriminated-union payload. Fire-ers fire BOTH shapes for every
17
+ transition — exactly once each — so wiring named hooks doesn't
18
+ preclude `onPhase` and vice versa.
19
+ 3. **`sendTransactionWithHooks(options)`** — wallet-side helper. Fires
20
+ the pre-wallet (`onAwaitingSignature`, `onPhase('awaiting-signature')`)
21
+ and post-hash (`onTransactionHash`, `onPhase('pending', { hash })`)
22
+ transitions. Converts wallet rejections to a typed
23
+ `WalletRejectedError`, fires `onFailed` + `onPhase('failed', { error })`,
24
+ then throws.
25
+ 4. **`awaitReceiptWithHooks(options)`** — chain-side helper. Awaits
26
+ `waitForTransactionReceipt`, fires `onConfirmed` +
27
+ `onPhase('confirmed', { hash, receipt })` on success, or `onFailed`
28
+ + `onPhase('failed', ...)` with a typed `ContractRevertedError` on
29
+ `status: 'reverted'`. Other receipt-await errors re-thrown unchanged
30
+ after firing the failure hooks.
31
+ 5. **`TX_STATUS` / `TrackedTx`** — vocabulary for "this transaction is
32
+ in flight" UIs (toast strips, inline indicators, history panes) so
33
+ they can sit on top of any tracker without redefining state names.
34
+
35
+ The two helpers split by concern: the wallet side and the chain side.
36
+ SDKs chain them with whatever protocol-specific work goes in the
37
+ middle (gating-service signatures, log decoding, indexer sync). The
38
+ only runtime dependency is `@valve-tech/viem-errors` for the
39
+ rejection-detection check; viem is a peer dependency for the `Hex`
40
+ and `TransactionReceipt` types.
41
+
42
+ **`onDropped` and `onReplaced` are part of the contract; the helpers
43
+ in this package don't fire them.** Honestly distinguishing "still
44
+ propagating" from "permanently dropped" requires observing the tx
45
+ across many blocks with a configurable timeout policy, and detecting
46
+ replacement requires nonce-watching across the same nonce — that's
47
+ `@valve-tech/tx-tracker`'s job (per-tx state machine). The contract
48
+ defines the hooks here so consumers wire one set of callbacks; the
49
+ tracker fires them when it ships. Wiring `onDropped` / `onReplaced`
50
+ against `awaitReceiptWithHooks` is harmless but they will not fire
51
+ from this package.
52
+
53
+ ## Why
54
+
55
+ Every SDK invents its own wallet shape; every dapp invents its own
56
+ "awaiting signature" state machine; every UI invents its own list of
57
+ status names. The result is a small ecosystem where the same word
58
+ means slightly different things at every boundary, and dapps end up
59
+ writing translation glue between them.
60
+
61
+ This package is the shared vocabulary. Use `WalletAdapter` so a single
62
+ wagmi/ethers/smart-account adapter works across every SDK. Use
63
+ `WriteHookParams` so the UI sees consistent transitions across every
64
+ SDK write. Use `TX_STATUS` so the in-flight strip and the receipt-poll
65
+ agree on what `'pending'` means.
66
+
67
+ ## Install
68
+
69
+ ```sh
70
+ npm install @valve-tech/wallet-adapter viem
71
+ # or
72
+ yarn add @valve-tech/wallet-adapter viem
73
+ ```
74
+
75
+ ## Quick start
76
+
77
+ ### Defining an SDK that accepts any wallet
78
+
79
+ ```ts
80
+ import {
81
+ sendTransactionWithHooks,
82
+ awaitReceiptWithHooks,
83
+ WalletRejectedError,
84
+ ContractRevertedError,
85
+ type WalletAdapter,
86
+ type WriteHookParams,
87
+ } from '@valve-tech/wallet-adapter'
88
+
89
+ export interface MyWriteParams { depositId: bigint; amount: bigint }
90
+
91
+ export class MyClient {
92
+ constructor(
93
+ private wallet: WalletAdapter,
94
+ private chainId: number,
95
+ private escrow: `0x${string}`,
96
+ /** Optional global / analytics channel — fires alongside the per-call hook. */
97
+ private onTransactionHash?: (hash: `0x${string}`) => void,
98
+ ) {}
99
+
100
+ async deposit(params: MyWriteParams & WriteHookParams) {
101
+ try {
102
+ const hash = await sendTransactionWithHooks({
103
+ wallet: this.wallet,
104
+ request: {
105
+ to: this.escrow,
106
+ data: this.encodeDeposit(params),
107
+ chainId: this.chainId,
108
+ },
109
+ hooks: params,
110
+ onTransactionHash: this.onTransactionHash,
111
+ })
112
+ const receipt = await awaitReceiptWithHooks({
113
+ publicClient: this.publicClient,
114
+ hash,
115
+ hooks: params,
116
+ })
117
+ // protocol-specific work here (decode logs, etc.) — onConfirmed already fired
118
+ return { hash, receipt }
119
+ } catch (err) {
120
+ if (err instanceof WalletRejectedError) {
121
+ throw new MySdkError('WALLET_REJECTED', err.message, err.cause)
122
+ }
123
+ if (err instanceof ContractRevertedError) {
124
+ throw new MySdkError('TX_REVERTED', err.message, err)
125
+ }
126
+ throw new MySdkError('CONTRACT_ERROR', (err as Error).message, err as Error)
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ `sendTransactionWithHooks` guarantees:
133
+
134
+ - `onAwaitingSignature` fires **once**, **immediately before**
135
+ `wallet.sendTransaction`.
136
+ - `onTransactionHash` (per-call **and** global) fires **once each**,
137
+ **after** `sendTransaction` resolves and **before** any receipt-await.
138
+ - Wallet rejections — detected via the three-signal check in
139
+ `@valve-tech/viem-errors` (EIP-1193 `code === 4001`, viem class name,
140
+ message regex, anywhere in the cause chain) — are thrown as
141
+ `WalletRejectedError`. `onFailed` fires with the rejection error
142
+ before the throw.
143
+ - Any other thrown error fires `onFailed` and re-throws unchanged so
144
+ the SDK keeps control of its error mapping.
145
+
146
+ `awaitReceiptWithHooks` guarantees:
147
+
148
+ - On `receipt.status === 'success'`: fires `onConfirmed(receipt)` and
149
+ resolves with the receipt.
150
+ - On `receipt.status === 'reverted'`: fires `onFailed` with a
151
+ `ContractRevertedError` (carrying `hash` + the full `receipt` for
152
+ log inspection) and throws it.
153
+ - On any thrown error during the receipt-await (network / RPC /
154
+ abort): fires `onFailed` with the original error and re-throws
155
+ unchanged.
156
+
157
+ A `WriteHookParams` consumer (toast strip, inline indicator, etc.)
158
+ that wires all four hooks can drive its full state machine — pre-wallet
159
+ "preparing", post-wallet "pending", terminal "confirmed" or "failed" —
160
+ purely from the contract, without any SDK-specific glue.
161
+
162
+ ### A tx-flight UI built on `TX_STATUS`
163
+
164
+ ```ts
165
+ import { TX_STATUS, type TrackedTx } from '@valve-tech/wallet-adapter'
166
+
167
+ function subtitle(tx: TrackedTx): string {
168
+ switch (tx.status) {
169
+ case TX_STATUS.preparing: return 'preparing transaction'
170
+ case TX_STATUS.awaitingSignature: return 'awaiting wallet signature'
171
+ case TX_STATUS.pending: return 'waiting for inclusion'
172
+ case TX_STATUS.mined: return 'confirmed on-chain'
173
+ case TX_STATUS.failed: return tx.notes ?? 'transaction failed'
174
+ case TX_STATUS.dropped: return 'dropped from mempool'
175
+ case TX_STATUS.replaced: return 'replaced by speed-up'
176
+ }
177
+ }
178
+ ```
179
+
180
+ ## Exports
181
+
182
+ | Export | Kind | Shape |
183
+ | --- | --- | --- |
184
+ | `WalletAdapter` | type | `{ address?, sendTransaction(req), readContract?(req) }` |
185
+ | `WalletSendTransactionRequest` | type | EIP-1559 send shape — `{ to, data, value?, chainId, maxFeePerGas?, maxPriorityFeePerGas? }` |
186
+ | `WalletReadContractRequest` | type | `{ address, abi, functionName, args?, chainId? }` |
187
+ | `WriteHookParams` | type | six named hooks (`onAwaitingSignature`, `onTransactionHash`, `onConfirmed`, `onFailed`, `onDropped`, `onReplaced`) + `onPhase(event)` |
188
+ | `WritePhase` | type | `'preparing' \| 'awaiting-signature' \| 'pending' \| 'confirmed' \| 'failed' \| 'dropped' \| 'replaced'` |
189
+ | `WritePhaseEvent` | type | discriminated union of phase + payload |
190
+ | `sendTransactionWithHooks(opts)` | function | `{ wallet, request, hooks?, onTransactionHash? } → Promise<Hex>`. Wallet-side helper. |
191
+ | `awaitReceiptWithHooks(opts)` | function | `{ publicClient, hash, hooks? } → Promise<TransactionReceipt>`. Chain-side helper. |
192
+ | `WalletRejectedError` | class | `Error` subclass with `cause: Error`. Thrown by `sendTransactionWithHooks` on user rejection. |
193
+ | `ContractRevertedError` | class | `Error` subclass with `hash` + `receipt`. Thrown by `awaitReceiptWithHooks` on `status: reverted`. |
194
+ | `SendTransactionWithHooksOptions` / `AwaitReceiptWithHooksOptions` / `ReceiptAwaiter` | type | options + minimal client shape |
195
+ | `TX_STATUS` | const | lifecycle states |
196
+ | `TX_FLOW` | const | empty by design — protocols extend |
197
+ | `TrackedTx` | type | `{ id, hash?, chainId, flow, submittedAt, ... status, notes? }` |
198
+ | `STALE_TX_AGE_MS` / `CONFIRMED_DISPLAY_MS` / `FAILED_DISPLAY_MS` | const | window defaults |
199
+
200
+ ## Design notes
201
+
202
+ - **One hook contract, two complementary shapes.** `WriteHookParams`
203
+ describes every phase a tracked tx can be in. Six named callbacks
204
+ cover the common transitions; `onPhase(event)` provides the same
205
+ information as a discriminated-union single-callback shape for
206
+ state-machine consumers. Fire-ers fire BOTH shapes for every
207
+ transition — exactly once each. Wiring named hooks doesn't preclude
208
+ `onPhase` and vice versa.
209
+ - **`onFailed` is the unified failure callback for revert / rejection /
210
+ network errors.** Wallet rejection, on-chain revert, and network
211
+ errors all flow through it. `instanceof` against
212
+ `WalletRejectedError` / `ContractRevertedError` discriminates the
213
+ source. Distinct from `onDropped` (no inclusion observed) and
214
+ `onReplaced` (different tx mined for the same nonce) — those are
215
+ their own terminal states with their own typed payloads.
216
+ - **`onDropped` and `onReplaced` are part of the contract; this
217
+ package's helpers don't fire them.** Detecting drop vs replacement
218
+ requires multi-block observation with nonce-watching — that's
219
+ `@valve-tech/tx-tracker`'s job. The hooks live in `WriteHookParams`
220
+ so consumers wire one set of callbacks; the tracker fires them when
221
+ it ships.
222
+ - **`TX_FLOW` is intentionally empty.** Every protocol's flow names
223
+ (`fulfillIntent`, `addFunds`, `mintNFT`, etc.) are its own concern.
224
+ Extend the `TxFlow` type via your own union.
225
+ - **Pre-hash states are first-class.** `preparing` and
226
+ `awaiting-signature` carry no `hash` — they exist so the UI has
227
+ something to show during the wallet-sign window.
228
+ - **`id` is stable, `hash` is not.** Registries assign `id` at
229
+ `beginTx` time and attach `hash` later. This lets pre-hash UI render
230
+ before the wallet returns.
231
+
232
+ ## License
233
+
234
+ MIT
@@ -0,0 +1,157 @@
1
+ /**
2
+ * @fileoverview Per-call lifecycle hooks for any SDK method that opens a
3
+ * wallet popup, awaits inclusion, and may later observe replacement or
4
+ * mempool drop.
5
+ *
6
+ * The contract describes EVERY phase a tracked tx can be in. Different
7
+ * fire-ers cover different slices:
8
+ *
9
+ * - `sendTransactionWithHooks` fires the wallet-side phases
10
+ * (`awaiting-signature`, `pending`, plus `failed` on rejection /
11
+ * wallet-side network error).
12
+ * - `awaitReceiptWithHooks` fires the chain-side terminal phases
13
+ * (`confirmed` or `failed` on revert / receipt-await error).
14
+ * - `@valve-tech/tx-tracker` (per-tx state machine, observes across
15
+ * blocks) fires `dropped` and `replaced` once it ships, plus may
16
+ * re-emit transitions if a tx surfaces / vanishes / surfaces again
17
+ * across reorgs.
18
+ * - The SDK itself may fire `preparing` at the very start of its
19
+ * write method, before any pre-wallet work begins.
20
+ *
21
+ * Two shapes are available — complementary, not alternatives:
22
+ *
23
+ * - **Named hooks** (`onAwaitingSignature`, `onConfirmed`, etc.) —
24
+ * ergonomic, easy to wire from a hook-like API, narrow types per
25
+ * callback.
26
+ * - **`onPhase(event)`** — single-callback discriminated union.
27
+ * Better for state-machine consumers that need a single transition
28
+ * point and exhaustive `switch`-coverage on the phase name.
29
+ *
30
+ * Fire-ers fire BOTH shapes for every transition — exactly once each —
31
+ * so consumers can choose which to wire without affecting the other.
32
+ */
33
+ import type { Hex, TransactionReceipt } from 'viem';
34
+ /**
35
+ * Every lifecycle phase a tracked transaction can be in, from intent
36
+ * through terminal observation. Carriers (helpers, trackers, SDKs)
37
+ * fire transitions in roughly this order, though `dropped` and
38
+ * `replaced` may arrive late or interleave with re-emissions on reorg.
39
+ */
40
+ export type WritePhase = 'preparing' | 'awaiting-signature' | 'pending' | 'confirmed' | 'failed' | 'dropped' | 'replaced';
41
+ /**
42
+ * Discriminated-union event payload for the `onPhase` callback. Switch
43
+ * on `event.phase` and TypeScript narrows the rest of the fields
44
+ * automatically — no `event.context?.receipt` indirection.
45
+ */
46
+ export type WritePhaseEvent = {
47
+ phase: 'preparing';
48
+ } | {
49
+ phase: 'awaiting-signature';
50
+ } | {
51
+ phase: 'pending';
52
+ hash: Hex;
53
+ } | {
54
+ phase: 'confirmed';
55
+ hash: Hex;
56
+ receipt: TransactionReceipt;
57
+ } | {
58
+ phase: 'failed';
59
+ error: Error;
60
+ hash?: Hex;
61
+ receipt?: TransactionReceipt;
62
+ } | {
63
+ phase: 'dropped';
64
+ hash: Hex;
65
+ } | {
66
+ phase: 'replaced';
67
+ original: Hex;
68
+ replacement: Hex;
69
+ receipt?: TransactionReceipt;
70
+ };
71
+ /**
72
+ * Per-call hooks fired at real boundaries during a tracked tx's
73
+ * lifecycle. Every field is optional. SDKs and trackers fire whichever
74
+ * subset corresponds to phases they actually observe; consumers wire
75
+ * only the ones their UI needs.
76
+ *
77
+ * Named hooks vs `onPhase`: complementary, not alternatives. A
78
+ * fire-er fires both for every transition — the named hook (if a
79
+ * consumer wired it) and `onPhase` (if a consumer wired it) — so no
80
+ * transition is observable from one shape but not the other.
81
+ */
82
+ export interface WriteHookParams {
83
+ /**
84
+ * Called once, immediately before `wallet.sendTransaction`. UI flips
85
+ * from "preparing" to "awaiting wallet signature" at the precise
86
+ * boundary, regardless of how much pre-wallet work the SDK did.
87
+ */
88
+ onAwaitingSignature?: () => void;
89
+ /**
90
+ * Called once with the on-chain tx hash, immediately after
91
+ * `sendTransaction` resolves and *before* any receipt-await. UI flips
92
+ * from "awaiting" to "pending" the moment the hash exists.
93
+ *
94
+ * Per-call vs constructor-level: SDKs may also expose a separate
95
+ * constructor-level `onTransactionHash` channel for analytics /
96
+ * global observers — they're complementary, fire on the same line.
97
+ */
98
+ onTransactionHash?: (hash: Hex) => void;
99
+ /**
100
+ * Called once with the mined receipt when `receipt.status === 'success'`.
101
+ * UI flips to a terminal "confirmed" state. Receives the full receipt
102
+ * so consumers can extract block number, gas used, decoded events.
103
+ */
104
+ onConfirmed?: (receipt: TransactionReceipt) => void;
105
+ /**
106
+ * Called once with the underlying error on any terminal failure that
107
+ * is NOT a replacement or a drop:
108
+ * - wallet rejection (`WalletRejectedError`)
109
+ * - on-chain revert (`ContractRevertedError`)
110
+ * - any other thrown error from the wallet or RPC.
111
+ *
112
+ * Use `instanceof` against `WalletRejectedError` / `ContractRevertedError`
113
+ * to discriminate; everything else is a plain `Error`.
114
+ */
115
+ onFailed?: (error: Error) => void;
116
+ /**
117
+ * Called once when a tracker has determined the tx will not be
118
+ * included — typically: not seen in mempool for N consecutive blocks
119
+ * AND no receipt arrived AND no replacement nonce mined. The exact
120
+ * timeout policy is the tracker's call (configurable per consumer).
121
+ *
122
+ * Helpers in THIS package never fire `onDropped` — distinguishing
123
+ * "still propagating" from "permanently dropped" requires multi-block
124
+ * observation. Wire this against a `tx-tracker` instance, not against
125
+ * `awaitReceiptWithHooks`.
126
+ */
127
+ onDropped?: (info: {
128
+ hash: Hex;
129
+ }) => void;
130
+ /**
131
+ * Called once when a tracker observes that a *different* tx with the
132
+ * same nonce mined in place of the one we were watching — typically
133
+ * the user's own speed-up / cancel from their wallet, or a
134
+ * fee-replacement broadcast separately.
135
+ *
136
+ * `replacement.receipt` is included when the replacement has been
137
+ * mined; trackers may emit `replaced` with no receipt if they only
138
+ * saw the replacement in the mempool.
139
+ */
140
+ onReplaced?: (info: {
141
+ original: Hex;
142
+ replacement: Hex;
143
+ receipt?: TransactionReceipt;
144
+ }) => void;
145
+ /**
146
+ * Single-callback complement to the named hooks. Fires for every
147
+ * lifecycle transition with a discriminated-union payload. Useful
148
+ * for state-machine consumers that prefer one transition point and
149
+ * exhaustive `switch`-coverage over wiring six separate callbacks.
150
+ *
151
+ * Fire-ers fire BOTH `onPhase` and the matching named hook on each
152
+ * transition — exactly once each — so wiring one shape doesn't
153
+ * preclude the other.
154
+ */
155
+ onPhase?: (event: WritePhaseEvent) => void;
156
+ }
157
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAClB,WAAW,GACX,oBAAoB,GACpB,SAAS,GACT,WAAW,GACX,QAAQ,GACR,SAAS,GACT,UAAU,CAAA;AAEd;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GACtB;IAAE,KAAK,EAAE,oBAAoB,CAAA;CAAE,GAC/B;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,GAC/B;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAC9D;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAAE,GAC3E;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,GAC/B;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC;IAAC,WAAW,EAAE,GAAG,CAAC;IAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAExF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAA;IAChC;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAA;IACvC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACnD;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IACjC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,KAAK,IAAI,CAAA;IACzC;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,GAAG,CAAC;QAAC,WAAW,EAAE,GAAG,CAAC;QAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAAE,KAAK,IAAI,CAAA;IAC9F;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAA;CAC3C"}
package/dist/hooks.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @fileoverview Per-call lifecycle hooks for any SDK method that opens a
3
+ * wallet popup, awaits inclusion, and may later observe replacement or
4
+ * mempool drop.
5
+ *
6
+ * The contract describes EVERY phase a tracked tx can be in. Different
7
+ * fire-ers cover different slices:
8
+ *
9
+ * - `sendTransactionWithHooks` fires the wallet-side phases
10
+ * (`awaiting-signature`, `pending`, plus `failed` on rejection /
11
+ * wallet-side network error).
12
+ * - `awaitReceiptWithHooks` fires the chain-side terminal phases
13
+ * (`confirmed` or `failed` on revert / receipt-await error).
14
+ * - `@valve-tech/tx-tracker` (per-tx state machine, observes across
15
+ * blocks) fires `dropped` and `replaced` once it ships, plus may
16
+ * re-emit transitions if a tx surfaces / vanishes / surfaces again
17
+ * across reorgs.
18
+ * - The SDK itself may fire `preparing` at the very start of its
19
+ * write method, before any pre-wallet work begins.
20
+ *
21
+ * Two shapes are available — complementary, not alternatives:
22
+ *
23
+ * - **Named hooks** (`onAwaitingSignature`, `onConfirmed`, etc.) —
24
+ * ergonomic, easy to wire from a hook-like API, narrow types per
25
+ * callback.
26
+ * - **`onPhase(event)`** — single-callback discriminated union.
27
+ * Better for state-machine consumers that need a single transition
28
+ * point and exhaustive `switch`-coverage on the phase name.
29
+ *
30
+ * Fire-ers fire BOTH shapes for every transition — exactly once each —
31
+ * so consumers can choose which to wire without affecting the other.
32
+ */
33
+ export {};
34
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @fileoverview Public API of `@valve-tech/wallet-adapter`.
3
+ */
4
+ export type { WalletAdapter, WalletSendTransactionRequest, WalletReadContractRequest, } from './wallet.js';
5
+ export type { WriteHookParams, WritePhase, WritePhaseEvent, } from './hooks.js';
6
+ export { TX_STATUS, TX_FLOW, STALE_TX_AGE_MS, CONFIRMED_DISPLAY_MS, FAILED_DISPLAY_MS, } from './tx-status.js';
7
+ export type { TrackedTx, TrackedTxGas, TrackedTxStatus, TxFlow, TxConfirmedCallback, } from './tx-status.js';
8
+ export { sendTransactionWithHooks, WalletRejectedError, type SendTransactionWithHooksOptions, } from './send.js';
9
+ export { awaitReceiptWithHooks, ContractRevertedError, type AwaitReceiptWithHooksOptions, type ReceiptAwaiter, } from './receipt.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACV,aAAa,EACb,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,aAAa,CAAA;AAEpB,YAAY,EACV,eAAe,EACf,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,SAAS,EACT,OAAO,EACP,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,SAAS,EACT,YAAY,EACZ,eAAe,EACf,MAAM,EACN,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,KAAK,+BAA+B,GACrC,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,cAAc,GACpB,MAAM,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @fileoverview Public API of `@valve-tech/wallet-adapter`.
3
+ */
4
+ export { TX_STATUS, TX_FLOW, STALE_TX_AGE_MS, CONFIRMED_DISPLAY_MS, FAILED_DISPLAY_MS, } from './tx-status.js';
5
+ export { sendTransactionWithHooks, WalletRejectedError, } from './send.js';
6
+ export { awaitReceiptWithHooks, ContractRevertedError, } from './receipt.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,OAAO,EACL,SAAS,EACT,OAAO,EACP,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,gBAAgB,CAAA;AAUvB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,GAEpB,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,qBAAqB,EACrB,qBAAqB,GAGtB,MAAM,cAAc,CAAA"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @fileoverview The chain-side complement of `sendTransactionWithHooks`.
3
+ *
4
+ * After the wallet returns a hash, an SDK has to:
5
+ * 1. Await the receipt.
6
+ * 2. Distinguish `success` from `reverted`.
7
+ * 3. Fire `onConfirmed` (success) or `onFailed` with a typed revert
8
+ * error (reverted), plus `onPhase` for the same transition, so any
9
+ * UI wired against `WriteHookParams` flips to a terminal state.
10
+ *
11
+ * Without a helper for this, every SDK re-implements the receipt-await +
12
+ * status-check + typed-error-throw block — the same drift trap
13
+ * `sendTransactionWithHooks` was added to fix on the wallet side.
14
+ *
15
+ * Drop detection (tx vanished from mempool without inclusion) and
16
+ * replacement detection are deliberately NOT in this helper. They
17
+ * require observing the tx across many blocks with a configurable
18
+ * timeout policy and nonce-watching — that's
19
+ * `@valve-tech/tx-tracker`'s job. The `WriteHookParams` contract
20
+ * defines `onDropped` / `onReplaced` so consumers can wire them once;
21
+ * this helper just doesn't fire them.
22
+ */
23
+ import type { Hex, TransactionReceipt } from 'viem';
24
+ import type { WriteHookParams } from './hooks.js';
25
+ /**
26
+ * Thrown by `awaitReceiptWithHooks` when the receipt arrives with
27
+ * `status === 'reverted'`. The full receipt is preserved so consumers
28
+ * can extract revert reasons from logs, gas usage, etc.
29
+ *
30
+ * Distinct from a thrown error during the receipt-await itself
31
+ * (network / RPC issues, timeouts) — those are re-thrown unchanged so
32
+ * the SDK can map them to its own error vocabulary.
33
+ */
34
+ export declare class ContractRevertedError extends Error {
35
+ /** The hash of the reverted transaction. */
36
+ readonly hash: Hex;
37
+ /** The full receipt with `status === 'reverted'`. */
38
+ readonly receipt: TransactionReceipt;
39
+ constructor(hash: Hex, receipt: TransactionReceipt);
40
+ }
41
+ /**
42
+ * Minimal viem `PublicClient` slice the helper needs. Defining it
43
+ * locally lets consumers pass a viem client OR a hand-rolled mock
44
+ * without depending on the full `PublicClient` surface.
45
+ */
46
+ export interface ReceiptAwaiter {
47
+ waitForTransactionReceipt(args: {
48
+ hash: Hex;
49
+ }): Promise<TransactionReceipt>;
50
+ }
51
+ export interface AwaitReceiptWithHooksOptions {
52
+ /** A viem `PublicClient` (or anything with the same `waitForTransactionReceipt` shape). */
53
+ publicClient: ReceiptAwaiter;
54
+ /** The hash returned by `sendTransactionWithHooks` (or any other broadcast path). */
55
+ hash: Hex;
56
+ /** Per-call hooks. `onMined` and `onFailed` fire from this helper. */
57
+ hooks?: WriteHookParams;
58
+ }
59
+ /**
60
+ * Await a transaction receipt and fire the post-hash lifecycle hooks.
61
+ * Throws `ContractRevertedError` on revert. Other errors during the
62
+ * receipt-await are re-thrown unchanged after `onFailed` fires.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const hash = await sendTransactionWithHooks({ wallet, request, hooks })
67
+ * const receipt = await awaitReceiptWithHooks({ publicClient, hash, hooks })
68
+ * // Both onMined / onFailed have fired by the time we get here.
69
+ * ```
70
+ */
71
+ export declare function awaitReceiptWithHooks(options: AwaitReceiptWithHooksOptions): Promise<TransactionReceipt>;
72
+ //# sourceMappingURL=receipt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipt.d.ts","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAA;IAClB,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAA;gBAExB,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,kBAAkB;CAMnD;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,yBAAyB,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;CAC5E;AAED,MAAM,WAAW,4BAA4B;IAC3C,2FAA2F;IAC3F,YAAY,EAAE,cAAc,CAAA;IAC5B,qFAAqF;IACrF,IAAI,EAAE,GAAG,CAAA;IACT,sEAAsE;IACtE,KAAK,CAAC,EAAE,eAAe,CAAA;CACxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,kBAAkB,CAAC,CAuB7B"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @fileoverview The chain-side complement of `sendTransactionWithHooks`.
3
+ *
4
+ * After the wallet returns a hash, an SDK has to:
5
+ * 1. Await the receipt.
6
+ * 2. Distinguish `success` from `reverted`.
7
+ * 3. Fire `onConfirmed` (success) or `onFailed` with a typed revert
8
+ * error (reverted), plus `onPhase` for the same transition, so any
9
+ * UI wired against `WriteHookParams` flips to a terminal state.
10
+ *
11
+ * Without a helper for this, every SDK re-implements the receipt-await +
12
+ * status-check + typed-error-throw block — the same drift trap
13
+ * `sendTransactionWithHooks` was added to fix on the wallet side.
14
+ *
15
+ * Drop detection (tx vanished from mempool without inclusion) and
16
+ * replacement detection are deliberately NOT in this helper. They
17
+ * require observing the tx across many blocks with a configurable
18
+ * timeout policy and nonce-watching — that's
19
+ * `@valve-tech/tx-tracker`'s job. The `WriteHookParams` contract
20
+ * defines `onDropped` / `onReplaced` so consumers can wire them once;
21
+ * this helper just doesn't fire them.
22
+ */
23
+ /**
24
+ * Thrown by `awaitReceiptWithHooks` when the receipt arrives with
25
+ * `status === 'reverted'`. The full receipt is preserved so consumers
26
+ * can extract revert reasons from logs, gas usage, etc.
27
+ *
28
+ * Distinct from a thrown error during the receipt-await itself
29
+ * (network / RPC issues, timeouts) — those are re-thrown unchanged so
30
+ * the SDK can map them to its own error vocabulary.
31
+ */
32
+ export class ContractRevertedError extends Error {
33
+ constructor(hash, receipt) {
34
+ super('Transaction reverted on-chain.');
35
+ this.name = 'ContractRevertedError';
36
+ this.hash = hash;
37
+ this.receipt = receipt;
38
+ }
39
+ }
40
+ /**
41
+ * Await a transaction receipt and fire the post-hash lifecycle hooks.
42
+ * Throws `ContractRevertedError` on revert. Other errors during the
43
+ * receipt-await are re-thrown unchanged after `onFailed` fires.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const hash = await sendTransactionWithHooks({ wallet, request, hooks })
48
+ * const receipt = await awaitReceiptWithHooks({ publicClient, hash, hooks })
49
+ * // Both onMined / onFailed have fired by the time we get here.
50
+ * ```
51
+ */
52
+ export async function awaitReceiptWithHooks(options) {
53
+ const { publicClient, hash, hooks } = options;
54
+ let receipt;
55
+ try {
56
+ receipt = await publicClient.waitForTransactionReceipt({ hash });
57
+ }
58
+ catch (err) {
59
+ const failure = err instanceof Error ? err : new Error(String(err));
60
+ hooks?.onFailed?.(failure);
61
+ hooks?.onPhase?.({ phase: 'failed', error: failure, hash });
62
+ throw failure;
63
+ }
64
+ if (receipt.status === 'reverted') {
65
+ const revert = new ContractRevertedError(hash, receipt);
66
+ hooks?.onFailed?.(revert);
67
+ hooks?.onPhase?.({ phase: 'failed', error: revert, hash, receipt });
68
+ throw revert;
69
+ }
70
+ hooks?.onConfirmed?.(receipt);
71
+ hooks?.onPhase?.({ phase: 'confirmed', hash, receipt });
72
+ return receipt;
73
+ }
74
+ //# sourceMappingURL=receipt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipt.js","sourceRoot":"","sources":["../src/receipt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH;;;;;;;;GAQG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAM9C,YAAY,IAAS,EAAE,OAA2B;QAChD,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACvC,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAA;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;CACF;AAoBD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAqC;IAErC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IAE7C,IAAI,OAA2B,CAAA;IAC/B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,YAAY,CAAC,yBAAyB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;IAClE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QACnE,KAAK,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAA;QAC1B,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,MAAM,OAAO,CAAA;IACf,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACvD,KAAK,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAA;QACzB,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;QACnE,MAAM,MAAM,CAAA;IACd,CAAC;IAED,KAAK,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,CAAA;IAC7B,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IACvD,OAAO,OAAO,CAAA;AAChB,CAAC"}
package/dist/send.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @fileoverview The single SDK helper for sending a transaction with
3
+ * lifecycle hooks fired at the real boundaries.
4
+ *
5
+ * This is the runtime piece of the lifecycle contract. SDK authors call
6
+ * this from inside any write method that opens a wallet popup; it
7
+ * guarantees:
8
+ * - `onAwaitingSignature` fires exactly once, immediately before
9
+ * `wallet.sendTransaction(...)`.
10
+ * - `onTransactionHash` (per-call) and the global `onTransactionHash`
11
+ * channel fire exactly once each, after `sendTransaction` resolves
12
+ * and BEFORE the SDK awaits any receipt — so callers can flip their
13
+ * UI from `awaiting-signature` to `pending` the moment a hash exists
14
+ * instead of stalling for the full inclusion window.
15
+ * - Wallet rejections (EIP-1193 `code === 4001`, viem's
16
+ * `UserRejectedRequestError`, or matching message text — see
17
+ * `@valve-tech/viem-errors` for the detection signals) are converted
18
+ * to a `WalletRejectedError` so consumers can `instanceof`-check
19
+ * them. Non-rejection errors are re-thrown unchanged so the SDK
20
+ * can map them to its own typed error vocabulary.
21
+ *
22
+ * Without this helper, every SDK that wants the contract has to
23
+ * re-implement: the error-mapping `try/catch` block (with the
24
+ * three-signal rejection check), the constructor-vs-per-call hook
25
+ * fan-out, and the precise ordering relative to `sendTransaction`.
26
+ */
27
+ import type { Hex } from 'viem';
28
+ import type { WalletAdapter, WalletSendTransactionRequest } from './wallet.js';
29
+ import type { WriteHookParams } from './hooks.js';
30
+ /**
31
+ * Thrown by `sendTransactionWithHooks` when the wallet rejection is
32
+ * detected at any level of the cause chain. The original error is
33
+ * preserved as `cause` so consumers can still inspect it (locale
34
+ * details, exact wallet phrasing, etc.) when they map this to their
35
+ * own typed error vocabulary.
36
+ */
37
+ export declare class WalletRejectedError extends Error {
38
+ /** The original rejection thrown by the wallet adapter. */
39
+ readonly cause: Error;
40
+ constructor(cause: Error);
41
+ }
42
+ /**
43
+ * Options accepted by `sendTransactionWithHooks`.
44
+ */
45
+ export interface SendTransactionWithHooksOptions {
46
+ /** The wallet adapter that will sign + broadcast the request. */
47
+ wallet: WalletAdapter;
48
+ /** The fully-formed send request (calldata, gas inputs, chainId). */
49
+ request: WalletSendTransactionRequest;
50
+ /** Per-call lifecycle hooks. Both fields are optional. */
51
+ hooks?: WriteHookParams;
52
+ /**
53
+ * Optional global / constructor-level `onTransactionHash` channel.
54
+ * Fires alongside `hooks.onTransactionHash` on the same line —
55
+ * complementary, not alternatives. Use this for analytics or
56
+ * debug-logging that should observe every write regardless of which
57
+ * caller fired it.
58
+ */
59
+ onTransactionHash?: (hash: Hex) => void;
60
+ }
61
+ /**
62
+ * Submit a transaction through the wallet adapter, firing lifecycle
63
+ * hooks at the real boundaries and converting wallet rejections to a
64
+ * typed `WalletRejectedError`.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * try {
69
+ * const hash = await sendTransactionWithHooks({
70
+ * wallet: this.wallet,
71
+ * request: { ...prepared, ...gasInputs },
72
+ * hooks: params, // user-supplied per-call hooks
73
+ * onTransactionHash: this.onHash, // constructor-level / analytics
74
+ * })
75
+ * const receipt = await this.publicClient.waitForTransactionReceipt({ hash })
76
+ * return { hash, receipt }
77
+ * } catch (err) {
78
+ * if (err instanceof WalletRejectedError) {
79
+ * throw new MySdkError('WALLET_REJECTED', err.message, err.cause)
80
+ * }
81
+ * throw new MySdkError('CONTRACT_ERROR', (err as Error).message, err as Error)
82
+ * }
83
+ * ```
84
+ */
85
+ export declare function sendTransactionWithHooks(options: SendTransactionWithHooksOptions): Promise<Hex>;
86
+ //# sourceMappingURL=send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../src/send.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;GAMG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;gBAET,KAAK,EAAE,KAAK;CAKzB;AAED;;GAEG;AACH,MAAM,WAAW,+BAA+B;IAC9C,iEAAiE;IACjE,MAAM,EAAE,aAAa,CAAA;IACrB,qEAAqE;IACrE,OAAO,EAAE,4BAA4B,CAAA;IACrC,0DAA0D;IAC1D,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAA;CACxC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,GAAG,CAAC,CAuBd"}
package/dist/send.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @fileoverview The single SDK helper for sending a transaction with
3
+ * lifecycle hooks fired at the real boundaries.
4
+ *
5
+ * This is the runtime piece of the lifecycle contract. SDK authors call
6
+ * this from inside any write method that opens a wallet popup; it
7
+ * guarantees:
8
+ * - `onAwaitingSignature` fires exactly once, immediately before
9
+ * `wallet.sendTransaction(...)`.
10
+ * - `onTransactionHash` (per-call) and the global `onTransactionHash`
11
+ * channel fire exactly once each, after `sendTransaction` resolves
12
+ * and BEFORE the SDK awaits any receipt — so callers can flip their
13
+ * UI from `awaiting-signature` to `pending` the moment a hash exists
14
+ * instead of stalling for the full inclusion window.
15
+ * - Wallet rejections (EIP-1193 `code === 4001`, viem's
16
+ * `UserRejectedRequestError`, or matching message text — see
17
+ * `@valve-tech/viem-errors` for the detection signals) are converted
18
+ * to a `WalletRejectedError` so consumers can `instanceof`-check
19
+ * them. Non-rejection errors are re-thrown unchanged so the SDK
20
+ * can map them to its own typed error vocabulary.
21
+ *
22
+ * Without this helper, every SDK that wants the contract has to
23
+ * re-implement: the error-mapping `try/catch` block (with the
24
+ * three-signal rejection check), the constructor-vs-per-call hook
25
+ * fan-out, and the precise ordering relative to `sendTransaction`.
26
+ */
27
+ import { isUserRejectionError } from '@valve-tech/viem-errors';
28
+ /**
29
+ * Thrown by `sendTransactionWithHooks` when the wallet rejection is
30
+ * detected at any level of the cause chain. The original error is
31
+ * preserved as `cause` so consumers can still inspect it (locale
32
+ * details, exact wallet phrasing, etc.) when they map this to their
33
+ * own typed error vocabulary.
34
+ */
35
+ export class WalletRejectedError extends Error {
36
+ constructor(cause) {
37
+ super('Transaction was rejected in wallet.');
38
+ this.name = 'WalletRejectedError';
39
+ this.cause = cause;
40
+ }
41
+ }
42
+ /**
43
+ * Submit a transaction through the wallet adapter, firing lifecycle
44
+ * hooks at the real boundaries and converting wallet rejections to a
45
+ * typed `WalletRejectedError`.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * try {
50
+ * const hash = await sendTransactionWithHooks({
51
+ * wallet: this.wallet,
52
+ * request: { ...prepared, ...gasInputs },
53
+ * hooks: params, // user-supplied per-call hooks
54
+ * onTransactionHash: this.onHash, // constructor-level / analytics
55
+ * })
56
+ * const receipt = await this.publicClient.waitForTransactionReceipt({ hash })
57
+ * return { hash, receipt }
58
+ * } catch (err) {
59
+ * if (err instanceof WalletRejectedError) {
60
+ * throw new MySdkError('WALLET_REJECTED', err.message, err.cause)
61
+ * }
62
+ * throw new MySdkError('CONTRACT_ERROR', (err as Error).message, err as Error)
63
+ * }
64
+ * ```
65
+ */
66
+ export async function sendTransactionWithHooks(options) {
67
+ const { wallet, request, hooks, onTransactionHash } = options;
68
+ let hash;
69
+ try {
70
+ hooks?.onAwaitingSignature?.();
71
+ hooks?.onPhase?.({ phase: 'awaiting-signature' });
72
+ hash = await wallet.sendTransaction(request);
73
+ }
74
+ catch (err) {
75
+ const failure = isUserRejectionError(err)
76
+ ? new WalletRejectedError(err instanceof Error ? err : new Error(String(err)))
77
+ : err instanceof Error
78
+ ? err
79
+ : new Error(String(err));
80
+ hooks?.onFailed?.(failure);
81
+ hooks?.onPhase?.({ phase: 'failed', error: failure });
82
+ throw failure;
83
+ }
84
+ onTransactionHash?.(hash);
85
+ hooks?.onTransactionHash?.(hash);
86
+ hooks?.onPhase?.({ phase: 'pending', hash });
87
+ return hash;
88
+ }
89
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../src/send.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAI9D;;;;;;GAMG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAI5C,YAAY,KAAY;QACtB,KAAK,CAAC,qCAAqC,CAAC,CAAA;QAC5C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;CACF;AAsBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAwC;IAExC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAA;IAE7D,IAAI,IAAS,CAAA;IACb,IAAI,CAAC;QACH,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAAA;QAC9B,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAA;QACjD,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC;YACvC,CAAC,CAAC,IAAI,mBAAmB,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9E,CAAC,CAAC,GAAG,YAAY,KAAK;gBACpB,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5B,KAAK,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAA;QAC1B,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QACrD,MAAM,OAAO,CAAA;IACf,CAAC;IAED,iBAAiB,EAAE,CAAC,IAAI,CAAC,CAAA;IACzB,KAAK,EAAE,iBAAiB,EAAE,CAAC,IAAI,CAAC,CAAA;IAChC,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5C,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @fileoverview Lifecycle vocabulary for tracked transactions.
3
+ *
4
+ * Defines the shared status / flow constants and the `TrackedTx` shape
5
+ * so any SDK or UI can speak the same vocabulary about a transaction
6
+ * in flight. This is the **opinion** layer that an in-flight UI sits on
7
+ * top of `@valve-tech/tx-tracker`'s neutral observations.
8
+ *
9
+ * Why constants instead of plain string types: consumers MUST reference
10
+ * via `TX_STATUS.preparing` / `TX_FLOW.signalIntent` rather than
11
+ * writing raw strings, so a rename here propagates through the type
12
+ * system instead of leaving stale literals at call sites.
13
+ */
14
+ import type { Hex } from 'viem';
15
+ /**
16
+ * Canonical lifecycle states for a tracked transaction.
17
+ *
18
+ * Lifecycle:
19
+ * preparing → awaiting-signature → pending → confirmed | failed | dropped
20
+ * ↘ replaced (on speed-up)
21
+ *
22
+ * The two pre-hash states (`preparing`, `awaitingSignature`) carry no
23
+ * `hash` and cannot be receipt-polled. They exist so the UI has
24
+ * something to show during gas-estimation + wallet-sign — without them
25
+ * the strip would stay blank until after the wallet returns.
26
+ *
27
+ * Naming: `confirmed` (not `mined`) matches the user-facing UI label
28
+ * and the `WritePhase` / `onConfirmed` hook surface. The receipt has
29
+ * arrived and the tx succeeded; consumers that need block-confirmation
30
+ * counts can layer that on top.
31
+ */
32
+ export declare const TX_STATUS: {
33
+ readonly preparing: "preparing";
34
+ readonly awaitingSignature: "awaiting-signature";
35
+ readonly pending: "pending";
36
+ readonly confirmed: "confirmed";
37
+ readonly failed: "failed";
38
+ readonly replaced: "replaced";
39
+ readonly dropped: "dropped";
40
+ };
41
+ export type TrackedTxStatus = typeof TX_STATUS[keyof typeof TX_STATUS];
42
+ /**
43
+ * The "what is the user doing" label for a tracked transaction. Distinct
44
+ * from `status` (which is the lifecycle phase): `flow` describes the
45
+ * action and stays constant for the whole lifecycle, while `status`
46
+ * advances over time.
47
+ *
48
+ * This is a generic / extensible enum — protocols add their own flow
49
+ * names by extending the type. The base set ships none of its own,
50
+ * intentionally: every protocol's flow vocabulary is its own.
51
+ */
52
+ export declare const TX_FLOW: {};
53
+ export type TxFlow = string;
54
+ /**
55
+ * Gas the wallet actually sent the transaction with. Captured at submit
56
+ * time so a speed-up replacement can compute the EIP-1559 ≥10% bump
57
+ * relative to what's actually in the mempool, not what the oracle
58
+ * estimated when the user clicked.
59
+ */
60
+ export interface TrackedTxGas {
61
+ maxFeePerGas: bigint;
62
+ maxPriorityFeePerGas: bigint;
63
+ }
64
+ /**
65
+ * One in-flight (or recently-terminal) transaction the UI is showing.
66
+ *
67
+ * `id` is the stable identifier — assigned at the registry's `beginTx`
68
+ * time, before any hash exists. `hash` is attached later (when
69
+ * `wallet.sendTransaction` resolves). For post-hash callers using a
70
+ * legacy `trackTx({ hash, ... })` API, registries SHOULD default `id`
71
+ * to `hash` so existing code keeps working unchanged.
72
+ *
73
+ * `submittedTier` is a string so this type doesn't need to depend on
74
+ * `@valve-tech/gas-oracle`'s `TierName`. Consumers using the oracle
75
+ * can refine it locally.
76
+ */
77
+ export interface TrackedTx {
78
+ id: string;
79
+ hash?: Hex;
80
+ chainId: number;
81
+ flow: TxFlow;
82
+ submittedAt: number;
83
+ confirmedAt?: number;
84
+ submittedGas?: TrackedTxGas;
85
+ submittedTier: string;
86
+ status: TrackedTxStatus;
87
+ replacedBy?: Hex;
88
+ replaces?: Hex;
89
+ /**
90
+ * Human-readable note for terminal-with-detail states. UIs SHOULD
91
+ * prefer `notes` over generic copy when rendering `failed` /
92
+ * `dropped` so a "cancelled in wallet" or decoded error name surfaces
93
+ * instead of a flat "transaction failed".
94
+ */
95
+ notes?: string;
96
+ }
97
+ /**
98
+ * How long a stale (older than this) tracked tx may be ignored by
99
+ * receipt-polling logic. Default mirrors the chosen UX in tx-flight
100
+ * surfaces: 10 minutes is long enough for a slow inclusion, short
101
+ * enough to garbage-collect zombie entries.
102
+ */
103
+ export declare const STALE_TX_AGE_MS: number;
104
+ /**
105
+ * Symmetric linger windows for terminal-with-detail states. These let
106
+ * confirmed/failed states stay on screen long enough for the user to
107
+ * read the outcome without permanently occupying the UI surface.
108
+ */
109
+ export declare const CONFIRMED_DISPLAY_MS = 10000;
110
+ export declare const FAILED_DISPLAY_MS = 10000;
111
+ /** Fired once when a tracked tx becomes `mined`. */
112
+ export type TxConfirmedCallback = (tx: TrackedTx) => void | Promise<void>;
113
+ //# sourceMappingURL=tx-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tx-status.d.ts","sourceRoot":"","sources":["../src/tx-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAI/B;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,SAAS;;;;;;;;CAQZ,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,OAAO,SAAS,CAAC,MAAM,OAAO,SAAS,CAAC,CAAA;AAItE;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,IAAc,CAAA;AAElC,MAAM,MAAM,MAAM,GAAG,MAAM,CAAA;AAI3B;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,oBAAoB,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,GAAG,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,eAAe,CAAA;IACvB,UAAU,CAAC,EAAE,GAAG,CAAA;IAChB,QAAQ,CAAC,EAAE,GAAG,CAAA;IACd;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAID;;;;;GAKG;AACH,eAAO,MAAM,eAAe,QAAiB,CAAA;AAE7C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAS,CAAA;AAC1C,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAIvC,oDAAoD;AACpD,MAAM,MAAM,mBAAmB,GAAG,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview Lifecycle vocabulary for tracked transactions.
3
+ *
4
+ * Defines the shared status / flow constants and the `TrackedTx` shape
5
+ * so any SDK or UI can speak the same vocabulary about a transaction
6
+ * in flight. This is the **opinion** layer that an in-flight UI sits on
7
+ * top of `@valve-tech/tx-tracker`'s neutral observations.
8
+ *
9
+ * Why constants instead of plain string types: consumers MUST reference
10
+ * via `TX_STATUS.preparing` / `TX_FLOW.signalIntent` rather than
11
+ * writing raw strings, so a rename here propagates through the type
12
+ * system instead of leaving stale literals at call sites.
13
+ */
14
+ // ─── Status ────────────────────────────────────────────────────────────────
15
+ /**
16
+ * Canonical lifecycle states for a tracked transaction.
17
+ *
18
+ * Lifecycle:
19
+ * preparing → awaiting-signature → pending → confirmed | failed | dropped
20
+ * ↘ replaced (on speed-up)
21
+ *
22
+ * The two pre-hash states (`preparing`, `awaitingSignature`) carry no
23
+ * `hash` and cannot be receipt-polled. They exist so the UI has
24
+ * something to show during gas-estimation + wallet-sign — without them
25
+ * the strip would stay blank until after the wallet returns.
26
+ *
27
+ * Naming: `confirmed` (not `mined`) matches the user-facing UI label
28
+ * and the `WritePhase` / `onConfirmed` hook surface. The receipt has
29
+ * arrived and the tx succeeded; consumers that need block-confirmation
30
+ * counts can layer that on top.
31
+ */
32
+ export const TX_STATUS = {
33
+ preparing: 'preparing',
34
+ awaitingSignature: 'awaiting-signature',
35
+ pending: 'pending',
36
+ confirmed: 'confirmed',
37
+ failed: 'failed',
38
+ replaced: 'replaced',
39
+ dropped: 'dropped',
40
+ };
41
+ // ─── Flow ──────────────────────────────────────────────────────────────────
42
+ /**
43
+ * The "what is the user doing" label for a tracked transaction. Distinct
44
+ * from `status` (which is the lifecycle phase): `flow` describes the
45
+ * action and stays constant for the whole lifecycle, while `status`
46
+ * advances over time.
47
+ *
48
+ * This is a generic / extensible enum — protocols add their own flow
49
+ * names by extending the type. The base set ships none of its own,
50
+ * intentionally: every protocol's flow vocabulary is its own.
51
+ */
52
+ export const TX_FLOW = {};
53
+ // ─── Display windows ───────────────────────────────────────────────────────
54
+ /**
55
+ * How long a stale (older than this) tracked tx may be ignored by
56
+ * receipt-polling logic. Default mirrors the chosen UX in tx-flight
57
+ * surfaces: 10 minutes is long enough for a slow inclusion, short
58
+ * enough to garbage-collect zombie entries.
59
+ */
60
+ export const STALE_TX_AGE_MS = 10 * 60 * 1000; // 10 minutes
61
+ /**
62
+ * Symmetric linger windows for terminal-with-detail states. These let
63
+ * confirmed/failed states stay on screen long enough for the user to
64
+ * read the outcome without permanently occupying the UI surface.
65
+ */
66
+ export const CONFIRMED_DISPLAY_MS = 10000;
67
+ export const FAILED_DISPLAY_MS = 10000;
68
+ //# sourceMappingURL=tx-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tx-status.js","sourceRoot":"","sources":["../src/tx-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,8EAA8E;AAE9E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,SAAS,EAAU,WAAW;IAC9B,iBAAiB,EAAE,oBAAoB;IACvC,OAAO,EAAY,SAAS;IAC5B,SAAS,EAAU,WAAW;IAC9B,MAAM,EAAa,QAAQ;IAC3B,QAAQ,EAAW,UAAU;IAC7B,OAAO,EAAY,SAAS;CACpB,CAAA;AAIV,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,EAAW,CAAA;AAmDlC,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,aAAa;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAM,CAAA;AAC1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAM,CAAA"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @fileoverview The framework-agnostic wallet contract.
3
+ *
4
+ * Decouples SDKs from any specific wallet library. A `WalletAdapter` is
5
+ * the only seam an SDK needs to sign and send a transaction; the dapp
6
+ * decides whether that backend is wagmi, ethers, viem direct, a smart
7
+ * account, a multisig, or a relayer.
8
+ */
9
+ import type { Hex } from 'viem';
10
+ /**
11
+ * The minimal request shape an SDK passes to a wallet for sign + send.
12
+ *
13
+ * Fields:
14
+ * - `to` — destination address.
15
+ * - `data` — encoded calldata (`0x...`).
16
+ * - `value` — native-token amount in wei. Defaults to 0 if omitted.
17
+ * - `chainId` — chain to sign for. Wallets MUST validate this against
18
+ * the connected chain and throw rather than silently
19
+ * sign for the wrong network.
20
+ * - `maxFeePerGas` / `maxPriorityFeePerGas` — EIP-1559 gas pricing in
21
+ * wei. Optional so a wallet can defer to its own gas
22
+ * logic; if both are present, the wallet should honour
23
+ * them.
24
+ */
25
+ export interface WalletSendTransactionRequest {
26
+ to: Hex;
27
+ data: Hex;
28
+ value?: bigint;
29
+ chainId: number;
30
+ maxFeePerGas?: bigint;
31
+ maxPriorityFeePerGas?: bigint;
32
+ }
33
+ /**
34
+ * Optional read-from-contract escape hatch. Wallets that proxy reads
35
+ * (e.g. account abstraction with custom RPC) implement this; the SDK
36
+ * falls back to a public RPC when omitted.
37
+ */
38
+ export interface WalletReadContractRequest {
39
+ address: Hex;
40
+ abi: readonly unknown[];
41
+ functionName: string;
42
+ args?: readonly unknown[];
43
+ chainId?: number;
44
+ }
45
+ /**
46
+ * Framework-agnostic wallet interface. Works with wagmi, viem direct,
47
+ * ethers, smart accounts, and relayers — anything that can sign and
48
+ * send a transaction.
49
+ *
50
+ * SDKs should accept a `WalletAdapter` rather than tying themselves to
51
+ * a specific wallet library, so the same SDK works across the whole
52
+ * downstream landscape without per-wallet code paths.
53
+ */
54
+ export interface WalletAdapter {
55
+ /** Connected address, or undefined if disconnected. */
56
+ address?: Hex;
57
+ /** Sign and send a transaction. Returns the on-chain tx hash. */
58
+ sendTransaction(request: WalletSendTransactionRequest): Promise<Hex>;
59
+ /**
60
+ * Optional contract read. SDKs SHOULD prefer this when present (lets a
61
+ * smart-account / paymaster-aware wallet route reads through its own
62
+ * pipeline) and fall back to a public RPC client otherwise.
63
+ */
64
+ readContract?(request: WalletReadContractRequest): Promise<unknown>;
65
+ }
66
+ //# sourceMappingURL=wallet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAE/B;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,GAAG,CAAA;IACP,IAAI,EAAE,GAAG,CAAA;IACT,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,GAAG,CAAA;IACZ,GAAG,EAAE,SAAS,OAAO,EAAE,CAAA;IACvB,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,OAAO,CAAC,EAAE,GAAG,CAAA;IACb,iEAAiE;IACjE,eAAe,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IACpE;;;;OAIG;IACH,YAAY,CAAC,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACpE"}
package/dist/wallet.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @fileoverview The framework-agnostic wallet contract.
3
+ *
4
+ * Decouples SDKs from any specific wallet library. A `WalletAdapter` is
5
+ * the only seam an SDK needs to sign and send a transaction; the dapp
6
+ * decides whether that backend is wagmi, ethers, viem direct, a smart
7
+ * account, a multisig, or a relayer.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@valve-tech/wallet-adapter",
3
+ "version": "0.3.1",
4
+ "description": "Framework-agnostic vocabulary for EVM dapp wallet integration: WalletAdapter interface (sign + send), WriteHookParams lifecycle hooks (onAwaitingSignature, per-call onTransactionHash), and TX_STATUS / TX_FLOW / TrackedTx for tx-state UI. Pure types, no runtime dependencies. Lets SDKs and dapps share one contract instead of each redefining it. Part of the valve-tech/evm-toolkit synchronized release line.",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/valve-tech/evm-toolkit/tree/main/packages/wallet-adapter#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/valve-tech/evm-toolkit.git",
10
+ "directory": "packages/wallet-adapter"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/valve-tech/evm-toolkit/issues"
14
+ },
15
+ "keywords": [
16
+ "ethereum",
17
+ "evm",
18
+ "viem",
19
+ "wagmi",
20
+ "wallet",
21
+ "wallet-adapter",
22
+ "tx-status",
23
+ "lifecycle-hooks"
24
+ ],
25
+ "type": "module",
26
+ "main": "dist/index.js",
27
+ "types": "dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "CHANGELOG.md",
38
+ "LICENSE"
39
+ ],
40
+ "scripts": {
41
+ "build": "tsc -p .",
42
+ "typecheck": "tsc -p . --noEmit",
43
+ "lint": "eslint src",
44
+ "test": "vitest run",
45
+ "test:coverage": "vitest run --coverage",
46
+ "prepare": "yarn build"
47
+ },
48
+ "dependencies": {
49
+ "@valve-tech/viem-errors": "workspace:^"
50
+ },
51
+ "peerDependencies": {
52
+ "viem": "^2.0.0"
53
+ }
54
+ }