UNPKG

@atomiqlabs/chain-evm

Version:

EVM specific base implementation

116 lines (95 loc) 4.14 kB
import {IClaimHandler} from "../ClaimHandlers"; import {BigIntBufferUtils, ChainSwapType, RelaySynchronizer} from "@atomiqlabs/base"; import {EVMBtcRelay} from "../../../../btcrelay/EVMBtcRelay"; import { EVMBtcStoredHeader } from "../../../../btcrelay/headers/EVMBtcStoredHeader"; import {EVMTx} from "../../../../chain/modules/EVMTransactions"; import {getLogger} from "../../../../../utils/Utils"; import {keccak256} from "ethers"; import {Buffer} from "buffer"; import {EVMSwapData} from "../../../EVMSwapData"; export type BitcoinCommitmentData = { btcRelay: EVMBtcRelay<any>, confirmations: number } export type BitcoinWitnessData = { tx: { blockhash: string, confirmations: number, txid: string, hex: string, height: number }, requiredConfirmations: number, commitedHeader?: EVMBtcStoredHeader, btcRelay?: EVMBtcRelay<any>, synchronizer?: RelaySynchronizer<EVMBtcStoredHeader, EVMTx, any> }; const logger = getLogger("IBitcoinClaimHandler: "); export abstract class IBitcoinClaimHandler<C, W extends BitcoinWitnessData> implements IClaimHandler<C & BitcoinCommitmentData, W> { public readonly address: string; constructor(address: string) { this.address = address; } public static readonly address = ""; public static readonly type: ChainSwapType = ChainSwapType.CHAIN_TXID; public static readonly gas: number = 10_000; protected serializeCommitment(data: BitcoinCommitmentData): Buffer { const buffer = Buffer.alloc(24); buffer.writeUint32BE(data.confirmations, 0); Buffer.from(data.btcRelay.contractAddress.substring(2), "hex").copy(buffer, 4, 0, 20); return buffer; } getCommitment(data: C & BitcoinCommitmentData): string { return keccak256(this.serializeCommitment(data)); } protected async _getWitness( signer: string, swapData: EVMSwapData, {tx, btcRelay, commitedHeader, synchronizer, requiredConfirmations}: BitcoinWitnessData, commitment: C, feeRate?: string ): Promise<{ initialTxns: EVMTx[]; witness: Buffer, commitment: Buffer, blockheader: Buffer, merkleProof: Buffer }> { const serializedCommitment: Buffer = this.serializeCommitment({ ...commitment, btcRelay, confirmations: requiredConfirmations }); const commitmentHash = keccak256(serializedCommitment); if(!swapData.isClaimData(commitmentHash)) throw new Error("Invalid commit data"); const merkleProof = await btcRelay.bitcoinRpc.getMerkleProof(tx.txid, tx.blockhash); logger.debug("getWitness(): merkle proof computed: ", merkleProof); const txs: EVMTx[] = []; if(commitedHeader==null) { const headers = await EVMBtcRelay.getCommitedHeadersAndSynchronize( signer, btcRelay, [{blockheight: tx.height, requiredConfirmations, blockhash: tx.blockhash}], txs, synchronizer, feeRate ); if(headers==null) throw new Error("Cannot fetch committed header!"); commitedHeader = headers[tx.blockhash]; } const serializedHeader = commitedHeader.serialize(); const serializedMerkleProof = Buffer.concat([ BigIntBufferUtils.toBuffer(BigInt(merkleProof.pos), "be", 4), BigIntBufferUtils.toBuffer(BigInt(merkleProof.merkle.length), "be", 32), ...merkleProof.merkle ]); return { initialTxns: txs, witness: Buffer.concat([ serializedCommitment, serializedHeader, serializedMerkleProof ]), commitment: serializedCommitment, blockheader: serializedHeader, merkleProof: serializedMerkleProof }; } abstract getWitness(signer: string, data: EVMSwapData, witnessData: W, feeRate?: string): Promise<{ initialTxns: EVMTx[]; witness: Buffer }>; abstract getGas(data: EVMSwapData): number; abstract getType(): ChainSwapType; }