From 1936db230c4ee78dd551fe79ec918a650acf6527 Mon Sep 17 00:00:00 2001 From: Crypto Minion <154598612+jrwbabylonlab@users.noreply.github.com> Date: Wed, 13 Nov 2024 20:48:56 +1100 Subject: [PATCH] feat: transition phase-1 delegation to 2 with inclusion proof (#337) --- package-lock.json | 8 ++-- package.json | 2 +- src/app/components/Delegations/Delegation.tsx | 4 +- .../hooks/services/useTransactionService.tsx | 40 ++++++++++++++++--- src/utils/mempool_api.ts | 25 +++++++++--- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4c01139..f863a14d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "simple-staking", "version": "0.3.9", "dependencies": { - "@babylonlabs-io/babylon-proto-ts": "0.0.3-canary.2", + "@babylonlabs-io/babylon-proto-ts": "0.0.3-canary.3", "@babylonlabs-io/btc-staking-ts": "0.4.0-canary.2", "@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3", "@bitcoinerlab/secp256k1": "^1.1.1", @@ -2058,9 +2058,9 @@ } }, "node_modules/@babylonlabs-io/babylon-proto-ts": { - "version": "0.0.3-canary.2", - "resolved": "https://registry.npmjs.org/@babylonlabs-io/babylon-proto-ts/-/babylon-proto-ts-0.0.3-canary.2.tgz", - "integrity": "sha512-S6Xe+xMUakog2EGLyhKxE2ynSps0qggblxksArnw5GMZBEGqc0OBWBLtyU+QfcNM14KMLUjGnjzjulY2qFWTOA==", + "version": "0.0.3-canary.3", + "resolved": "https://registry.npmjs.org/@babylonlabs-io/babylon-proto-ts/-/babylon-proto-ts-0.0.3-canary.3.tgz", + "integrity": "sha512-nmZ+KH3vog/iWzebNqOvYoihgVmVDkT7e+JPFtEdRQX1mYnWAzTtl3YFkH5p+8eM6m6JXvIDGcGMV6t99AVvHg==", "license": "ISC", "dependencies": { "@bufbuild/protobuf": "^2.2.0" diff --git a/package.json b/package.json index a89f08b4..71c0fd3a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "node": "22.3.0" }, "dependencies": { - "@babylonlabs-io/babylon-proto-ts": "0.0.3-canary.2", + "@babylonlabs-io/babylon-proto-ts": "0.0.3-canary.3", "@babylonlabs-io/btc-staking-ts": "0.4.0-canary.2", "@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3", "@bitcoinerlab/secp256k1": "^1.1.1", diff --git a/src/app/components/Delegations/Delegation.tsx b/src/app/components/Delegations/Delegation.tsx index 84d2bd59..cc70e367 100644 --- a/src/app/components/Delegations/Delegation.tsx +++ b/src/app/components/Delegations/Delegation.tsx @@ -5,12 +5,12 @@ import { IoIosWarning } from "react-icons/io"; import { Tooltip } from "react-tooltip"; import { - SigningStep, + type SigningStep, useTransactionService, } from "@/app/hooks/services/useTransactionService"; import { useHealthCheck } from "@/app/hooks/useHealthCheck"; import { - Delegation as DelegationInterface, + type Delegation as DelegationInterface, DelegationState, } from "@/app/types/delegations"; import { shouldDisplayPoints } from "@/config"; diff --git a/src/app/hooks/services/useTransactionService.tsx b/src/app/hooks/services/useTransactionService.tsx index a46e3377..b2e0a987 100644 --- a/src/app/hooks/services/useTransactionService.tsx +++ b/src/app/hooks/services/useTransactionService.tsx @@ -1,5 +1,8 @@ -import { btcstakingtx } from "@babylonlabs-io/babylon-proto-ts"; -import { InclusionProof } from "@babylonlabs-io/babylon-proto-ts/dist/generated/babylon/btcstaking/v1/btcstaking"; +import { + btccheckpoint, + btcstaking, + btcstakingtx, +} from "@babylonlabs-io/babylon-proto-ts"; import { BTCSigType, ProofOfPossessionBTC, @@ -19,6 +22,7 @@ import { extractSchnorrSignaturesFromTransaction, uint8ArrayToHex, } from "@/utils/delegations"; +import { getTxMerkleProof, MerkleProof } from "@/utils/mempool_api"; export interface BtcStakingInputs { finalityProviderPkNoCoordHex: string; @@ -43,7 +47,7 @@ export enum SigningStep { } export const useTransactionService = () => { - const { availableUTXOs: inputUTXOs } = useAppState(); + const { availableUTXOs: inputUTXOs, params } = useAppState(); const { connected: cosmosConnected, bech32Address, @@ -58,7 +62,6 @@ export const useTransactionService = () => { network: btcNetwork, } = useBTCWallet(); - const { params } = useAppState(); const latestParam = params?.bbnStakingParams?.latestParam; const genesisParam = params?.bbnStakingParams?.genesisParam; @@ -194,6 +197,9 @@ export const useTransactionService = () => { stakingInput.stakingTimeBlocks, ); + // Get the merkle proof + const inclusionProof = await getInclusionProof(stakingTx); + // Create delegation message const delegationMsg = await createBtcDelegationMsg( stakingInstance, stakingInput, @@ -206,6 +212,7 @@ export const useTransactionService = () => { signMessage, signingCallback, }, + inclusionProof, ); await sendBbnTx(signingStargateClient!, bech32Address, delegationMsg); await signingCallback(SigningStep.SEND_BBN); @@ -268,7 +275,7 @@ const createBtcDelegationMsg = async ( }, param: BbnStakingParamsVersion, btcSigningFuncs: BtcSigningFuncs, - inclusionProof?: InclusionProof, + inclusionProof?: btcstaking.InclusionProof, ) => { const cleanedStakingTx = clearTxSignatures(stakingTx); @@ -388,3 +395,26 @@ const checkWalletConnection = ( ) throw new Error("Wallet not connected"); }; + +const getInclusionProof = async ( + stakingTx: Transaction, +): Promise => { + // Get the merkle proof + let txMerkleProof: MerkleProof; + try { + txMerkleProof = await getTxMerkleProof(stakingTx.getId()); + } catch (err) { + throw new Error("Failed to get the merkle proof", { cause: err }); + } + + const hash = Uint8Array.from(Buffer.from(stakingTx.getId(), "hex")); + const inclusionProofKey: btccheckpoint.TransactionKey = + btccheckpoint.TransactionKey.fromPartial({ + index: txMerkleProof.pos, + hash, + }); + return btcstaking.InclusionProof.fromPartial({ + key: inclusionProofKey, + proof: Uint8Array.from(Buffer.from(txMerkleProof.proofHex, "hex")), + }); +}; diff --git a/src/utils/mempool_api.ts b/src/utils/mempool_api.ts index 1db82f12..4fb7f94a 100644 --- a/src/utils/mempool_api.ts +++ b/src/utils/mempool_api.ts @@ -4,9 +4,9 @@ import { Fees, UTXO } from "./wallet/btc_wallet_provider"; const { mempoolApiUrl } = getNetworkConfig(); -interface MerkleProof { +export interface MerkleProof { blockHeight: number; - merkle: string[]; + proofHex: string; pos: number; } @@ -235,10 +235,23 @@ export async function getTxMerkleProof(txId: string): Promise { const err = await response.text(); throw new ServerError(err, response.status); } - const data = await response.json(); + const data: { + block_height: number; + merkle: string[]; + pos: number; + } = await response.json(); + + const { block_height, merkle, pos } = data; + if (!block_height || !merkle.length || !pos) { + throw new Error("Invalid transaction merkle proof result returned"); + } + const proofHex = merkle.reduce((acc: string, m: string) => { + return acc + m; + }, ""); + return { - blockHeight: data.block_height, - merkle: data.merkle, - pos: data.pos, + blockHeight: block_height, + proofHex, + pos, }; }