From b145867ca108277adee4f99d8db42f2d750e2b30 Mon Sep 17 00:00:00 2001 From: manoahLinks Date: Sun, 29 Mar 2026 19:14:19 +0100 Subject: [PATCH 1/2] fix(stellar): unify secret env var to STELLAR_AGENT_SECRET_KEY closes #29 --- .env.example | 2 +- package-lock.json | 9 --------- src/agent/README.md | 4 ++-- src/stellar/README.md | 2 +- src/stellar/client.ts | 4 ++-- tests/unit/stellar/client.test.ts | 6 +++--- 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index a23c178..35639d5 100644 --- a/.env.example +++ b/.env.example @@ -5,7 +5,7 @@ NODE_ENV=development # Stellar STELLAR_NETWORK=testnet STELLAR_RPC_URL=https://soroban-testnet.stellar.org -AGENT_SECRET_KEY=your_agent_stellar_secret_key_here +STELLAR_AGENT_SECRET_KEY=your_agent_stellar_secret_key_here VAULT_CONTRACT_ID=your_deployed_contract_id_here USDC_TOKEN_ADDRESS=testnet_usdc_contract_address_here diff --git a/package-lock.json b/package-lock.json index 8f6fd30..7fa1d71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -94,7 +94,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1614,7 +1613,6 @@ "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.18.0" } @@ -2446,7 +2444,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -3370,7 +3367,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -4364,7 +4360,6 @@ "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", @@ -5790,7 +5785,6 @@ "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@prisma/engines": "5.22.0" }, @@ -6790,7 +6784,6 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -6913,7 +6906,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7422,7 +7414,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/agent/README.md b/src/agent/README.md index fb9d743..4f8b7e7 100644 --- a/src/agent/README.md +++ b/src/agent/README.md @@ -305,7 +305,7 @@ MAX_GAS_PERCENT=0.1 # Max gas as % of amount # Stellar Network STELLAR_NETWORK=testnet # testnet | mainnet | futurenet STELLAR_RPC_URL=https://soroban-testnet.stellar.org -STELLAR_AGENT_SECRET=SBXXXXXX # Agent keypair +STELLAR_AGENT_SECRET_KEY=SBXXXXXX # Agent keypair VAULT_CONTRACT_ID=CXXXXXX # Vault smart contract USDC_TOKEN_ADDRESS=GXXXXXX # USDC token address @@ -339,7 +339,7 @@ DATABASE_URL=postgresql://... grep "Agent Loop" logs/combined.log # Verify environment variables -echo $STELLAR_AGENT_SECRET +echo $STELLAR_AGENT_SECRET_KEY ``` **Protocol scan failing:** diff --git a/src/stellar/README.md b/src/stellar/README.md index 6771af2..a7441b1 100644 --- a/src/stellar/README.md +++ b/src/stellar/README.md @@ -30,7 +30,7 @@ import { ```bash STELLAR_NETWORK=testnet STELLAR_RPC_URL=https://soroban-testnet.stellar.org -STELLAR_AGENT_SECRET=SXXX... +STELLAR_AGENT_SECRET_KEY=SXXX... VAULT_CONTRACT_ID=CXXX... WALLET_ENCRYPTION_KEY=<64_hex_chars> ``` diff --git a/src/stellar/client.ts b/src/stellar/client.ts index 9c0980e..240168a 100644 --- a/src/stellar/client.ts +++ b/src/stellar/client.ts @@ -37,9 +37,9 @@ export function getNetworkPassphrase(): string { */ export function getAgentKeypair(): Keypair { if (!agentKeypair) { - const secret = process.env.STELLAR_AGENT_SECRET; + const secret = process.env.STELLAR_AGENT_SECRET_KEY; if (!secret) { - throw new Error('STELLAR_AGENT_SECRET not configured'); + throw new Error('STELLAR_AGENT_SECRET_KEY not configured'); } agentKeypair = Keypair.fromSecret(secret); } diff --git a/tests/unit/stellar/client.test.ts b/tests/unit/stellar/client.test.ts index 027c386..16cec4b 100644 --- a/tests/unit/stellar/client.test.ts +++ b/tests/unit/stellar/client.test.ts @@ -76,13 +76,13 @@ describe('Stellar Client', () => { // ── getAgentKeypair ─────────────────────────────────────────────────────── describe('getAgentKeypair()', () => { - it('returns a keypair when STELLAR_AGENT_SECRET is configured', () => { - process.env.STELLAR_AGENT_SECRET = 'SMOCK_SECRET_KEY_FOR_TESTS_ONLY'; + it('returns a keypair when STELLAR_AGENT_SECRET_KEY is configured', () => { + process.env.STELLAR_AGENT_SECRET_KEY = 'SMOCK_SECRET_KEY_FOR_TESTS_ONLY'; expect(() => getAgentKeypair()).not.toThrow(); }); it('the returned keypair exposes publicKey()', () => { - process.env.STELLAR_AGENT_SECRET = 'SMOCK_SECRET_KEY_FOR_TESTS_ONLY'; + process.env.STELLAR_AGENT_SECRET_KEY = 'SMOCK_SECRET_KEY_FOR_TESTS_ONLY'; const keypair = getAgentKeypair(); expect(typeof keypair.publicKey()).toBe('string'); }); From ef2074f4c28e102ad1a1bcdb51cc037414a9d4a2 Mon Sep 17 00:00:00 2001 From: manoahLinks Date: Sun, 29 Mar 2026 19:22:45 +0100 Subject: [PATCH 2/2] fix(stellar): correct network passphrase mapping for futurenet closes #31 --- src/stellar/client.ts | 19 +++++++++++++--- tests/unit/stellar/client.test.ts | 36 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/stellar/client.ts b/src/stellar/client.ts index 240168a..6926d1f 100644 --- a/src/stellar/client.ts +++ b/src/stellar/client.ts @@ -8,9 +8,22 @@ import { import { TransactionResult } from './types'; const RPC_URL = process.env.STELLAR_RPC_URL || 'https://soroban-testnet.stellar.org'; -const NETWORK_PASSPHRASE = process.env.STELLAR_NETWORK === 'mainnet' - ? Networks.PUBLIC - : Networks.TESTNET; +export function resolveNetworkPassphrase(network: string | undefined): string { + switch (network?.toLowerCase()) { + case 'mainnet': + return Networks.PUBLIC; + case 'testnet': + return Networks.TESTNET; + case 'futurenet': + return Networks.FUTURENET; + default: + throw new Error( + `Unknown STELLAR_NETWORK: "${network}". Expected "mainnet", "testnet", or "futurenet".` + ); + } +} + +const NETWORK_PASSPHRASE = resolveNetworkPassphrase(process.env.STELLAR_NETWORK); let agentKeypair: Keypair | null = null; let rpcServer: rpc.Server | null = null; diff --git a/tests/unit/stellar/client.test.ts b/tests/unit/stellar/client.test.ts index 16cec4b..31a8440 100644 --- a/tests/unit/stellar/client.test.ts +++ b/tests/unit/stellar/client.test.ts @@ -26,6 +26,7 @@ jest.mock('@stellar/stellar-sdk', () => ({ Networks: { PUBLIC: 'Public Global Stellar Network ; September 2015', TESTNET: 'Test SDF Network ; September 2015', + FUTURENET: 'Test SDF Future Network ; October 2022', }, Transaction: jest.fn(), TransactionBuilder: jest.fn(), @@ -38,6 +39,7 @@ import { getAgentKeypair, submitTransaction, waitForConfirmation, + resolveNetworkPassphrase, } from '../../../src/stellar/client'; describe('Stellar Client', () => { @@ -73,6 +75,40 @@ describe('Stellar Client', () => { }); }); + // ── resolveNetworkPassphrase ─────────────────────────────────────────────── + + describe('resolveNetworkPassphrase()', () => { + it('returns PUBLIC passphrase for mainnet', () => { + expect(resolveNetworkPassphrase('mainnet')).toBe( + 'Public Global Stellar Network ; September 2015', + ); + }); + + it('returns TESTNET passphrase for testnet', () => { + expect(resolveNetworkPassphrase('testnet')).toBe( + 'Test SDF Network ; September 2015', + ); + }); + + it('returns FUTURENET passphrase for futurenet', () => { + expect(resolveNetworkPassphrase('futurenet')).toBe( + 'Test SDF Future Network ; October 2022', + ); + }); + + it('throws for unknown network value', () => { + expect(() => resolveNetworkPassphrase('badnet')).toThrow( + 'Unknown STELLAR_NETWORK: "badnet"', + ); + }); + + it('throws for undefined network value', () => { + expect(() => resolveNetworkPassphrase(undefined)).toThrow( + 'Unknown STELLAR_NETWORK', + ); + }); + }); + // ── getAgentKeypair ─────────────────────────────────────────────────────── describe('getAgentKeypair()', () => {