@spectratools/tx-shared 0.4.3 → 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.
- package/README.md +128 -32
- package/dist/chunk-HFRJBEDT.js +1144 -0
- package/dist/errors.d.ts +1 -1
- package/dist/execute-tx-DO8p_9dP.d.ts +160 -0
- package/dist/execute-tx.d.ts +4 -63
- package/dist/execute-tx.js +1 -1
- package/dist/index.d.ts +36 -60
- package/dist/index.js +24 -596
- package/package.json +1 -1
- package/dist/chunk-4XI6TBKX.js +0 -130
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
|
|
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,13 +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
|
-
|
|
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)
|
|
60
83
|
|
|
61
84
|
## `resolveSigner()` usage
|
|
62
85
|
|
|
@@ -70,7 +93,7 @@ const signer = await resolveSigner({
|
|
|
70
93
|
});
|
|
71
94
|
|
|
72
95
|
console.log(signer.provider); // 'private-key' | 'keystore' | 'privy'
|
|
73
|
-
console.log(signer.address);
|
|
96
|
+
console.log(signer.address); // 0x...
|
|
74
97
|
```
|
|
75
98
|
|
|
76
99
|
### From shared CLI flags + env
|
|
@@ -84,8 +107,8 @@ import {
|
|
|
84
107
|
} from '@spectratools/tx-shared';
|
|
85
108
|
|
|
86
109
|
const flags = signerFlagSchema.parse({
|
|
87
|
-
|
|
88
|
-
privy:
|
|
110
|
+
privy: true,
|
|
111
|
+
'privy-api-url': process.env.PRIVY_API_URL,
|
|
89
112
|
});
|
|
90
113
|
|
|
91
114
|
const env = signerEnvSchema.parse(process.env);
|
|
@@ -98,46 +121,108 @@ const signer = await resolveSigner(toSignerOptions(flags, env));
|
|
|
98
121
|
|
|
99
122
|
1. estimate gas (`estimateContractGas`)
|
|
100
123
|
2. simulate (`simulateContract`)
|
|
101
|
-
3.
|
|
102
|
-
4.
|
|
103
|
-
5.
|
|
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
|
|
104
128
|
|
|
105
|
-
###
|
|
129
|
+
### Privy transaction flow example (dry-run + live)
|
|
106
130
|
|
|
107
131
|
```ts
|
|
108
|
-
import {
|
|
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']);
|
|
109
160
|
|
|
110
|
-
const
|
|
161
|
+
const dryRun = await executeTx({
|
|
111
162
|
publicClient,
|
|
112
163
|
walletClient,
|
|
113
164
|
account: signer.account,
|
|
114
|
-
address,
|
|
115
|
-
abi,
|
|
165
|
+
address: '0x1111111111111111111111111111111111111111',
|
|
166
|
+
abi: registryAbi,
|
|
116
167
|
functionName: 'register',
|
|
117
|
-
value:
|
|
168
|
+
value: 1000000000000000n,
|
|
169
|
+
dryRun: true,
|
|
118
170
|
});
|
|
119
171
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
172
|
+
if (dryRun.status === 'dry-run') {
|
|
173
|
+
console.log(dryRun.estimatedGas.toString());
|
|
174
|
+
console.log(dryRun.privyPolicy?.status); // 'allowed' | 'blocked'
|
|
175
|
+
}
|
|
124
176
|
|
|
125
|
-
|
|
126
|
-
const result = await executeTx({
|
|
177
|
+
const live = await executeTx({
|
|
127
178
|
publicClient,
|
|
128
179
|
walletClient,
|
|
129
180
|
account: signer.account,
|
|
130
|
-
address,
|
|
131
|
-
abi,
|
|
181
|
+
address: '0x1111111111111111111111111111111111111111',
|
|
182
|
+
abi: registryAbi,
|
|
132
183
|
functionName: 'register',
|
|
133
|
-
value:
|
|
134
|
-
dryRun: true,
|
|
184
|
+
value: 1000000000000000n,
|
|
135
185
|
});
|
|
136
186
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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);
|
|
141
226
|
```
|
|
142
227
|
|
|
143
228
|
## Structured errors
|
|
@@ -151,6 +236,8 @@ if (result.status === 'dry-run') {
|
|
|
151
236
|
- `SIGNER_NOT_CONFIGURED`
|
|
152
237
|
- `KEYSTORE_DECRYPT_FAILED`
|
|
153
238
|
- `PRIVY_AUTH_FAILED`
|
|
239
|
+
- `PRIVY_TRANSPORT_FAILED`
|
|
240
|
+
- `PRIVY_POLICY_BLOCKED`
|
|
154
241
|
|
|
155
242
|
```ts
|
|
156
243
|
import { TxError } from '@spectratools/tx-shared';
|
|
@@ -167,6 +254,8 @@ try {
|
|
|
167
254
|
case 'SIGNER_NOT_CONFIGURED':
|
|
168
255
|
case 'KEYSTORE_DECRYPT_FAILED':
|
|
169
256
|
case 'PRIVY_AUTH_FAILED':
|
|
257
|
+
case 'PRIVY_TRANSPORT_FAILED':
|
|
258
|
+
case 'PRIVY_POLICY_BLOCKED':
|
|
170
259
|
throw error;
|
|
171
260
|
}
|
|
172
261
|
}
|
|
@@ -184,8 +273,15 @@ try {
|
|
|
184
273
|
- verify file path and password
|
|
185
274
|
- ensure keystore is valid V3 JSON
|
|
186
275
|
- **`PRIVY_AUTH_FAILED`**
|
|
187
|
-
- verify
|
|
188
|
-
-
|
|
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
|
|
189
285
|
- **`GAS_ESTIMATION_FAILED` / `TX_REVERTED`**
|
|
190
286
|
- validate function args and `value`
|
|
191
287
|
- run with `dryRun: true` first
|