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
85 changes: 85 additions & 0 deletions src/config/assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// config/assets.js
//
// Network-aware asset registry. USDC stays the default so existing
// USDC-only flows (and existing Transaction rows with no currency set)
// keep working unchanged. Issuer addresses below are Circle's official
// EURC issuers (verified against developers.circle.com); XLM is native
// and has no issuer.

const REGISTRY = {
testnet: {
USDC: {
code: "USDC",
issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
decimals: 7,
displayName: "USD Coin",
isDefault: true,
},
EURC: {
code: "EURC",
issuer: "GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO",
decimals: 7,
displayName: "Euro Coin",
isDefault: false,
},
XLM: {
code: "XLM",
issuer: null,
decimals: 7,
displayName: "Stellar Lumens",
isDefault: false,
},
},
mainnet: {
USDC: {
code: "USDC",
issuer: "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
decimals: 7,
displayName: "USD Coin",
isDefault: true,
},
EURC: {
code: "EURC",
issuer: "GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2",
decimals: 7,
displayName: "Euro Coin",
isDefault: false,
},
XLM: {
code: "XLM",
issuer: null,
decimals: 7,
displayName: "Stellar Lumens",
isDefault: false,
},
},
};

const NETWORK = process.env.STELLAR_NETWORK || "testnet";

export const getRegistry = (network = NETWORK) => {
const registry = REGISTRY[network];
if (!registry) {
throw new Error(`Unknown Stellar network: ${network}`);
}
return registry;
};

export const getAssetConfig = (code, network = NETWORK) => {
const registry = getRegistry(network);
return registry[code] || null;
};

export const getSupportedCodes = (network = NETWORK) =>
Object.keys(getRegistry(network));

export const getDefaultAssetCode = (network = NETWORK) => {
const registry = getRegistry(network);
const entry = Object.values(registry).find((a) => a.isDefault);
return entry ? entry.code : "USDC";
};

export const isAssetSupported = (code, network = NETWORK) =>
!!getAssetConfig(code, network);

export { REGISTRY };
41 changes: 41 additions & 0 deletions src/config/assets.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { getRegistry, getAssetConfig, getSupportedCodes, getDefaultAssetCode, isAssetSupported } from "./assets.js";

describe("asset registry resolution", () => {
it("resolves USDC as the default asset on testnet", () => {
expect(getDefaultAssetCode("testnet")).toBe("USDC");
const usdc = getAssetConfig("USDC", "testnet");
expect(usdc.isDefault).toBe(true);
expect(usdc.issuer).toBe("GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5");
});

it("resolves USDC as the default asset on mainnet, with a different issuer than testnet", () => {
expect(getDefaultAssetCode("mainnet")).toBe("USDC");
const usdc = getAssetConfig("USDC", "mainnet");
expect(usdc.issuer).toBe("GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN");
expect(usdc.issuer).not.toBe(getAssetConfig("USDC", "testnet").issuer);
});

it("resolves EURC with the correct issuer per network", () => {
expect(getAssetConfig("EURC", "testnet").issuer).toBe("GB3Q6QDZYTHWT7E5PVS3W7FUT5GVAFC5KSZFFLPU25GO7VTC3NM2ZTVO");
expect(getAssetConfig("EURC", "mainnet").issuer).toBe("GDHU6WRG4IEQXM5NZ4BMPKOXHW76MZM4Y2IEMFDVXBSDP6SJY4ITNPP2");
});

it("resolves XLM as native (no issuer) on both networks", () => {
expect(getAssetConfig("XLM", "testnet").issuer).toBeNull();
expect(getAssetConfig("XLM", "mainnet").issuer).toBeNull();
});

it("lists all supported codes per network", () => {
expect(getSupportedCodes("testnet").sort()).toEqual(["EURC", "USDC", "XLM"]);
expect(getSupportedCodes("mainnet").sort()).toEqual(["EURC", "USDC", "XLM"]);
});

it("reports unsupported codes as unsupported", () => {
expect(isAssetSupported("DOGE", "testnet")).toBe(false);
expect(getAssetConfig("DOGE", "testnet")).toBeNull();
});

it("throws a clear error for an unknown network", () => {
expect(() => getRegistry("devnet")).toThrow("Unknown Stellar network: devnet");
});
});
Loading
Loading