@reppo/cli 0.4.0 → 0.5.0
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 +2 -1
- package/dist/bin.js +3 -1
- package/dist/bin.js.map +1 -1
- package/dist/commands/approve.d.ts +12 -0
- package/dist/commands/approve.d.ts.map +1 -0
- package/dist/commands/approve.js +224 -0
- package/dist/commands/approve.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Command-line interface for [Reppo](https://reppo.ai) — mint pods, vote, lock REPPO, manage datanets. Built for **AI agents** as the primary user, but humans can use it too.
|
|
4
4
|
|
|
5
|
-
> **Status:** v0.4.0 — fully wired against PodManager V2 on mainnet. Shipped: `auth`, `query balance`, `query datanet`, `query emissions-due`, `query pod`, `query voting-power`, `list datanets`, `list pods` (incl. `--all`), `claim-emissions`, `extend-lock`, `grant-access`, `lock`, `mint-pod`, `register-agent`, `unlock`, `vote`. Remaining 2 commands (`create-datanet`, `swap`) are scaffolded but not yet wired.
|
|
5
|
+
> **Status:** v0.4.0 — fully wired against PodManager V2 on mainnet. Shipped: `approve`, `auth`, `query balance`, `query datanet`, `query emissions-due`, `query pod`, `query voting-power`, `list datanets`, `list pods` (incl. `--all`), `claim-emissions`, `extend-lock`, `grant-access`, `lock`, `mint-pod`, `register-agent`, `unlock`, `vote`. Remaining 2 commands (`create-datanet`, `swap`) are scaffolded but not yet wired.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -55,6 +55,7 @@ Errors **always** emit JSON on stderr regardless of mode, with a stable `code` f
|
|
|
55
55
|
|
|
56
56
|
### Write
|
|
57
57
|
|
|
58
|
+
- `reppo approve --spender <pod-manager|subnet-manager|ve-reppo|0x…> [--amount <units|max>] [--token reppo|usdc]` — set an ERC20 allowance so subsequent writes (lock, grant-access, mint-pod) don't fail with INSUFFICIENT_ALLOWANCE. Defaults to unlimited (`max`); reads the current allowance first and emits `{status:'no-op'}` if it already covers the request.
|
|
58
59
|
- `reppo vote --pod <id> --votes <n> --like|--dislike` — cast a vote on a pod, spending `<n>` voting power
|
|
59
60
|
- `reppo mint-pod --datanet <id> [--token reppo|primary] [--to <addr>]` — mint a pod into a datanet
|
|
60
61
|
- `reppo lock <amount> --duration <seconds>` — lock REPPO into veREPPO for voting power
|
package/dist/bin.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* via clipanion's runExit.
|
|
5
5
|
*/
|
|
6
6
|
import { Cli, Builtins } from 'clipanion';
|
|
7
|
+
import { ApproveCommand } from './commands/approve.js';
|
|
7
8
|
import { AuthCommand } from './commands/auth.js';
|
|
8
9
|
import { ClaimEmissionsCommand } from './commands/claim-emissions.js';
|
|
9
10
|
import { ExtendLockCommand } from './commands/extend-lock.js';
|
|
@@ -23,11 +24,12 @@ import { VoteCommand } from './commands/vote.js';
|
|
|
23
24
|
const cli = new Cli({
|
|
24
25
|
binaryLabel: 'Reppo CLI',
|
|
25
26
|
binaryName: 'reppo',
|
|
26
|
-
binaryVersion: '0.
|
|
27
|
+
binaryVersion: '0.5.0',
|
|
27
28
|
enableCapture: false,
|
|
28
29
|
});
|
|
29
30
|
cli.register(Builtins.HelpCommand);
|
|
30
31
|
cli.register(Builtins.VersionCommand);
|
|
32
|
+
cli.register(ApproveCommand);
|
|
31
33
|
cli.register(AuthCommand);
|
|
32
34
|
cli.register(ClaimEmissionsCommand);
|
|
33
35
|
cli.register(ExtendLockCommand);
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseCommand } from './_base.js';
|
|
2
|
+
export declare class ApproveCommand extends BaseCommand {
|
|
3
|
+
static paths: string[][];
|
|
4
|
+
static usage: import("clipanion").Usage;
|
|
5
|
+
spender: string;
|
|
6
|
+
amount: string;
|
|
7
|
+
token: string;
|
|
8
|
+
idempotencyKey: string | undefined;
|
|
9
|
+
dryRun: boolean;
|
|
10
|
+
execute(): Promise<number>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=approve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approve.d.ts","sourceRoot":"","sources":["../../src/commands/approve.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA2CzC,qBAAa,cAAe,SAAQ,WAAW;IAC7C,OAAgB,KAAK,aAAiB;IAEtC,OAAgB,KAAK,4BAclB;IAEH,OAAO,SAAuH;IAC9H,MAAM,SAAwH;IAC9H,KAAK,SAAiF;IACtF,cAAc,qBAAsC;IACpD,MAAM,UAAsC;IAEtC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;CAiLjC"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reppo approve --spender <alias|0x...> [--amount <units|max>] [--token reppo|usdc]`
|
|
3
|
+
* — set an ERC20 allowance so subsequent write commands (lock, grant-access,
|
|
4
|
+
* mint-pod) don't fail with INSUFFICIENT_ALLOWANCE.
|
|
5
|
+
*
|
|
6
|
+
* Most agent flows want unlimited approval once, so `--amount` defaults to
|
|
7
|
+
* `max` (MaxUint256). Pass a numeric value (in human REPPO/USDC units) for a
|
|
8
|
+
* bounded approval.
|
|
9
|
+
*
|
|
10
|
+
* Spender aliases resolve per network:
|
|
11
|
+
* - pod-manager → PodManager (mintPodWithREPPO, mintPodWithPrimaryToken)
|
|
12
|
+
* - subnet-manager → SubnetManager (grantAccess REPPO fee — pulled here)
|
|
13
|
+
* - ve-reppo → veREPPO (lock, extendLockup)
|
|
14
|
+
* - 0x… → raw address (validated with viem isAddress)
|
|
15
|
+
*
|
|
16
|
+
* Pre-flight: reads the current allowance and SHORT-CIRCUITS if it's already
|
|
17
|
+
* ≥ the requested amount, emitting `{ status: 'no-op' }` with no tx. This
|
|
18
|
+
* matches the idempotent re-runnability that agents expect.
|
|
19
|
+
*
|
|
20
|
+
* Two-phase write protocol identical to vote.ts; args fingerprint
|
|
21
|
+
* (token, spender, amount) prevents same-key reuse with different intent.
|
|
22
|
+
*/
|
|
23
|
+
import { Option } from 'clipanion';
|
|
24
|
+
import { isAddress, parseUnits, formatUnits, maxUint256 } from 'viem';
|
|
25
|
+
import { BaseCommand } from './_base.js';
|
|
26
|
+
import { cliError, emit } from '../output/format.js';
|
|
27
|
+
import { createClients, nextNonce } from '../chain/clients.js';
|
|
28
|
+
import { podManager, subnetManager, veReppo, reppoToken, usdcToken, } from '../chain/contracts.js';
|
|
29
|
+
import { decodeRevert } from '../chain/errors.js';
|
|
30
|
+
import { begin, markSubmitted, markConfirmed, markFailed, peekIdempotent, } from '../state/idempotency.js';
|
|
31
|
+
const COMMAND = 'approve';
|
|
32
|
+
const SPENDER_ALIASES = new Set(['pod-manager', 'subnet-manager', 've-reppo']);
|
|
33
|
+
const TOKEN_NAMES = new Set(['reppo', 'usdc']);
|
|
34
|
+
function resolveSpender(spender, network) {
|
|
35
|
+
if (SPENDER_ALIASES.has(spender)) {
|
|
36
|
+
switch (spender) {
|
|
37
|
+
case 'pod-manager': return podManager(network).address;
|
|
38
|
+
case 'subnet-manager': return subnetManager(network).address;
|
|
39
|
+
case 've-reppo': return veReppo(network).address;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (isAddress(spender))
|
|
43
|
+
return spender;
|
|
44
|
+
throw cliError('INVALID_SPENDER', `--spender must be one of pod-manager|subnet-manager|ve-reppo or a 0x-prefixed address; got "${spender}".`);
|
|
45
|
+
}
|
|
46
|
+
export class ApproveCommand extends BaseCommand {
|
|
47
|
+
static paths = [['approve']];
|
|
48
|
+
static usage = BaseCommand.Usage({
|
|
49
|
+
description: 'Approve a Reppo contract to spend your REPPO (or USDC) tokens.',
|
|
50
|
+
examples: [
|
|
51
|
+
['Unlimited REPPO approval for veREPPO (default amount=max)',
|
|
52
|
+
'reppo approve --spender ve-reppo'],
|
|
53
|
+
['Bounded approval (100 REPPO) for SubnetManager',
|
|
54
|
+
'reppo approve --spender subnet-manager --amount 100'],
|
|
55
|
+
['USDC approval for PodManager (mintPodWithPrimaryToken)',
|
|
56
|
+
'reppo approve --spender pod-manager --token usdc --amount 50'],
|
|
57
|
+
['Raw spender address + idempotency key',
|
|
58
|
+
'reppo approve --spender 0xabc...def --amount max --idempotency-key approve-veReppo-once'],
|
|
59
|
+
['Dry-run',
|
|
60
|
+
'reppo approve --spender ve-reppo --dry-run'],
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
spender = Option.String('--spender', { required: true, description: 'pod-manager | subnet-manager | ve-reppo | 0x-address' });
|
|
64
|
+
amount = Option.String('--amount', 'max', { description: 'Token amount in human units, or "max" for MaxUint256 (default).' });
|
|
65
|
+
token = Option.String('--token', 'reppo', { description: 'reppo (default) or usdc' });
|
|
66
|
+
idempotencyKey = Option.String('--idempotency-key');
|
|
67
|
+
dryRun = Option.Boolean('--dry-run', false);
|
|
68
|
+
async execute() {
|
|
69
|
+
try {
|
|
70
|
+
// Validate token + spender BEFORE loadConfig (cheapest path).
|
|
71
|
+
if (!TOKEN_NAMES.has(this.token)) {
|
|
72
|
+
throw cliError('INVALID_TOKEN', `--token must be reppo or usdc; got "${this.token}".`);
|
|
73
|
+
}
|
|
74
|
+
const tokenName = this.token;
|
|
75
|
+
const decimals = tokenName === 'reppo' ? 18 : 6;
|
|
76
|
+
const cfg = this.loadConfig();
|
|
77
|
+
const pk = cfg.privateKey;
|
|
78
|
+
if (!pk) {
|
|
79
|
+
throw cliError('MISSING_PRIVATE_KEY', 'No signing key available.', 'Set REPPO_PRIVATE_KEY in env.');
|
|
80
|
+
}
|
|
81
|
+
const spenderAddr = resolveSpender(this.spender, cfg.network);
|
|
82
|
+
let amount;
|
|
83
|
+
if (this.amount === 'max') {
|
|
84
|
+
amount = maxUint256;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
try {
|
|
88
|
+
amount = parseUnits(this.amount, decimals);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
throw cliError('INVALID_AMOUNT', `--amount must be a positive decimal number or "max"; got "${this.amount}".`);
|
|
92
|
+
}
|
|
93
|
+
if (amount <= 0n) {
|
|
94
|
+
throw cliError('INVALID_AMOUNT', `--amount must be > 0 or "max"; got "${this.amount}".`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Args fingerprint baked into the cache so re-using one key with a
|
|
98
|
+
// different (token, spender, amount) → IDEMPOTENCY_ARGS_MISMATCH.
|
|
99
|
+
const args = {
|
|
100
|
+
token: tokenName,
|
|
101
|
+
spender: spenderAddr.toLowerCase(),
|
|
102
|
+
amount: amount.toString(),
|
|
103
|
+
};
|
|
104
|
+
// Dry-run NEVER consults or mutates the cache (peekIdempotent enforces
|
|
105
|
+
// this with its 4th arg). Cached real-tx returns vs simulation results
|
|
106
|
+
// must not be conflated.
|
|
107
|
+
const decision = await peekIdempotent(this.idempotencyKey, COMMAND, args, this.dryRun);
|
|
108
|
+
if (decision.kind === 'return-confirmed') {
|
|
109
|
+
emit({ ...decision.result, idempotent: true, status: 'confirmed' }, [`(cached, confirmed) tx: ${decision.txHash ?? 'n/a'}`]);
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
if (decision.kind === 'return-submitted') {
|
|
113
|
+
emit({ ...decision.result, idempotent: true, status: 'submitted' }, [`(cached, submitted but not confirmed yet) tx: ${decision.txHash ?? 'n/a'}`,
|
|
114
|
+
`Re-run after the tx confirms, or check the explorer.`]);
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
const clients = createClients({
|
|
118
|
+
network: cfg.network,
|
|
119
|
+
privateKey: pk,
|
|
120
|
+
...(cfg.rpcUrl ? { rpcUrl: cfg.rpcUrl } : {}),
|
|
121
|
+
});
|
|
122
|
+
const token = tokenName === 'reppo' ? reppoToken(cfg.network) : usdcToken(cfg.network);
|
|
123
|
+
// Pre-flight: skip the tx entirely if the existing allowance already
|
|
124
|
+
// covers the request. Saves gas and matches agent re-runnability.
|
|
125
|
+
const currentAllowance = await clients.publicClient.readContract({
|
|
126
|
+
address: token.address, abi: token.abi, functionName: 'allowance',
|
|
127
|
+
args: [clients.account.address, spenderAddr],
|
|
128
|
+
});
|
|
129
|
+
const fmtAmt = (a) => a === maxUint256
|
|
130
|
+
? { raw: a.toString(), formatted: 'max' }
|
|
131
|
+
: { raw: a.toString(), formatted: formatUnits(a, decimals) };
|
|
132
|
+
if (currentAllowance >= amount) {
|
|
133
|
+
const result = {
|
|
134
|
+
token: tokenName,
|
|
135
|
+
spender: spenderAddr,
|
|
136
|
+
owner: clients.account.address,
|
|
137
|
+
requested: fmtAmt(amount),
|
|
138
|
+
currentAllowance: fmtAmt(currentAllowance),
|
|
139
|
+
status: 'no-op',
|
|
140
|
+
reason: 'allowance already sufficient',
|
|
141
|
+
};
|
|
142
|
+
// No tx, so we intentionally skip writing the idempotency cache —
|
|
143
|
+
// `markConfirmed` requires a real txHash. Re-reading the chain
|
|
144
|
+
// allowance on retry is cheap and authoritative.
|
|
145
|
+
emit(result, [
|
|
146
|
+
`= No-op: ${tokenName.toUpperCase()} allowance from ${clients.account.address} to ${spenderAddr}`,
|
|
147
|
+
` is already ${fmtAmt(currentAllowance).formatted} (>= requested ${fmtAmt(amount).formatted}).`,
|
|
148
|
+
]);
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
if (this.dryRun) {
|
|
152
|
+
const sim = await clients.publicClient.simulateContract({
|
|
153
|
+
address: token.address, abi: token.abi, functionName: 'approve',
|
|
154
|
+
args: [spenderAddr, amount], account: clients.account,
|
|
155
|
+
}).catch((e) => {
|
|
156
|
+
const decoded = decodeRevert(e);
|
|
157
|
+
throw cliError(decoded.code, 'Simulation reverted', decoded.hint);
|
|
158
|
+
});
|
|
159
|
+
emit({
|
|
160
|
+
simulated: true,
|
|
161
|
+
token: tokenName,
|
|
162
|
+
spender: spenderAddr,
|
|
163
|
+
owner: clients.account.address,
|
|
164
|
+
requested: fmtAmt(amount),
|
|
165
|
+
currentAllowance: fmtAmt(currentAllowance),
|
|
166
|
+
gas: sim.request.gas?.toString() ?? null,
|
|
167
|
+
});
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
// Two-phase write: begin → submit → markSubmitted → wait → markConfirmed.
|
|
171
|
+
if (this.idempotencyKey)
|
|
172
|
+
await begin(this.idempotencyKey, COMMAND, args);
|
|
173
|
+
let tx;
|
|
174
|
+
try {
|
|
175
|
+
const nonce = await nextNonce(clients.publicClient, clients.account.address);
|
|
176
|
+
tx = await clients.walletClient.writeContract({
|
|
177
|
+
address: token.address, abi: token.abi, functionName: 'approve',
|
|
178
|
+
args: [spenderAddr, amount],
|
|
179
|
+
chain: clients.walletClient.chain, account: clients.account, nonce,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
const decoded = decodeRevert(e);
|
|
184
|
+
if (this.idempotencyKey)
|
|
185
|
+
await markFailed(this.idempotencyKey, COMMAND, args, decoded.code);
|
|
186
|
+
throw cliError(decoded.code, 'Approve tx failed to submit', decoded.hint);
|
|
187
|
+
}
|
|
188
|
+
// Persist 'submitted' BEFORE waiting for receipt — closes the
|
|
189
|
+
// retry-resend window an agent could otherwise hit.
|
|
190
|
+
if (this.idempotencyKey)
|
|
191
|
+
await markSubmitted(this.idempotencyKey, COMMAND, args, tx);
|
|
192
|
+
const receipt = await clients.publicClient.waitForTransactionReceipt({ hash: tx, timeout: 120_000 });
|
|
193
|
+
if (receipt.status === 'reverted') {
|
|
194
|
+
if (this.idempotencyKey)
|
|
195
|
+
await markFailed(this.idempotencyKey, COMMAND, args, 'TX_REVERTED', tx);
|
|
196
|
+
throw cliError('TX_REVERTED', `Approve tx reverted: ${tx}`);
|
|
197
|
+
}
|
|
198
|
+
const result = {
|
|
199
|
+
txHash: tx,
|
|
200
|
+
token: tokenName,
|
|
201
|
+
spender: spenderAddr,
|
|
202
|
+
owner: clients.account.address,
|
|
203
|
+
requested: fmtAmt(amount),
|
|
204
|
+
previousAllowance: fmtAmt(currentAllowance),
|
|
205
|
+
block: receipt.blockNumber.toString(),
|
|
206
|
+
basescanUrl: cfg.network === 'mainnet'
|
|
207
|
+
? `https://basescan.org/tx/${tx}`
|
|
208
|
+
: `https://sepolia.basescan.org/tx/${tx}`,
|
|
209
|
+
};
|
|
210
|
+
if (this.idempotencyKey)
|
|
211
|
+
await markConfirmed(this.idempotencyKey, COMMAND, args, result, tx);
|
|
212
|
+
emit(result, [
|
|
213
|
+
`✓ Approved ${spenderAddr} to spend ${fmtAmt(amount).formatted} ${tokenName.toUpperCase()}`,
|
|
214
|
+
` tx: ${result.basescanUrl}`,
|
|
215
|
+
` block: ${receipt.blockNumber}`,
|
|
216
|
+
]);
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
this.handleError(err);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=approve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approve.js","sourceRoot":"","sources":["../../src/commands/approve.ts"],"names":[],"mappings":"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"}
|