From 34062ae9841e2bc594fd46ad8f8d13348f03edec Mon Sep 17 00:00:00 2001 From: 0xmegie <0xmegie@users.noreply.github.com> Date: Tue, 23 Jun 2026 18:50:14 +0100 Subject: [PATCH 1/3] Add indexer contract manifest sync --- apps/s03-indexer/package.json | 2 + apps/s03-indexer/scripts/sync-contracts.ts | 403 +++++++++++++++++++++ 2 files changed, 405 insertions(+) create mode 100644 apps/s03-indexer/scripts/sync-contracts.ts diff --git a/apps/s03-indexer/package.json b/apps/s03-indexer/package.json index 8160c90..8a81c67 100644 --- a/apps/s03-indexer/package.json +++ b/apps/s03-indexer/package.json @@ -6,6 +6,8 @@ "scripts": { "build": "subql build", "codegen": "subql codegen", + "sync:contracts:testnet": "bun run scripts/sync-contracts.ts --network testnet", + "sync:contracts:local": "bun run scripts/sync-contracts.ts --network local", "start": "docker compose pull && docker compose up --remove-orphans", "start:docker": "bun run start", "dev": "bun run codegen && bun run build && bun run start", diff --git a/apps/s03-indexer/scripts/sync-contracts.ts b/apps/s03-indexer/scripts/sync-contracts.ts new file mode 100644 index 0000000..b839a3a --- /dev/null +++ b/apps/s03-indexer/scripts/sync-contracts.ts @@ -0,0 +1,403 @@ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; +import path from "path"; + +type EnvMap = Record; + +type ContractsJson = { + network?: string; + network_passphrase?: string; + contracts?: Record; +}; + +type MarketConfig = { + name: string; + marketToken: string; + indexToken: string; + longToken: string; + shortToken: string; +}; + +const CORE_CONTRACT_KEYS = [ + "role_store", + "data_store", + "oracle", + "market_factory", + "deposit_handler", + "withdrawal_handler", + "order_handler", + "liquidation_handler", + "adl_handler", + "fee_handler", + "referral_storage", + "reader", + "exchange_router", +] as const; + +const TOKEN_KEYS = ["TUSDC", "TWBTC", "TETH", "TXLM", "faucet"] as const; + +const NETWORK_DEFAULTS: Record< + string, + { horizonEndpoint: string; sorobanRpcEndpoint: string; networkPassphrase: string } +> = { + testnet: { + horizonEndpoint: "https://horizon-testnet.stellar.org", + sorobanRpcEndpoint: "https://soroban-testnet.stellar.org", + networkPassphrase: "Test SDF Network ; September 2015", + }, + local: { + horizonEndpoint: "http://host.docker.internal:8000", + sorobanRpcEndpoint: "http://host.docker.internal:8000/soroban/rpc", + networkPassphrase: "Standalone Network ; February 2017", + }, +}; + +const args = parseArgs(process.argv.slice(2)); +const network = (args.network ?? args._[0] ?? "testnet").toLowerCase(); +const packageRoot = path.resolve(import.meta.dir, ".."); +const repoRoot = path.resolve(packageRoot, "../.."); +const contractsRepoPath = resolveContractsRepoPath(args.contractsRepo); +const outputPath = path.resolve( + packageRoot, + args.output ?? `config/contracts.${network}.json`, +); + +const contractIdsPath = path.join( + contractsRepoPath, + ".stellar", + "contract-ids", + `${network}.json`, +); +const deployEnvPath = path.join(contractsRepoPath, ".deployed", `${network}.env`); +const tokensEnvPath = path.join( + contractsRepoPath, + ".deployed", + `tokens-${network}.env`, +); +const frontendEnvPath = path.join( + contractsRepoPath, + ".deployed", + `frontend-${network}.env`, +); +const frontendTsPath = path.join( + contractsRepoPath, + ".deployed", + `frontend-${network}.ts`, +); + +main(); + +function main(): void { + const missingFiles = [ + contractIdsPath, + deployEnvPath, + tokensEnvPath, + frontendEnvPath, + ].filter((file) => !existsSync(file)); + + if (missingFiles.length > 0) { + fail( + [ + `Missing deployment output for network "${network}".`, + `Contracts repo: ${contractsRepoPath}`, + "Expected files:", + ...missingFiles.map((file) => ` - ${path.relative(contractsRepoPath, file)}`), + "Deploy/bootstrap contracts first, or set SO4_CONTRACTS_REPO to the contracts repo path.", + ].join("\n"), + ); + } + + const contractIds = readJson(contractIdsPath); + const deployedEnv = readEnvFile(deployEnvPath); + const tokenEnv = readEnvFile(tokensEnvPath); + const frontendEnv = readEnvFile(frontendEnvPath); + const frontendTs = existsSync(frontendTsPath) ? readFileSync(frontendTsPath, "utf8") : ""; + + const networkName = deployedEnv.NETWORK ?? contractIds.network ?? network; + const defaults = NETWORK_DEFAULTS[networkName] ?? NETWORK_DEFAULTS[network]; + const networkPassphrase = + process.env.INDEXER_NETWORK_PASSPHRASE ?? + contractIds.network_passphrase ?? + readTsString(frontendTs, "networkPassphrase") ?? + defaults?.networkPassphrase; + const horizonEndpoint = + process.env.INDEXER_HORIZON_ENDPOINT ?? + process.env.ENDPOINT ?? + defaults?.horizonEndpoint; + const sorobanRpcEndpoint = + process.env.INDEXER_SOROBAN_RPC_ENDPOINT ?? + process.env.SOROBAN_ENDPOINT ?? + readTsString(frontendTs, "rpcUrl") ?? + defaults?.sorobanRpcEndpoint; + + requireValue(networkName, "network name"); + requireValue(networkPassphrase, "network passphrase"); + requireValue(horizonEndpoint, "Horizon endpoint"); + requireValue(sorobanRpcEndpoint, "Soroban RPC endpoint"); + + const coreContracts = collectCoreContracts(deployedEnv, frontendEnv, contractIds); + const tokens = collectTokens(tokenEnv, frontendEnv); + const { markets, warnings } = collectMarkets(deployedEnv); + + const config = { + generatedAt: new Date().toISOString(), + source: { + contractsRepoPath, + files: { + contractIds: path.relative(contractsRepoPath, contractIdsPath), + deployedEnv: path.relative(contractsRepoPath, deployEnvPath), + tokensEnv: path.relative(contractsRepoPath, tokensEnvPath), + frontendEnv: path.relative(contractsRepoPath, frontendEnvPath), + frontendTs: existsSync(frontendTsPath) + ? path.relative(contractsRepoPath, frontendTsPath) + : null, + }, + }, + network: { + name: networkName, + passphrase: networkPassphrase, + horizonEndpoint, + sorobanRpcEndpoint, + }, + contracts: coreContracts, + tokens, + markets, + warnings, + }; + + mkdirSync(path.dirname(outputPath), { recursive: true }); + writeFileSync(outputPath, `${JSON.stringify(config, null, 2)}\n`); + + console.log(`Synced ${networkName} contracts to ${path.relative(repoRoot, outputPath)}`); + console.log(`Core contracts: ${Object.keys(coreContracts).length}`); + console.log(`Tokens: ${Object.keys(tokens).length}`); + console.log(`Markets: ${markets.length}`); + for (const warning of warnings) { + console.warn(`Warning: ${warning}`); + } +} + +function collectCoreContracts( + deployedEnv: EnvMap, + frontendEnv: EnvMap, + contractIds: ContractsJson, +): Record<(typeof CORE_CONTRACT_KEYS)[number], string> { + const contracts = {} as Record<(typeof CORE_CONTRACT_KEYS)[number], string>; + const missing: string[] = []; + + for (const key of CORE_CONTRACT_KEYS) { + const envKey = key.toUpperCase(); + const value = + deployedEnv[envKey] ?? + frontendEnv[envKey] ?? + contractIds.contracts?.[key]; + + if (!value) { + missing.push(envKey); + continue; + } + assertContractId(value, envKey); + contracts[key] = value; + } + + if (missing.length > 0) { + fail(`Missing required core contract IDs: ${missing.join(", ")}`); + } + + return contracts; +} + +function collectTokens( + tokenEnv: EnvMap, + frontendEnv: EnvMap, +): Record<(typeof TOKEN_KEYS)[number], string> { + const tokens = {} as Record<(typeof TOKEN_KEYS)[number], string>; + const missing: string[] = []; + + for (const key of TOKEN_KEYS) { + const envKey = key === "faucet" ? "FAUCET" : key; + const frontendKey = key === "faucet" ? "FAUCET" : `TOKEN_${key}`; + const value = tokenEnv[envKey] ?? frontendEnv[frontendKey]; + + if (!value) { + missing.push(envKey); + continue; + } + assertContractId(value, envKey); + tokens[key] = value; + } + + if (missing.length > 0) { + fail(`Missing required test token contract IDs: ${missing.join(", ")}`); + } + + return tokens; +} + +function collectMarkets(deployedEnv: EnvMap): { markets: MarketConfig[]; warnings: string[] } { + const warnings: string[] = []; + const marketNames = new Set(); + + for (const key of Object.keys(deployedEnv)) { + const match = key.match(/^MARKET_TOKEN_(.+)_(LONG|SHORT|INDEX)$/); + if (match) { + marketNames.add(match[1]); + } + } + + const markets: MarketConfig[] = []; + const incomplete: string[] = []; + + for (const envName of [...marketNames].sort()) { + const displayName = envName.replace("_", "/"); + const marketToken = deployedEnv[`MARKET_TOKEN_${envName}`]; + const indexToken = deployedEnv[`MARKET_TOKEN_${envName}_INDEX`]; + const longToken = deployedEnv[`MARKET_TOKEN_${envName}_LONG`]; + const shortToken = deployedEnv[`MARKET_TOKEN_${envName}_SHORT`]; + const missing = [ + [`MARKET_TOKEN_${envName}`, marketToken], + [`MARKET_TOKEN_${envName}_INDEX`, indexToken], + [`MARKET_TOKEN_${envName}_LONG`, longToken], + [`MARKET_TOKEN_${envName}_SHORT`, shortToken], + ] + .filter(([, value]) => !value) + .map(([key]) => key); + + if (missing.length > 0) { + incomplete.push(`${displayName}: ${missing.join(", ")}`); + continue; + } + + assertContractId(marketToken, `MARKET_TOKEN_${envName}`); + assertContractId(indexToken, `MARKET_TOKEN_${envName}_INDEX`); + assertContractId(longToken, `MARKET_TOKEN_${envName}_LONG`); + assertContractId(shortToken, `MARKET_TOKEN_${envName}_SHORT`); + markets.push({ name: displayName, marketToken, indexToken, longToken, shortToken }); + } + + if (incomplete.length > 0) { + warnings.push( + `Some MARKET_TOKEN_* values are missing. This is only expected before market bootstrap: ${incomplete.join("; ")}`, + ); + } + + if (markets.length === 0) { + warnings.push( + "No complete market token triplets found. Run market bootstrap before indexing market-specific contract events.", + ); + } + + return { markets, warnings }; +} + +function resolveContractsRepoPath(cliPath?: string): string { + const configured = + cliPath ?? + process.env.SO4_CONTRACTS_REPO ?? + process.env.CONTRACTS_REPO_PATH ?? + process.env.CONTRACTS_REPO; + + if (configured) { + return path.resolve(configured); + } + + const candidates = [ + path.resolve(repoRoot, "../contracts"), + path.resolve(packageRoot, "../contracts"), + "/home/sunny/zero/so4-market-project/contracts", + ]; + + const found = candidates.find((candidate) => + existsSync(path.join(candidate, ".deployed")), + ); + + return found ?? candidates[0]; +} + +function readEnvFile(filePath: string): EnvMap { + const contents = readFileSync(filePath, "utf8"); + const env: EnvMap = {}; + + for (const line of contents.split(/\r?\n/)) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) { + continue; + } + + const separator = trimmed.indexOf("="); + if (separator === -1) { + continue; + } + + const key = trimmed.slice(0, separator).trim(); + const rawValue = trimmed.slice(separator + 1).trim(); + env[key] = stripQuotes(rawValue); + } + + return env; +} + +function readJson(filePath: string): T { + try { + return JSON.parse(readFileSync(filePath, "utf8")) as T; + } catch (error) { + fail(`Could not parse ${filePath}: ${formatError(error)}`); + } +} + +function readTsString(contents: string, propertyName: string): string | undefined { + const match = contents.match(new RegExp(`${propertyName}:\\s*"([^"]+)"`)); + return match?.[1]; +} + +function requireValue(value: string | undefined, label: string): asserts value is string { + if (!value) { + fail(`Missing ${label}. Set it in deployment output or an INDEXER_* environment override.`); + } +} + +function assertContractId(value: string, label: string): void { + if (!/^C[A-Z2-7]{55}$/.test(value)) { + fail(`${label} is not a valid Stellar contract ID: ${value}`); + } +} + +function stripQuotes(value: string): string { + if ( + (value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'")) + ) { + return value.slice(1, -1); + } + return value; +} + +function parseArgs(argv: string[]): Record & { _: string[] } { + const parsed: Record & { _: string[] } = { _: [] }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (!arg.startsWith("--")) { + parsed._.push(arg); + continue; + } + + const [rawKey, inlineValue] = arg.slice(2).split("=", 2); + const key = rawKey.replace(/-([a-z])/g, (_, char: string) => char.toUpperCase()); + const value = inlineValue ?? argv[index + 1]; + if (inlineValue === undefined) { + index += 1; + } + parsed[key] = value; + } + + return parsed; +} + +function formatError(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +function fail(message: string): never { + console.error(message); + process.exit(1); +} From 5291b674109b5db010c1b51b471b24b615ccd4bb Mon Sep 17 00:00:00 2001 From: 0xmegie <0xmegie@users.noreply.github.com> Date: Tue, 23 Jun 2026 18:51:05 +0100 Subject: [PATCH 2/3] Read indexer contract config at build time --- apps/s03-indexer/project.ts | 109 ++++++++++++------ .../src/mappings/mappingHandlers.ts | 5 + 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/apps/s03-indexer/project.ts b/apps/s03-indexer/project.ts index a010152..38698bd 100644 --- a/apps/s03-indexer/project.ts +++ b/apps/s03-indexer/project.ts @@ -3,9 +3,9 @@ import { StellarHandlerKind, StellarProject, } from "@subql/types-stellar"; -import { Horizon } from "@stellar/stellar-sdk"; import * as dotenv from 'dotenv'; +import { existsSync, readFileSync } from 'fs'; import path from 'path'; const mode = process.env.NODE_ENV || 'production'; @@ -14,12 +14,38 @@ const mode = process.env.NODE_ENV || 'production'; const dotenvPath = path.resolve(__dirname, `.env${mode !== 'production' ? `.${mode}` : ''}`); dotenv.config({ path: dotenvPath, quiet: true }); +type IndexerContractsConfig = { + network?: { + name?: string; + passphrase?: string; + horizonEndpoint?: string; + sorobanRpcEndpoint?: string; + }; + contracts?: Record; + tokens?: Record; + markets?: Array<{ + name: string; + marketToken: string; + indexToken: string; + longToken: string; + shortToken: string; + }>; +}; + +const contractConfig = loadContractConfig(); const endpoint = - process.env.ENDPOINT ?? "https://horizon-testnet.stellar.org"; + process.env.ENDPOINT ?? + contractConfig?.network?.horizonEndpoint ?? + "https://horizon-testnet.stellar.org"; const chainId = - process.env.CHAIN_ID ?? "Test SDF Network ; September 2015"; + process.env.CHAIN_ID ?? + contractConfig?.network?.passphrase ?? + "Test SDF Network ; September 2015"; const sorobanEndpoint = - process.env.SOROBAN_ENDPOINT ?? "https://soroban-testnet.stellar.org"; + process.env.SOROBAN_ENDPOINT ?? + contractConfig?.network?.sorobanRpcEndpoint ?? + "https://soroban-testnet.stellar.org"; +const indexedContractIds = getIndexedContractIds(contractConfig); /* This is your project configuration */ const project: StellarProject = { @@ -68,40 +94,13 @@ const project: StellarProject = { startBlock: 228206, mapping: { file: "./dist/index.js", - handlers: [ - { - handler: "handleOperation", - kind: StellarHandlerKind.Operation, - filter: { - type: Horizon.HorizonApi.OperationResponseType.payment, - }, - }, - { - handler: "handleCredit", - kind: StellarHandlerKind.Effects, - filter: { - type: "account_credited", - }, + handlers: indexedContractIds.map((contractId) => ({ + handler: "handleEvent", + kind: StellarHandlerKind.Event, + filter: { + contractId, }, - { - handler: "handleDebit", - kind: StellarHandlerKind.Effects, - filter: { - type: "account_debited", - }, - }, - { - handler: "handleEvent", - kind: StellarHandlerKind.Event, - filter: { - /* You can optionally specify a smart contract address here - contractId: "" */ - topics: [ - "transfer", // Topic signature(s) for the events, there can be up to 4 - ], - }, - }, - ], + })), }, }, ], @@ -109,3 +108,39 @@ const project: StellarProject = { // Must set default to the project instance export default project; + +function loadContractConfig(): IndexerContractsConfig | undefined { + const network = process.env.INDEXER_NETWORK ?? "testnet"; + const configPath = process.env.INDEXER_CONTRACTS_CONFIG + ? path.resolve(process.cwd(), process.env.INDEXER_CONTRACTS_CONFIG) + : path.resolve(__dirname, "config", `contracts.${network}.json`); + + if (!existsSync(configPath)) { + return undefined; + } + + return JSON.parse(readFileSync(configPath, "utf8")) as IndexerContractsConfig; +} + +function getIndexedContractIds(config: IndexerContractsConfig | undefined): string[] { + if (!config) { + const fallbackContractId = process.env.INDEXER_CONTRACT_ID; + return fallbackContractId ? [fallbackContractId] : []; + } + + const ids = new Set(); + for (const value of Object.values(config.contracts ?? {})) { + ids.add(value); + } + for (const value of Object.values(config.tokens ?? {})) { + ids.add(value); + } + for (const market of config.markets ?? []) { + ids.add(market.marketToken); + ids.add(market.indexToken); + ids.add(market.longToken); + ids.add(market.shortToken); + } + + return [...ids].sort(); +} diff --git a/apps/s03-indexer/src/mappings/mappingHandlers.ts b/apps/s03-indexer/src/mappings/mappingHandlers.ts index 8d26b8a..a3969e0 100644 --- a/apps/s03-indexer/src/mappings/mappingHandlers.ts +++ b/apps/s03-indexer/src/mappings/mappingHandlers.ts @@ -80,6 +80,11 @@ export async function handleEvent(event: SorobanEvent): Promise { // Get data from the event // The transfer event has the following payload \[env, from, to\] + if (event.topic.length < 3) { + logger.info(`Event ${event.id} does not match transfer topic shape, skipping`); + return; + } + const { topic: [env, from, to], } = event; From 6ba1195526e43c6dfa7be86314be051a59dd6c96 Mon Sep 17 00:00:00 2001 From: 0xmegie <0xmegie@users.noreply.github.com> Date: Tue, 23 Jun 2026 18:52:37 +0100 Subject: [PATCH 3/3] Document synced indexer contract config --- apps/s03-indexer/.env.example | 5 ++ apps/s03-indexer/README.md | 41 ++++++++++++ .../s03-indexer/config/contracts.testnet.json | 65 +++++++++++++++++++ apps/s03-indexer/package.json | 2 +- 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 apps/s03-indexer/config/contracts.testnet.json diff --git a/apps/s03-indexer/.env.example b/apps/s03-indexer/.env.example index 3872c01..7c13f7d 100644 --- a/apps/s03-indexer/.env.example +++ b/apps/s03-indexer/.env.example @@ -2,9 +2,14 @@ ENDPOINT=https://horizon-testnet.stellar.org CHAIN_ID="Test SDF Network ; September 2015" SOROBAN_ENDPOINT=https://soroban-testnet.stellar.org +INDEXER_NETWORK=testnet +# INDEXER_CONTRACTS_CONFIG=config/contracts.testnet.json +# SO4_CONTRACTS_REPO=../contracts # Local standalone defaults. Uncomment these when running against a local # stellar/quickstart or standalone network instead of public testnet. # ENDPOINT=http://host.docker.internal:8000 # CHAIN_ID="Standalone Network ; February 2017" # SOROBAN_ENDPOINT=http://host.docker.internal:8000/soroban/rpc +# INDEXER_NETWORK=local +# INDEXER_CONTRACTS_CONFIG=config/contracts.local.json diff --git a/apps/s03-indexer/README.md b/apps/s03-indexer/README.md index a4ee9f6..694da52 100644 --- a/apps/s03-indexer/README.md +++ b/apps/s03-indexer/README.md @@ -20,6 +20,8 @@ The same commands are available inside the workspace package: ```bash bun run --cwd apps/s03-indexer codegen bun run --cwd apps/s03-indexer build +bun run --cwd apps/s03-indexer sync:contracts:testnet +bun run --cwd apps/s03-indexer sync:contracts:local bun run --cwd apps/s03-indexer dev bun run --cwd apps/s03-indexer start ``` @@ -62,6 +64,7 @@ The default configuration targets public SDF testnet: ENDPOINT=https://horizon-testnet.stellar.org CHAIN_ID=Test SDF Network ; September 2015 SOROBAN_ENDPOINT=https://soroban-testnet.stellar.org +INDEXER_NETWORK=testnet ``` Use these defaults when indexing public testnet data or when contributors need @@ -74,6 +77,7 @@ variables to the local values shown in `.env.example`: ENDPOINT=http://host.docker.internal:8000 CHAIN_ID=Standalone Network ; February 2017 SOROBAN_ENDPOINT=http://host.docker.internal:8000/soroban/rpc +INDEXER_NETWORK=local ``` Use local endpoints when you are testing against a local Stellar network, @@ -86,6 +90,43 @@ Endpoint and chain settings are read while SubQuery generates/builds `bun run indexer:build` before `bun run indexer:start`. `bun run indexer:dev` does all three steps for you. +## Contract Manifests + +The indexer reads SO4 contract IDs from generated JSON files in `config/`. +Refresh them after deploying or bootstrapping contracts: + +```bash +bun run --cwd apps/s03-indexer sync:contracts:testnet +bun run --cwd apps/s03-indexer sync:contracts:local +``` + +The sync script reads the contracts repo deployment outputs: + +- `.deployed/.env` +- `.deployed/tokens-.env` +- `.deployed/frontend-.env` +- `.deployed/frontend-.ts` +- `.stellar/contract-ids/.json` + +By default it looks for the sibling contracts repo used by the SO4 workspace +layout. Override that path when needed: + +```bash +SO4_CONTRACTS_REPO=/path/to/contracts bun run --cwd apps/s03-indexer sync:contracts:testnet +``` + +`contracts.testnet.json` and `contracts.local.json` are separate files, so local +and testnet manifests can coexist without overwriting each other. `project.ts` +uses `INDEXER_NETWORK` to select `config/contracts..json`, or +`INDEXER_CONTRACTS_CONFIG` when you need to point at a specific manifest. + +The generated config includes the network name, network passphrase, Horizon +endpoint, Soroban RPC endpoint, core protocol contracts, test token contracts, +faucet contract, and complete market token/index/long/short triplets. The sync +fails fast on malformed contract IDs and required missing values. Missing +`MARKET_TOKEN_*` values are reported as warnings because they are expected before +market bootstrap. + ## Generated Artifacts `project.ts`, `schema.graphql`, and the TypeScript mapping sources are the diff --git a/apps/s03-indexer/config/contracts.testnet.json b/apps/s03-indexer/config/contracts.testnet.json new file mode 100644 index 0000000..cb2818e --- /dev/null +++ b/apps/s03-indexer/config/contracts.testnet.json @@ -0,0 +1,65 @@ +{ + "generatedAt": "2026-06-23T17:51:38.413Z", + "source": { + "contractsRepoPath": "/home/sunny/zero/so4-market-project/contracts", + "files": { + "contractIds": ".stellar/contract-ids/testnet.json", + "deployedEnv": ".deployed/testnet.env", + "tokensEnv": ".deployed/tokens-testnet.env", + "frontendEnv": ".deployed/frontend-testnet.env", + "frontendTs": ".deployed/frontend-testnet.ts" + } + }, + "network": { + "name": "testnet", + "passphrase": "Test SDF Network ; September 2015", + "horizonEndpoint": "https://horizon-testnet.stellar.org", + "sorobanRpcEndpoint": "https://soroban-testnet.stellar.org" + }, + "contracts": { + "role_store": "CBSUAIAMIFFS4AXQYZ7KR7FNO7IMKAPS5WF4DXANVXDTPKH2F7YUIN6Q", + "data_store": "CCZ3VKBEDLNBO2JM3EXL3SNBDJOV5BTN52FVQPER7F6D5GCE53PITQ3J", + "oracle": "CBEMTV23SIJJBIST3V5HTMWHR4MHYGHNBIG4M26U4LGUJTWZXTFSVQEY", + "market_factory": "CBGX3EJFI3JRHSN5B533O2L5P57JFPTCRS55IPWFS5BNDXLJLXDWA5Z2", + "deposit_handler": "CDWOFIP4YQJGMCYAOWLSRBAWN2OTJUG2I5WOFC32O2TX2SRU56RWBE5C", + "withdrawal_handler": "CBRWM6PNRRFL5RSTJH6HWEXBTMWCGLQRO45NTRDB6BBABWXZ4ZE7DGTO", + "order_handler": "CC35OFZVWUTAZPV3B6UKSDVAVORZEWUUMOMTHO33H4YR4C5FKPEFODKY", + "liquidation_handler": "CBXUAR5GCHIRFQL75WTZS3FLA6SMWDPIKG4EKNPWVQVNGVFXBHGTJHTM", + "adl_handler": "CACFPG3QAKG6DCAJSOP7YGDTM44NV6NPI3SKAG7GUGIV6DMGXPCAMMME", + "fee_handler": "CC4P3FJ7EAH6F3RYJPQ2T7VIB4I7UJ4EEYGVWTZVXTAUN647QRVSDHS4", + "referral_storage": "CDHTPQO4RRJ6OUBIW3GDXTIVLVOMIKPJC65PGDJH2G5OLDJRE5KTROWK", + "reader": "CC6OZUHF3LVO6PNP3V2EB36ORB3YSVYSH3LWD3RFLO4NUO3BYCXSWSYC", + "exchange_router": "CBD6BQSQFROWIIT5QCYN7KL5LJJWUIH7CEWUSZIFMUJO6NPXE6CVGYNW" + }, + "tokens": { + "TUSDC": "CBAN5YU3KRDKPTQ2H76D6S7HQFPRBGUD524F65BUM2RQCITPTRLKWKES", + "TWBTC": "CCFTOPHUPSUDO2MB4X5D3XYJ2HRJ7NJPAW4UVPAVN7ZLE63EZLSMXDUO", + "TETH": "CAJ6BZKGFT47ALGMVFZZGAOXBV2RWIVYVCU4WJCQIURKRNXU346RWVAU", + "TXLM": "CAHNXBBSXVMGI6G3FUBY3OTNWKQ7434FDDEEE7ZT733WIW6NUZL4ONU6", + "faucet": "CCWXXBKXHHP5DXC6TYVIL22XUNHD5A75O6WM5D2KM5PY45IOV5VDMARJ" + }, + "markets": [ + { + "name": "TETH/TUSDC", + "marketToken": "CCBUUSYZJTGVA6PYUNQDFPZFHTBZ2QSHOUO7YAGRQVA46T3ZLSIYULS4", + "indexToken": "CAJ6BZKGFT47ALGMVFZZGAOXBV2RWIVYVCU4WJCQIURKRNXU346RWVAU", + "longToken": "CAJ6BZKGFT47ALGMVFZZGAOXBV2RWIVYVCU4WJCQIURKRNXU346RWVAU", + "shortToken": "CBAN5YU3KRDKPTQ2H76D6S7HQFPRBGUD524F65BUM2RQCITPTRLKWKES" + }, + { + "name": "TWBTC/TUSDC", + "marketToken": "CDDVSLBGGDV2UOFN5W72R4LW7ABYL7H7ZWVSFHGMXXB3D52ZYANC5G3L", + "indexToken": "CCFTOPHUPSUDO2MB4X5D3XYJ2HRJ7NJPAW4UVPAVN7ZLE63EZLSMXDUO", + "longToken": "CCFTOPHUPSUDO2MB4X5D3XYJ2HRJ7NJPAW4UVPAVN7ZLE63EZLSMXDUO", + "shortToken": "CBAN5YU3KRDKPTQ2H76D6S7HQFPRBGUD524F65BUM2RQCITPTRLKWKES" + }, + { + "name": "TXLM/TUSDC", + "marketToken": "CDIBR7BDCDWGAG3CC6PBKRSLMISPYKNDGE57DCZO5TMTLZK34TMGKFQQ", + "indexToken": "CAHNXBBSXVMGI6G3FUBY3OTNWKQ7434FDDEEE7ZT733WIW6NUZL4ONU6", + "longToken": "CAHNXBBSXVMGI6G3FUBY3OTNWKQ7434FDDEEE7ZT733WIW6NUZL4ONU6", + "shortToken": "CBAN5YU3KRDKPTQ2H76D6S7HQFPRBGUD524F65BUM2RQCITPTRLKWKES" + } + ], + "warnings": [] +} diff --git a/apps/s03-indexer/package.json b/apps/s03-indexer/package.json index 8a81c67..1fc7ca5 100644 --- a/apps/s03-indexer/package.json +++ b/apps/s03-indexer/package.json @@ -4,7 +4,7 @@ "description": "This project can be use as a starting point for developing your new Stellar Soroban Test Network SubQuery project", "main": "dist/index.js", "scripts": { - "build": "subql build", + "build": "bun run codegen && subql build", "codegen": "subql codegen", "sync:contracts:testnet": "bun run scripts/sync-contracts.ts --network testnet", "sync:contracts:local": "bun run scripts/sync-contracts.ts --network local",