nodpay 0.2.37 → 0.2.38

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodpay",
3
- "version": "0.2.37",
3
+ "version": "0.2.38",
4
4
  "description": "NodPay CLI — propose on-chain payments from agent-human shared wallets",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,6 +32,7 @@ import { join, dirname } from 'path';
32
32
  import { fileURLToPath } from 'url';
33
33
  import { computeUserOpHash, ENTRYPOINT } from '@nodpay/core';
34
34
  import { loadDotEnv, env, HOME } from './env.mjs';
35
+ import { loadConfig } from './config.mjs';
35
36
 
36
37
  const __dirname = dirname(fileURLToPath(import.meta.url));
37
38
  const PENDING_DIR = join(__dirname, '..', '.pending-txs');
@@ -85,7 +86,9 @@ const DEFAULT_SAFE = null; // always use --safe flag
85
86
  const opStoreBase = env('OP_STORE_URL', 'https://nodpay.ai/api');
86
87
  const BUNDLER_URL = `${opStoreBase}/bundler/${CHAIN_ID}`;
87
88
 
88
- // --- Agent key: remote signer (SafeClaw proxy) or local key (~/.nodpay/.env) ---
89
+ // --- Agent key resolution: remote_wallet (config.json) > --remote-signer > local key ---
90
+ const _config = loadConfig();
91
+ const _remoteWalletUrl = _config.remote_wallet || null;
89
92
  const _remoteSignerUrl = process.argv.includes('--remote-signer')
90
93
  ? process.argv[process.argv.indexOf('--remote-signer') + 1]
91
94
  : undefined;
@@ -93,9 +96,41 @@ const _remoteSignerUrl = process.argv.includes('--remote-signer')
93
96
  let AGENT_ADDRESS;
94
97
  let signHash;
95
98
  let _localAgentKey; // only set in local mode, used for SDK init (EOA signer)
99
+ let _remoteWalletsCache = null; // cached wallets from remote_wallet fetch
96
100
 
97
- if (_remoteSignerUrl) {
98
- // Remote signer mode: get address + signing from SafeClaw proxy
101
+ if (_remoteWalletUrl) {
102
+ // remote_wallet mode (config.json): get agent address from wallets, sign via proxy
103
+ const walletsRes = await fetch(`${_remoteWalletUrl.replace(/\/$/, '')}/wallets`);
104
+ if (!walletsRes.ok) {
105
+ const err = await walletsRes.json().catch(() => ({}));
106
+ console.error(JSON.stringify({
107
+ error: err.error || 'Failed to get wallets from remote_wallet',
108
+ code: err.code || 'REMOTE_WALLET_ERROR'
109
+ }));
110
+ process.exit(1);
111
+ }
112
+ const wallets = await walletsRes.json();
113
+ _remoteWalletsCache = wallets;
114
+ if (!wallets.length || !wallets[0].agentSigner) {
115
+ console.error(JSON.stringify({ error: 'No wallets found on remote_wallet' }));
116
+ process.exit(1);
117
+ }
118
+ AGENT_ADDRESS = wallets[0].agentSigner;
119
+
120
+ signHash = async (hash) => {
121
+ const signRes = await fetch(`${_remoteWalletUrl.replace(/\/$/, '')}/sign`, {
122
+ method: 'POST',
123
+ headers: { 'Content-Type': 'application/json' },
124
+ body: JSON.stringify({ hash })
125
+ });
126
+ if (!signRes.ok) {
127
+ const err = await signRes.json().catch(() => ({}));
128
+ throw new Error(err.error || 'Remote signing failed');
129
+ }
130
+ return (await signRes.json()).signature;
131
+ };
132
+ } else if (_remoteSignerUrl) {
133
+ // Legacy --remote-signer mode (deprecated, use config.json remote_wallet)
99
134
  const addrRes = await fetch(`${_remoteSignerUrl}/address`);
100
135
  if (!addrRes.ok) {
101
136
  const err = await addrRes.json().catch(() => ({}));
@@ -123,7 +158,7 @@ if (_remoteSignerUrl) {
123
158
  // Local mode: read key from process.env (loaded from real env or ~/.nodpay/.env)
124
159
  const NODPAY_AGENT_KEY = env('NODPAY_AGENT_KEY');
125
160
  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' }));
161
+ 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
162
  process.exit(1);
128
163
  }
129
164
  _localAgentKey = NODPAY_AGENT_KEY;
@@ -160,9 +195,9 @@ const passkeyVerifier = getArg('--passkey-verifier') || '0x445a0683e494ea0c5AF3E
160
195
  const recoverySigner = getArg('--recovery-signer');
161
196
  const isPasskey = !!(passkeyX && passkeyY);
162
197
 
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.' }));
198
+ // Phase 1: remote modes + --human-signer-eoa is not supported
199
+ if ((_remoteSignerUrl || _remoteWalletUrl) && humanSigner) {
200
+ console.error(JSON.stringify({ error: 'Remote signer/wallet and --human-signer-eoa cannot be combined. Remote mode only supports passkey wallets.' }));
166
201
  process.exit(1);
167
202
  }
168
203
 
@@ -179,8 +214,13 @@ if (!ethers.isAddress(to)) {
179
214
  const SAFE_ADDRESS = safeOverride || DEFAULT_SAFE;
180
215
 
181
216
  // Read optional wallet JSON for rpId (SafeClaw cross-origin passkey support)
217
+ // In remote_wallet mode, wallets were already fetched — use that data.
182
218
  let walletRpId = null;
183
- if (SAFE_ADDRESS) {
219
+ if (SAFE_ADDRESS && _remoteWalletUrl && _remoteWalletsCache) {
220
+ const match = _remoteWalletsCache.find(w => w.safe?.toLowerCase() === SAFE_ADDRESS.toLowerCase());
221
+ if (match?.rpId) walletRpId = match.rpId;
222
+ }
223
+ if (!walletRpId && SAFE_ADDRESS) {
184
224
  const walletJsonPath = join(HOME, '.nodpay', 'wallets', `${SAFE_ADDRESS}.json`);
185
225
  if (existsSync(walletJsonPath)) {
186
226
  try {