nodpay 0.2.37 → 0.2.39

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/package.json +1 -1
  2. package/scripts/propose.mjs +31 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodpay",
3
- "version": "0.2.37",
3
+ "version": "0.2.39",
4
4
  "description": "NodPay CLI — propose on-chain payments from agent-human shared wallets",
5
5
  "type": "module",
6
6
  "bin": {
@@ -6,7 +6,7 @@
6
6
  * The agent signs first (1 of 2). The serialized SafeOperation is
7
7
  * output so the web app can have the user co-sign and submit.
8
8
  *
9
- * Agent key: from process.env.NODPAY_AGENT_KEY (real env > ~/.nodpay/.env file > --remote-signer).
9
+ * Agent key: from process.env.NODPAY_AGENT_KEY (real env > ~/.nodpay/.env file), or remote_wallet proxy.
10
10
  * Chain config: resolved via --chain from @nodpay/core networks registry.
11
11
  * Bundler: NodPay public proxy (override with OP_STORE_URL for self-hosted).
12
12
  *
@@ -17,7 +17,6 @@
17
17
  * --safe <address> - Wallet (Safe) address
18
18
  * --counterfactual - Safe not yet deployed; include deployment in UserOp
19
19
  * --human-signer-eoa <address> - Human's EOA signer address (for EOA mode)
20
- * --remote-signer <url> - SafeClaw proxy URL for remote signing (mutually exclusive with --human-signer-eoa)
21
20
  * --salt <nonce> - Salt nonce (required for counterfactual)
22
21
  * --reuse-gas-from <shortHash> - Reuse gas values from a previous op (shortHash prefix of safeOpHash)
23
22
  * --nonce <n> - Required. Use `txs` to find current nonce.
@@ -32,6 +31,7 @@ import { join, dirname } from 'path';
32
31
  import { fileURLToPath } from 'url';
33
32
  import { computeUserOpHash, ENTRYPOINT } from '@nodpay/core';
34
33
  import { loadDotEnv, env, HOME } from './env.mjs';
34
+ import { loadConfig } from './config.mjs';
35
35
 
36
36
  const __dirname = dirname(fileURLToPath(import.meta.url));
37
37
  const PENDING_DIR = join(__dirname, '..', '.pending-txs');
@@ -85,30 +85,36 @@ const DEFAULT_SAFE = null; // always use --safe flag
85
85
  const opStoreBase = env('OP_STORE_URL', 'https://nodpay.ai/api');
86
86
  const BUNDLER_URL = `${opStoreBase}/bundler/${CHAIN_ID}`;
87
87
 
88
- // --- Agent key: remote signer (SafeClaw proxy) or local key (~/.nodpay/.env) ---
89
- const _remoteSignerUrl = process.argv.includes('--remote-signer')
90
- ? process.argv[process.argv.indexOf('--remote-signer') + 1]
91
- : undefined;
88
+ // --- Agent key resolution: remote_wallet (config.json) or local key ---
89
+ const _config = loadConfig();
90
+ const _remoteWalletUrl = _config.remote_wallet || null;
92
91
 
93
92
  let AGENT_ADDRESS;
94
93
  let signHash;
95
94
  let _localAgentKey; // only set in local mode, used for SDK init (EOA signer)
95
+ let _remoteWalletsCache = null; // cached wallets from remote_wallet fetch
96
96
 
97
- if (_remoteSignerUrl) {
98
- // Remote signer mode: get address + signing from SafeClaw proxy
99
- const addrRes = await fetch(`${_remoteSignerUrl}/address`);
100
- if (!addrRes.ok) {
101
- const err = await addrRes.json().catch(() => ({}));
97
+ if (_remoteWalletUrl) {
98
+ // remote_wallet mode (config.json): get agent address from wallets, sign via proxy
99
+ const walletsRes = await fetch(`${_remoteWalletUrl.replace(/\/$/, '')}/wallets`);
100
+ if (!walletsRes.ok) {
101
+ const err = await walletsRes.json().catch(() => ({}));
102
102
  console.error(JSON.stringify({
103
- error: err.error || 'Failed to get agent address from remote signer',
104
- code: err.code || 'REMOTE_SIGNER_ERROR'
103
+ error: err.error || 'Failed to get wallets from remote_wallet',
104
+ code: err.code || 'REMOTE_WALLET_ERROR'
105
105
  }));
106
106
  process.exit(1);
107
107
  }
108
- AGENT_ADDRESS = (await addrRes.json()).address;
108
+ const wallets = await walletsRes.json();
109
+ _remoteWalletsCache = wallets;
110
+ if (!wallets.length || !wallets[0].agentSigner) {
111
+ console.error(JSON.stringify({ error: 'No wallets found on remote_wallet' }));
112
+ process.exit(1);
113
+ }
114
+ AGENT_ADDRESS = wallets[0].agentSigner;
109
115
 
110
116
  signHash = async (hash) => {
111
- const signRes = await fetch(`${_remoteSignerUrl}/sign/${AGENT_ADDRESS}`, {
117
+ const signRes = await fetch(`${_remoteWalletUrl.replace(/\/$/, '')}/sign`, {
112
118
  method: 'POST',
113
119
  headers: { 'Content-Type': 'application/json' },
114
120
  body: JSON.stringify({ hash })
@@ -123,7 +129,7 @@ if (_remoteSignerUrl) {
123
129
  // Local mode: read key from process.env (loaded from real env or ~/.nodpay/.env)
124
130
  const NODPAY_AGENT_KEY = env('NODPAY_AGENT_KEY');
125
131
  if (!NODPAY_AGENT_KEY) {
126
- console.error(JSON.stringify({ error: 'Missing NODPAY_AGENT_KEY — set env var, add to ~/.nodpay/.env, or use --remote-signer' }));
132
+ console.error(JSON.stringify({ error: 'Missing NODPAY_AGENT_KEY — set env var, add to ~/.nodpay/.env, or set remote_wallet in ~/.nodpay/config.json' }));
127
133
  process.exit(1);
128
134
  }
129
135
  _localAgentKey = NODPAY_AGENT_KEY;
@@ -160,9 +166,9 @@ const passkeyVerifier = getArg('--passkey-verifier') || '0x445a0683e494ea0c5AF3E
160
166
  const recoverySigner = getArg('--recovery-signer');
161
167
  const isPasskey = !!(passkeyX && passkeyY);
162
168
 
163
- // Phase 1: --remote-signer + --human-signer-eoa is not supported
164
- if (_remoteSignerUrl && humanSigner) {
165
- console.error(JSON.stringify({ error: '--remote-signer and --human-signer-eoa cannot be combined. Remote signer mode only supports passkey wallets.' }));
169
+ // remote_wallet + --human-signer-eoa is not supported
170
+ if (_remoteWalletUrl && humanSigner) {
171
+ console.error(JSON.stringify({ error: 'remote_wallet and --human-signer-eoa cannot be combined. Remote mode only supports passkey wallets.' }));
166
172
  process.exit(1);
167
173
  }
168
174
 
@@ -179,8 +185,13 @@ if (!ethers.isAddress(to)) {
179
185
  const SAFE_ADDRESS = safeOverride || DEFAULT_SAFE;
180
186
 
181
187
  // Read optional wallet JSON for rpId (SafeClaw cross-origin passkey support)
188
+ // In remote_wallet mode, wallets were already fetched — use that data.
182
189
  let walletRpId = null;
183
- if (SAFE_ADDRESS) {
190
+ if (SAFE_ADDRESS && _remoteWalletUrl && _remoteWalletsCache) {
191
+ const match = _remoteWalletsCache.find(w => w.safe?.toLowerCase() === SAFE_ADDRESS.toLowerCase());
192
+ if (match?.rpId) walletRpId = match.rpId;
193
+ }
194
+ if (!walletRpId && SAFE_ADDRESS) {
184
195
  const walletJsonPath = join(HOME, '.nodpay', 'wallets', `${SAFE_ADDRESS}.json`);
185
196
  if (existsSync(walletJsonPath)) {
186
197
  try {