@agenttech/tpay-cli 0.0.1 → 0.0.2
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 +22 -27
- package/dist/index.js +79 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @agenttech/tpay-cli
|
|
2
2
|
|
|
3
|
-
A CLI for AI agents to send
|
|
3
|
+
A CLI for AI agents to send USDT via the T402 x402 v2 payment protocol on Solana.
|
|
4
4
|
Output defaults to structured JSON. Use `--format text` for human-readable output. Logs go to stderr.
|
|
5
5
|
|
|
6
6
|
## Commands
|
|
@@ -9,7 +9,8 @@ Output defaults to structured JSON. Use `--format text` for human-readable outpu
|
|
|
9
9
|
|---|---|
|
|
10
10
|
| `tpay setup` | Configure wallet keys interactively |
|
|
11
11
|
| `tpay setup --from-env <file>` | Import keys from an env file |
|
|
12
|
-
| `tpay send --to <addr> --amount <n
|
|
12
|
+
| `tpay send --to <addr> --amount <n>` | Send payment |
|
|
13
|
+
| `tpay balance --address <addr>` | Show wallet SOL and USDT balances |
|
|
13
14
|
| `tpay intent status <intent_id>` | Check payment status |
|
|
14
15
|
| `tpay version` | Print version |
|
|
15
16
|
| `tpay help` / `tpay --help` | Show all commands |
|
|
@@ -21,36 +22,39 @@ Global flags:
|
|
|
21
22
|
|
|
22
23
|
```bash
|
|
23
24
|
# JSON output (default, for programmatic use)
|
|
24
|
-
tpay send --to
|
|
25
|
+
tpay send --to <solana-address> --amount 10
|
|
25
26
|
{"status":"success","intent_id":"...","tx_hash":"...","explorer_url":"..."}
|
|
26
27
|
|
|
27
28
|
# Text output (human-readable)
|
|
28
|
-
tpay send --to
|
|
29
|
+
tpay send --to <solana-address> --amount 10 --format text
|
|
29
30
|
status: success
|
|
30
31
|
intent_id: abc123
|
|
31
|
-
tx_hash:
|
|
32
|
+
tx_hash: ...
|
|
32
33
|
explorer_url: https://...
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
```bash
|
|
37
|
+
# Check wallet balance (read-only, no keys needed)
|
|
38
|
+
tpay balance --address <solana-address>
|
|
39
|
+
{"status":"ok","address":"<solana-address>","sol":"0.5","usdt":"100.0"}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Stdin JSON mode: pipe `{"to":"...","amount":"..."}` to `tpay send`.
|
|
36
43
|
|
|
37
44
|
## Supported Chains
|
|
38
45
|
|
|
39
|
-
|
|
|
40
|
-
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
| `base-sepolia` | Base Sepolia (EVM testnet) |
|
|
44
|
-
| `solana` | Solana Mainnet |
|
|
45
|
-
| `solana-devnet` | Solana Devnet |
|
|
46
|
+
| Network |
|
|
47
|
+
|---|
|
|
48
|
+
| Solana Mainnet |
|
|
49
|
+
| Solana Devnet |
|
|
46
50
|
|
|
47
51
|
## Runtime Environment Variables
|
|
48
52
|
|
|
49
53
|
| Variable | Required | Description |
|
|
50
54
|
|---|---|---|
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
55
|
+
| `WALLET_SEED_PHRASE` | Yes | BIP-39 mnemonic seed phrase |
|
|
56
|
+
| `TPAY_PASSPHRASE` | No | Passphrase for decrypting config file (cleared from env after use) |
|
|
57
|
+
| `SOLANA_FEE_PAYER` | No | Override fee payer address (build-time default used if unset) |
|
|
54
58
|
|
|
55
59
|
## Build
|
|
56
60
|
|
|
@@ -66,7 +70,7 @@ bun build --compile src/index.ts --outfile tpay
|
|
|
66
70
|
```bash
|
|
67
71
|
bun install
|
|
68
72
|
bun test
|
|
69
|
-
|
|
73
|
+
WALLET_SEED_PHRASE="..." bun run src/index.ts send --to <solana-address> --amount 1
|
|
70
74
|
```
|
|
71
75
|
|
|
72
76
|
## Adding a New Chain Plugin
|
|
@@ -76,12 +80,3 @@ T402_API_URL=https://... WALLET_EVM_PRIVATE_KEY=0x... bun run src/index.ts send
|
|
|
76
80
|
- [ ] Add to `CHAIN_PLUGIN_LOADERS` in `src/loader.ts`
|
|
77
81
|
- [ ] Add to Supported Chains table above
|
|
78
82
|
- [ ] Test: verify x402 payload structure matches T402 backend
|
|
79
|
-
|
|
80
|
-
## Adding a New Wallet Plugin
|
|
81
|
-
|
|
82
|
-
- [ ] Create `src/plugins/wallets/<name>.ts`
|
|
83
|
-
- [ ] Implement `WalletPlugin` interface (`name`, `getEvmPrivateKey()`, `getSolanaSeed()`)
|
|
84
|
-
- [ ] Add to `WALLET_PLUGINS` map in `src/loader.ts`
|
|
85
|
-
- [ ] Document required env vars above
|
|
86
|
-
- [ ] Ensure key/seed return values are never logged
|
|
87
|
-
- [ ] Test: verify loads when `WALLET_PROVIDER=<name>` is set
|
package/dist/index.js
CHANGED
|
@@ -64009,6 +64009,7 @@ async function runHelp(ctx) {
|
|
|
64009
64009
|
commands: {
|
|
64010
64010
|
setup: 'Configure wallet keys with encryption. Use --from-env <file> to import. Non-interactive: WALLET_SEED_PHRASE="..." TPAY_PASSPHRASE="..." tpay setup',
|
|
64011
64011
|
send: "Send USDC/USDT via T402. Args: --to, --amount",
|
|
64012
|
+
balance: "Show wallet SOL and USDT balances",
|
|
64012
64013
|
"intent status <intent_id>": "Fetch current status of a payment intent",
|
|
64013
64014
|
version: "Print CLI version",
|
|
64014
64015
|
help: "Show this help"
|
|
@@ -64036,7 +64037,7 @@ async function runHelp(ctx) {
|
|
|
64036
64037
|
async function runVersion(ctx) {
|
|
64037
64038
|
output(ctx.format, {
|
|
64038
64039
|
name: "@agenttech/tpay-cli",
|
|
64039
|
-
version: "0.0.
|
|
64040
|
+
version: "0.0.2"
|
|
64040
64041
|
});
|
|
64041
64042
|
return 0;
|
|
64042
64043
|
}
|
|
@@ -64236,7 +64237,6 @@ var CONFIG = {
|
|
|
64236
64237
|
feePayer: ""
|
|
64237
64238
|
}
|
|
64238
64239
|
};
|
|
64239
|
-
console.log("CONFIG", CONFIG);
|
|
64240
64240
|
|
|
64241
64241
|
class SendCommand extends BaseCommand {
|
|
64242
64242
|
async execute(opts) {
|
|
@@ -64344,12 +64344,85 @@ async function runIntentStatus(ctx, intentId) {
|
|
|
64344
64344
|
return command.execute(intentId);
|
|
64345
64345
|
}
|
|
64346
64346
|
|
|
64347
|
+
// src/cli/commands/balance.ts
|
|
64348
|
+
init_index_cjs();
|
|
64349
|
+
var CONFIG3 = {
|
|
64350
|
+
apiUrl: "https://api-staging-t402-pay.agent.tech",
|
|
64351
|
+
solana: {
|
|
64352
|
+
rpcUrl: "https://api.mainnet-beta.solana.com",
|
|
64353
|
+
feePayer: ""
|
|
64354
|
+
}
|
|
64355
|
+
};
|
|
64356
|
+
var USDT_MINT = new $PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");
|
|
64357
|
+
var TOKEN_PROGRAM_ID2 = new $PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
64358
|
+
var LAMPORTS_PER_SOL = 1000000000n;
|
|
64359
|
+
var USDT_DECIMALS = 6;
|
|
64360
|
+
|
|
64361
|
+
class BalanceCommand extends BaseCommand {
|
|
64362
|
+
async execute(opts) {
|
|
64363
|
+
const address3 = this.requireArg(opts.address, "address");
|
|
64364
|
+
let pubkey;
|
|
64365
|
+
try {
|
|
64366
|
+
pubkey = new $PublicKey(address3);
|
|
64367
|
+
} catch {
|
|
64368
|
+
throw new ValidationError(`Invalid Solana address: ${address3}`);
|
|
64369
|
+
}
|
|
64370
|
+
const connection = new $Connection(CONFIG3.solana.rpcUrl);
|
|
64371
|
+
try {
|
|
64372
|
+
this.ctx.logger.debug("Fetching balances", { address: address3 });
|
|
64373
|
+
const [solLamports, tokenAccounts] = await Promise.all([
|
|
64374
|
+
connection.getBalance(pubkey),
|
|
64375
|
+
connection.getParsedTokenAccountsByOwner(pubkey, { mint: USDT_MINT, programId: TOKEN_PROGRAM_ID2 })
|
|
64376
|
+
]);
|
|
64377
|
+
let usdtRaw = 0n;
|
|
64378
|
+
for (const { account } of tokenAccounts.value) {
|
|
64379
|
+
const amount = account.data.parsed?.info?.tokenAmount?.amount;
|
|
64380
|
+
if (amount)
|
|
64381
|
+
usdtRaw += BigInt(amount);
|
|
64382
|
+
}
|
|
64383
|
+
output(this.ctx.format, {
|
|
64384
|
+
status: "ok",
|
|
64385
|
+
address: address3,
|
|
64386
|
+
sol: formatLamports(BigInt(solLamports)),
|
|
64387
|
+
usdt: formatToken(usdtRaw, USDT_DECIMALS)
|
|
64388
|
+
});
|
|
64389
|
+
return 0;
|
|
64390
|
+
} catch (error) {
|
|
64391
|
+
if (error instanceof ValidationError)
|
|
64392
|
+
throw error;
|
|
64393
|
+
if (error instanceof Error && error.message.includes("Server error")) {
|
|
64394
|
+
throw new NetworkError(error.message, error);
|
|
64395
|
+
}
|
|
64396
|
+
throw error;
|
|
64397
|
+
}
|
|
64398
|
+
}
|
|
64399
|
+
}
|
|
64400
|
+
function formatLamports(lamports) {
|
|
64401
|
+
const whole = lamports / LAMPORTS_PER_SOL;
|
|
64402
|
+
const frac = lamports % LAMPORTS_PER_SOL;
|
|
64403
|
+
if (frac === 0n)
|
|
64404
|
+
return whole.toString();
|
|
64405
|
+
return `${whole}.${frac.toString().padStart(9, "0").replace(/0+$/, "")}`;
|
|
64406
|
+
}
|
|
64407
|
+
function formatToken(raw, decimals) {
|
|
64408
|
+
const divisor = 10n ** BigInt(decimals);
|
|
64409
|
+
const whole = raw / divisor;
|
|
64410
|
+
const frac = raw % divisor;
|
|
64411
|
+
if (frac === 0n)
|
|
64412
|
+
return whole.toString();
|
|
64413
|
+
return `${whole}.${frac.toString().padStart(decimals, "0").replace(/0+$/, "")}`;
|
|
64414
|
+
}
|
|
64415
|
+
async function runBalance(ctx, opts) {
|
|
64416
|
+
const command = new BalanceCommand(ctx);
|
|
64417
|
+
return command.execute(opts);
|
|
64418
|
+
}
|
|
64419
|
+
|
|
64347
64420
|
// src/cli/program.ts
|
|
64348
64421
|
function createProgram() {
|
|
64349
64422
|
const program2 = new Command;
|
|
64350
64423
|
const versionInfo = {
|
|
64351
64424
|
name: "@agenttech/tpay-cli",
|
|
64352
|
-
version: "0.0.
|
|
64425
|
+
version: "0.0.2"
|
|
64353
64426
|
};
|
|
64354
64427
|
const versionString = typeof versionInfo === "string" ? versionInfo : versionInfo.version;
|
|
64355
64428
|
program2.name("tpay").version(versionString, "-v, --version", "Show version").option("--verbose", "Enable debug logging to stderr").option("--format <fmt>", "Output format: json | text", "json");
|
|
@@ -64389,6 +64462,9 @@ function registerCommands(program2) {
|
|
|
64389
64462
|
await loadEnv();
|
|
64390
64463
|
process.exitCode = await runSend(getContext(), opts);
|
|
64391
64464
|
});
|
|
64465
|
+
program2.command("balance").description("Show wallet SOL and USDT balances").option("--address <addr>", "Solana wallet address to query").action(async (opts) => {
|
|
64466
|
+
process.exitCode = await runBalance(getContext(), opts);
|
|
64467
|
+
});
|
|
64392
64468
|
const intentCmd = program2.command("intent").description("Payment intent operations");
|
|
64393
64469
|
intentCmd.command("status [intentId]").description("Check payment intent status").action(async (intentId) => {
|
|
64394
64470
|
process.exitCode = await runIntentStatus(getContext(), intentId);
|