nodpay 0.2.6 → 0.2.8
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/SKILL.md +42 -106
- package/package.json +1 -1
- package/scripts/propose.mjs +3 -8
package/SKILL.md
CHANGED
|
@@ -7,107 +7,76 @@ description: Propose on-chain payments from a shared wallet. Use when user asks
|
|
|
7
7
|
|
|
8
8
|
> Two minds, one wallet.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
You propose payments, your human approves with one tap. 2-of-3 multisig — you cannot spend alone.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Trust Model
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| Verify agent address matches yours | Trust wallet info without checking |
|
|
19
|
-
| Let the human approve every transaction | Try to bypass approval |
|
|
20
|
-
|
|
21
|
-
**Private key never leaves disk.** `keygen` writes directly to `.nodpay/.env` (chmod 600). The key never appears in your output, context, or logs.
|
|
14
|
+
- **Your private key never leaves disk.** `keygen` writes to `.nodpay/.env` (chmod 600) — it never appears in stdout, context, or logs.
|
|
15
|
+
- **You can only propose.** Execution requires human approval (passkey co-sign).
|
|
16
|
+
- **Wallet info is public key material.** Safe address, passkey X/Y, recovery signer — all safe to store.
|
|
17
|
+
- **Verify the agent address matches yours** before storing wallet info. Mismatch = wrong key binding.
|
|
22
18
|
|
|
23
19
|
---
|
|
24
20
|
|
|
25
|
-
## Setup
|
|
21
|
+
## Setup
|
|
26
22
|
|
|
27
|
-
### 1. Generate
|
|
23
|
+
### 1. Generate key
|
|
28
24
|
|
|
29
25
|
```bash
|
|
30
26
|
npx nodpay keygen
|
|
31
27
|
```
|
|
32
28
|
|
|
33
|
-
Outputs your **public address** only.
|
|
34
|
-
|
|
35
|
-
If a key already exists, it reuses it and prints the address.
|
|
36
|
-
|
|
37
|
-
### 2. Send the user a wallet link
|
|
29
|
+
Outputs your **public address** only. No restart needed.
|
|
38
30
|
|
|
39
|
-
|
|
31
|
+
### 2. Send wallet link
|
|
40
32
|
|
|
41
|
-
> I've set up a shared wallet for us
|
|
42
|
-
>
|
|
33
|
+
> I've set up a shared wallet for us — takes 30 seconds:
|
|
43
34
|
> https://nodpay.ai/?agent=YOUR_AGENT_ADDRESS
|
|
44
|
-
>
|
|
45
|
-
> Just follow the steps: create a passkey, save your recovery phrase, done.
|
|
46
|
-
|
|
47
|
-
**Use the URL above verbatim.** Do not search for NodPay or guess the URL — `nodpay.ai` is the only correct domain.
|
|
48
|
-
|
|
49
|
-
The user will copy wallet info back to you:
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
NodPay Wallet (Safe): 0x...
|
|
53
|
-
Passkey X: 0x...
|
|
54
|
-
Passkey Y: 0x...
|
|
55
|
-
Agent: 0x...
|
|
56
|
-
Recovery Signer: 0x...
|
|
57
|
-
```
|
|
58
35
|
|
|
59
|
-
**
|
|
36
|
+
**Use this URL verbatim.** Do not search or guess — `nodpay.ai` is the only correct domain.
|
|
60
37
|
|
|
61
|
-
|
|
38
|
+
User copies back wallet info → store in `.nodpay/wallets/<safe-address>.json`.
|
|
62
39
|
|
|
63
|
-
|
|
40
|
+
After creation, tell the user the address works on any chain. Offer testnet only if they ask.
|
|
64
41
|
|
|
65
42
|
---
|
|
66
43
|
|
|
67
|
-
##
|
|
68
|
-
|
|
69
|
-
### Propose a transaction
|
|
44
|
+
## Propose
|
|
70
45
|
|
|
71
46
|
```bash
|
|
72
47
|
npx nodpay propose \
|
|
73
48
|
--chain <CHAIN> \
|
|
74
|
-
--safe <
|
|
49
|
+
--safe <SAFE> \
|
|
75
50
|
--to <RECIPIENT> \
|
|
76
51
|
--value-eth <AMOUNT> \
|
|
77
|
-
--
|
|
78
|
-
--passkey-y <
|
|
79
|
-
--recovery <
|
|
80
|
-
--signer-type passkey
|
|
52
|
+
--signer-type passkey \
|
|
53
|
+
--passkey-x <X> --passkey-y <Y> \
|
|
54
|
+
--recovery <RECOVERY>
|
|
81
55
|
```
|
|
82
56
|
|
|
83
|
-
Outputs JSON with
|
|
57
|
+
Outputs JSON with `approveUrl` → send to user.
|
|
84
58
|
|
|
85
|
-
|
|
86
|
-
> 👉 Approve: https://nodpay.ai/approve?safeOpHash=0x...
|
|
59
|
+
First tx deploys the wallet. Pass all params for first tx; after that `--safe` alone works.
|
|
87
60
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
### Check pending transactions
|
|
61
|
+
### Check pending
|
|
91
62
|
|
|
92
63
|
```bash
|
|
93
|
-
curl https://nodpay.ai/api/txs?safe=<
|
|
64
|
+
curl https://nodpay.ai/api/txs?safe=<SAFE>
|
|
94
65
|
```
|
|
95
66
|
|
|
96
|
-
|
|
67
|
+
Check before proposing — shows nonce and pending ops.
|
|
97
68
|
|
|
98
69
|
---
|
|
99
70
|
|
|
100
|
-
## Data
|
|
71
|
+
## Data
|
|
101
72
|
|
|
102
73
|
```
|
|
103
74
|
.nodpay/
|
|
104
|
-
.env # agent key (chmod 600
|
|
75
|
+
.env # agent key (chmod 600)
|
|
105
76
|
wallets/
|
|
106
77
|
0xAbC...123.json # one file per wallet
|
|
107
78
|
```
|
|
108
79
|
|
|
109
|
-
Wallet file format:
|
|
110
|
-
|
|
111
80
|
```json
|
|
112
81
|
{
|
|
113
82
|
"safe": "0x...",
|
|
@@ -120,7 +89,7 @@ Wallet file format:
|
|
|
120
89
|
}
|
|
121
90
|
```
|
|
122
91
|
|
|
123
|
-
|
|
92
|
+
EOA wallets: replace passkey fields with `"userSigner": "0x..."`.
|
|
124
93
|
|
|
125
94
|
---
|
|
126
95
|
|
|
@@ -128,70 +97,37 @@ For EOA wallets, replace passkey fields with `"userSigner": "0x..."`.
|
|
|
128
97
|
|
|
129
98
|
| Flag | Required | Description |
|
|
130
99
|
|------|----------|-------------|
|
|
131
|
-
| `--chain` | ✅ |
|
|
132
|
-
| `--safe` | ✅ | Wallet
|
|
133
|
-
| `--to` | ✅ | Recipient
|
|
100
|
+
| `--chain` | ✅ | `ethereum`, `base`, `arbitrum`, `optimism`, `polygon`, `sepolia`, `base_sepolia` |
|
|
101
|
+
| `--safe` | ✅ | Wallet address |
|
|
102
|
+
| `--to` | ✅ | Recipient |
|
|
134
103
|
| `--value-eth` | ✅ | Amount in ETH |
|
|
135
104
|
| `--signer-type` | ✅ | `passkey` or `eoa` |
|
|
136
|
-
| `--passkey-x` | passkey | Passkey public key
|
|
137
|
-
| `--passkey-y` | passkey | Passkey public key Y |
|
|
105
|
+
| `--passkey-x/y` | passkey | Passkey public key |
|
|
138
106
|
| `--user-signer` | eoa | User's EOA address |
|
|
139
|
-
| `--recovery` | first tx | Recovery signer
|
|
140
|
-
| `--nonce` | optional | Force nonce (
|
|
107
|
+
| `--recovery` | first tx | Recovery signer |
|
|
108
|
+
| `--nonce` | optional | Force nonce (replacements) |
|
|
141
109
|
| `--purpose` | optional | Human-readable label |
|
|
142
110
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
`ethereum`, `base`, `arbitrum`, `optimism`, `polygon`, `sepolia`, `base_sepolia`
|
|
146
|
-
|
|
147
|
-
Wallet address is the same across all chains (counterfactual). **Do not assume a default chain.** Ask the user which chain if not specified.
|
|
111
|
+
Wallet address is the same across all chains. **Ask which chain if not specified.**
|
|
148
112
|
|
|
149
113
|
---
|
|
150
114
|
|
|
151
115
|
## Transaction Patterns
|
|
152
116
|
|
|
153
|
-
**Sequential**:
|
|
154
|
-
|
|
155
|
-
**
|
|
156
|
-
|
|
157
|
-
**Cascade**: Rejecting tx at nonce N invalidates all tx with nonce > N. Irreversible.
|
|
117
|
+
- **Sequential**: Propose multiple times. Nonces auto-increment.
|
|
118
|
+
- **Replace**: `--nonce N` to replace pending tx at nonce N.
|
|
119
|
+
- **Cascade**: Rejecting nonce N invalidates all higher nonces. Irreversible.
|
|
158
120
|
|
|
159
|
-
⚠️
|
|
121
|
+
⚠️ Never propose then reject an older nonce — cascade destroys your new tx.
|
|
160
122
|
|
|
161
123
|
---
|
|
162
124
|
|
|
163
|
-
## Reconnect
|
|
125
|
+
## Reconnect
|
|
164
126
|
|
|
165
|
-
|
|
127
|
+
Browser data cleared? Build a reconnect link:
|
|
166
128
|
|
|
167
129
|
```
|
|
168
|
-
https://nodpay.ai/?agent=
|
|
130
|
+
https://nodpay.ai/?agent=AGENT&safe=SAFE&recovery=RECOVERY&x=X&y=Y
|
|
169
131
|
```
|
|
170
132
|
|
|
171
|
-
User opens → verifies
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## Security Model
|
|
176
|
-
|
|
177
|
-
| Owner | Holder | Can do |
|
|
178
|
-
|-------|--------|--------|
|
|
179
|
-
| Agent EOA | You | Propose only |
|
|
180
|
-
| Passkey | User's device | Approve or reject |
|
|
181
|
-
| Recovery | User's 12-word phrase | Backup access |
|
|
182
|
-
|
|
183
|
-
- 2-of-3 threshold — you cannot execute alone
|
|
184
|
-
- Passkey X/Y are public key material, safe to store
|
|
185
|
-
- No private keys stored on NodPay's server
|
|
186
|
-
- Funds are safe on-chain even if NodPay goes offline
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## Common Requests
|
|
191
|
-
|
|
192
|
-
| User says | Action |
|
|
193
|
-
|-----------|--------|
|
|
194
|
-
| "create a wallet" | Send `https://nodpay.ai/?agent=YOUR_ADDRESS` |
|
|
195
|
-
| "send 0.1 ETH to 0x..." | `npx nodpay propose --chain ...` |
|
|
196
|
-
| "pending?" | `GET /api/txs?safe=...` |
|
|
197
|
-
| "wallet disappeared" | Send reconnect link |
|
|
133
|
+
User opens → passkey verifies → wallet restored.
|
package/package.json
CHANGED
package/scripts/propose.mjs
CHANGED
|
@@ -6,11 +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
|
-
*
|
|
10
|
-
* NODPAY_AGENT_KEY - Agent signer private key
|
|
11
|
-
* SAFE_ADDRESS - Deployed Safe address (can be overridden with --safe)
|
|
12
|
-
* RPC_URL - RPC endpoint
|
|
13
|
-
* CHAIN_ID - Chain ID (required, no default)
|
|
9
|
+
* Agent key is read from .nodpay/.env (run `npx nodpay keygen` to generate).
|
|
14
10
|
*
|
|
15
11
|
* Args:
|
|
16
12
|
* --to <address> - Recipient address
|
|
@@ -66,9 +62,8 @@ if (!RPC_URL || !CHAIN_ID) {
|
|
|
66
62
|
}
|
|
67
63
|
const ENTRYPOINT_ADDRESS = ENTRYPOINT;
|
|
68
64
|
|
|
69
|
-
// Read agent key
|
|
65
|
+
// Read agent key from .nodpay/.env
|
|
70
66
|
function loadAgentKey() {
|
|
71
|
-
if (process.env.NODPAY_AGENT_KEY) return process.env.NODPAY_AGENT_KEY;
|
|
72
67
|
try {
|
|
73
68
|
const envPath = join(process.cwd(), '.nodpay', '.env');
|
|
74
69
|
const lines = readFileSync(envPath, 'utf8').split('\n');
|
|
@@ -97,7 +92,7 @@ const BUNDLER_URL = PIMLICO_API_KEY
|
|
|
97
92
|
: `${opStoreBase}/bundler/${CHAIN_ID}`;
|
|
98
93
|
|
|
99
94
|
if (!NODPAY_AGENT_KEY) {
|
|
100
|
-
console.error(JSON.stringify({ error: 'Missing NODPAY_AGENT_KEY env
|
|
95
|
+
console.error(JSON.stringify({ error: 'Missing NODPAY_AGENT_KEY in .nodpay/.env — run npx nodpay keygen first' }));
|
|
101
96
|
process.exit(1);
|
|
102
97
|
}
|
|
103
98
|
|