@atomiqlabs/chain-starknet
Version:
Starknet specific base implementation
103 lines (82 loc) • 4.01 kB
text/typescript
import {IClaimHandler} from "../ClaimHandlers";
import {StarknetSwapData} from "../../../StarknetSwapData";
import {StarknetGas} from "../../../../chain/StarknetAction";
import {ChainSwapType, RelaySynchronizer} from "@atomiqlabs/base";
import {BigNumberish, hash} from "starknet";
import {StarknetBtcStoredHeader} from "../../../../btcrelay/headers/StarknetBtcStoredHeader";
import {StarknetTx} from "../../../../chain/modules/StarknetTransactions";
import {StarknetBtcRelay} from "../../../../btcrelay/StarknetBtcRelay";
import {bufferToU32Array, getLogger, u32ArrayToBuffer} from "../../../../../utils/Utils";
export type BitcoinCommitmentData = {
btcRelay: StarknetBtcRelay<any>,
confirmations: number
}
export type BitcoinWitnessData = {
tx: { blockhash: string, confirmations: number, txid: string, hex: string, height: number },
requiredConfirmations: number,
commitedHeader?: StarknetBtcStoredHeader,
btcRelay?: StarknetBtcRelay<any>,
synchronizer?: RelaySynchronizer<StarknetBtcStoredHeader, StarknetTx, 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: StarknetGas = {l1: 20000};
protected serializeCommitment(data: BitcoinCommitmentData): BigNumberish[] {
return [
data.confirmations,
data.btcRelay.contract.address
]
}
getCommitment(data: C & BitcoinCommitmentData): BigNumberish {
return hash.computePoseidonHashOnElements(this.serializeCommitment(data));
}
protected async _getWitness(
signer: string,
swapData: StarknetSwapData,
{tx, btcRelay, commitedHeader, synchronizer, requiredConfirmations}: BitcoinWitnessData,
commitment: C,
feeRate?: string
): Promise<{
initialTxns: StarknetTx[];
witness: BigNumberish[]
}> {
const serializedData: BigNumberish[] = this.serializeCommitment({
...commitment,
btcRelay,
confirmations: requiredConfirmations
});
const commitmentHash = hash.computePoseidonHashOnElements(serializedData);
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: StarknetTx[] = [];
if(commitedHeader==null) {
const headers = await StarknetBtcRelay.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];
}
serializedData.push(...commitedHeader.serialize());
serializedData.push(merkleProof.merkle.length, ...merkleProof.merkle.map(bufferToU32Array).flat());
serializedData.push(merkleProof.pos);
return {initialTxns: txs, witness: serializedData};
}
abstract getWitness(signer: string, data: StarknetSwapData, witnessData: W, feeRate?: string): Promise<{
initialTxns: StarknetTx[];
witness: BigNumberish[]
}>;
abstract getGas(data: StarknetSwapData): StarknetGas;
abstract getType(): ChainSwapType;
parseWitnessResult(result: BigNumberish[]): string {
return u32ArrayToBuffer(result).toString("hex");
}
}