diff --git a/.changeset/firo-asset-calculator.md b/.changeset/firo-asset-calculator.md new file mode 100644 index 000000000..0f1efcf18 --- /dev/null +++ b/.changeset/firo-asset-calculator.md @@ -0,0 +1,11 @@ +--- +'@rosen-ui/asset-calculator': minor +'@rosen-ui/constants': minor +--- + +Add Firo chain support to asset-calculator + +- Register `firo` in the `NETWORKS` constant (no token support, native token `firo`). +- Add `FiroCalculator` that reads locked amounts from the Firo insight-api + (`/insight-api-zcoin/addr/{address}/balance`). +- Add `FiroCalculatorInterface` and register `FiroCalculator` in `AssetCalculator`. diff --git a/.changeset/firo-rosen-service.md b/.changeset/firo-rosen-service.md new file mode 100644 index 000000000..80d2ea10a --- /dev/null +++ b/.changeset/firo-rosen-service.md @@ -0,0 +1,17 @@ +--- +'@rosen-bridge/rosen-service': minor +--- + +Add Firo chain support to rosen-service + +- Add `@rosen-bridge/firo-scanner` and `@rosen-bridge/firo-observation-extractor` + as dependencies. +- Wire up a new `FiroRpcScanner` in `scanner-service`, reading from the + configured Firo RPC node. +- Register `FiroRpcObservationExtractor` for the lock address. +- Register the `firo-extractor` event-trigger extractor on the Ergo scanner. +- Register a Firo scanner-sync health check. +- Pass the Firo calculator config (addresses + `explorerUrl`) to + `AssetCalculator`. +- Add `firo` network section plus health-check thresholds and + `calculator.addresses.firo` defaults to `config/default.yaml`. diff --git a/.changeset/firo-utils.md b/.changeset/firo-utils.md new file mode 100644 index 000000000..a67c91ba0 --- /dev/null +++ b/.changeset/firo-utils.md @@ -0,0 +1,7 @@ +--- +'@rosen-ui/utils': minor +--- + +Add Firo URL entries to `getAddressUrl`, `getTxUrl`, and `getTokenUrl`. + +Required because `Network = keyof typeof NETWORKS` now includes `'firo'`, and the three maps are exhaustive `{ [key in Network]: ... }` — without these entries, `tsc --noEmit` fails in `packages/utils`. Uses Firo's native explorer (`https://explorer.firo.org`) for address and transaction URLs; token URL is empty (Firo has no native token scheme). diff --git a/apps/rosen-service/config/default.yaml b/apps/rosen-service/config/default.yaml index b69144970..d8e57e605 100644 --- a/apps/rosen-service/config/default.yaml +++ b/apps/rosen-service/config/default.yaml @@ -70,6 +70,21 @@ doge: # - url: # username: # password: +firo: + addresses: + lock: + eventTrigger: + permit: + fraud: + commitment: + tokens: + rwt: + initialHeight: + explorerUrl: https://explorer.firo.org + rpc: + url: + username: + password: ethereum: addresses: lock: @@ -107,6 +122,7 @@ calculator: doge: [] ethereum: [] binance: [] + firo: [] healthCheck: ergoScannerWarnDiff: 3 ergoScannerCriticalDiff: 5 @@ -120,6 +136,8 @@ healthCheck: ethereumScannerCriticalDiff: 5 binanceScannerWarnDiff: 3 binanceScannerCriticalDiff: 5 + firoScannerWarnDiff: 3 + firoScannerCriticalDiff: 5 interval: 60 # health check update interval (in seconds) duration: 600 # log duration time check (in seconds) maxAllowedErrorCount: 1 # maximum allowed error log lines diff --git a/apps/rosen-service/package.json b/apps/rosen-service/package.json index b589e69fe..6419ab352 100644 --- a/apps/rosen-service/package.json +++ b/apps/rosen-service/package.json @@ -38,6 +38,8 @@ "@rosen-bridge/ergo-scanner": "^1.0.2", "@rosen-bridge/evm-observation-extractor": "^6.0.3", "@rosen-bridge/evm-scanner": "^1.0.2", + "@rosen-bridge/firo-observation-extractor": "^0.1.2", + "@rosen-bridge/firo-scanner": "^0.1.1", "@rosen-bridge/health-check": "^8.0.0", "@rosen-bridge/log-level-check": "^4.0.0", "@rosen-bridge/scanner-interfaces": "^0.2.2", diff --git a/apps/rosen-service/src/calculator/calculator-service.ts b/apps/rosen-service/src/calculator/calculator-service.ts index fe48f0935..99c467e3f 100644 --- a/apps/rosen-service/src/calculator/calculator-service.ts +++ b/apps/rosen-service/src/calculator/calculator-service.ts @@ -78,6 +78,10 @@ const start = async () => { addresses: config.calculator.addresses.doge, blockcypherUrl: config.doge.blockcypherUrl, }, + { + addresses: config.calculator.addresses.firo, + explorerUrl: config.firo.explorerUrl, + }, dataSource, logger, ); diff --git a/apps/rosen-service/src/configs.ts b/apps/rosen-service/src/configs.ts index ca0972501..047acdd62 100644 --- a/apps/rosen-service/src/configs.ts +++ b/apps/rosen-service/src/configs.ts @@ -144,6 +144,23 @@ const getConfig = () => { }> >('doge.rpcConnections'), }, + firo: { + addresses: { + lock: nodeConfig.get('firo.addresses.lock'), + eventTrigger: nodeConfig.get('firo.addresses.eventTrigger'), + permit: nodeConfig.get('firo.addresses.permit'), + fraud: nodeConfig.get('firo.addresses.fraud'), + commitment: nodeConfig.get('firo.addresses.commitment'), + }, + initialHeight: nodeConfig.get('firo.initialHeight'), + tokens: { + rwt: nodeConfig.get('firo.tokens.rwt'), + }, + explorerUrl: nodeConfig.get('firo.explorerUrl'), + rpcUrl: nodeConfig.get('firo.rpc.url'), + rpcUsername: getOptionalString('firo.rpc.username'), + rpcPassword: getOptionalString('firo.rpc.password'), + }, postgres: { url: nodeConfig.get('postgres.url'), logging: nodeConfig.get('postgres.logging'), @@ -160,6 +177,7 @@ const getConfig = () => { ethereum: nodeConfig.get('calculator.addresses.ethereum'), binance: nodeConfig.get('calculator.addresses.binance'), doge: nodeConfig.get('calculator.addresses.doge'), + firo: nodeConfig.get('calculator.addresses.firo'), }, interval: nodeConfig.get('calculator.interval'), }, @@ -200,6 +218,12 @@ const getConfig = () => { binanceScannerCriticalDiff: nodeConfig.get( 'healthCheck.binanceScannerCriticalDiff', ), + firoScannerWarnDiff: nodeConfig.get( + 'healthCheck.firoScannerWarnDiff', + ), + firoScannerCriticalDiff: nodeConfig.get( + 'healthCheck.firoScannerCriticalDiff', + ), updateInterval: nodeConfig.get('healthCheck.interval'), logDuration: nodeConfig.get('healthCheck.duration'), errorLogAllowedCount: nodeConfig.get( diff --git a/apps/rosen-service/src/constants.ts b/apps/rosen-service/src/constants.ts index aea846ff5..4ea52cb95 100644 --- a/apps/rosen-service/src/constants.ts +++ b/apps/rosen-service/src/constants.ts @@ -6,6 +6,7 @@ export const BITCOIN_SCANNER_INTERVAL = 10 * 60 * 1000; export const DOGE_SCANNER_INTERVAL = 60 * 1000; export const ETHEREUM_SCANNER_INTERVAL = 60 * 1000; export const BINANCE_SCANNER_INTERVAL = 10 * 1000; +export const FIRO_SCANNER_INTERVAL = 2 * 60 * 1000; export const ERGO_SCANNER_LOGGER_NAME = 'ergoScanner'; export const CARDANO_SCANNER_LOGGER_NAME = 'cardanoScanner'; @@ -13,11 +14,13 @@ export const BITCOIN_SCANNER_LOGGER_NAME = 'bitcoinScanner'; export const DOGE_SCANNER_LOGGER_NAME = 'dogeScanner'; export const ETHEREUM_SCANNER_LOGGER_NAME = 'ethereumScanner'; export const BINANCE_SCANNER_LOGGER_NAME = 'binanceScanner'; +export const FIRO_SCANNER_LOGGER_NAME = 'firoScanner'; export const ERGO_BLOCK_TIME = 120; export const CARDANO_BLOCK_TIME = 20; export const BITCOIN_BLOCK_TIME = 600; export const ETHEREUM_BLOCK_TIME = 12; export const BINANCE_BLOCK_TIME = 3; export const DOGE_BLOCK_TIME = 60; +export const FIRO_BLOCK_TIME = 150; export const BITCOIN_RUNES_CONFIG_KEY = 'bitcoinRunes'; diff --git a/apps/rosen-service/src/event-trigger/event-trigger-service.ts b/apps/rosen-service/src/event-trigger/event-trigger-service.ts index 69c47fd16..2dec9fca3 100644 --- a/apps/rosen-service/src/event-trigger/event-trigger-service.ts +++ b/apps/rosen-service/src/event-trigger/event-trigger-service.ts @@ -29,6 +29,9 @@ const binanceEventTriggerExtractorLogger = logger.child( const dogeEventTriggerExtractorLogger = logger.child( 'dogeEventTriggerExtractor', ); +const firoEventTriggerExtractorLogger = logger.child( + 'firoEventTriggerExtractor', +); /** * register event trigger extractors for all chains @@ -113,6 +116,17 @@ export const registerExtractors = async (scanner: ErgoScanner) => { configs.binance.addresses.fraud, binanceEventTriggerExtractorLogger, ); + const firoEventTriggerExtractor = new EventTriggerExtractor( + 'firo-extractor', + dataSource, + ErgoNetworkType.Explorer, + configs.ergo.explorerUrl, + configs.firo.addresses.eventTrigger, + configs.firo.tokens.rwt, + configs.firo.addresses.permit, + configs.firo.addresses.fraud, + firoEventTriggerExtractorLogger, + ); await scanner.registerExtractor(ergoEventTriggerExtractor); await scanner.registerExtractor(cardanoEventTriggerExtractor); await scanner.registerExtractor(bitcoinEventTriggerExtractor); @@ -120,6 +134,7 @@ export const registerExtractors = async (scanner: ErgoScanner) => { await scanner.registerExtractor(dogeEventTriggerExtractor); await scanner.registerExtractor(ethereumEventTriggerExtractor); await scanner.registerExtractor(binanceEventTriggerExtractor); + await scanner.registerExtractor(firoEventTriggerExtractor); logger.debug('event trigger extractors registered', { scannerName: scanner.name(), @@ -131,6 +146,7 @@ export const registerExtractors = async (scanner: ErgoScanner) => { dogeEventTriggerExtractor.getId(), ethereumEventTriggerExtractor.getId(), binanceEventTriggerExtractor.getId(), + firoEventTriggerExtractor.getId(), ], }); } catch (error) { diff --git a/apps/rosen-service/src/health-check/health-check-service.ts b/apps/rosen-service/src/health-check/health-check-service.ts index 90c290d0a..a20d8e68b 100644 --- a/apps/rosen-service/src/health-check/health-check-service.ts +++ b/apps/rosen-service/src/health-check/health-check-service.ts @@ -21,6 +21,8 @@ import { ERGO_SCANNER_INTERVAL, ETHEREUM_BLOCK_TIME, ETHEREUM_SCANNER_INTERVAL, + FIRO_BLOCK_TIME, + FIRO_SCANNER_INTERVAL, } from '../constants'; import scannerService from '../scanner/scanner-service'; import { getLastSavedBlock } from './health-check-utils'; @@ -131,6 +133,17 @@ const registerAllHealthChecks = (healthCheck: HealthCheck) => { ), label: 'binance', }, + { + instance: new ScannerSyncHealthCheckParam( + scannerService.getFiroScanner().name(), + async () => getLastSavedBlock(scannerService.getFiroScanner().name()), + config.healthCheck.firoScannerWarnDiff, + config.healthCheck.firoScannerCriticalDiff, + FIRO_BLOCK_TIME, + FIRO_SCANNER_INTERVAL, + ), + label: 'firo', + }, ]; for (const { instance, label } of checks) { diff --git a/apps/rosen-service/src/observation/chains/firo.ts b/apps/rosen-service/src/observation/chains/firo.ts new file mode 100644 index 000000000..ddf265468 --- /dev/null +++ b/apps/rosen-service/src/observation/chains/firo.ts @@ -0,0 +1,41 @@ +import { DefaultLogger } from '@rosen-bridge/abstract-logger'; +import { FiroRpcObservationExtractor } from '@rosen-bridge/firo-observation-extractor'; +import { FiroRpcScanner } from '@rosen-bridge/firo-scanner'; + +import config from '../../configs'; +import dataSource from '../../data-source'; +import AppError from '../../errors/AppError'; +import { getTokenMap } from '../../utils'; + +const logger = DefaultLogger.getInstance().child(import.meta.url); + +/** + * register an observation extractor for the provided scanner + * @param scanner + */ +export const registerFiroExtractor = async (scanner: FiroRpcScanner) => { + try { + const observationExtractor = new FiroRpcObservationExtractor( + config.firo.addresses.lock, + dataSource, + await getTokenMap(), + logger.child('firoRpcObservationExtractor'), + ); + + await scanner.registerExtractor(observationExtractor); + + logger.debug('firo observation extractor registered', { + scannerName: scanner.name(), + }); + } catch (error) { + throw new AppError( + `cannot create or register firo observation extractor due to error: ${error}`, + false, + 'error', + error instanceof Error ? error.stack : undefined, + { + scannerName: scanner.name(), + }, + ); + } +}; diff --git a/apps/rosen-service/src/observation/observation-service.ts b/apps/rosen-service/src/observation/observation-service.ts index 8d070f39f..a10531b2c 100644 --- a/apps/rosen-service/src/observation/observation-service.ts +++ b/apps/rosen-service/src/observation/observation-service.ts @@ -5,6 +5,7 @@ import { registerCardanoExtractor } from './chains/cardano'; import { registerDogeExtractor } from './chains/doge'; import { registerErgoExtractor } from './chains/ergo'; import { registerEthereumExtractor } from './chains/ethereum'; +import { registerFiroExtractor } from './chains/firo'; const observationService = { registerBitcoinExtractor, @@ -14,6 +15,7 @@ const observationService = { registerErgoExtractor, registerEthereumExtractor, registerBinanceExtractor, + registerFiroExtractor, }; export default observationService; diff --git a/apps/rosen-service/src/scanner/chains/firo.ts b/apps/rosen-service/src/scanner/chains/firo.ts new file mode 100644 index 000000000..14116cb5f --- /dev/null +++ b/apps/rosen-service/src/scanner/chains/firo.ts @@ -0,0 +1,80 @@ +import { DefaultLogger } from '@rosen-bridge/abstract-logger'; +import { + FailoverStrategy, + NetworkConnectorManager, +} from '@rosen-bridge/abstract-scanner'; +import { + FiroRpcNetwork, + FiroRpcScanner, + FiroRpcTransaction, +} from '@rosen-bridge/firo-scanner'; + +import config from '../../configs'; +import { + FIRO_SCANNER_INTERVAL, + FIRO_SCANNER_LOGGER_NAME, + SCANNER_API_TIMEOUT, +} from '../../constants'; +import dataSource from '../../data-source'; +import AppError from '../../errors/AppError'; +import observationService from '../../observation/observation-service'; +import { startScanner } from '../scanner-utils'; + +const logger = DefaultLogger.getInstance().child(import.meta.url); +const scannerLogger = logger.child(FIRO_SCANNER_LOGGER_NAME); + +/** + * Creates and configures a NetworkConnectorManager instance for firo scanner + */ +export const createFiroNetworkConnectorManager = () => { + const networkConnectorManager = + new NetworkConnectorManager( + new FailoverStrategy(), + scannerLogger, + ); + + networkConnectorManager.addConnector( + new FiroRpcNetwork( + config.firo.rpcUrl, + SCANNER_API_TIMEOUT * 1000, + config.firo.rpcUsername && config.firo.rpcPassword + ? { + username: config.firo.rpcUsername, + password: config.firo.rpcPassword, + } + : undefined, + ), + ); + + return networkConnectorManager; +}; + +/** + * create a firo scanner, initializing it and calling its update method + * periodically + */ +export const startFiroScanner = async () => { + try { + const scanner = new FiroRpcScanner({ + dataSource, + initialHeight: config.firo.initialHeight, + logger: scannerLogger, + network: createFiroNetworkConnectorManager(), + }); + + await observationService.registerFiroExtractor(scanner); + + startScanner(scanner, import.meta.url, FIRO_SCANNER_INTERVAL); + + logger.debug('firo scanner started'); + + return scanner; + } catch (error) { + throw new AppError( + `cannot create or start firo scanner due to error: ${error}`, + false, + 'error', + error instanceof Error ? error.stack : undefined, + ); + } +}; diff --git a/apps/rosen-service/src/scanner/scanner-service.ts b/apps/rosen-service/src/scanner/scanner-service.ts index 5b589c910..b8c0231b4 100644 --- a/apps/rosen-service/src/scanner/scanner-service.ts +++ b/apps/rosen-service/src/scanner/scanner-service.ts @@ -6,6 +6,7 @@ import { import { CardanoKoiosScanner } from '@rosen-bridge/cardano-scanner'; import { ErgoScanner } from '@rosen-bridge/ergo-scanner'; import { EvmRpcScanner } from '@rosen-bridge/evm-scanner'; +import { FiroRpcScanner } from '@rosen-bridge/firo-scanner'; import { handleError } from '../utils'; import { startBinanceScanner } from './chains/binance'; @@ -14,6 +15,7 @@ import { startCardanoScanner } from './chains/cardano'; import { startDogeScanner } from './chains/doge'; import { startErgoScanner } from './chains/ergo'; import { startEthereumScanner } from './chains/ethereum'; +import { startFiroScanner } from './chains/firo'; const logger = DefaultLogger.getInstance().child(import.meta.url); @@ -24,6 +26,7 @@ let bitcoinScanner: BitcoinRpcScanner; let ethereumScanner: EvmRpcScanner; let binanceScanner: EvmRpcScanner; let dogeScanner: DogeRpcScanner; +let firoScanner: FiroRpcScanner; /** * start all scanners and register their extractors @@ -37,6 +40,7 @@ const start = async () => { ethereumScanner, binanceScanner, dogeScanner, + firoScanner, ] = await Promise.all([ startErgoScanner(), startCardanoScanner(), @@ -44,6 +48,7 @@ const start = async () => { startEthereumScanner(), startBinanceScanner(), startDogeScanner(), + startFiroScanner(), ]); logger.debug('all scanners started and their extractors registered', { @@ -54,6 +59,7 @@ const start = async () => { ethereumScanner.name(), binanceScanner.name(), dogeScanner.name(), + firoScanner.name(), ], }); } catch (error) { @@ -70,6 +76,7 @@ const scannerService = { getEthereumScanner: () => ethereumScanner, getBinanceScanner: () => binanceScanner, getDogeScanner: () => dogeScanner, + getFiroScanner: () => firoScanner, }; export default scannerService; diff --git a/apps/rosen-service2/src/services/assetAggregator.ts b/apps/rosen-service2/src/services/assetAggregator.ts index 40600fa79..e334b525c 100644 --- a/apps/rosen-service2/src/services/assetAggregator.ts +++ b/apps/rosen-service2/src/services/assetAggregator.ts @@ -95,7 +95,8 @@ export class AssetAggregatorService extends PeriodicTaskService { const assetBalances: Partial> = {}; await Promise.all( Object.keys(configs.chains).map(async (chain) => { - const chainConfig = configs.chains[chain as ChainChoices]; + const chainConfig = + configs.chains[chain as keyof typeof configs.chains]; if ( chain == NETWORKS.ergo.key || ('active' in chainConfig && chainConfig.active) diff --git a/apps/rosen-service2/src/services/assetDataAdapters.ts b/apps/rosen-service2/src/services/assetDataAdapters.ts index 23a0c488d..4fb03564b 100644 --- a/apps/rosen-service2/src/services/assetDataAdapters.ts +++ b/apps/rosen-service2/src/services/assetDataAdapters.ts @@ -22,7 +22,7 @@ import { createClient } from '@vercel/kv'; import { configs } from '../configs'; import { TOTAL_SUPPLY_REDIS_KEY } from '../constants'; import { TokensConfig } from '../tokensConfig'; -import { ChainChoices, TotalSupply } from '../types'; +import { TotalSupply } from '../types'; import { stringSerializer } from '../utils'; import { DBService } from './db'; @@ -82,7 +82,9 @@ export class AssetDataAdapterService extends PeriodicTaskService { * @example * const adapter = createDataAdapter(NETWORKS.bitcoin.key, { url: "https://blockstream.info" }); */ - protected createChainSpecificDataAdapter = (chain: ChainChoices) => { + protected createChainSpecificDataAdapter = ( + chain: keyof typeof configs.chains, + ) => { const tokenMap = TokensConfig.getInstance().getTokenMap(); const addresses: string[] = [ diff --git a/package-lock.json b/package-lock.json index ff302e6b2..32f24535f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -149,6 +149,8 @@ "@rosen-bridge/ergo-scanner": "^1.0.2", "@rosen-bridge/evm-observation-extractor": "^6.0.3", "@rosen-bridge/evm-scanner": "^1.0.2", + "@rosen-bridge/firo-observation-extractor": "^0.1.2", + "@rosen-bridge/firo-scanner": "^0.1.1", "@rosen-bridge/health-check": "^8.0.0", "@rosen-bridge/log-level-check": "^4.0.0", "@rosen-bridge/scanner-interfaces": "^0.2.2", @@ -498,7 +500,6 @@ "version": "7.26.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.0", @@ -1652,6 +1653,7 @@ "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -1684,6 +1686,7 @@ "node_modules/@emotion/is-prop-valid": { "version": "1.4.0", "license": "MIT", + "peer": true, "dependencies": { "@emotion/memoize": "^0.9.0" } @@ -1759,6 +1762,7 @@ "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.2.0", "license": "MIT", + "peer": true, "peerDependencies": { "react": ">=16.8.0" } @@ -2410,6 +2414,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@ethersproject/logger": "^5.8.0" } @@ -2428,7 +2433,8 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@ethersproject/sha2": { "version": "5.8.0", @@ -2455,7 +2461,8 @@ "node_modules/@gar/promisify": { "version": "1.1.3", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@hapi/hoek": { "version": "9.3.0", @@ -3410,7 +3417,6 @@ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", "license": "MIT", - "peer": true, "dependencies": { "node-fetch": "^2.7.0" } @@ -4014,7 +4020,6 @@ "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "license": "MIT", - "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -4110,6 +4115,7 @@ "version": "1.1.1", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -4119,6 +4125,7 @@ "version": "1.1.2", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -4131,6 +4138,7 @@ "version": "1.0.4", "license": "MIT", "optional": true, + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -4142,6 +4150,7 @@ "version": "3.0.2", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -5090,17 +5099,17 @@ } }, "node_modules/@rosen-bridge/abstract-extractor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rosen-bridge/abstract-extractor/-/abstract-extractor-3.1.0.tgz", - "integrity": "sha512-gqVeMCRiJNsu37wltUNvHFYvsEDuYClGvAiWerlHWWmBPQsIxvodfmEdlOf1FAukaq3O9FA13RAYINtGuQW/Yw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@rosen-bridge/abstract-extractor/-/abstract-extractor-3.1.1.tgz", + "integrity": "sha512-V6qXHQkmlr5ZCfzmQegQOxgQkS8k7opeWdrm1xElUSDlU45tTSmW+KMOKU4IYvw/7f1aMOIF98Rz3Dyeh1M87A==", "license": "MIT", "dependencies": { "@rosen-bridge/abstract-logger": "^4.0.0", "@rosen-bridge/extended-typeorm": "^1.0.1", "@rosen-bridge/json-bigint": "^1.1.0", "@rosen-bridge/scanner-interfaces": "^0.2.2", - "@rosen-clients/ergo-explorer": "^2.1.1", - "@rosen-clients/ergo-node": "^3.1.1", + "@rosen-clients/ergo-explorer": "^2.1.2", + "@rosen-clients/ergo-node": "^3.1.2", "await-semaphore": "^0.1.3", "lodash-es": "^4.17.21", "p-queue": "^9.0.1", @@ -5129,12 +5138,12 @@ } }, "node_modules/@rosen-bridge/abstract-observation-extractor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rosen-bridge/abstract-observation-extractor/-/abstract-observation-extractor-1.0.3.tgz", - "integrity": "sha512-I1ANvR9fx/9FB41QbQxVuJFtwqvuPPax1bSdywgLtvLJktdFUGTm94BoSQTc+JJQtHlAMcyp1kA/zUiFfh81FA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@rosen-bridge/abstract-observation-extractor/-/abstract-observation-extractor-1.0.4.tgz", + "integrity": "sha512-FdvOVF2fCh8OCKOrPNOf3CPcDyJTdalHPI6dva+1/1gZd7p7mxS2LkXRyNjsCXhDtefTlhfjSI7w6V2OfA2F1w==", "license": "MIT", "dependencies": { - "@rosen-bridge/abstract-extractor": "^3.1.0", + "@rosen-bridge/abstract-extractor": "^3.1.1", "@rosen-bridge/abstract-logger": "^4.0.0", "@rosen-bridge/extended-typeorm": "^1.0.1", "@rosen-bridge/rosen-extractor": "^11.3.0", @@ -5148,12 +5157,12 @@ } }, "node_modules/@rosen-bridge/abstract-scanner": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@rosen-bridge/abstract-scanner/-/abstract-scanner-1.0.2.tgz", - "integrity": "sha512-C1QtMjS5LiDWsHN8pucCQ1Wm37ElliWYl8pk/QP7mGPVQx1k3N9AeKqrpkeF7H9kUVqS9QB/EymTCoCUp2QmqA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rosen-bridge/abstract-scanner/-/abstract-scanner-1.0.3.tgz", + "integrity": "sha512-UjxODDOZY7VflgquXm7RzpDCCHvAkVmzte3h1eJuVMaLR84GvPsjoIsWtrhuKu/ekAp2xPrm+oPAfnC4Hr0UsA==", "license": "MIT", "dependencies": { - "@rosen-bridge/abstract-extractor": "^3.1.0", + "@rosen-bridge/abstract-extractor": "^3.1.1", "@rosen-bridge/abstract-logger": "^4.0.0", "@rosen-bridge/extended-typeorm": "^1.0.1", "@rosen-bridge/json-bigint": "^1.1.0", @@ -5918,8 +5927,7 @@ }, "node_modules/@rosen-bridge/extended-typeorm/node_modules/reflect-metadata": { "version": "0.2.2", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/@rosen-bridge/extended-typeorm/node_modules/typeorm": { "version": "0.3.26", @@ -6032,6 +6040,54 @@ "uuid": "dist/esm/bin/uuid" } }, + "node_modules/@rosen-bridge/firo-observation-extractor": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@rosen-bridge/firo-observation-extractor/-/firo-observation-extractor-0.1.2.tgz", + "integrity": "sha512-eW8rvU5hfKQq5EF1QKDEZwMZaHqqLIyrXYRRIlQdNAh4nen4UQZNjH+Xiz6iz9Ir7ZT7SASsCMuFKTxn3iby0g==", + "license": "MIT", + "dependencies": { + "@rosen-bridge/abstract-logger": "^4.0.0", + "@rosen-bridge/abstract-observation-extractor": "^1.0.4", + "@rosen-bridge/extended-typeorm": "^1.0.1", + "@rosen-bridge/firo-scanner": "^0.1.1", + "@rosen-bridge/rosen-extractor": "^11.3.0", + "@rosen-bridge/tokens": "^6.0.0" + }, + "engines": { + "node": ">=22.18.0", + "npm": "11.6.2" + } + }, + "node_modules/@rosen-bridge/firo-scanner": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@rosen-bridge/firo-scanner/-/firo-scanner-0.1.1.tgz", + "integrity": "sha512-IL2wSZs/pZokXCX3R3iBL3x7jgj5VcVNuNqjITFbjjnRRBpRfyrmjwD3VbRnAwOBGrjuY24M7sqiVO1Pldsdxg==", + "license": "MIT", + "dependencies": { + "@rosen-bridge/abstract-scanner": "^1.0.3", + "@rosen-bridge/scanner-interfaces": "^0.2.2", + "@rosen-clients/rate-limited-axios": "^2.0.0" + }, + "engines": { + "node": ">=22.18.0", + "npm": "11.6.2" + } + }, + "node_modules/@rosen-bridge/firo-scanner/node_modules/@rosen-clients/rate-limited-axios": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@rosen-clients/rate-limited-axios/-/rate-limited-axios-2.0.0.tgz", + "integrity": "sha512-2fYR5O+c57uvI8V0jXi2Ny6eZ8ykIHmtN6wlEg8SNhW1gvfJas8scIoF+AOLx9C+5Z9KlN6usV8fnaTa7OicaQ==", + "license": "MIT", + "dependencies": { + "@rosen-bridge/abstract-logger": "^4.0.0", + "await-semaphore": "^0.1.3", + "axios": "^1.13.2" + }, + "engines": { + "node": ">=22.18.0", + "npm": "11.6.2" + } + }, "node_modules/@rosen-bridge/guard-app": { "resolved": "apps/guard", "link": true @@ -6448,13 +6504,28 @@ } }, "node_modules/@rosen-clients/axios": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rosen-clients/axios/-/axios-1.1.1.tgz", - "integrity": "sha512-whG91IfspeD9fZ4hRBrUCLn+FQGGPGz22y86VrnphLyo8VlrHgGXZQHn0H32dT8pPrQLyX4Fb4AekX4u90WOMw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rosen-clients/axios/-/axios-1.1.2.tgz", + "integrity": "sha512-w7oPmZwklo22YU9Ale+BwBJ9jnCmHTLqEXD1kCVqhH8nvU27KawNs5FlhGBZc3NJemd0L16MlKc5P9Cqa+kqcg==", "license": "MIT", "dependencies": { "@rosen-bridge/json-bigint": "^1.1.0", - "@rosen-clients/rate-limited-axios": "^1.1.1" + "@rosen-clients/rate-limited-axios": "^2.0.0" + }, + "engines": { + "node": ">=22.18.0", + "npm": "11.6.2" + } + }, + "node_modules/@rosen-clients/axios/node_modules/@rosen-clients/rate-limited-axios": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@rosen-clients/rate-limited-axios/-/rate-limited-axios-2.0.0.tgz", + "integrity": "sha512-2fYR5O+c57uvI8V0jXi2Ny6eZ8ykIHmtN6wlEg8SNhW1gvfJas8scIoF+AOLx9C+5Z9KlN6usV8fnaTa7OicaQ==", + "license": "MIT", + "dependencies": { + "@rosen-bridge/abstract-logger": "^4.0.0", + "await-semaphore": "^0.1.3", + "axios": "^1.13.2" }, "engines": { "node": ">=22.18.0", @@ -6475,12 +6546,12 @@ } }, "node_modules/@rosen-clients/ergo-explorer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@rosen-clients/ergo-explorer/-/ergo-explorer-2.1.1.tgz", - "integrity": "sha512-o59VwrBogqCePbIaG23UCJk/5xSpM182QW1yhKOUF2LS1Wx3DplcufG2ZIqxaH3XVfFCy8Xe1g8/UZdOxlOzFw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@rosen-clients/ergo-explorer/-/ergo-explorer-2.1.2.tgz", + "integrity": "sha512-gB1K+jO3T391nQq69N/TBne+rjjDGmf7ChF9IQEk7t6Q7YHnwVGQAF8oOWJPY9NUPpAEogxfNfptTdoIc1k3rw==", "license": "MIT", "dependencies": { - "@rosen-clients/axios": "^1.1.1" + "@rosen-clients/axios": "^1.1.2" }, "engines": { "node": ">=22.18.0", @@ -6488,12 +6559,12 @@ } }, "node_modules/@rosen-clients/ergo-node": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@rosen-clients/ergo-node/-/ergo-node-3.1.1.tgz", - "integrity": "sha512-XMEJ8E65HocS2mT2mOQTWo61UwPjQqI5GMhBTK7mOW9chgPsrM5zgWbUdiyPC77dBsGDzDuywur8JuxFlhKztA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@rosen-clients/ergo-node/-/ergo-node-3.1.2.tgz", + "integrity": "sha512-cjoo9J+zyzvr6KLsfxcVmxGU+ot/qwd82u98po7geHWRTFHuUmh88SeLQIU3bi+VPfkAUh3iLOUeh0zSgMsEpw==", "license": "MIT", "dependencies": { - "@rosen-clients/axios": "^1.1.1" + "@rosen-clients/axios": "^1.1.2" }, "engines": { "node": ">=22.18.0", @@ -6672,7 +6743,6 @@ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -6872,6 +6942,7 @@ "resolved": "https://registry.npmjs.org/@sats-connect/core/-/core-0.17.1.tgz", "integrity": "sha512-HYEU3+739nGgoUU0RlMwu7YXQOLaFhDiob31U8+Gr8aY4ezFskpqaFZqIHoRvkIrEhjT09PKzX/hh31Mm1NQZg==", "license": "ISC", + "peer": true, "dependencies": { "axios": "1.13.5", "bitcoin-address-validation": "3.0.0", @@ -6888,6 +6959,7 @@ "resolved": "https://registry.npmjs.org/base58-js/-/base58-js-3.0.3.tgz", "integrity": "sha512-3hf42BysHnUqmZO7mK6e5X/hs1AvyEJIhdVLbG/Mxn/fhFnhGxOO37mWbMHg1RT4TxqcPKXgqj9/bp1YG0GBXA==", "license": "MIT", + "peer": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -6898,6 +6970,7 @@ "resolved": "https://registry.npmjs.org/bitcoin-address-validation/-/bitcoin-address-validation-3.0.0.tgz", "integrity": "sha512-R1X1c9EdgjgjTpjshjk5e16TbgF7HYasxBcu7l5ScWMxVs53845vMUg5PvnQ/R/3h8Grly6Y52DgH6/77gazLQ==", "license": "MIT", + "peer": true, "dependencies": { "base58-js": "^3.0.2", "bech32": "^2.0.0", @@ -7507,6 +7580,7 @@ "version": "1.1.2", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 6" } @@ -7668,14 +7742,14 @@ "node_modules/@types/node": { "version": "22.18.11", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@types/parse-json": { "version": "4.0.2", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/prop-types": { "version": "15.7.15", @@ -7773,7 +7847,6 @@ "version": "8.44.1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.44.1", "@typescript-eslint/types": "8.44.1", @@ -8814,12 +8887,14 @@ }, "node_modules/@yr/monotone-cubic-spline": { "version": "1.0.3", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/abbrev": { "version": "1.1.1", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/abitype": { "version": "1.0.6", @@ -8847,7 +8922,6 @@ "version": "8.15.0", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8871,6 +8945,7 @@ "version": "6.0.2", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "debug": "4" }, @@ -8893,6 +8968,7 @@ "version": "3.1.0", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -9045,7 +9121,8 @@ "node_modules/aproba": { "version": "2.0.0", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/argparse": { "version": "2.0.1", @@ -9282,7 +9359,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", @@ -9405,6 +9481,7 @@ "node_modules/bindings": { "version": "1.5.0", "license": "MIT", + "peer": true, "dependencies": { "file-uri-to-path": "1.0.0" } @@ -9443,6 +9520,7 @@ "node_modules/bl": { "version": "4.1.0", "license": "MIT", + "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -9466,6 +9544,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -9584,7 +9663,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -9658,7 +9736,6 @@ "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -9678,6 +9755,7 @@ "version": "15.3.0", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -9706,6 +9784,7 @@ "version": "6.0.0", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -9717,6 +9796,7 @@ "version": "1.0.4", "license": "MIT", "optional": true, + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -9728,6 +9808,7 @@ "version": "3.0.2", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -9741,7 +9822,8 @@ "node_modules/cacache/node_modules/yallist": { "version": "4.0.0", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/cacheable-lookup": { "version": "5.0.4", @@ -9945,6 +10027,7 @@ "node_modules/chownr": { "version": "2.0.0", "license": "ISC", + "peer": true, "engines": { "node": ">=10" } @@ -9966,6 +10049,7 @@ "version": "2.2.0", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -10154,6 +10238,7 @@ "version": "1.1.3", "license": "ISC", "optional": true, + "peer": true, "bin": { "color-support": "bin.js" } @@ -10226,11 +10311,13 @@ "node_modules/console-control-strings": { "version": "1.1.0", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/convert-source-map": { "version": "1.9.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cookie-es": { "version": "1.2.2", @@ -10247,6 +10334,7 @@ "node_modules/cosmiconfig": { "version": "7.1.0", "license": "MIT", + "peer": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -10464,6 +10552,7 @@ "node_modules/deep-extend": { "version": "0.6.0", "license": "MIT", + "peer": true, "engines": { "node": ">=4.0.0" } @@ -10540,7 +10629,8 @@ "node_modules/delegates": { "version": "1.0.0", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/dequal": { "version": "2.0.3", @@ -10689,7 +10779,6 @@ "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.17.tgz", "integrity": "sha512-TOOURki4G7sD1wDCjj7NfLaXZZ49dFOeEb5y39IXpb8p0hRzVvfvzZHOi5JcT+PpyAbi/Y+lxPb8eTag2WYH8w==", "license": "MIT", - "peer": true, "dependencies": { "@ecies/ciphers": "^0.2.5", "@noble/ciphers": "^1.3.0", @@ -10749,8 +10838,7 @@ }, "node_modules/embla-carousel": { "version": "8.5.2", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/embla-carousel-react": { "version": "8.5.2", @@ -10895,6 +10983,7 @@ "version": "2.2.1", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -10906,7 +10995,8 @@ "node_modules/err-code": { "version": "2.0.3", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/error-ex": { "version": "1.3.2", @@ -11576,7 +11666,6 @@ "version": "9.36.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -11773,7 +11862,6 @@ "version": "2.31.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -12137,7 +12225,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", @@ -12205,8 +12292,7 @@ "version": "6.4.9", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/eventemitter3": { "version": "5.0.1", @@ -12268,6 +12354,7 @@ "node_modules/expand-template": { "version": "2.0.3", "license": "(MIT OR WTFPL)", + "peer": true, "engines": { "node": ">=6" } @@ -12426,7 +12513,8 @@ }, "node_modules/file-uri-to-path": { "version": "1.0.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fill-range": { "version": "7.1.1", @@ -12440,7 +12528,8 @@ }, "node_modules/find-root": { "version": "1.1.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/find-up": { "version": "5.0.0", @@ -12574,7 +12663,8 @@ }, "node_modules/fs-constants": { "version": "1.0.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fs-extra": { "version": "10.1.0", @@ -12591,6 +12681,7 @@ "node_modules/fs-minipass": { "version": "2.1.0", "license": "ISC", + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -12601,7 +12692,8 @@ "node_modules/fs.realpath": { "version": "1.0.0", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -12752,12 +12844,14 @@ }, "node_modules/github-from-package": { "version": "0.0.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/glob": { "version": "7.1.7", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12949,7 +13043,8 @@ "node_modules/has-unicode": { "version": "2.0.1", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/hash.js": { "version": "1.1.7", @@ -12989,13 +13084,15 @@ "node_modules/hoist-non-react-statics": { "version": "3.3.2", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "react-is": "^16.7.0" } }, "node_modules/hoist-non-react-statics/node_modules/react-is": { "version": "16.13.1", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/html-escaper": { "version": "2.0.2", @@ -13010,6 +13107,7 @@ "version": "4.0.1", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -13034,6 +13132,7 @@ "version": "5.0.1", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -13156,6 +13255,7 @@ "version": "4.0.0", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -13163,12 +13263,14 @@ "node_modules/infer-owner": { "version": "1.0.4", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/inflight": { "version": "1.0.6", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -13180,7 +13282,8 @@ }, "node_modules/ini": { "version": "1.3.8", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/internal-slot": { "version": "1.0.7", @@ -13199,6 +13302,7 @@ "version": "9.0.5", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -13210,7 +13314,8 @@ "node_modules/ip-address/node_modules/sprintf-js": { "version": "1.1.3", "license": "BSD-3-Clause", - "optional": true + "optional": true, + "peer": true }, "node_modules/iron-webcrypto": { "version": "1.2.1", @@ -13464,7 +13569,8 @@ "node_modules/is-lambda": { "version": "1.0.1", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/is-map": { "version": "2.0.3", @@ -13894,7 +14000,6 @@ "version": "2.6.0", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -13944,7 +14049,8 @@ "node_modules/jsbn": { "version": "1.1.0", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/json-bigint": { "version": "1.0.0", @@ -14486,6 +14592,7 @@ "version": "9.1.0", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -14512,6 +14619,7 @@ "version": "6.0.0", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -14522,7 +14630,8 @@ "node_modules/make-fetch-happen/node_modules/yallist": { "version": "4.0.0", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/math-intrinsics": { "version": "1.1.0", @@ -14650,6 +14759,7 @@ "node_modules/minipass": { "version": "3.3.6", "license": "ISC", + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -14661,6 +14771,7 @@ "version": "1.0.2", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -14672,6 +14783,7 @@ "version": "1.4.1", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", @@ -14688,6 +14800,7 @@ "version": "1.0.5", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -14699,6 +14812,7 @@ "version": "1.2.4", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -14710,6 +14824,7 @@ "version": "1.0.3", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -14719,11 +14834,13 @@ }, "node_modules/minipass/node_modules/yallist": { "version": "4.0.0", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/minizlib": { "version": "2.1.2", "license": "MIT", + "peer": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -14734,11 +14851,13 @@ }, "node_modules/minizlib/node_modules/yallist": { "version": "4.0.0", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/mkdirp-classic": { "version": "0.5.3", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/mlly": { "version": "1.8.0", @@ -14817,7 +14936,8 @@ }, "node_modules/napi-build-utils": { "version": "2.0.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/napi-postinstall": { "version": "0.3.4", @@ -14842,6 +14962,7 @@ "version": "0.6.3", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -14919,6 +15040,7 @@ "node_modules/node-abi": { "version": "3.77.0", "license": "MIT", + "peer": true, "dependencies": { "semver": "^7.3.5" }, @@ -14928,7 +15050,8 @@ }, "node_modules/node-addon-api": { "version": "7.1.1", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/node-fetch": { "version": "2.7.0", @@ -14958,6 +15081,7 @@ "version": "8.4.1", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -15003,6 +15127,7 @@ "version": "3.0.1", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -15014,12 +15139,14 @@ "node_modules/node-gyp/node_modules/emoji-regex": { "version": "8.0.0", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/node-gyp/node_modules/gauge": { "version": "4.0.4", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -15038,6 +15165,7 @@ "version": "3.0.0", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -15046,6 +15174,7 @@ "version": "6.0.2", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -15060,6 +15189,7 @@ "version": "3.0.2", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -15074,6 +15204,7 @@ "version": "4.2.3", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -15105,6 +15236,7 @@ "version": "5.0.0", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "abbrev": "1" }, @@ -15698,6 +15830,7 @@ "version": "4.0.0", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "aggregate-error": "^3.0.0" }, @@ -15885,6 +16018,7 @@ "version": "1.0.1", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -15951,7 +16085,6 @@ "node_modules/pg": { "version": "8.11.3", "license": "MIT", - "peer": true, "dependencies": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", @@ -16201,6 +16334,7 @@ "node_modules/prebuild-install": { "version": "7.1.3", "license": "MIT", + "peer": true, "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -16234,7 +16368,6 @@ "version": "3.6.2", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -16270,12 +16403,14 @@ "node_modules/promise-inflight": { "version": "1.0.1", "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/promise-retry": { "version": "2.0.1", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -16600,6 +16735,7 @@ "node_modules/rc": { "version": "1.2.8", "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "peer": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -16613,6 +16749,7 @@ "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -16622,7 +16759,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -16643,7 +16779,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -16732,7 +16867,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -16910,6 +17044,7 @@ "version": "0.12.0", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 4" } @@ -17479,7 +17614,8 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/simple-get": { "version": "4.0.1", @@ -17498,6 +17634,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -17536,6 +17673,7 @@ "version": "4.2.0", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -17598,7 +17736,6 @@ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", "license": "MIT", - "peer": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", @@ -17672,6 +17809,7 @@ "version": "2.8.5", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -17685,6 +17823,7 @@ "version": "6.2.1", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -17706,6 +17845,7 @@ "node_modules/source-map": { "version": "0.5.7", "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -17787,6 +17927,7 @@ "version": "8.0.1", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.1.1" }, @@ -18145,6 +18286,7 @@ "node_modules/svg.draggable.js": { "version": "2.2.2", "license": "MIT", + "peer": true, "dependencies": { "svg.js": "^2.0.1" }, @@ -18155,6 +18297,7 @@ "node_modules/svg.easing.js": { "version": "2.0.0", "license": "MIT", + "peer": true, "dependencies": { "svg.js": ">=2.3.x" }, @@ -18165,6 +18308,7 @@ "node_modules/svg.filter.js": { "version": "2.0.2", "license": "MIT", + "peer": true, "dependencies": { "svg.js": "^2.2.5" }, @@ -18174,11 +18318,13 @@ }, "node_modules/svg.js": { "version": "2.7.1", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/svg.pathmorphing.js": { "version": "0.1.3", "license": "MIT", + "peer": true, "dependencies": { "svg.js": "^2.4.0" }, @@ -18189,6 +18335,7 @@ "node_modules/svg.resize.js": { "version": "1.4.3", "license": "MIT", + "peer": true, "dependencies": { "svg.js": "^2.6.5", "svg.select.js": "^2.1.2" @@ -18200,6 +18347,7 @@ "node_modules/svg.resize.js/node_modules/svg.select.js": { "version": "2.1.2", "license": "MIT", + "peer": true, "dependencies": { "svg.js": "^2.2.5" }, @@ -18210,6 +18358,7 @@ "node_modules/svg.select.js": { "version": "3.0.1", "license": "MIT", + "peer": true, "dependencies": { "svg.js": "^2.6.5" }, @@ -18222,7 +18371,6 @@ "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.1.tgz", "integrity": "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==", "license": "MIT", - "peer": true, "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.6.0" @@ -18242,6 +18390,7 @@ "node_modules/tar": { "version": "6.2.1", "license": "ISC", + "peer": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -18257,6 +18406,7 @@ "node_modules/tar-fs": { "version": "2.1.4", "license": "MIT", + "peer": true, "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -18266,11 +18416,13 @@ }, "node_modules/tar-fs/node_modules/chownr": { "version": "1.1.4", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/tar-stream": { "version": "2.2.0", "license": "MIT", + "peer": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -18285,6 +18437,7 @@ "node_modules/tar/node_modules/minipass": { "version": "5.0.0", "license": "ISC", + "peer": true, "engines": { "node": ">=8" } @@ -18292,6 +18445,7 @@ "node_modules/tar/node_modules/mkdirp": { "version": "1.0.4", "license": "MIT", + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -18301,7 +18455,8 @@ }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/term-size": { "version": "2.2.1", @@ -18441,7 +18596,6 @@ "version": "4.0.3", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -18545,7 +18699,8 @@ "version": "5.9.0", "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.9.0.tgz", "integrity": "sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -18648,6 +18803,7 @@ "node_modules/tunnel-agent": { "version": "0.6.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -18752,7 +18908,6 @@ "node_modules/typescript": { "version": "5.8.3", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18811,6 +18966,7 @@ "version": "1.1.1", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -18819,6 +18975,7 @@ "version": "2.0.2", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -18991,7 +19148,6 @@ "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -19032,7 +19188,6 @@ "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.1.0.tgz", "integrity": "sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw==", "license": "MIT", - "peer": true, "peerDependencies": { "typescript": ">=5" }, @@ -19762,7 +19917,6 @@ "version": "4.0.3", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -19870,11 +20024,28 @@ } } }, + "node_modules/vite-node/node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/vitest": { "version": "3.2.4", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -20481,7 +20652,6 @@ "version": "4.0.3", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -20520,7 +20690,6 @@ "version": "7.2.2", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -20590,6 +20759,24 @@ } } }, + "node_modules/vitest/node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/vscode-uri": { "version": "3.1.0", "dev": true, @@ -20740,6 +20927,7 @@ "version": "1.1.5", "license": "ISC", "optional": true, + "peer": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -20747,12 +20935,14 @@ "node_modules/wide-align/node_modules/emoji-regex": { "version": "8.0.0", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/wide-align/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -20761,6 +20951,7 @@ "version": "4.2.3", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -20773,7 +20964,6 @@ "node_modules/winston": { "version": "3.18.3", "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", @@ -20930,7 +21120,6 @@ "node_modules/ws": { "version": "7.5.10", "license": "MIT", - "peer": true, "engines": { "node": ">=8.3.0" }, @@ -21383,7 +21572,6 @@ "version": "4.0.3", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -21444,7 +21632,6 @@ "version": "7.3.1", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", diff --git a/packages/asset-calculator/lib/asset-calculator.ts b/packages/asset-calculator/lib/asset-calculator.ts index 2ce8f0414..babf50736 100644 --- a/packages/asset-calculator/lib/asset-calculator.ts +++ b/packages/asset-calculator/lib/asset-calculator.ts @@ -18,6 +18,7 @@ import { CardanoCalculator } from './calculator/chains/cardano-calculator'; import { DogeCalculator } from './calculator/chains/doge-calculator'; import { ErgoCalculator } from './calculator/chains/ergo-calculator'; import { EvmCalculator } from './calculator/chains/evm-calculator'; +import { FiroCalculator } from './calculator/chains/firo-calculator'; import { BridgedAssetModel } from './database/bridgedAsset/BridgedAssetModel'; import { LockedAssetEntity } from './database/lockedAsset/LockedAssetEntity'; import { LockedAssetModel } from './database/lockedAsset/LockedAssetModel'; @@ -29,6 +30,7 @@ import { DogeCalculatorInterface, ErgoCalculatorInterface, EvmCalculatorInterface, + FiroCalculatorInterface, } from './interfaces'; class AssetCalculator { @@ -49,6 +51,7 @@ class AssetCalculator { ethereumCalculator: EvmCalculatorInterface, binanceCalculator: EvmCalculatorInterface, dogeCalculator: DogeCalculatorInterface, + firoCalculator: FiroCalculatorInterface, dataSource: DataSource, protected readonly logger: AbstractLogger = new DummyLogger(), ) { @@ -101,6 +104,12 @@ class AssetCalculator { dogeCalculator.blockcypherUrl, logger.child('dogeCalculator'), ); + const firoAssetCalculator = new FiroCalculator( + this.tokens, + firoCalculator.addresses, + firoCalculator.explorerUrl, + logger.child('firoCalculator'), + ); this.calculatorMap.set(NETWORKS.ergo.key, ergoAssetCalculator); this.calculatorMap.set(NETWORKS.cardano.key, cardanoAssetCalculator); this.calculatorMap.set(NETWORKS.bitcoin.key, bitcoinAssetCalculator); @@ -111,6 +120,7 @@ class AssetCalculator { this.calculatorMap.set(NETWORKS.ethereum.key, ethereumAssetCalculator); this.calculatorMap.set(NETWORKS.binance.key, binanceAssetCalculator); this.calculatorMap.set(NETWORKS.doge.key, dogeAssetCalculator); + this.calculatorMap.set(NETWORKS.firo.key, firoAssetCalculator); this.bridgedAssetModel = new BridgedAssetModel( dataSource, logger.child('bridgedAssetModel'), diff --git a/packages/asset-calculator/lib/calculator/chains/firo-calculator.ts b/packages/asset-calculator/lib/calculator/chains/firo-calculator.ts new file mode 100644 index 000000000..7ae5afb62 --- /dev/null +++ b/packages/asset-calculator/lib/calculator/chains/firo-calculator.ts @@ -0,0 +1,63 @@ +import { AbstractLogger } from '@rosen-bridge/abstract-logger'; +import { NATIVE_TOKEN, RosenChainToken, TokenMap } from '@rosen-bridge/tokens'; +import axios, { Axios } from '@rosen-clients/rate-limited-axios'; +import { NETWORKS } from '@rosen-ui/constants'; +import { Network } from '@rosen-ui/types'; +import { zipWith } from 'lodash-es'; + +import AbstractCalculator from '../abstract-calculator'; + +export class FiroCalculator extends AbstractCalculator { + readonly chain: Network = NETWORKS.firo.key; + + protected client: Axios; + + constructor( + tokenMap: TokenMap, + addresses: string[], + url: string = 'https://explorer.firo.org', + logger?: AbstractLogger, + ) { + super(addresses, logger, tokenMap); + this.client = axios.create({ + baseURL: url, + }); + } + + /** + * @param token Firo chain token supply, always 0 + */ + totalRawSupply = async (): Promise => { + return 0n; + }; + + /** + * @param token Firo chain token balance, always 0 + */ + totalRawBalance = async (): Promise => { + return 0n; + }; + + /** + * returns locked amounts of a specific token for different addresses + * @param token + */ + getRawLockedAmountsPerAddress = async (token: RosenChainToken) => { + if (token.type === NATIVE_TOKEN) { + const balances = await Promise.all( + this.addresses.map(async (address) => { + const response = await this.client.get( + `/insight-api-zcoin/addr/${address}/balance`, + ); + return BigInt(response.data); + }), + ); + return zipWith(this.addresses, balances, (address, amount) => ({ + address, + amount, + })).filter((amountPerAddress) => amountPerAddress.amount); + } + + return []; + }; +} diff --git a/packages/asset-calculator/lib/interfaces.ts b/packages/asset-calculator/lib/interfaces.ts index 03ab3023c..7f1427aa1 100644 --- a/packages/asset-calculator/lib/interfaces.ts +++ b/packages/asset-calculator/lib/interfaces.ts @@ -18,6 +18,10 @@ interface DogeCalculatorInterface extends CalculatorInterface { blockcypherUrl: string; } +interface FiroCalculatorInterface extends CalculatorInterface { + explorerUrl?: string; +} + interface EvmCalculatorInterface extends CalculatorInterface { rpcUrl: string; authToken?: string; @@ -34,4 +38,5 @@ export { BitcoinRunesCalculatorInterface, EvmCalculatorInterface, DogeCalculatorInterface, + FiroCalculatorInterface, }; diff --git a/packages/asset-calculator/tests/asset-calculator.spec.ts b/packages/asset-calculator/tests/asset-calculator.spec.ts index 7c6d1d068..ad8866256 100644 --- a/packages/asset-calculator/tests/asset-calculator.spec.ts +++ b/packages/asset-calculator/tests/asset-calculator.spec.ts @@ -33,6 +33,10 @@ describe('AssetCalculator', () => { addresses: ['hotAddr', 'coldAddr'], blockcypherUrl: 'blockcypherUrl', }, + { + addresses: ['hotAddr', 'coldAddr'], + explorerUrl: 'firoExplorerUrl', + }, dataSource, ); }); @@ -120,6 +124,10 @@ describe('AssetCalculator', () => { addresses: ['hotAddr', 'coldAddr'], blockcypherUrl: 'blockcypherUrl', }, + { + addresses: ['hotAddr', 'coldAddr'], + explorerUrl: 'firoExplorerUrl', + }, dataSource, ); }); @@ -193,6 +201,7 @@ describe('AssetCalculator', () => { { addresses: ['Addr'], rpcUrl: 'rpcUrl' }, { addresses: ['Addr'], rpcUrl: 'bnbRpcUrl' }, { addresses: ['Addr'], blockcypherUrl: 'blockcypherUrl' }, + { addresses: ['Addr'], explorerUrl: 'firoExplorerUrl' }, dataSource, ); assetCalculator['totalSupplyInit'] = true; @@ -312,6 +321,7 @@ describe('AssetCalculator', () => { { addresses: ['Addr'], rpcUrl: 'rpcUrl' }, { addresses: ['Addr'], rpcUrl: 'bnbRpcUrl' }, { addresses: ['Addr'], blockcypherUrl: 'blockcypherUrl' }, + { addresses: ['Addr'], explorerUrl: 'firoExplorerUrl' }, dataSource, ); assetCalculator['totalSupplyInit'] = true; @@ -422,6 +432,10 @@ describe('AssetCalculator', () => { addresses: ['hotAddr', 'coldAddr'], blockcypherUrl: 'blockcypherUrl', }, + { + addresses: ['hotAddr', 'coldAddr'], + explorerUrl: 'firoExplorerUrl', + }, dataSource, ); }); diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts index cfc149ac5..cff2f29b3 100644 --- a/packages/constants/src/index.ts +++ b/packages/constants/src/index.ts @@ -65,6 +65,14 @@ export const NETWORKS = { id: '', hasTokenSupport: false, }, + 'firo': { + index: 7, + key: 'firo', + label: 'Firo', + nativeToken: 'firo', + id: '', + hasTokenSupport: false, + }, } as const; export const NETWORKS_KEYS = Object.values(NETWORKS).map( diff --git a/packages/utils/src/getAddressUrl.ts b/packages/utils/src/getAddressUrl.ts index 366a64e60..4fdea1190 100644 --- a/packages/utils/src/getAddressUrl.ts +++ b/packages/utils/src/getAddressUrl.ts @@ -9,6 +9,7 @@ const baseAddressURLs: { [key in Network]: string } = { [NETWORKS['bitcoin-runes'].key]: 'https://uniscan.cc/address', [NETWORKS.ethereum.key]: 'https://etherscan.io/address', [NETWORKS.doge.key]: 'https://blockexplorer.one/dogecoin/mainnet/address', + [NETWORKS.firo.key]: 'https://explorer.firo.org/address', }; export const getAddressUrl = ( diff --git a/packages/utils/src/getTokenUrl.ts b/packages/utils/src/getTokenUrl.ts index 66cb748be..c3542b808 100644 --- a/packages/utils/src/getTokenUrl.ts +++ b/packages/utils/src/getTokenUrl.ts @@ -9,6 +9,7 @@ const baseTokenURLs: { [key in Network]: string } = { [NETWORKS['bitcoin-runes'].key]: 'https://unisat.io/runes/detail', [NETWORKS.ethereum.key]: 'https://etherscan.io/token', [NETWORKS.doge.key]: '', + [NETWORKS.firo.key]: '', }; export const getTokenUrl = ( diff --git a/packages/utils/src/getTxUrl.ts b/packages/utils/src/getTxUrl.ts index 7cc3f95bb..1d6070cc5 100644 --- a/packages/utils/src/getTxUrl.ts +++ b/packages/utils/src/getTxUrl.ts @@ -18,6 +18,7 @@ const baseTxURLs: { [key in Network]: HttpsURL } = { [NETWORKS['bitcoin-runes'].key]: 'https://uniscan.cc/tx', [NETWORKS.ethereum.key]: 'https://etherscan.io/tx', [NETWORKS.doge.key]: 'https://blockexplorer.one/dogecoin/mainnet/tx', + [NETWORKS.firo.key]: 'https://explorer.firo.org/tx', }; export const getTxURL = (