UNPKG

@reservoir0x/relay-sdk

Version:

Relay is the Fastest and Cheapest Way to Bridge and Transact Across Chains.

207 lines 8.46 kB
import { LogLevel } from './logger.js'; import { getClient } from '../client.js'; import { createPublicClient, createWalletClient, custom, fallback, hexToBigInt, http } from 'viem'; export function isViemWalletClient(wallet) { return (wallet.extend !== undefined && wallet.getPermissions !== undefined); } export const adaptViemWallet = (wallet) => { return { vmType: 'evm', getChainId: async () => { return wallet.getChainId(); }, transport: custom(wallet.transport), address: async () => { let address = wallet.account?.address; if (!address) { ; [address] = await wallet.getAddresses(); } return address; }, handleSignMessageStep: async (stepItem) => { const client = getClient(); const signData = stepItem.data?.sign; let signature; if (signData) { if (signData.signatureKind === 'eip191') { client.log(['Execute Steps: Signing with eip191'], LogLevel.Verbose); if (signData.message.match(/0x[0-9a-fA-F]{64}/)) { // If the message represents a hash, we need to convert it to raw bytes first signature = await wallet.signMessage({ account: wallet.account, message: { raw: signData.message } }); } else { signature = await wallet.signMessage({ account: wallet.account, message: signData.message }); } } else if (signData.signatureKind === 'eip712') { const signatureData = { account: wallet.account, domain: signData.domain, types: signData.types, primaryType: signData.primaryType, message: signData.value }; client.log(['Execute Steps: Signing with eip712', signatureData], LogLevel.Verbose); signature = await wallet.signTypedData(signatureData); } } return signature; }, handleSendTransactionStep: async (chainId, stepItem) => { const stepData = stepItem.data; const client = getClient(); const chain = getClient().chains.find((chain) => chain.id === chainId)?.viemChain; if (!chain) { throw 'Chain not found when sending transaction'; } const viemClient = createWalletClient({ account: wallet.account ?? stepData.from, chain, transport: custom(wallet.transport, { retryCount: 10, retryDelay: 200 }) }); return await viemClient.sendTransaction({ chain, data: stepData.data, account: wallet.account ?? stepData.from, // use signer.account if it's defined to: stepData.to, value: hexToBigInt(stepData.value || 0), ...(stepData.maxFeePerGas && client.useGasFeeEstimations && { maxFeePerGas: hexToBigInt(stepData.maxFeePerGas) }), ...(stepData.maxPriorityFeePerGas && client.useGasFeeEstimations && { maxPriorityFeePerGas: hexToBigInt(stepData.maxPriorityFeePerGas) }), ...(stepData.gas && client.useGasFeeEstimations && { gas: hexToBigInt(stepData.gas) }) }); }, handleConfirmTransactionStep: async (txHash, chainId, onReplaced, onCancelled) => { const client = getClient(); const chain = client.chains.find((chain) => chain.id === chainId); const rpcUrl = chain?.httpRpcUrl; const viemClient = createPublicClient({ chain: chain?.viemChain, transport: wallet.transport ? fallback(rpcUrl ? [http(rpcUrl), custom(wallet.transport), http()] : [custom(wallet.transport), http()]) : fallback([http(rpcUrl), http()]), pollingInterval: client.confirmationPollingInterval }); const receipt = await viemClient.waitForTransactionReceipt({ hash: txHash, onReplaced: (replacement) => { if (replacement.reason === 'cancelled') { onCancelled(); throw Error('Transaction cancelled'); } onReplaced(replacement.transaction.hash); } }); return receipt; }, switchChain: async (chainId) => { try { await wallet.switchChain({ id: chainId }); return; } catch (e) { if (e && e?.message) { if (e.message.includes('does not support the requested chain')) { throw new Error('Wallet does not support chain'); } else if (e.message.includes('rejected')) { throw e; } else if (e.message.includes('already pending')) { return; } } const client = getClient(); const chain = client.chains.find((chain) => chain.id === chainId); if (!chain) { throw 'Chain missing from Relay Client'; } try { await wallet.addChain({ chain: chain?.viemChain }); } catch (e) { if (e instanceof Error && e.name && e.name === 'InternalRpcError' && e.message.includes('is not a function')) { getClient()?.log([ 'Execute Steps: Detected internal RPC Error when adding a chain to the wallet', e ], LogLevel.Verbose); return; } else { throw e; } } return; } }, supportsAtomicBatch: async (chainId) => { if (!wallet.account) return false; try { const capabilities = await wallet.getCapabilities({ account: wallet.account, chainId }); return capabilities?.atomicBatch?.supported; } catch { return false; } }, handleBatchTransactionStep: async (chainId, items) => { const calls = items.map((item) => ({ to: item.data.to, data: item.data.data, value: hexToBigInt(item.data.value || 0), ...(item.data.maxFeePerGas && { maxFeePerGas: hexToBigInt(item.data.maxFeePerGas) }), ...(item.data.maxPriorityFeePerGas && { maxPriorityFeePerGas: hexToBigInt(item.data.maxPriorityFeePerGas) }), ...(item.data.gas && { gas: hexToBigInt(item.data.gas) }) })); const client = getClient(); const chain = client.chains.find((chain) => chain.id === chainId)?.viemChain; if (!chain) { throw 'Chain not found when sending transaction'; } const { id } = await wallet.sendCalls({ chain, account: wallet.account, calls }); return id; } }; }; //# sourceMappingURL=viemWallet.js.map