diff --git a/config/dbis-exchange.production.v1.json b/config/dbis-exchange.production.v1.json index 7a592d2..120776b 100644 --- a/config/dbis-exchange.production.v1.json +++ b/config/dbis-exchange.production.v1.json @@ -1,27 +1,53 @@ -{ - "$schema": "DBIS Exchange — production (128-chain OMNL Bank)", - "version": "1.0.0", - "chainId": 138, - "brandName": "DBIS Exchange", - "officeId": 24, - "settlementOfficeExternalId": "HOSPITALLERS-ALI-IRAQ-IRAN", - "chainRegistry": "config/omnl-supported-chains.v1.json", - "maxSupportedChains": 128, - "routers": { - "enhancedSwapRouterV2": "0xa421706768aeb7fafa2d912c5e10824ef3437ad4", - "uniswapV2": "0x3019A7fDc76ba7F64F18d78e66842760037ee638", - "sushiV2": "0xB37b93D38559f53b62ab020A14919f2630a1aE34" - }, - "factory": { - "uniswapV2": "0x0C30F6e67Ab3667fCc2f5CEA8e274ef1FB920279" - }, - "tokens": [], - "defaultSlippageBps": 50, - "production": { - "requireApiKey": true, - "monitorSwaps": true, - "postSwapSettlementAudit": true, - "onlineBankMode": true - } -} - \ No newline at end of file +{ + + "$schema": "DBIS Exchange — production (128-chain OMNL Bank)", + + "version": "1.0.0", + + "chainId": 138, + + "brandName": "DBIS Exchange", + + "officeId": 24, + + "settlementOfficeExternalId": "HOSPITALLERS-ALI-IRAQ-IRAN", + + "chainRegistry": "config/omnl-supported-chains.v1.json", + + "maxSupportedChains": 128, + + "routers": { + + "enhancedSwapRouterV2": "0xa421706768aeb7fafa2d912c5e10824ef3437ad4", + + "uniswapV2": "0x3019A7fDc76ba7F64F18d78e66842760037ee638", + + "sushiV2": "0xB37b93D38559f53b62ab020A14919f2630a1aE34" + + }, + + "factory": { + + "uniswapV2": "0x0C30F6e67Ab3667fCc2f5CEA8e274ef1FB920279" + + }, + + "tokens": [], + + "defaultSlippageBps": 50, + + "production": { + + "requireApiKey": true, + + "monitorSwaps": true, + + "postSwapSettlementAudit": true, + + "onlineBankMode": true + + } + +} + + diff --git a/config/settlement-middleware.production.v1.json b/config/settlement-middleware.production.v1.json index 078a05a..999ed84 100644 --- a/config/settlement-middleware.production.v1.json +++ b/config/settlement-middleware.production.v1.json @@ -1,35 +1,69 @@ -{ - "$schema": "OMNL central-bank settlement — production profile", - "version": "1.0.0", - "omnlLegalName": "ORGANISATION MONDIALE DU NUMERIQUE L.P.B.C.", - "defaultOfficeId": 24, - "enforceSingleOffice": true, - "settlementOffice": { - "officeId": 24, - "externalId": "HOSPITALLERS-ALI-IRAQ-IRAN", - "name": "HOSPITALLERS Ali Iraq-Iran", - "profilePath": "config/offices/office-24-settlement.v1.json" - }, - "defaultCurrency": "USD", - "chainRegistry": "config/omnl-supported-chains.v1.json", - "maxSupportedChains": 128, - "rails": { - "swift": { "enabled": true, "listenerUrl": "http://192.168.11.114:8788" }, - "hybx": { "enabled": true, "sidecarUrl": "http://192.168.11.89:8080" }, - "chain138": { "enabled": true, "rpcEnv": "RPC_URL_138", "defaultLineId": "USD-M2" }, - "multiChain": { "enabled": true, "registryPath": "config/omnl-supported-chains.v1.json", "primaryChainId": 138 } - }, - "moneySupply": { - "glM0": "1050", - "glM1": "2100", - "glM2": "2200", - "glSettlement": "1000" - }, - "production": { - "requireApiKey": true, - "allowHybxProduction": true, - "allowChainMintExecute": true, - "onlineBankMode": true - } -} - \ No newline at end of file +{ + + "$schema": "OMNL central-bank settlement — production profile", + + "version": "1.0.0", + + "omnlLegalName": "ORGANISATION MONDIALE DU NUMERIQUE L.P.B.C.", + + "defaultOfficeId": 24, + + "enforceSingleOffice": true, + + "settlementOffice": { + + "officeId": 24, + + "externalId": "HOSPITALLERS-ALI-IRAQ-IRAN", + + "name": "HOSPITALLERS Ali Iraq-Iran", + + "profilePath": "config/offices/office-24-settlement.v1.json" + + }, + + "defaultCurrency": "USD", + + "chainRegistry": "config/omnl-supported-chains.v1.json", + + "maxSupportedChains": 128, + + "rails": { + + "swift": { "enabled": true, "listenerUrl": "http://192.168.11.114:8788" }, + + "hybx": { "enabled": true, "sidecarUrl": "http://192.168.11.89:8080" }, + + "chain138": { "enabled": true, "rpcEnv": "RPC_URL_138", "defaultLineId": "USD-M2" }, + + "multiChain": { "enabled": true, "registryPath": "config/omnl-supported-chains.v1.json", "primaryChainId": 138 } + + }, + + "moneySupply": { + + "glM0": "1050", + + "glM1": "2100", + + "glM2": "2200", + + "glSettlement": "1000" + + }, + + "production": { + + "requireApiKey": true, + + "allowHybxProduction": true, + + "allowChainMintExecute": true, + + "onlineBankMode": true + + } + +} + + diff --git a/frontend-dapp/src/config/dex.ts b/frontend-dapp/src/config/dex.ts index 89cee8c..b2973c0 100644 --- a/frontend-dapp/src/config/dex.ts +++ b/frontend-dapp/src/config/dex.ts @@ -1,71 +1,141 @@ -/** DBIS Exchange — Chain 138 DEX addresses (Pancake/Uniswap V2 compatible) */ -export const DBIS_EXCHANGE_CHAIN_ID = 138; - -export const TOKEN_AGGREGATION_URL = - import.meta.env.VITE_TOKEN_AGGREGATION_URL || 'http://localhost:3000'; - -export const DBIS_EXCHANGE_URL = - import.meta.env.VITE_DBIS_EXCHANGE_URL || 'http://localhost:3012'; - -export const SETTLEMENT_MIDDLEWARE_URL = - import.meta.env.VITE_SETTLEMENT_MIDDLEWARE_URL || 'http://localhost:3011'; - -export const ENHANCED_SWAP_ROUTER_V2 = - import.meta.env.VITE_ENHANCED_SWAP_ROUTER_V2 || - '0xa421706768aeb7fafa2d912c5e10824ef3437ad4'; - -export const UNISWAP_V2_ROUTER_138 = - import.meta.env.VITE_UNISWAP_V2_ROUTER_138 || - '0x3019A7fDc76ba7F64F18d78e66842760037ee638'; - -export type DexToken = { - symbol: string; - name: string; - address: string; - decimals: number; - native?: boolean; - omnlLine?: string; - moneyLayer?: string; - currencyCode?: string; - swappable?: boolean; - convertible?: boolean; - transferableInternal?: boolean; - transferableExternal?: boolean; -}; - -/** Fallback when exchange API unavailable */ -export const DEFAULT_TOKENS: DexToken[] = [ - { symbol: 'ETH', name: 'Ether', address: '0x0000000000000000000000000000000000000000', decimals: 18, native: true, omnlLine: 'USD-M2', moneyLayer: 'M2' }, - { symbol: 'WETH', name: 'Wrapped Ether', address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', decimals: 18, omnlLine: 'USD-M2', moneyLayer: 'M2' }, - { symbol: 'USDT', name: 'Tether USD', address: '0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, - { symbol: 'USDC', name: 'USD Coin', address: '0x71D6687F38b93CCad569Fa6352c876eea967201b', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, - { symbol: 'cUSDT', name: 'Compliant USDT', address: '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, - { symbol: 'cUSDC', name: 'Compliant USDC', address: '0xf22258f57794CC8E06237084b353Ab30fFfa640b', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, -]; - -export function parseAmountToWei(amount: string, decimals: number): string { - const [whole, frac = ''] = amount.split('.'); - const padded = (frac + '0'.repeat(decimals)).slice(0, decimals); - return BigInt(`${whole}${padded}` || '0').toString(); -} - -export function formatAmountFromWei(wei: string, decimals: number): string { - const v = BigInt(wei || '0'); - const base = 10n ** BigInt(decimals); - const whole = v / base; - const frac = v % base; - if (frac === 0n) return whole.toString(); - return `${whole}.${frac.toString().padStart(decimals, '0').replace(/0+$/, '')}`; -} - -export async function fetchExchangeTokens(): Promise { - try { - const res = await fetch(`${DBIS_EXCHANGE_URL.replace(/\/$/, '')}/api/v1/exchange/tokens`); - if (!res.ok) return DEFAULT_TOKENS; - const data = await res.json(); - return Array.isArray(data.tokens) && data.tokens.length > 0 ? data.tokens : DEFAULT_TOKENS; - } catch { - return DEFAULT_TOKENS; - } -} - \ No newline at end of file +/** DBIS Exchange — Chain 138 DEX addresses (Pancake/Uniswap V2 compatible) */ + +export const DBIS_EXCHANGE_CHAIN_ID = 138; + + + +export const TOKEN_AGGREGATION_URL = + + import.meta.env.VITE_TOKEN_AGGREGATION_URL || 'http://localhost:3000'; + + + +export const DBIS_EXCHANGE_URL = + + import.meta.env.VITE_DBIS_EXCHANGE_URL || 'http://localhost:3012'; + + + +export const SETTLEMENT_MIDDLEWARE_URL = + + import.meta.env.VITE_SETTLEMENT_MIDDLEWARE_URL || 'http://localhost:3011'; + + + +export const ENHANCED_SWAP_ROUTER_V2 = + + import.meta.env.VITE_ENHANCED_SWAP_ROUTER_V2 || + + '0xa421706768aeb7fafa2d912c5e10824ef3437ad4'; + + + +export const UNISWAP_V2_ROUTER_138 = + + import.meta.env.VITE_UNISWAP_V2_ROUTER_138 || + + '0x3019A7fDc76ba7F64F18d78e66842760037ee638'; + + + +export type DexToken = { + + symbol: string; + + name: string; + + address: string; + + decimals: number; + + native?: boolean; + + omnlLine?: string; + + moneyLayer?: string; + + currencyCode?: string; + + swappable?: boolean; + + convertible?: boolean; + + transferableInternal?: boolean; + + transferableExternal?: boolean; + +}; + + + +/** Fallback when exchange API unavailable */ + +export const DEFAULT_TOKENS: DexToken[] = [ + + { symbol: 'ETH', name: 'Ether', address: '0x0000000000000000000000000000000000000000', decimals: 18, native: true, omnlLine: 'USD-M2', moneyLayer: 'M2' }, + + { symbol: 'WETH', name: 'Wrapped Ether', address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', decimals: 18, omnlLine: 'USD-M2', moneyLayer: 'M2' }, + + { symbol: 'USDT', name: 'Tether USD', address: '0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, + + { symbol: 'USDC', name: 'USD Coin', address: '0x71D6687F38b93CCad569Fa6352c876eea967201b', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, + + { symbol: 'cUSDT', name: 'Compliant USDT', address: '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, + + { symbol: 'cUSDC', name: 'Compliant USDC', address: '0xf22258f57794CC8E06237084b353Ab30fFfa640b', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, + +]; + + + +export function parseAmountToWei(amount: string, decimals: number): string { + + const [whole, frac = ''] = amount.split('.'); + + const padded = (frac + '0'.repeat(decimals)).slice(0, decimals); + + return BigInt(`${whole}${padded}` || '0').toString(); + +} + + + +export function formatAmountFromWei(wei: string, decimals: number): string { + + const v = BigInt(wei || '0'); + + const base = 10n ** BigInt(decimals); + + const whole = v / base; + + const frac = v % base; + + if (frac === 0n) return whole.toString(); + + return `${whole}.${frac.toString().padStart(decimals, '0').replace(/0+$/, '')}`; + +} + + + +export async function fetchExchangeTokens(): Promise { + + try { + + const res = await fetch(`${DBIS_EXCHANGE_URL.replace(/\/$/, '')}/api/v1/exchange/tokens`); + + if (!res.ok) return DEFAULT_TOKENS; + + const data = await res.json(); + + return Array.isArray(data.tokens) && data.tokens.length > 0 ? data.tokens : DEFAULT_TOKENS; + + } catch { + + return DEFAULT_TOKENS; + + } + +} + + diff --git a/services/dbis-exchange/src/adapters/settlement.ts b/services/dbis-exchange/src/adapters/settlement.ts index 5be9667..f48873c 100644 --- a/services/dbis-exchange/src/adapters/settlement.ts +++ b/services/dbis-exchange/src/adapters/settlement.ts @@ -1,159 +1,317 @@ -import axios from 'axios'; -import { JsonRpcProvider, Contract, formatUnits } from 'ethers'; -import { settlementUrl } from '../config'; -import type { M2TokenCapabilities } from '@dbis/settlement-core'; - -const ERC20_ABI = ['function balanceOf(address) view returns (uint256)', 'function decimals() view returns (uint8)']; - -export async function fetchFundLedger(officeId: number, apiKey?: string) { - const headers: Record = {}; - if (apiKey) headers.Authorization = `Bearer ${apiKey}`; - const { data } = await axios.get(`${settlementUrl()}/api/v1/settlement/money-supply`, { - headers, - timeout: 60000, - }); - return { officeId, fundLedger: data }; -} - -export async function fetchOfficeProfile() { - const { data } = await axios.get(`${settlementUrl()}/api/v1/settlement/office`, { timeout: 15000 }); - return data; -} - -export async function auditSwapToSettlement(payload: { - idempotencyKey: string; - amount: string; - currency: string; - recipientAddress: string; - remittanceInfo: string; - tokenLineId?: string; - apiKey?: string; -}) { - const lineId = payload.tokenLineId ?? `${payload.currency}-M2`; - const headers: Record = { 'Content-Type': 'application/json' }; - if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; - const { data } = await axios.post( - `${settlementUrl()}/api/v1/settlement/convert/fiat-to-crypto`, - { - idempotencyKey: payload.idempotencyKey, - amount: payload.amount, - currency: payload.currency, - creditorIban: 'GB82WEST12345698765432', - beneficiaryName: 'DBIS Exchange settlement audit', - remittanceInfo: payload.remittanceInfo, - convertToCrypto: { - enabled: true, - targetChainId: 138, - tokenLineId: lineId, - recipientAddress: payload.recipientAddress, - }, - }, - { headers, timeout: 120000, validateStatus: () => true }, - ); - return data; -} - -export async function requestM2TokenLoad(payload: { - idempotencyKey: string; - lineId: string; - symbol: string; - tokenAddress: string; - amount: string; - recipientAddress: string; - currency?: string; - apiKey?: string; -}) { - const headers: Record = { 'Content-Type': 'application/json' }; - if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; - const { data } = await axios.post( - `${settlementUrl()}/api/v1/settlement/token-load`, - { - idempotencyKey: payload.idempotencyKey, - lineId: payload.lineId, - symbol: payload.symbol, - tokenAddress: payload.tokenAddress, - amount: payload.amount, - recipientAddress: payload.recipientAddress, - currency: payload.currency, - }, - { headers, timeout: 120000, validateStatus: () => true }, - ); - return data; -} - -export async function requestInternalTransfer(payload: { - idempotencyKey: string; - tokenAddress: string; - tokenSymbol: string; - amount: string; - recipientAddress: string; - senderAddress?: string; - apiKey?: string; -}) { - const headers: Record = { 'Content-Type': 'application/json' }; - if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; - const { data } = await axios.post( - `${settlementUrl()}/api/v1/settlement/transfer/internal`, - { - ...payload, - moneyLayers: ['M2'], - }, - { headers, timeout: 120000, validateStatus: () => true }, - ); - return data; -} - -export async function requestExternalTransfer(payload: { - idempotencyKey: string; - tokenAddress: string; - tokenSymbol: string; - amount: string; - recipientAddress: string; - creditorIban: string; - beneficiaryName?: string; - currency?: string; - remittanceInfo?: string; - apiKey?: string; -}) { - const headers: Record = { 'Content-Type': 'application/json' }; - if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; - const { data } = await axios.post( - `${settlementUrl()}/api/v1/settlement/transfer/external`, - { - ...payload, - moneyLayers: ['M2'], - rail: 'SWIFT', - }, - { headers, timeout: 120000, validateStatus: () => true }, - ); - return data; -} - -export async function fetchCryptoLedger( - rpcUrl: string, - wallet: string, - tokens: { address: string; symbol: string; decimals: number; native?: boolean }[], -) { - const provider = new JsonRpcProvider(rpcUrl); - const balances: Record = {}; - for (const t of tokens) { - if (t.native || t.address === '0x0000000000000000000000000000000000000000') { - const wei = await provider.getBalance(wallet); - balances[t.symbol] = formatUnits(wei, 18); - continue; - } - try { - const c = new Contract(t.address, ERC20_ABI, provider); - const raw = await c.balanceOf(wallet); - balances[t.symbol] = formatUnits(raw, t.decimals); - } catch { - balances[t.symbol] = '0'; - } - } - return { wallet, balances }; -} - -export function resolveTokenLine(token: M2TokenCapabilities): string { - return token.omnlLine; -} - \ No newline at end of file +import axios from 'axios'; + +import { JsonRpcProvider, Contract, formatUnits } from 'ethers'; + +import { settlementUrl } from '../config'; + +import type { M2TokenCapabilities } from '@dbis/settlement-core'; + + + +const ERC20_ABI = ['function balanceOf(address) view returns (uint256)', 'function decimals() view returns (uint8)']; + + + +export async function fetchFundLedger(officeId: number, apiKey?: string) { + + const headers: Record = {}; + + if (apiKey) headers.Authorization = `Bearer ${apiKey}`; + + const { data } = await axios.get(`${settlementUrl()}/api/v1/settlement/money-supply`, { + + headers, + + timeout: 60000, + + }); + + return { officeId, fundLedger: data }; + +} + + + +export async function fetchOfficeProfile() { + + const { data } = await axios.get(`${settlementUrl()}/api/v1/settlement/office`, { timeout: 15000 }); + + return data; + +} + + + +export async function auditSwapToSettlement(payload: { + + idempotencyKey: string; + + amount: string; + + currency: string; + + recipientAddress: string; + + remittanceInfo: string; + + tokenLineId?: string; + + apiKey?: string; + +}) { + + const lineId = payload.tokenLineId ?? `${payload.currency}-M2`; + + const headers: Record = { 'Content-Type': 'application/json' }; + + if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; + + const { data } = await axios.post( + + `${settlementUrl()}/api/v1/settlement/convert/fiat-to-crypto`, + + { + + idempotencyKey: payload.idempotencyKey, + + amount: payload.amount, + + currency: payload.currency, + + creditorIban: 'GB82WEST12345698765432', + + beneficiaryName: 'DBIS Exchange settlement audit', + + remittanceInfo: payload.remittanceInfo, + + convertToCrypto: { + + enabled: true, + + targetChainId: 138, + + tokenLineId: lineId, + + recipientAddress: payload.recipientAddress, + + }, + + }, + + { headers, timeout: 120000, validateStatus: () => true }, + + ); + + return data; + +} + + + +export async function requestM2TokenLoad(payload: { + + idempotencyKey: string; + + lineId: string; + + symbol: string; + + tokenAddress: string; + + amount: string; + + recipientAddress: string; + + currency?: string; + + apiKey?: string; + +}) { + + const headers: Record = { 'Content-Type': 'application/json' }; + + if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; + + const { data } = await axios.post( + + `${settlementUrl()}/api/v1/settlement/token-load`, + + { + + idempotencyKey: payload.idempotencyKey, + + lineId: payload.lineId, + + symbol: payload.symbol, + + tokenAddress: payload.tokenAddress, + + amount: payload.amount, + + recipientAddress: payload.recipientAddress, + + currency: payload.currency, + + }, + + { headers, timeout: 120000, validateStatus: () => true }, + + ); + + return data; + +} + + + +export async function requestInternalTransfer(payload: { + + idempotencyKey: string; + + tokenAddress: string; + + tokenSymbol: string; + + amount: string; + + recipientAddress: string; + + senderAddress?: string; + + apiKey?: string; + +}) { + + const headers: Record = { 'Content-Type': 'application/json' }; + + if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; + + const { data } = await axios.post( + + `${settlementUrl()}/api/v1/settlement/transfer/internal`, + + { + + ...payload, + + moneyLayers: ['M2'], + + }, + + { headers, timeout: 120000, validateStatus: () => true }, + + ); + + return data; + +} + + + +export async function requestExternalTransfer(payload: { + + idempotencyKey: string; + + tokenAddress: string; + + tokenSymbol: string; + + amount: string; + + recipientAddress: string; + + creditorIban: string; + + beneficiaryName?: string; + + currency?: string; + + remittanceInfo?: string; + + apiKey?: string; + +}) { + + const headers: Record = { 'Content-Type': 'application/json' }; + + if (payload.apiKey) headers.Authorization = `Bearer ${payload.apiKey}`; + + const { data } = await axios.post( + + `${settlementUrl()}/api/v1/settlement/transfer/external`, + + { + + ...payload, + + moneyLayers: ['M2'], + + rail: 'SWIFT', + + }, + + { headers, timeout: 120000, validateStatus: () => true }, + + ); + + return data; + +} + + + +export async function fetchCryptoLedger( + + rpcUrl: string, + + wallet: string, + + tokens: { address: string; symbol: string; decimals: number; native?: boolean }[], + +) { + + const provider = new JsonRpcProvider(rpcUrl); + + const balances: Record = {}; + + for (const t of tokens) { + + if (t.native || t.address === '0x0000000000000000000000000000000000000000') { + + const wei = await provider.getBalance(wallet); + + balances[t.symbol] = formatUnits(wei, 18); + + continue; + + } + + try { + + const c = new Contract(t.address, ERC20_ABI, provider); + + const raw = await c.balanceOf(wallet); + + balances[t.symbol] = formatUnits(raw, t.decimals); + + } catch { + + balances[t.symbol] = '0'; + + } + + } + + return { wallet, balances }; + +} + + + +export function resolveTokenLine(token: M2TokenCapabilities): string { + + return token.omnlLine; + +} + + diff --git a/services/dbis-exchange/src/config.ts b/services/dbis-exchange/src/config.ts index 7e271a4..4293d45 100644 --- a/services/dbis-exchange/src/config.ts +++ b/services/dbis-exchange/src/config.ts @@ -1,75 +1,149 @@ -import fs from 'fs'; -import path from 'path'; -import { - mergeExchangeTokensWithM2Registry, - type M2TokenCapabilities, - type M2TokenRegistryFile, -} from '@dbis/settlement-core'; - -export type ExchangeConfig = { - version: string; - chainId: number; - brandName: string; - officeId: number; - settlementOfficeExternalId: string; - routers: Record; - factory: Record; - tokens: { - symbol: string; - name: string; - address: string; - decimals: number; - native?: boolean; - omnlLine?: string; - moneyLayer?: string; - swappable?: boolean; - convertible?: boolean; - transferableInternal?: boolean; - transferableExternal?: boolean; - }[]; - defaultSlippageBps: number; - production: { - requireApiKey: boolean; - monitorSwaps: boolean; - postSwapSettlementAudit: boolean; - }; -}; - -let cached: ExchangeConfig | null = null; -let cachedM2: M2TokenRegistryFile | null = null; - -export function loadM2TokenRegistry(): M2TokenRegistryFile { - if (cachedM2) return cachedM2; - const p = - process.env.OMNL_M2_TOKEN_REGISTRY || - path.resolve(__dirname, '../../../config/omnl-m2-token-registry.v1.json'); - cachedM2 = JSON.parse(fs.readFileSync(p, 'utf8')) as M2TokenRegistryFile; - return cachedM2; -} - -export function loadExchangeTokens(): M2TokenCapabilities[] { - const cfg = loadExchangeConfig(); - return mergeExchangeTokensWithM2Registry(cfg.tokens, loadM2TokenRegistry()); -} - -export function loadExchangeConfig(): ExchangeConfig { - if (cached) return cached; - const p = - process.env.DBIS_EXCHANGE_CONFIG || - path.resolve(__dirname, '../../../config/dbis-exchange.v1.json'); - cached = JSON.parse(fs.readFileSync(p, 'utf8')) as ExchangeConfig; - return cached; -} - -export function exchangePort(): number { - return parseInt(process.env.DBIS_EXCHANGE_PORT || '3012', 10); -} - -export function tokenAggUrl(): string { - return (process.env.TOKEN_AGGREGATION_URL || 'http://localhost:3000').replace(/\/$/, ''); -} - -export function settlementUrl(): string { - return (process.env.SETTLEMENT_MIDDLEWARE_URL || 'http://localhost:3011').replace(/\/$/, ''); -} - \ No newline at end of file +import fs from 'fs'; + +import path from 'path'; + +import { + + mergeExchangeTokensWithM2Registry, + + type M2TokenCapabilities, + + type M2TokenRegistryFile, + +} from '@dbis/settlement-core'; + + + +export type ExchangeConfig = { + + version: string; + + chainId: number; + + brandName: string; + + officeId: number; + + settlementOfficeExternalId: string; + + routers: Record; + + factory: Record; + + tokens: { + + symbol: string; + + name: string; + + address: string; + + decimals: number; + + native?: boolean; + + omnlLine?: string; + + moneyLayer?: string; + + swappable?: boolean; + + convertible?: boolean; + + transferableInternal?: boolean; + + transferableExternal?: boolean; + + }[]; + + defaultSlippageBps: number; + + production: { + + requireApiKey: boolean; + + monitorSwaps: boolean; + + postSwapSettlementAudit: boolean; + + }; + +}; + + + +let cached: ExchangeConfig | null = null; + +let cachedM2: M2TokenRegistryFile | null = null; + + + +export function loadM2TokenRegistry(): M2TokenRegistryFile { + + if (cachedM2) return cachedM2; + + const p = + + process.env.OMNL_M2_TOKEN_REGISTRY || + + path.resolve(__dirname, '../../../config/omnl-m2-token-registry.v1.json'); + + cachedM2 = JSON.parse(fs.readFileSync(p, 'utf8')) as M2TokenRegistryFile; + + return cachedM2; + +} + + + +export function loadExchangeTokens(): M2TokenCapabilities[] { + + const cfg = loadExchangeConfig(); + + return mergeExchangeTokensWithM2Registry(cfg.tokens, loadM2TokenRegistry()); + +} + + + +export function loadExchangeConfig(): ExchangeConfig { + + if (cached) return cached; + + const p = + + process.env.DBIS_EXCHANGE_CONFIG || + + path.resolve(__dirname, '../../../config/dbis-exchange.v1.json'); + + cached = JSON.parse(fs.readFileSync(p, 'utf8')) as ExchangeConfig; + + return cached; + +} + + + +export function exchangePort(): number { + + return parseInt(process.env.DBIS_EXCHANGE_PORT || '3012', 10); + +} + + + +export function tokenAggUrl(): string { + + return (process.env.TOKEN_AGGREGATION_URL || 'http://localhost:3000').replace(/\/$/, ''); + +} + + + +export function settlementUrl(): string { + + return (process.env.SETTLEMENT_MIDDLEWARE_URL || 'http://localhost:3011').replace(/\/$/, ''); + +} + +