Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@agent-score/pay",
"version": "0.1.0-rc.14",
"version": "0.1.0-rc.15",
"description": "CLI wallet for one-shell-command agent payments across x402 (Base, Solana) and MPP (Tempo)",
"type": "module",
"main": "./dist/index.js",
Expand Down
28 changes: 28 additions & 0 deletions src/commands/fund.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { setTimeout as sleep } from 'timers/promises';
import qrcode from 'qrcode-terminal';
import * as baseChain from '../chains/base';
import * as solanaChain from '../chains/solana';
import * as tempoChain from '../chains/tempo';
import { type Chain, type Network } from '../constants';
import { loadKeystore } from '../keystore';
import { DEFAULT_WALLET_NAME } from '../paths';
import { emitProgress } from '../progress';

const POLL_INTERVAL_MS = 5_000;
const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
Expand Down Expand Up @@ -87,6 +89,32 @@ export async function fund(input: FundInput): Promise<FundResult> {

const uri = buildQrUri(input.chain, ks.address, input.amountUsd, network);
const initial = await readBalance(input.chain, ks.address, network);

// Surface the receive surface BEFORE the poll loop so the user sees actionable
// info immediately. Without this, fund() silently polls for up to 15 minutes
// and only renders at the end. JSON consumers get the structured event on
// stderr; TTY users additionally see the rendered QR + status message.
emitProgress('funding_started', {
chain: input.chain,
network,
address: ks.address,
amount_usd: input.amountUsd ?? null,
qr_uri: uri,
poll_interval_seconds: POLL_INTERVAL_MS / 1000,
timeout_seconds: DEFAULT_TIMEOUT_MS / 1000,
});
if (process.stderr.isTTY) {
const ascii = await new Promise<string>((resolve) => {
qrcode.generate(uri, { small: true }, (q) => resolve(q));
});
const minutes = Math.round(DEFAULT_TIMEOUT_MS / 60_000);
const seconds = POLL_INTERVAL_MS / 1000;
process.stderr.write(
`\nSend USDC on ${input.chain} (${network}) to:\n ${ks.address}\n\n${ascii}\n` +
`Polling balance every ${seconds}s (timeout ${minutes}m). Send from any wallet, exchange, or fiat onramp; pay will detect the deposit and exit.\n\n`,
);
}

const deadline = Date.now() + DEFAULT_TIMEOUT_MS;
let current = initial;
while (Date.now() < deadline) {
Expand Down
Loading