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 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 three commands:
19
+ The CLI provides five commands:
20
20
 
21
21
  ```
22
22
  nodpay keygen # Generate agent keypair (~/.nodpay/.env, chmod 600)
23
- nodpay propose # Propose a transaction for human approval
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. Propose a payment
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
- # 3. Check pending transactions (with verification)
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 directly to `~/.nodpay/.env` (chmod 600), strictly excluded from stdout and agent context.
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, never exposed to agent context)",
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 internally at runtime — only the public address appears in stdout. |
34
- | **Keyless & Non-Custodial Server** | **Stateless relayer:** the server stores no private keys and maintains no session state that could compromise assets. All signing happens locally. Funds stay on-chain if the server goes offline. |
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodpay",
3
- "version": "0.2.31",
3
+ "version": "0.2.33",
4
4
  "description": "NodPay CLI — propose on-chain payments from agent-human shared wallets",
5
5
  "type": "module",
6
6
  "bin": {
@@ -309,7 +309,50 @@ try {
309
309
 
310
310
  const safe4337Pack = await Safe4337Pack.init(initOptions);
311
311
 
312
- const safeAddress = await safe4337Pack.protocolKit.getAddress();
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) {