@spectratools/tx-shared 0.5.1 → 0.5.2

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.
Files changed (2) hide show
  1. package/README.md +128 -36
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -16,13 +16,13 @@ This package is designed for consuming CLIs (for example `@spectratools/assembly
16
16
  pnpm add @spectratools/tx-shared
17
17
  ```
18
18
 
19
- ## Signer Providers
19
+ ## Signer providers
20
20
 
21
21
  `resolveSigner()` uses deterministic precedence:
22
22
 
23
23
  1. `privateKey`
24
24
  2. `keystorePath` (+ `keystorePassword`)
25
- 3. `privy` / `PRIVY_*`
25
+ 3. Privy (`privy` flag and/or `PRIVY_*` env)
26
26
 
27
27
  If no provider is configured, it throws `TxError` with code `SIGNER_NOT_CONFIGURED`.
28
28
 
@@ -50,17 +50,36 @@ export KEYSTORE_PASSWORD="..."
50
50
 
51
51
  #### 3) Privy
52
52
 
53
+ Required env:
54
+
53
55
  ```bash
54
56
  export PRIVY_APP_ID="..."
55
57
  export PRIVY_WALLET_ID="..."
56
- export PRIVY_AUTHORIZATION_KEY="..."
58
+ export PRIVY_AUTHORIZATION_KEY="wallet-auth:<base64-pkcs8-p256-private-key>"
59
+ ```
60
+
61
+ Optional env:
62
+
63
+ ```bash
64
+ export PRIVY_API_URL="https://api.sandbox.privy.io"
65
+ ```
66
+
67
+ Optional CLI flags (from `signerFlagSchema`):
68
+
69
+ ```bash
70
+ --privy
71
+ --privy-api-url "https://api.sandbox.privy.io"
57
72
  ```
58
73
 
59
- > Privy signer resolution performs wallet address lookup and returns a Privy-backed account adapter with:
60
- > - `sendTransaction` → `eth_sendTransaction`
61
- > - `signMessage` `personal_sign`
62
- > - `signTypedData` `eth_signTypedData_v4`
63
- > - `signTransaction` `eth_signTransaction` (returns serialized tx hex; broadcast separately via `sendRawTransaction`)
74
+ Notes:
75
+
76
+ - `--privy` is optional when `PRIVY_APP_ID` + `PRIVY_WALLET_ID` + `PRIVY_AUTHORIZATION_KEY` are present; `resolveSigner()` auto-detects Privy config.
77
+ - `--privy-api-url` / `PRIVY_API_URL` override the default `https://api.privy.io`.
78
+ - Privy account methods are mapped as:
79
+ - `sendTransaction` → `eth_sendTransaction`
80
+ - `signMessage` → `personal_sign`
81
+ - `signTypedData` → `eth_signTypedData_v4`
82
+ - `signTransaction` → `eth_signTransaction` (returns serialized tx hex; broadcast separately if needed)
64
83
 
65
84
  ## `resolveSigner()` usage
66
85
 
@@ -74,7 +93,7 @@ const signer = await resolveSigner({
74
93
  });
75
94
 
76
95
  console.log(signer.provider); // 'private-key' | 'keystore' | 'privy'
77
- console.log(signer.address); // 0x...
96
+ console.log(signer.address); // 0x...
78
97
  ```
79
98
 
80
99
  ### From shared CLI flags + env
@@ -88,8 +107,8 @@ import {
88
107
  } from '@spectratools/tx-shared';
89
108
 
90
109
  const flags = signerFlagSchema.parse({
91
- 'private-key': process.env.PRIVATE_KEY,
92
- privy: false,
110
+ privy: true,
111
+ 'privy-api-url': process.env.PRIVY_API_URL,
93
112
  });
94
113
 
95
114
  const env = signerEnvSchema.parse(process.env);
@@ -102,46 +121,108 @@ const signer = await resolveSigner(toSignerOptions(flags, env));
102
121
 
103
122
  1. estimate gas (`estimateContractGas`)
104
123
  2. simulate (`simulateContract`)
105
- 3. submit (`writeContract`) unless `dryRun: true`
106
- 4. wait for receipt (`waitForTransactionReceipt`)
107
- 5. normalize result into a shared output shape
124
+ 3. preflight Privy policies (when signer is Privy-backed)
125
+ 4. submit (`writeContract`) unless `dryRun: true`
126
+ 5. wait for receipt (`waitForTransactionReceipt`)
127
+ 6. normalize result into a shared output shape
108
128
 
109
- ### Live transaction example
129
+ ### Privy transaction flow example (dry-run + live)
110
130
 
111
131
  ```ts
112
- import { executeTx } from '@spectratools/tx-shared';
132
+ import { http, createPublicClient, createWalletClient, parseAbi } from 'viem';
133
+ import {
134
+ abstractMainnet,
135
+ executeTx,
136
+ resolveSigner,
137
+ signerEnvSchema,
138
+ signerFlagSchema,
139
+ toSignerOptions,
140
+ } from '@spectratools/tx-shared';
141
+
142
+ const flags = signerFlagSchema.parse({
143
+ privy: true,
144
+ 'privy-api-url': process.env.PRIVY_API_URL,
145
+ });
146
+ const env = signerEnvSchema.parse(process.env);
147
+ const signer = await resolveSigner(toSignerOptions(flags, env));
148
+
149
+ const publicClient = createPublicClient({
150
+ chain: abstractMainnet,
151
+ transport: http(process.env.ABSTRACT_RPC_URL),
152
+ });
153
+ const walletClient = createWalletClient({
154
+ account: signer.account,
155
+ chain: abstractMainnet,
156
+ transport: http(process.env.ABSTRACT_RPC_URL),
157
+ });
158
+
159
+ const registryAbi = parseAbi(['function register() payable']);
113
160
 
114
- const result = await executeTx({
161
+ const dryRun = await executeTx({
115
162
  publicClient,
116
163
  walletClient,
117
164
  account: signer.account,
118
- address,
119
- abi,
165
+ address: '0x1111111111111111111111111111111111111111',
166
+ abi: registryAbi,
120
167
  functionName: 'register',
121
- value: registrationFee,
168
+ value: 1000000000000000n,
169
+ dryRun: true,
122
170
  });
123
171
 
124
- console.log(result.hash, result.status, result.gasUsed.toString());
125
- ```
126
-
127
- ### Dry-run example
172
+ if (dryRun.status === 'dry-run') {
173
+ console.log(dryRun.estimatedGas.toString());
174
+ console.log(dryRun.privyPolicy?.status); // 'allowed' | 'blocked'
175
+ }
128
176
 
129
- ```ts
130
- const result = await executeTx({
177
+ const live = await executeTx({
131
178
  publicClient,
132
179
  walletClient,
133
180
  account: signer.account,
134
- address,
135
- abi,
181
+ address: '0x1111111111111111111111111111111111111111',
182
+ abi: registryAbi,
136
183
  functionName: 'register',
137
- value: registrationFee,
138
- dryRun: true,
184
+ value: 1000000000000000n,
139
185
  });
140
186
 
141
- if (result.status === 'dry-run') {
142
- console.log('estimatedGas', result.estimatedGas.toString());
143
- console.log('simulationResult', result.simulationResult);
144
- }
187
+ console.log(live.hash, live.status);
188
+ ```
189
+
190
+ ### Privy signing flow example
191
+
192
+ ```ts
193
+ const signer = await resolveSigner({
194
+ privy: true,
195
+ privyAppId: process.env.PRIVY_APP_ID,
196
+ privyWalletId: process.env.PRIVY_WALLET_ID,
197
+ privyAuthorizationKey: process.env.PRIVY_AUTHORIZATION_KEY,
198
+ privyApiUrl: process.env.PRIVY_API_URL,
199
+ });
200
+
201
+ if (signer.provider !== 'privy') throw new Error('Expected Privy signer');
202
+
203
+ const messageSig = await signer.account.signMessage({ message: 'hello from tx-shared' });
204
+
205
+ const typedDataSig = await signer.account.signTypedData({
206
+ domain: { name: 'SpectraTools', version: '1', chainId: 2741 },
207
+ primaryType: 'Ping',
208
+ types: {
209
+ Ping: [{ name: 'message', type: 'string' }],
210
+ },
211
+ message: { message: 'privy typed data' },
212
+ });
213
+
214
+ const signedTxHex = await signer.account.signTransaction({
215
+ to: '0x1111111111111111111111111111111111111111',
216
+ chainId: 2741,
217
+ nonce: 1,
218
+ gas: 21000n,
219
+ maxFeePerGas: 1000000000n,
220
+ maxPriorityFeePerGas: 1000000000n,
221
+ value: 0n,
222
+ data: '0x',
223
+ });
224
+
225
+ console.log(messageSig, typedDataSig, signedTxHex);
145
226
  ```
146
227
 
147
228
  ## Structured errors
@@ -155,6 +236,8 @@ if (result.status === 'dry-run') {
155
236
  - `SIGNER_NOT_CONFIGURED`
156
237
  - `KEYSTORE_DECRYPT_FAILED`
157
238
  - `PRIVY_AUTH_FAILED`
239
+ - `PRIVY_TRANSPORT_FAILED`
240
+ - `PRIVY_POLICY_BLOCKED`
158
241
 
159
242
  ```ts
160
243
  import { TxError } from '@spectratools/tx-shared';
@@ -171,6 +254,8 @@ try {
171
254
  case 'SIGNER_NOT_CONFIGURED':
172
255
  case 'KEYSTORE_DECRYPT_FAILED':
173
256
  case 'PRIVY_AUTH_FAILED':
257
+ case 'PRIVY_TRANSPORT_FAILED':
258
+ case 'PRIVY_POLICY_BLOCKED':
174
259
  throw error;
175
260
  }
176
261
  }
@@ -188,8 +273,15 @@ try {
188
273
  - verify file path and password
189
274
  - ensure keystore is valid V3 JSON
190
275
  - **`PRIVY_AUTH_FAILED`**
191
- - verify all `PRIVY_*` variables are set
192
- - check signer/owner policy constraints for the Privy wallet
276
+ - verify required env: `PRIVY_APP_ID`, `PRIVY_WALLET_ID`, `PRIVY_AUTHORIZATION_KEY`
277
+ - validate `PRIVY_AUTHORIZATION_KEY` format: `wallet-auth:<base64-pkcs8-p256-private-key>`
278
+ - verify `PRIVY_API_URL` override points at a valid Privy API host
279
+ - **`PRIVY_TRANSPORT_FAILED`**
280
+ - check Privy API availability and credentials
281
+ - inspect upstream intent failure payloads for status + reason
282
+ - **`PRIVY_POLICY_BLOCKED`**
283
+ - review active wallet policy allowlists and native value caps
284
+ - use `dryRun: true` and inspect `result.privyPolicy` before broadcasting
193
285
  - **`GAS_ESTIMATION_FAILED` / `TX_REVERTED`**
194
286
  - validate function args and `value`
195
287
  - run with `dryRun: true` first
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectratools/tx-shared",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Shared transaction primitives, signer types, and chain config for spectra tools",
5
5
  "type": "module",
6
6
  "license": "MIT",