diff --git a/bun.lockb b/bun.lockb index dc6410e..933f6d6 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 0bbb598..82f2278 100644 --- a/package.json +++ b/package.json @@ -36,12 +36,14 @@ "@cosmjs/proto-signing": "^0.30.1", "@cosmjs/stargate": "^0.30.1", "@emurgo/cardano-serialization-lib-nodejs": "^11.5.0", + "@fireblocks/psbt-sdk": "^0.0.5", "@solana/web3.js": "^1.93.0", "@substrate/txwrapper-polkadot": "^7.5.1", "@taquito/local-forging": "^17.5.2", "@taquito/rpc": "^16.2.0", "@types/bn.js": "^5.1.5", "axios": "^1.7.2", + "bitcoinjs-lib": "^6.1.6", "bn.js": "^5.2.1", "ethers": "^5.7.2", "fireblocks-sdk": "^4.2.0", diff --git a/src/kiln.ts b/src/kiln.ts index 2b60e9a..8fd4589 100644 --- a/src/kiln.ts +++ b/src/kiln.ts @@ -21,6 +21,7 @@ import { ZetaService } from "./services/zeta"; import { KILN_VALIDATORS as v } from "./validators"; import { KavaService } from "./services/kava"; import { PolService } from "./services/pol"; +import { BabylonService } from "./services/babylon"; type Config = { apiToken: string; @@ -52,6 +53,7 @@ export class Kiln { zeta: ZetaService; kava: KavaService; pol: PolService; + babylon: BabylonService; constructor({ testnet, apiToken, baseUrl }: Config) { api.defaults.headers.common.Authorization = `Bearer ${apiToken}`; @@ -79,5 +81,6 @@ export class Kiln { this.zeta = new ZetaService({ testnet }); this.kava = new KavaService({ testnet }); this.pol = new PolService({ testnet }); + this.babylon = new BabylonService({ testnet }); } } diff --git a/src/services/babylon.ts b/src/services/babylon.ts new file mode 100644 index 0000000..b915f9f --- /dev/null +++ b/src/services/babylon.ts @@ -0,0 +1,67 @@ +import { Service } from "./service"; +import type { BitcoinTx, BitcoinSignedTx, BitcoinTxHash } from "../types/bitcoin"; +import api from "../api"; +import { Psbt } from "bitcoinjs-lib"; +import type { ServiceProps } from "../types/service"; +import type { Integration } from "../types/integrations"; +import { FireblocksSigner as FireblocksPsbtSigner } from "@fireblocks/psbt-sdk"; + +export class BabylonService extends Service { + constructor({ testnet }: ServiceProps) { + super({ testnet }); + } + + /** + * Craft a babylon stake transaction + */ + async craftStakeTx(accountId: string, publicKey: string, amountSatoshi: number, timeLock: number, feeRate: number): Promise { + const { data } = await api.post('/v1/babylon/transaction/stake', { + account_id: accountId, + public_key: publicKey, + amount_satoshi: amountSatoshi, + time_lock: timeLock, + fee_rate: feeRate, + }); + return data; + } + + /** + * Sign transaction with given integration + * @param integration custody solution to sign with + * @param tx raw babylon transaction + * @param note note to identify the transaction in your custody solution + */ + async sign(integration: Integration, tx: BitcoinTx, note?: string): Promise { + const fbSigner = await FireblocksPsbtSigner.create({ + fireblocks: { + basePath: "https://api.fireblocks.io/v1", + apiKey: integration.fireblocksApiKey, + secretKey: integration.fireblocksSecretKey, + }, + assetId: this.testnet ? "BTC_TEST" : "BTC", + vaultId: integration.vaultId.toString(), + addressIndex: 0, + note: note ?? "BTC tx from @kilnfi/sdk", + }); + + const psbt = Psbt.fromHex(tx.data.unsigned_tx_serialized); + + await psbt.signAllInputsAsync(fbSigner); + + psbt.finalizeAllInputs(); + const signedTransaction = psbt.extractTransaction().toHex(); + + return { data: { signed_tx_serialized: signedTransaction } }; + } + + /** + * Broadcast transaction to the network + * @param signedTx the transaction to broadcast + */ + async broadcast(signedTx: BitcoinSignedTx): Promise { + const { data } = await api.post('/v1/babylon/transaction/broadcast', { + tx_serialized: signedTx.data.signed_tx_serialized, + }); + return data; + } +} diff --git a/src/types/bitcoin.ts b/src/types/bitcoin.ts new file mode 100644 index 0000000..a183914 --- /dev/null +++ b/src/types/bitcoin.ts @@ -0,0 +1,17 @@ +export type BitcoinTx = { + data: { + unsigned_tx_serialized: string; + }; +}; + +export type BitcoinSignedTx = { + data: { + signed_tx_serialized: string; + }; +}; + +export type BitcoinTxHash = { + data: { + tx_id: string; + }; +};