nodpay 0.2.31 → 0.2.33
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 +14 -5
- package/SKILL.md +9 -7
- package/package.json +1 -1
- package/scripts/propose.mjs +44 -1
package/README.md
CHANGED
|
@@ -16,12 +16,14 @@ This npm package (`nodpay`) is the **agent-facing CLI**. It is also published as
|
|
|
16
16
|
| **ClawHub** (`clawhub install nodpay`) | `SKILL.md` only | OpenClaw agents |
|
|
17
17
|
| **nodpay.ai/skill.md** | `SKILL.md` via CDN proxy | All agent frameworks |
|
|
18
18
|
|
|
19
|
-
The CLI provides
|
|
19
|
+
The CLI provides five commands:
|
|
20
20
|
|
|
21
21
|
```
|
|
22
22
|
nodpay keygen # Generate agent keypair (~/.nodpay/.env, chmod 600)
|
|
23
|
-
nodpay
|
|
23
|
+
nodpay nonce # Query next nonce (on-chain EntryPoint + pending proposals)
|
|
24
|
+
nodpay propose # Propose a transaction for human approval (--nonce required)
|
|
24
25
|
nodpay txs # List and verify transactions for a wallet
|
|
26
|
+
nodpay gasprice # Get current gas price + estimated cost per chain
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
## Quick Start
|
|
@@ -30,25 +32,32 @@ nodpay txs # List and verify transactions for a wallet
|
|
|
30
32
|
# 1. Generate key (public address only in stdout; key never exposed)
|
|
31
33
|
npx nodpay keygen
|
|
32
34
|
|
|
33
|
-
# 2.
|
|
35
|
+
# 2. Get next nonce (on-chain + pending)
|
|
36
|
+
npx nodpay nonce --safe 0xWALLET --chain base
|
|
37
|
+
|
|
38
|
+
# 3. Propose a payment
|
|
34
39
|
npx nodpay propose \
|
|
35
40
|
--chain base \
|
|
36
41
|
--safe 0xWALLET \
|
|
37
42
|
--to 0xRECIPIENT \
|
|
38
43
|
--value-eth 0.01 \
|
|
44
|
+
--nonce 0 \
|
|
39
45
|
--human-signer-passkey-x 0x... \
|
|
40
46
|
--human-signer-passkey-y 0x... \
|
|
41
47
|
--recovery-signer 0x...
|
|
42
48
|
|
|
43
|
-
#
|
|
49
|
+
# 4. Check transactions (with verification)
|
|
44
50
|
npx nodpay txs --safe 0xWALLET
|
|
51
|
+
|
|
52
|
+
# 5. Estimate gas cost for a sweep
|
|
53
|
+
npx nodpay gasprice --chain base
|
|
45
54
|
```
|
|
46
55
|
|
|
47
56
|
## Security
|
|
48
57
|
|
|
49
58
|
All config lives in `~/.nodpay/` — zero `process.env` references in code.
|
|
50
59
|
|
|
51
|
-
- **Hardened Key Isolation:** private key written
|
|
60
|
+
- **Hardened Key Isolation:** private key written to `~/.nodpay/.env` (chmod 600), read via file I/O at runtime. Not passed through CLI args, env vars, or stdout.
|
|
52
61
|
- **Zero Trust:** `txs` independently verifies every server response (decode calldata → recompute hash → recover signer → check owner set).
|
|
53
62
|
- **Threshold Security:** 2-of-3 multisig — agent cannot move funds unilaterally.
|
|
54
63
|
|
package/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ metadata:
|
|
|
9
9
|
"homepage": "https://nodpay.ai",
|
|
10
10
|
"install": [{ "id": "node", "kind": "node", "package": "nodpay", "label": "Install NodPay CLI (npm)", "author": "xhyumiracle", "source": "https://github.com/xhyumiracle/nodpay-cli" }]
|
|
11
11
|
},
|
|
12
|
-
"credentials": "Agent signing key stored in ~/.nodpay/.env (generated by npx nodpay keygen,
|
|
12
|
+
"credentials": "Agent signing key stored in ~/.nodpay/.env (chmod 600, generated by npx nodpay keygen). Read at runtime by CLI process; not passed via CLI args, env vars, or stdout.",
|
|
13
13
|
"persistence": ["~/.nodpay/.env (agent key, chmod 600)", "~/.nodpay/wallets/*.json (wallet info, public key material)"],
|
|
14
14
|
"network": ["nodpay.ai (op-store relay + wallet creation UI)", "Public RPC endpoints via --chain"]
|
|
15
15
|
}
|
|
@@ -30,8 +30,8 @@ You propose payments, your human approves with one tap. 2-of-3 multisig — you
|
|
|
30
30
|
| **Threshold Security** | **Elimination of single point of failure:** authority keys are distributed between the agent, human, and a recovery signer (2-of-3 multisig). Ensures non-custodial control — the agent cannot move funds unilaterally. |
|
|
31
31
|
| **Zero Trust** | **End-to-end verification:** no party is implicitly trusted. Server validates signatures; client and CLI independently verify server responses (decode calldata → recompute hash → recover signer → check owner set). The blockchain serves as the canonical source of truth. |
|
|
32
32
|
| **Disaster Recovery** | **Key redundancy & continuity:** uses a locally-stored 12-word mnemonic as recovery signer. Any two of the three signers can reconstruct authority to unlock the wallet, ensuring the user is never locked out by a single lost credential. |
|
|
33
|
-
| **Hardened Key Isolation** | `keygen` writes to `~/.nodpay/.env` (chmod 600). The CLI reads the key
|
|
34
|
-
| **Keyless & Non-Custodial Server** | **Stateless relayer:** the server stores no private keys and
|
|
33
|
+
| **Hardened Key Isolation** | `keygen` writes to `~/.nodpay/.env` (chmod 600). The CLI reads the key via file I/O at runtime — not passed through CLI arguments, environment variables, or stdout. Only the public address is returned to the caller. |
|
|
34
|
+
| **Keyless & Non-Custodial Server** | **Stateless relayer:** the server stores no private keys, no passkey credentials, and no session state. Identity verification uses CREATE2 address prediction + cryptographic signatures — zero trusted storage. Funds stay on-chain if the server goes offline. |
|
|
35
35
|
|
|
36
36
|
All wallet parameters (Safe address, passkey X/Y, recovery signer address) are public key material — safe to store, pass in URLs, and include in CLI flags.
|
|
37
37
|
|
|
@@ -181,16 +181,18 @@ Wallet address is the same across all chains. **Ask which chain if not specified
|
|
|
181
181
|
|
|
182
182
|
## Reconnect
|
|
183
183
|
|
|
184
|
-
Browser data cleared? Build a reconnect link from the wallet's stored parameters (all public — no secrets)
|
|
184
|
+
Browser data cleared? Build a reconnect link from the wallet's stored parameters (all public — no secrets).
|
|
185
|
+
|
|
186
|
+
**You MUST include `signerType`** — the client uses it to show the correct verification flow.
|
|
185
187
|
|
|
186
188
|
**Passkey:**
|
|
187
189
|
```
|
|
188
|
-
https://nodpay.ai/?agent=AGENT_SIGNER&safe=SAFE_ADDRESS&recovery=RECOVERY_SIGNER&x=PASSKEY_X&y=PASSKEY_Y
|
|
190
|
+
https://nodpay.ai/?agent=AGENT_SIGNER&safe=SAFE_ADDRESS&recovery=RECOVERY_SIGNER&signerType=passkey&x=PASSKEY_X&y=PASSKEY_Y
|
|
189
191
|
```
|
|
190
192
|
|
|
191
193
|
**EOA:**
|
|
192
194
|
```
|
|
193
|
-
https://nodpay.ai/?agent=AGENT_SIGNER&safe=SAFE_ADDRESS&recovery=RECOVERY_SIGNER&eoa=HUMAN_SIGNER_EOA
|
|
195
|
+
https://nodpay.ai/?agent=AGENT_SIGNER&safe=SAFE_ADDRESS&recovery=RECOVERY_SIGNER&signerType=eoa&eoa=HUMAN_SIGNER_EOA
|
|
194
196
|
```
|
|
195
197
|
|
|
196
|
-
User opens → verifies identity → wallet restored.
|
|
198
|
+
User opens → verifies identity (passkey assertion or MetaMask connect) → wallet restored.
|
package/package.json
CHANGED
package/scripts/propose.mjs
CHANGED
|
@@ -309,7 +309,50 @@ try {
|
|
|
309
309
|
|
|
310
310
|
const safe4337Pack = await Safe4337Pack.init(initOptions);
|
|
311
311
|
|
|
312
|
-
|
|
312
|
+
let safeAddress = await safe4337Pack.protocolKit.getAddress();
|
|
313
|
+
|
|
314
|
+
// --- Ethereum mainnet: force L2 singleton for cross-chain address consistency ---
|
|
315
|
+
//
|
|
316
|
+
// Safe SDK defaults to the L1 singleton on chainId 1, but all other chains use the L2
|
|
317
|
+
// singleton. Different singleton → different CREATE2 address → cross-chain mismatch.
|
|
318
|
+
//
|
|
319
|
+
// The L2 singleton (0x29fc...) IS deployed on Ethereum mainnet. Using it there costs
|
|
320
|
+
// ~2.3% more gas per tx (~$0.14 at 15 Gwei) due to extra event emissions — acceptable.
|
|
321
|
+
//
|
|
322
|
+
// Trade-off: safe.global may not fully index L2-singleton Safes on mainnet (their L1
|
|
323
|
+
// indexer uses trace-based filtering by known singleton addresses). NodPay uses its own
|
|
324
|
+
// op-store, so this doesn't affect us.
|
|
325
|
+
//
|
|
326
|
+
// Long-term plan: support separate L1/L2 wallet families — user chooses at creation time.
|
|
327
|
+
// For now, we unify on L2 singleton across all chains for address consistency.
|
|
328
|
+
if (
|
|
329
|
+
isCounterfactual &&
|
|
330
|
+
CHAIN_ID === '1' &&
|
|
331
|
+
SAFE_ADDRESS &&
|
|
332
|
+
safeAddress.toLowerCase() !== SAFE_ADDRESS.toLowerCase()
|
|
333
|
+
) {
|
|
334
|
+
const Safe = (await import('@safe-global/protocol-kit')).default;
|
|
335
|
+
// getPredictedSafe() returns the full config Safe4337Pack assembled — owners, threshold,
|
|
336
|
+
// module setup (to/data), fallbackHandler, salt, etc. We re-init with the same config
|
|
337
|
+
// but isL1SafeSingleton=false so the SDK picks L2 singleton.
|
|
338
|
+
const predictedSafe = safe4337Pack.protocolKit.getPredictedSafe();
|
|
339
|
+
safe4337Pack.protocolKit = await Safe.init({
|
|
340
|
+
provider: RPC_URL,
|
|
341
|
+
signer: initOptions.signer,
|
|
342
|
+
isL1SafeSingleton: false,
|
|
343
|
+
predictedSafe,
|
|
344
|
+
});
|
|
345
|
+
safeAddress = await safe4337Pack.protocolKit.getAddress();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Safety check: if --safe was explicitly given, the computed address MUST match.
|
|
349
|
+
// Mismatch means owner set / salt / SDK version differs from wallet creation — abort.
|
|
350
|
+
if (SAFE_ADDRESS && safeAddress.toLowerCase() !== SAFE_ADDRESS.toLowerCase()) {
|
|
351
|
+
console.error(JSON.stringify({
|
|
352
|
+
error: `Address mismatch: --safe ${SAFE_ADDRESS} but SDK computed ${safeAddress}. Check --human-signer-eoa, --recovery-signer, and --salt match the original wallet creation params.`
|
|
353
|
+
}));
|
|
354
|
+
process.exit(1);
|
|
355
|
+
}
|
|
313
356
|
|
|
314
357
|
// Auto-detect deployment status: if Safe is already deployed, drop counterfactual
|
|
315
358
|
if (isCounterfactual) {
|