Files
smom-dbis-138/services/solana-relay/src/SolanaRelayService.ts

117 lines
3.3 KiB
TypeScript

import {
NON_EVM_RELAY_LIFECYCLE,
type NonEvmNetworkPolicy,
type NonEvmRelayObservation
} from '../../non-evm-relay/lifecycle';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export const SOLANA_RELAY_POLICY: NonEvmNetworkPolicy = {
identifier: 'Solana',
relayMode: 'custom_relay',
destinationProgramModel: 'spl_or_bridge_wrapped_cw',
signerFundingPolicy: 'sol_operator_signer',
finalityPolicy: 'slot_finality>=32',
publicExposureStatus: 'live'
};
export interface SolanaRelayAssetRuntime {
chain138Symbol: string;
sourceToken: string;
solanaSymbol: string;
solanaMint: string;
decimals: number;
smokeTestAmountRaw: string;
}
export interface SolanaRelayRuntimeConfig {
sourceChain: {
chainId: number;
chainRegistryAddress: string;
registryIdentifier: string;
adapterAddress: string | null;
};
solana: {
cluster: string;
rpcUrl: string;
operatorWallet: string;
confirmationFinality: number;
recipientEncoding: string;
};
relay: {
mode: string;
runtimeConfigEnv: string;
syntheticConfirmationPrefix: string;
publicExposureStatus?: string;
workerEntryPoint?: string;
};
smokeTests: {
defaultAssets: string[];
wethRawAmount: string;
gruRawAmount: string;
requireAdapterRegistration: boolean;
};
assets: SolanaRelayAssetRuntime[];
}
export function resolveSolanaRelayRuntimeConfigPath(): string {
const explicit = process.env.SOLANA_RELAY_RUNTIME_CONFIG;
if (explicit && explicit.trim() !== '') {
return path.resolve(process.cwd(), explicit);
}
return path.resolve(__dirname, '../../../../config/solana-relay-runtime.json');
}
export function loadSolanaRelayRuntimeConfig(): SolanaRelayRuntimeConfig {
const runtimePath = resolveSolanaRelayRuntimeConfigPath();
const raw = fs.readFileSync(runtimePath, 'utf8');
return JSON.parse(raw) as SolanaRelayRuntimeConfig;
}
/**
* Shared lifecycle surface for the Solana relay worker.
* The actual host-side worker entry point lives in relay-worker.mjs and performs
* real Solana settlement plus Chain 138 finalization.
*/
export class SolanaRelayService {
readonly lifecycle = NON_EVM_RELAY_LIFECYCLE;
readonly runtime: SolanaRelayRuntimeConfig;
constructor(runtime = loadSolanaRelayRuntimeConfig()) {
this.runtime = runtime;
}
recordObservation(observation: NonEvmRelayObservation): NonEvmRelayObservation {
return {
...observation,
lifecycleStep: observation.lifecycleStep
};
}
getAsset(symbol: string): SolanaRelayAssetRuntime | undefined {
return this.runtime.assets.find((asset) => asset.solanaSymbol === symbol || asset.chain138Symbol === symbol);
}
buildSmokeObservation(
requestId: string,
symbol: string,
destinationReference?: string
): NonEvmRelayObservation {
const asset = this.getAsset(symbol);
const destination = destinationReference || asset?.solanaMint || this.runtime.solana.operatorWallet;
return {
requestId,
lifecycleStep: 'confirm_finalize',
destinationReference: destination,
fulfillmentId: `${this.runtime.relay.syntheticConfirmationPrefix}:${symbol}:${requestId}`,
finalityValue: this.runtime.solana.confirmationFinality,
replayRejected: false
};
}
}