Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/base-network-registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@rosen-bridge/icons': minor
'@rosen-network/evm': minor
'@rosen-ui/constants': minor
'@rosen-ui/utils': minor
---

Register Base in the shared UI network registry, EVM RPC handling, explorer URL helpers, and network icons.
6 changes: 6 additions & 0 deletions .changeset/base-service-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rosen-ui/asset-calculator': minor
'@rosen-bridge/rosen-service': minor
---

Add Base support to the asset calculator and rosen-service scanner, observation, event-trigger, config, and health-check flows.
15 changes: 15 additions & 0 deletions apps/rosen-service/config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ binance:
initialHeight:
rpcUrl: https://bsc-mainnet.public.blastapi.io/
# rpcAuthToken:
base:
addresses:
lock:
eventTrigger:
permit:
fraud:
commitment:
tokens:
rwt:
initialHeight:
rpcUrl: # use a production provider; the public Base endpoint is rate-limited
# rpcAuthToken:
postgres:
url: # postgresql://username:password@host:port/databasename
logging: false
Expand All @@ -107,6 +119,7 @@ calculator:
doge: []
ethereum: []
binance: []
base: []
healthCheck:
ergoScannerWarnDiff: 3
ergoScannerCriticalDiff: 5
Expand All @@ -120,6 +133,8 @@ healthCheck:
ethereumScannerCriticalDiff: 5
binanceScannerWarnDiff: 3
binanceScannerCriticalDiff: 5
baseScannerWarnDiff: 3
baseScannerCriticalDiff: 5
interval: 60 # health check update interval (in seconds)
duration: 600 # log duration time check (in seconds)
maxAllowedErrorCount: 1 # maximum allowed error log lines
Expand Down
3 changes: 2 additions & 1 deletion apps/rosen-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@
"@rosen-bridge/discord-notification": "^1.0.0",
"@rosen-bridge/ergo-observation-extractor": "^1.0.3",
"@rosen-bridge/ergo-scanner": "^1.0.2",
"@rosen-bridge/evm-observation-extractor": "^6.0.3",
"@rosen-bridge/evm-observation-extractor": "^7.0.0",
"@rosen-bridge/evm-scanner": "^1.0.2",
"@rosen-bridge/health-check": "^8.0.0",
"@rosen-bridge/log-level-check": "^4.0.0",
"@rosen-bridge/rosen-extractor": "^12.0.1",
"@rosen-bridge/scanner-interfaces": "^0.2.2",
"@rosen-bridge/scanner-sync-check": "^8.2.0",
"@rosen-bridge/tokens": "^6.0.0",
Expand Down
5 changes: 5 additions & 0 deletions apps/rosen-service/src/calculator/calculator-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ const start = async () => {
rpcUrl: config.binance.rpcUrl,
authToken: config.binance.rpcAuthToken,
},
{
addresses: config.calculator.addresses.base,
rpcUrl: config.base.rpcUrl,
authToken: config.base.rpcAuthToken,
},
{
addresses: config.calculator.addresses.doge,
blockcypherUrl: config.doge.blockcypherUrl,
Expand Down
22 changes: 22 additions & 0 deletions apps/rosen-service/src/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,21 @@ const getConfig = () => {
rpcUrl: nodeConfig.get<string>('binance.rpcUrl'),
rpcAuthToken: getOptionalString('binance.rpcAuthToken'),
},
base: {
addresses: {
lock: nodeConfig.get<string>('base.addresses.lock'),
eventTrigger: nodeConfig.get<string>('base.addresses.eventTrigger'),
permit: nodeConfig.get<string>('base.addresses.permit'),
fraud: nodeConfig.get<string>('base.addresses.fraud'),
commitment: nodeConfig.get<string>('base.addresses.commitment'),
},
initialHeight: nodeConfig.get<number>('base.initialHeight'),
tokens: {
rwt: nodeConfig.get<string>('base.tokens.rwt'),
},
rpcUrl: nodeConfig.get<string>('base.rpcUrl'),
rpcAuthToken: getOptionalString('base.rpcAuthToken'),
},
doge: {
addresses: {
lock: nodeConfig.get<string>('doge.addresses.lock'),
Expand Down Expand Up @@ -159,6 +174,7 @@ const getConfig = () => {
),
ethereum: nodeConfig.get<string[]>('calculator.addresses.ethereum'),
binance: nodeConfig.get<string[]>('calculator.addresses.binance'),
base: nodeConfig.get<string[]>('calculator.addresses.base'),
doge: nodeConfig.get<string[]>('calculator.addresses.doge'),
},
interval: nodeConfig.get<number>('calculator.interval'),
Expand Down Expand Up @@ -200,6 +216,12 @@ const getConfig = () => {
binanceScannerCriticalDiff: nodeConfig.get<number>(
'healthCheck.binanceScannerCriticalDiff',
),
baseScannerWarnDiff: nodeConfig.get<number>(
'healthCheck.baseScannerWarnDiff',
),
baseScannerCriticalDiff: nodeConfig.get<number>(
'healthCheck.baseScannerCriticalDiff',
),
updateInterval: nodeConfig.get<number>('healthCheck.interval'),
logDuration: nodeConfig.get<number>('healthCheck.duration'),
errorLogAllowedCount: nodeConfig.get<number>(
Expand Down
3 changes: 3 additions & 0 deletions apps/rosen-service/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ 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 BASE_SCANNER_INTERVAL = 20 * 1000;

export const ERGO_SCANNER_LOGGER_NAME = 'ergoScanner';
export const CARDANO_SCANNER_LOGGER_NAME = 'cardanoScanner';
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 BASE_SCANNER_LOGGER_NAME = 'baseScanner';
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 BASE_BLOCK_TIME = 2;
export const DOGE_BLOCK_TIME = 60;

export const BITCOIN_RUNES_CONFIG_KEY = 'bitcoinRunes';
16 changes: 16 additions & 0 deletions apps/rosen-service/src/event-trigger/event-trigger-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const ethereumEventTriggerExtractorLogger = logger.child(
const binanceEventTriggerExtractorLogger = logger.child(
'binanceEventTriggerExtractor',
);
const baseEventTriggerExtractorLogger = logger.child(
'baseEventTriggerExtractor',
);
const dogeEventTriggerExtractorLogger = logger.child(
'dogeEventTriggerExtractor',
);
Expand Down Expand Up @@ -113,13 +116,25 @@ export const registerExtractors = async (scanner: ErgoScanner) => {
configs.binance.addresses.fraud,
binanceEventTriggerExtractorLogger,
);
const baseEventTriggerExtractor = new EventTriggerExtractor(
'base-extractor',
dataSource,
ErgoNetworkType.Explorer,
configs.ergo.explorerUrl,
configs.base.addresses.eventTrigger,
configs.base.tokens.rwt,
configs.base.addresses.permit,
configs.base.addresses.fraud,
baseEventTriggerExtractorLogger,
);
await scanner.registerExtractor(ergoEventTriggerExtractor);
await scanner.registerExtractor(cardanoEventTriggerExtractor);
await scanner.registerExtractor(bitcoinEventTriggerExtractor);
await scanner.registerExtractor(bitcoinRunesEventTriggerExtractor);
await scanner.registerExtractor(dogeEventTriggerExtractor);
await scanner.registerExtractor(ethereumEventTriggerExtractor);
await scanner.registerExtractor(binanceEventTriggerExtractor);
await scanner.registerExtractor(baseEventTriggerExtractor);

logger.debug('event trigger extractors registered', {
scannerName: scanner.name(),
Expand All @@ -131,6 +146,7 @@ export const registerExtractors = async (scanner: ErgoScanner) => {
dogeEventTriggerExtractor.getId(),
ethereumEventTriggerExtractor.getId(),
binanceEventTriggerExtractor.getId(),
baseEventTriggerExtractor.getId(),
],
});
} catch (error) {
Expand Down
13 changes: 13 additions & 0 deletions apps/rosen-service/src/health-check/health-check-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import path from 'node:path';

import config from '../configs';
import {
BASE_BLOCK_TIME,
BASE_SCANNER_INTERVAL,
BINANCE_BLOCK_TIME,
BINANCE_SCANNER_INTERVAL,
BITCOIN_BLOCK_TIME,
Expand Down Expand Up @@ -131,6 +133,17 @@ const registerAllHealthChecks = (healthCheck: HealthCheck) => {
),
label: 'binance',
},
{
instance: new ScannerSyncHealthCheckParam(
scannerService.getBaseScanner().name(),
async () => getLastSavedBlock(scannerService.getBaseScanner().name()),
config.healthCheck.baseScannerWarnDiff,
config.healthCheck.baseScannerCriticalDiff,
BASE_BLOCK_TIME,
BASE_SCANNER_INTERVAL,
),
label: 'base',
},
];

for (const { instance, label } of checks) {
Expand Down
41 changes: 41 additions & 0 deletions apps/rosen-service/src/observation/chains/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { DefaultLogger } from '@rosen-bridge/abstract-logger';
import { BaseRpcObservationExtractor } from '@rosen-bridge/evm-observation-extractor';
import { EvmRpcScanner } from '@rosen-bridge/evm-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 registerBaseExtractor = async (scanner: EvmRpcScanner) => {
try {
const observationExtractor = new BaseRpcObservationExtractor(
config.base.addresses.lock,
dataSource,
await getTokenMap(),
logger.child('baseRpcObservationExtractor'),
);

await scanner.registerExtractor(observationExtractor);

logger.debug('base observation extractor registered', {
scannerName: scanner.name(),
});
} catch (error) {
throw new AppError(
`cannot create or register base observation extractor due to error: ${error}`,
false,
'error',
error instanceof Error ? error.stack : undefined,
{
scannerName: scanner.name(),
},
);
}
};
2 changes: 2 additions & 0 deletions apps/rosen-service/src/observation/observation-service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { registerBaseExtractor } from './chains/base';
import { registerBinanceExtractor } from './chains/binance';
import { registerBitcoinExtractor } from './chains/bitcoin';
import { registerBitcoinRunesExtractor } from './chains/bitcoin-runes';
Expand All @@ -14,6 +15,7 @@ const observationService = {
registerErgoExtractor,
registerEthereumExtractor,
registerBinanceExtractor,
registerBaseExtractor,
};

export default observationService;
72 changes: 72 additions & 0 deletions apps/rosen-service/src/scanner/chains/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { DefaultLogger } from '@rosen-bridge/abstract-logger';
import {
FailoverStrategy,
NetworkConnectorManager,
} from '@rosen-bridge/abstract-scanner';
import { EvmRpcNetwork, EvmRpcScanner } from '@rosen-bridge/evm-scanner';
import { TransactionResponse } from 'ethers';

import config from '../../configs';
import {
BASE_SCANNER_INTERVAL,
BASE_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(BASE_SCANNER_LOGGER_NAME);

/**
* Creates and configures a NetworkConnectorManager instance for base scanner
*/
export const createBaseNetworkConnectorManager = () => {
const networkConnectorManager =
new NetworkConnectorManager<TransactionResponse>(
new FailoverStrategy(),
scannerLogger,
);

networkConnectorManager.addConnector(
new EvmRpcNetwork(
config.base.rpcUrl,
SCANNER_API_TIMEOUT * 1000,
config.base.rpcAuthToken,
),
);

return networkConnectorManager;
};

/**
* create a base scanner, initializing it and calling its update method
* periodically
*/
export const startBaseScanner = async () => {
try {
const scanner = new EvmRpcScanner('base', {
dataSource,
initialHeight: config.base.initialHeight,
logger: scannerLogger,
network: createBaseNetworkConnectorManager(),
});

await observationService.registerBaseExtractor(scanner);

startScanner(scanner, import.meta.url, BASE_SCANNER_INTERVAL);

logger.debug('base scanner started');

return scanner;
} catch (error) {
throw new AppError(
`cannot create or start base scanner due to error: ${error}`,
false,
'error',
error instanceof Error ? error.stack : undefined,
);
}
};
6 changes: 6 additions & 0 deletions apps/rosen-service/src/scanner/scanner-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ErgoScanner } from '@rosen-bridge/ergo-scanner';
import { EvmRpcScanner } from '@rosen-bridge/evm-scanner';

import { handleError } from '../utils';
import { startBaseScanner } from './chains/base';
import { startBinanceScanner } from './chains/binance';
import { startBitcoinScanner } from './chains/bitcoin';
import { startCardanoScanner } from './chains/cardano';
Expand All @@ -23,6 +24,7 @@ let cardanoScanner: CardanoKoiosScanner;
let bitcoinScanner: BitcoinRpcScanner;
let ethereumScanner: EvmRpcScanner;
let binanceScanner: EvmRpcScanner;
let baseScanner: EvmRpcScanner;
let dogeScanner: DogeRpcScanner;

/**
Expand All @@ -36,13 +38,15 @@ const start = async () => {
bitcoinScanner,
ethereumScanner,
binanceScanner,
baseScanner,
dogeScanner,
] = await Promise.all([
startErgoScanner(),
startCardanoScanner(),
startBitcoinScanner(),
startEthereumScanner(),
startBinanceScanner(),
startBaseScanner(),
startDogeScanner(),
]);

Expand All @@ -53,6 +57,7 @@ const start = async () => {
bitcoinScanner.name(),
ethereumScanner.name(),
binanceScanner.name(),
baseScanner.name(),
dogeScanner.name(),
],
});
Expand All @@ -69,6 +74,7 @@ const scannerService = {
getBitcoinScanner: () => bitcoinScanner,
getEthereumScanner: () => ethereumScanner,
getBinanceScanner: () => binanceScanner,
getBaseScanner: () => baseScanner,
getDogeScanner: () => dogeScanner,
};

Expand Down
1 change: 1 addition & 0 deletions apps/rosen/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ CARDANO_KOIOS_API=''
ERGO_EXPLORER_API=''
BITCOIN_ESPLORA_API=''
DOGE_BLOCKCYPHER_API=''
BASE_RPC_API=''
ETHEREUM_RPC_API=''
BINANCE_RPC_API=''
BITCOIN_RUNES_API=''
Expand Down
Loading