diff --git a/relayer/middleware/staging-area.middleware.ts b/relayer/middleware/staging-area.middleware.ts index ca23912a..9a43ede7 100644 --- a/relayer/middleware/staging-area.middleware.ts +++ b/relayer/middleware/staging-area.middleware.ts @@ -14,24 +14,31 @@ export interface StagingAreaContext extends Context { kv: StagingAreaKeyLock; } -export interface StagingAreaOpts { - redisClusterEndpoints?: ClusterNode[]; - redisCluster?: ClusterOptions; +export type StagingAreaOpts = ( + | { + redisClusterEndpoints: ClusterNode[]; + redisCluster: ClusterOptions; + } + | {} +) & { redis?: RedisOptions; namespace?: string; -} +}; export function stagingArea( opts: StagingAreaOpts = {}, ): Middleware { - opts.redis = opts.redis || { host: "localhost", port: 6379 }; + const options = { + redis: { host: "localhost", port: 6379 }, + ...opts, + } // TODO: maybe refactor redis pool for all plugins that rely on it. const factory = { create: async function () { - const redis = opts.redisCluster + const redis = "redisCluster" in opts ? new Redis.Cluster(opts.redisClusterEndpoints, opts.redisCluster) - : new Redis(opts.redis); + : new Redis(options.redis); return redis; }, destroy: async function () { @@ -51,8 +58,8 @@ export function stagingArea( ctx.kv = new DefaultStagingAreaKeyLock( redis, - ctx.logger, opts.namespace ?? "default", + ctx.logger, ); try { ctx.logger?.debug("Staging area attached to context"); @@ -83,8 +90,8 @@ class DefaultStagingAreaKeyLock implements StagingAreaKeyLock { constructor( private readonly redis: Redis | Cluster, - readonly logger: Logger, namespace: string, + readonly logger?: Logger, ) { this.stagingAreaKey = `stagingAreas:${sanitize(namespace)}`; } @@ -117,14 +124,14 @@ class DefaultStagingAreaKeyLock implements StagingAreaKeyLock { }; return tx ? await op((tx as unknown as Tx).redis) : op(this.redis); } catch (e) { - // Figure out how to catch wath error in ioredis + // Figure out how to catch watch error in ioredis // if (e instanceof WatchError) { // // todo: retry in this case? // this.logger.warn("Staging area key was mutated while executing"); // } else { // this.logger.error("Error while reading and writing staging area keys"); // } - this.logger.error(e); + this.logger?.error(e); throw e; } } diff --git a/relayer/middleware/tokenBridge.middleware.ts b/relayer/middleware/tokenBridge.middleware.ts index a502efb3..d3b04785 100644 --- a/relayer/middleware/tokenBridge.middleware.ts +++ b/relayer/middleware/tokenBridge.middleware.ts @@ -136,11 +136,15 @@ export function tokenBridgeContracts(): Middleware { } // User might or might not use sui, so a provider for sui // might not be present. - if (!suiState && ctx.providers.sui[0]) { - suiState = await getObjectFields( + if (suiState === undefined && ctx.providers.sui.length > 0) { + const fields = await getObjectFields( ctx.providers.sui[0], - CONTRACTS[ctx.env.toUpperCase() as "MAINNET"].sui.token_bridge, + CONTRACTS[ctx.env.toUpperCase() as "MAINNET" | "TESTNET" | "DEVNET"].sui.token_bridge, ); + if (fields === null) { + throw new UnrecoverableError("Couldn't read ") + } + suiState = fields; tokenBridgeEmitterCapSui = suiState?.emitter_cap.fields.id.id; } if (!evmContracts) { diff --git a/relayer/middleware/wallet/wallet-management.ts b/relayer/middleware/wallet/wallet-management.ts index 1e8ab749..0f273bff 100644 --- a/relayer/middleware/wallet/wallet-management.ts +++ b/relayer/middleware/wallet/wallet-management.ts @@ -30,6 +30,8 @@ import { } from "@certusone/wormhole-sdk/lib/cjs/utils/consts.js"; import { Environment } from "../../environment.js"; +export type MetricsOptions = (WalletManagerFullConfig["options"] & {}) ["metrics"] & {}; + const networks = { [Environment.MAINNET]: { [CHAIN_ID_ETH]: "mainnet", @@ -140,7 +142,7 @@ export function startWalletManagement( env: Environment, privateKeys: PrivateKeys, tokensByChain?: TokensByChain, - metricsOpts?: WalletManagerFullConfig["options"]["metrics"], + metricsOpts?: MetricsOptions, logger?: Logger, ): IClientWalletManager | ILibraryWalletManager { const wallets = buildWalletsConfig(env, privateKeys, tokensByChain); diff --git a/relayer/middleware/wallet/walletToolBox.ts b/relayer/middleware/wallet/walletToolBox.ts index cba2df63..f5425cc9 100644 --- a/relayer/middleware/wallet/walletToolBox.ts +++ b/relayer/middleware/wallet/walletToolBox.ts @@ -44,6 +44,8 @@ export async function createWalletToolbox( const seiPkBuf = Buffer.from(privateKey, "hex"); return createSeiWalletToolBox(providers, seiPkBuf); } + + throw new Error(`Unknown chain id ${chainId}`); } function createEVMWalletToolBox( @@ -51,7 +53,11 @@ function createEVMWalletToolBox( privateKey: string, chainId: wh.EVMChainId, ): WalletToolBox { - const wallet = new ethers.Wallet(privateKey, providers.evm[chainId][0]); + const chainProviders = providers.evm[chainId]; + if (chainProviders === undefined || chainProviders.length === 0) { + throw new Error(`No provider found for chain ${chainId}`); + } + const wallet = new ethers.Wallet(privateKey, chainProviders[0]); return { ...providers, wallet: wallet, diff --git a/relayer/rpc/fail-fast-grpc-transport.ts b/relayer/rpc/fail-fast-grpc-transport.ts index f65a41bd..518b324e 100644 --- a/relayer/rpc/fail-fast-grpc-transport.ts +++ b/relayer/rpc/fail-fast-grpc-transport.ts @@ -85,6 +85,10 @@ class TimeoutableTransport implements pkg.grpc.Transport { } sendMessage(msgBytes: Uint8Array): void { + if (this.request === undefined) { + throw new Error("Attempted to send a message without a request context"); + } + if ( !this.options.methodDefinition.requestStream && !this.options.methodDefinition.responseStream diff --git a/relayer/storage/redis-storage.ts b/relayer/storage/redis-storage.ts index ff56a2c7..2069f1df 100644 --- a/relayer/storage/redis-storage.ts +++ b/relayer/storage/redis-storage.ts @@ -89,11 +89,11 @@ const defaultOptions: Partial = { }; export class RedisStorage implements Storage { - logger: Logger; + logger?: Logger; vaaQueue: Queue; public registry: Registry; - workerId: string; - private worker: Worker; + workerId?: string; + private worker?: Worker; private readonly prefix: string; private readonly redis: Cluster | Redis; private metrics: StorageMetrics; @@ -109,7 +109,7 @@ export class RedisStorage implements Storage { this.opts.redis.maxRetriesPerRequest = null; //Added because of: DEPRECATION WARNING! Your redis options maxRetriesPerRequest must be null. On the next versions having this settings will throw an exception this.prefix = `{${this.opts.namespace ?? this.opts.queueName}}`; this.redis = - this.opts.redisClusterEndpoints?.length > 0 + this.opts.redisClusterEndpoints !== undefined && this.opts.redisClusterEndpoints.length > 0 ? new Redis.Cluster( this.opts.redisClusterEndpoints, this.opts.redisCluster, @@ -169,7 +169,7 @@ export class RedisStorage implements Storage { return { attempts: 0, data: { vaaBytes, parsedVaa }, - id: job.id, + id: job.id!, name: job.name, log: job.log.bind(job), receivedAt: startTime, @@ -218,7 +218,7 @@ export class RedisStorage implements Storage { sequence: parsedVaa.sequence.toString(), }); } else { - this.logger.debug("Received job with no parsedVaa"); + this.logger?.debug("Received job with no parsedVaa"); } const vaaBytes = Buffer.from(job.data.vaaBytes, "base64"); @@ -228,7 +228,7 @@ export class RedisStorage implements Storage { vaaBytes, parsedVaa: parseVaa(vaaBytes), }, - id: job.id, + id: job.id!, maxAttempts: this.opts.attempts, name: job.name, receivedAt: job.timestamp, @@ -253,11 +253,11 @@ export class RedisStorage implements Storage { async stopWorker() { await this.worker?.close(); - this.worker = null; + this.worker = undefined; } async spawnGaugeUpdateWorker(ms = 5000) { - while (this.worker !== null) { + while (this.worker !== undefined) { await this.updateGauges(); await sleep(ms); }