import { AbiEvent, Base58, Hex } from 'ox' import * as FundingCatalog from '../../db/tables/fundingCatalog.js' import * as TestApp from '../../../test/App.js' import * as TestFunding from '../../../test/Funding.js' import * as TestRelay from '../../../test/Relay.js' import * as Chain from './Chain.js' import * as Evidence from './Evidence.js' const transferTopic = AbiEvent.getSelector('event Transfer(address,address,uint256)').slice(2) const db = TestApp.database() describe('resolveRpcUrls', () => { test('prefers matching Worker overrides and retains catalog fallbacks', () => { const ethereum = Chain.from({ id: 'eip155:1', name: 'Ethereum', rpcUrls: ['https://ethereum.catalog.test'], slug: 'ethereum', }) const solana = Chain.from({ id: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', name: 'Solana', rpcUrls: ['https://solana.catalog.test'], slug: 'solana', }) const tempo = Chain.from({ id: 'eip155:4217', name: 'Tempo', rpcUrls: ['https://tempo.catalog.test'], slug: 'tempo', }) const override = JSON.stringify({ 1: 'https://ethereum.worker.test' }) expect({ mappedEthereum: Evidence.resolveRpcUrls({ chain: ethereum, defaultChainId: 4217, rpcUrlEnv: override, }), mappedTempo: Evidence.resolveRpcUrls({ chain: tempo, defaultChainId: 4217, rpcUrlEnv: override, }), sharedEthereum: Evidence.resolveRpcUrls({ chain: ethereum, defaultChainId: 4217, rpcUrlEnv: 'https://tempo.worker.test', }), sharedSolana: Evidence.resolveRpcUrls({ chain: solana, defaultChainId: 4217, rpcUrlEnv: 'https://tempo.worker.test', }), sharedTempo: Evidence.resolveRpcUrls({ chain: tempo, defaultChainId: 4217, rpcUrlEnv: 'https://tempo.worker.test', }), }).toMatchInlineSnapshot(` { "mappedEthereum": [ "https://ethereum.worker.test", "https://ethereum.catalog.test", ], "mappedTempo": [ "https://tempo.catalog.test", ], "sharedEthereum": [ "https://ethereum.catalog.test", ], "sharedSolana": [ "https://solana.catalog.test", ], "sharedTempo": [ "https://tempo.worker.test", "https://tempo.catalog.test", ], } `) }) }) describe('createVerifier', () => { test('verifies finalized Solana and one-confirmation Tron token transfers', async () => { const tron = TestFunding.depositAddressSnapshot() const solana = TestFunding.transferSnapshot({ sourceChain: { addressFormat: 'base58', id: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', kind: 'solana', name: 'Solana', }, sourceToken: { address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', currency: 'USD', decimals: 6, name: 'USD Coin', standard: 'SPL', symbol: 'USDC', tokenKey: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', verified: true, }, }) const solanaRecipient = 'RelayRecipient11111111111111111111111111111' const refreshedSolana = { ...solana.sourceChain, id: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', name: 'Solana Devnet', } as const const server = await TestRelay.createServer((request, response) => { request.resume() if (request.url === '/unavailable') { response.writeHead(503) response.end() return } const result = request.url?.includes('getnowblock') ? { block_header: { raw_data: { number: 150 } } } : request.url?.includes('gettransactioninfobyid') ? { blockNumber: 150, id: 'tron-transaction', log: [ { address: tronHex(tron.sourceToken.address).slice(-40), data: 1_000_000n.toString(16).padStart(64, '0'), topics: [ transferTopic, `0x${'66'.repeat(20).padStart(64, '0')}`, `0x${tronHex(tron.address).slice(-40).padStart(64, '0')}`, ], }, ], receipt: { result: 'SUCCESS' }, } : { meta: { err: null, postTokenBalances: [ { accountIndex: 1, mint: solana.sourceToken.address, owner: solanaRecipient, }, ], }, transaction: { message: { accountKeys: [ 'Sender1111111111111111111111111111111111', 'RecipientTokenAccount', ], instructions: [ { parsed: { info: { authority: 'Sender1111111111111111111111111111111111', destination: 'RecipientTokenAccount', mint: solana.sourceToken.address, tokenAmount: { amount: '2000000' }, }, type: 'transferChecked', }, program: 'spl-token', }, ], }, }, } response.writeHead(200, { 'content-type': 'application/json' }) response.end( request.url === '/' ? JSON.stringify({ id: 1, jsonrpc: '2.0', result }) : JSON.stringify(result), ) }) try { vi.useFakeTimers({ now: new Date('2027-01-01T00:00:00.000Z') }) await FundingCatalog.publish(db, { chainTokens: [], chains: [ { aliases: [], id: solana.sourceChain.id as Chain.Id, name: solana.sourceChain.name, parentChainId: null, rpcUrls: [new URL('/unavailable', server.url).toString(), server.url], slug: 'solana', }, { aliases: [], id: tron.sourceChain.id as Chain.Id, name: tron.sourceChain.name, parentChainId: null, rpcUrls: [new URL('/unavailable', server.url).toString(), server.url], slug: 'tron', }, ], routes: [], tokens: [], }) const verify = Evidence.createVerifier({ db, }) const solanaEvidence = await verify({ chain: solana.sourceChain, recipient: solanaRecipient, token: solana.sourceToken, transactionHash: 'solana-transaction', }) const tronEvidence = await verify({ chain: tron.sourceChain, recipient: tron.address, token: tron.sourceToken, transactionHash: 'tron-transaction', }) await FundingCatalog.publish(db, { chainTokens: [], chains: [ { aliases: [], id: refreshedSolana.id as Chain.Id, name: refreshedSolana.name, parentChainId: null, rpcUrls: [server.url], slug: 'solana-devnet', }, { aliases: [], id: solana.sourceChain.id as Chain.Id, name: solana.sourceChain.name, parentChainId: null, rpcUrls: [new URL('/unavailable', server.url).toString(), server.url], slug: 'solana', }, { aliases: [], id: tron.sourceChain.id as Chain.Id, name: tron.sourceChain.name, parentChainId: null, rpcUrls: [new URL('/unavailable', server.url).toString(), server.url], slug: 'tron', }, ], routes: [], tokens: [], }) await vi.advanceTimersByTimeAsync(60_001) const refreshedSolanaEvidence = await verify({ chain: refreshedSolana, recipient: solanaRecipient, token: solana.sourceToken, transactionHash: 'solana-refreshed-transaction', }) expect({ refreshedSolanaEvidence, solanaEvidence, tronEvidence }).toMatchInlineSnapshot(` { "refreshedSolanaEvidence": [ { "amount": "2000000", "sender": "Sender1111111111111111111111111111111111", "transactionHash": "solana-refreshed-transaction", "transferIndex": 0, }, ], "solanaEvidence": [ { "amount": "2000000", "sender": "Sender1111111111111111111111111111111111", "transactionHash": "solana-transaction", "transferIndex": 0, }, ], "tronEvidence": [ { "amount": "1000000", "sender": "TKJebW6SdoJhgkKU13BeKCbrMzT6HeQhJ6", "transactionHash": "tron-transaction", "transferIndex": 0, }, ], } `) } finally { vi.useRealTimers() await server.closeAsync() } }) }) function tronHex(address: string) { return Hex.fromBytes(Base58.toBytes(address).slice(0, 21)).slice(2) }