UNPKG

@atomiqlabs/chain-starknet

Version:

Starknet specific base implementation

142 lines (124 loc) 6.61 kB
import {ChainSwapType, RelaySynchronizer, SwapDataVerificationError} from "@atomiqlabs/base"; import {toHex} from "../../../utils/Utils"; import {StarknetSwapModule} from "../StarknetSwapModule"; import {StarknetSwapData} from "../StarknetSwapData"; import {StarknetAction, StarknetGas, sumStarknetGas} from "../../base/StarknetAction"; import {BigNumberish} from "starknet"; import {IClaimHandler} from "../handlers/claim/ClaimHandlers"; import {StarknetTx} from "../../base/modules/StarknetTransactions"; import {StarknetFees} from "../../base/modules/StarknetFees"; import {StarknetBtcStoredHeader} from "../../btcrelay/headers/StarknetBtcStoredHeader"; import {BitcoinOutputWitnessData} from "../handlers/claim/btc/BitcoinOutputClaimHandler"; import {BitcoinWitnessData} from "../handlers/claim/btc/IBitcoinClaimHandler"; import {Buffer} from "buffer"; export class StarknetSwapClaim extends StarknetSwapModule { private static readonly GasCosts = { CLAIM: {l1: 500, l2: 0}, CLAIM_PAY_OUT: {l1: 1000, l2: 0} }; /** * Claim action which uses the provided witness for claiming the swap * * @param signer * @param swapData * @param witness * @param claimHandlerGas * @constructor * @private */ private Claim( signer: string, swapData: StarknetSwapData, witness: BigNumberish[], claimHandlerGas?: StarknetGas ): StarknetAction { return new StarknetAction(signer, this.root, this.contract.populateTransaction.claim(swapData.toEscrowStruct(), witness), sumStarknetGas(swapData.payOut ? StarknetSwapClaim.GasCosts.CLAIM_PAY_OUT : StarknetSwapClaim.GasCosts.CLAIM, claimHandlerGas) ); } /** * Creates transactions claiming the swap using a secret (for HTLC swaps) * * @param signer * @param swapData swap to claim * @param secret hex encoded secret pre-image to the HTLC hash * @param checkExpiry whether to check if the swap is already expired (trying to claim an expired swap with a secret * is dangerous because we might end up revealing the secret to the counterparty without being able to claim the swap) * @param feeRate fee rate to use for the transaction */ async txsClaimWithSecret( signer: string, swapData: StarknetSwapData, secret: string, checkExpiry?: boolean, feeRate?: string ): Promise<StarknetTx[]> { //We need to be sure that this transaction confirms in time, otherwise we reveal the secret to the counterparty // and won't claim the funds if(checkExpiry && await this.root.isExpired(swapData.claimer.toString(), swapData)) { throw new SwapDataVerificationError("Not enough time to reliably pay the invoice"); } const claimHandler: IClaimHandler<Buffer, string> = this.root.claimHandlersByAddress[swapData.claimHandler.toLowerCase()]; if(claimHandler==null) throw new SwapDataVerificationError("Unknown claim handler!"); if(claimHandler.getType()!==ChainSwapType.HTLC) throw new SwapDataVerificationError("Invalid claim handler!"); feeRate ??= await this.root.Fees.getFeeRate(); const {initialTxns, witness} = await claimHandler.getWitness(signer, swapData, secret, feeRate); const action = this.Claim(signer, swapData, witness, claimHandler.getGas(swapData)); await action.addToTxs(initialTxns, feeRate); this.logger.debug("txsClaimWithSecret(): creating claim transaction, swap: "+swapData.getClaimHash()+" witness: ", witness.map(toHex)); return initialTxns; } /** * Creates transaction claiming the swap using a confirmed transaction data (for BTC on-chain swaps) * * @param signer * @param swapData swap to claim * @param tx bitcoin transaction that satisfies the swap condition * @param requiredConfirmations * @param vout vout of the bitcoin transaction that satisfies the swap condition * @param commitedHeader commited header data from btc relay (fetched internally if null) * @param synchronizer optional synchronizer to use in case we need to sync up the btc relay ourselves * @param feeRate fee rate to be used for the transactions */ async txsClaimWithTxData( signer: string, swapData: StarknetSwapData, tx: { blockhash: string, confirmations: number, txid: string, hex: string, height: number }, requiredConfirmations: number, vout: number, commitedHeader?: StarknetBtcStoredHeader, synchronizer?: RelaySynchronizer<StarknetBtcStoredHeader, StarknetTx, any>, feeRate?: string ): Promise<StarknetTx[] | null> { const claimHandler: IClaimHandler<any, BitcoinOutputWitnessData | BitcoinWitnessData> = this.root.claimHandlersByAddress[swapData.claimHandler.toLowerCase()]; if(claimHandler==null) throw new SwapDataVerificationError("Unknown claim handler!"); if( claimHandler.getType()!==ChainSwapType.CHAIN_NONCED && claimHandler.getType()!==ChainSwapType.CHAIN_TXID && claimHandler.getType()!==ChainSwapType.CHAIN ) throw new SwapDataVerificationError("Invalid claim handler!"); feeRate ??= await this.root.Fees.getFeeRate(); const {initialTxns, witness} = await claimHandler.getWitness(signer, swapData, { tx, vout, requiredConfirmations, commitedHeader, btcRelay: this.root.btcRelay, synchronizer, }, feeRate); const action = this.Claim(signer, swapData, witness, claimHandler.getGas(swapData)); await action.addToTxs(initialTxns, feeRate); return initialTxns; } /** * Get the estimated starknet transaction fee of the claim transaction */ public async getClaimFee(swapData: StarknetSwapData, feeRate?: string): Promise<bigint> { feeRate ??= await this.root.Fees.getFeeRate(); let gasRequired = swapData.payOut ? StarknetSwapClaim.GasCosts.CLAIM_PAY_OUT : StarknetSwapClaim.GasCosts.CLAIM; const claimHandler: IClaimHandler<any, any> = this.root.claimHandlersByAddress[swapData.claimHandler.toLowerCase()]; if(claimHandler!=null) gasRequired = sumStarknetGas(gasRequired, claimHandler.getGas(swapData)); return StarknetFees.getGasFee(gasRequired.l1, feeRate); } }