117 lines
3.3 KiB
TypeScript
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
|
|
};
|
|
}
|
|
}
|