From 2bd5e66b366fef039406413b5b514dfa0d874440 Mon Sep 17 00:00:00 2001 From: dezzy-music Date: Tue, 13 Oct 2026 20:30:59 -0600 Subject: [PATCH] feat(client): add --contract and --rpc flags with env var fallbacks (closes #183) --- PROGRESS.md | 8 ++++++++ client/README.md | 19 ++++++++++++++++++- client/src/index.ts | 42 +++++++++++++++++++++++++++++------------- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index bab63fb..89c861f 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -319,3 +319,11 @@ is closed — see [CONTRIBUTING.md](CONTRIBUTING.md). - **By:** ALLEN-AYODEJI - **Closes:** N/A - **Status:** Merged. + +### Testnet read client — configurable contract ID and RPC endpoint + +- **What:** Replaces the hard-coded `CONTRACT_ID` and `RPC_URL` in `client/src/index.ts` with `--contract` and `--rpc` CLI flags, with `DEPRADAR_CONTRACT_ID` and `DEPRADAR_RPC_URL` environment variables as fallbacks, defaulting to the current testnet deployment values. Updates `client/README.md` with usage examples and options table. +- **Verified:** `npm run typecheck` passes in `client/`. Tested live reads against Stellar testnet with default flags and explicit `--contract` and `--rpc` options. +- **By:** dezzy-music +- **Closes:** #183 +- **Status:** PR open. diff --git a/client/README.md b/client/README.md index 5b6705e..0e13d3b 100644 --- a/client/README.md +++ b/client/README.md @@ -6,7 +6,8 @@ submitted against it via `get_claim`, and prints the result. No transactions are submitted, no funded account is required — reads are simulated calls against the RPC endpoint. -Contract ID: `CCPRQANY467KKE4ROKCNW6TH3LY3EPVFRXIXJ5V4VCYHLJKWZPOZYQJQ` +Default Contract ID: `CCPRQANY467KKE4ROKCNW6TH3LY3EPVFRXIXJ5V4VCYHLJKWZPOZYQJQ` +Default RPC URL: `https://soroban-testnet.stellar.org` ## Usage @@ -14,8 +15,24 @@ Contract ID: `CCPRQANY467KKE4ROKCNW6TH3LY3EPVFRXIXJ5V4VCYHLJKWZPOZYQJQ` npm install npm start # defaults to bounty-id 1 npm start -- --bounty-id 2 + +# Point to custom contract or RPC endpoint via CLI flags: +npm start -- --bounty-id 1 --contract --rpc + +# Or configure via environment variables: +export DEPRADAR_CONTRACT_ID="" +export DEPRADAR_RPC_URL="" +npm start -- --bounty-id 1 ``` +### Options + +| Flag | Env Var | Description | Default | +|---|---|---|---| +| `--bounty-id ` | — | Bounty ID to inspect (non-negative integer) | `1` | +| `--contract ` | `DEPRADAR_CONTRACT_ID` | Soroban contract ID | `CCPRQANY...` (testnet deployment) | +| `--rpc ` | `DEPRADAR_RPC_URL` | Stellar RPC endpoint URL | `https://soroban-testnet.stellar.org` | + Bounty `1` is real on-chain data: the `create_bounty` -> `submit_claim` (x2) -> `reject_claim` -> `release` cycle recorded in [PROGRESS.md](../PROGRESS.md), so it shows one rejected and one accepted diff --git a/client/src/index.ts b/client/src/index.ts index d2f213b..6b693e2 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -5,6 +5,12 @@ * * Usage: * npm start -- --bounty-id 1 + * npm start -- --bounty-id 1 --contract --rpc + * + * Flags and Environment Variables: + * --bounty-id Bounty ID to inspect (default: 1) + * --contract Contract ID (fallback: DEPRADAR_CONTRACT_ID env var, default: testnet deployment) + * --rpc Stellar RPC endpoint (fallback: DEPRADAR_RPC_URL env var, default: testnet RPC) * * --bounty-id defaults to 1, the bounty used in the on-chain * create_bounty -> submit_claim -> reject_claim -> release cycle described @@ -12,10 +18,16 @@ */ import { rpc } from "@stellar/stellar-sdk"; -const CONTRACT_ID = "CCPRQANY467KKE4ROKCNW6TH3LY3EPVFRXIXJ5V4VCYHLJKWZPOZYQJQ"; -const RPC_URL = "https://soroban-testnet.stellar.org"; +const DEFAULT_CONTRACT_ID = "CCPRQANY467KKE4ROKCNW6TH3LY3EPVFRXIXJ5V4VCYHLJKWZPOZYQJQ"; +const DEFAULT_RPC_URL = "https://soroban-testnet.stellar.org"; + +interface ClientConfig { + bountyId: number; + contractId: string; + rpcUrl: string; +} -function parseArgs(argv: string[]): { bountyId: number } { +function parseArgs(argv: string[]): ClientConfig { const flags = new Map(); for (let i = 0; i < argv.length; i += 1) { const arg = argv[i]; @@ -25,26 +37,30 @@ function parseArgs(argv: string[]): { bountyId: number } { } } - const bountyId = Number(flags.get("bounty-id") ?? "1"); + const bountyIdRaw = flags.get("bounty-id") ?? "1"; + const bountyId = Number(bountyIdRaw); if (!Number.isInteger(bountyId) || bountyId < 0) { - throw new Error(`--bounty-id must be a non-negative integer, got: ${flags.get("bounty-id")}`); + throw new Error(`--bounty-id must be a non-negative integer, got: ${bountyIdRaw}`); } - return { bountyId }; + const contractId = flags.get("contract") ?? process.env.DEPRADAR_CONTRACT_ID ?? DEFAULT_CONTRACT_ID; + const rpcUrl = flags.get("rpc") ?? process.env.DEPRADAR_RPC_URL ?? DEFAULT_RPC_URL; + + return { bountyId, contractId, rpcUrl }; } async function main() { - const { bountyId } = parseArgs(process.argv.slice(2)); - const server = new rpc.Server(RPC_URL); + const { bountyId, contractId, rpcUrl } = parseArgs(process.argv.slice(2)); + const server = new rpc.Server(rpcUrl); const health = await server.getHealth(); - console.log(`Connected to ${RPC_URL} (status: ${health.status}, latest ledger: ${health.latestLedger})`); - console.log(`Contract: ${CONTRACT_ID}`); + console.log(`Connected to ${rpcUrl} (status: ${health.status}, latest ledger: ${health.latestLedger})`); + console.log(`Contract: ${contractId}`); - const { result: count } = await server.queryContract(CONTRACT_ID, "bounty_count", {}); + const { result: count } = await server.queryContract(contractId, "bounty_count", {}); console.log(`Bounties created: ${count}\n`); - const { result: bounty } = await server.queryContract(CONTRACT_ID, "get_bounty", { bounty_id: bountyId }); + const { result: bounty } = await server.queryContract(contractId, "get_bounty", { bounty_id: bountyId }); console.log(`get_bounty(${bountyId}) =>`); if (bounty === null) { console.log(" (no bounty with this ID)"); @@ -54,7 +70,7 @@ async function main() { const claimCount = Number((bounty as { claim_count: number }).claim_count); for (let claimId = 0; claimId < claimCount; claimId += 1) { - const { result: claim } = await server.queryContract(CONTRACT_ID, "get_claim", { + const { result: claim } = await server.queryContract(contractId, "get_claim", { bounty_id: bountyId, claim_id: claimId, });