Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/btcindexer/src/btcindexer-http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { Indexer } from "./btcindexer";
import { networks } from "bitcoinjs-lib";
import { SuiClient } from "./sui-client";

const NBTC_MODULE = "nbtc";
const MINT_FUNCTION = "mint";

export class HIndexer {
public nbtcAddr: string;
public suiFallbackAddr: string;
Expand All @@ -20,6 +23,8 @@ export class HIndexer {
const suiClient = new SuiClient({
suiNetwork: env.SUI_NETWORK,
suiPackageId: env.SUI_PACKAGE_ID,
suiModule: NBTC_MODULE,
suiFunction: MINT_FUNCTION,
suiNbtcObjectId: env.NBTC_OBJECT_ID,
suiLightClientObjectId: env.LIGHT_CLIENT_OBJECT_ID,
suiSignerMnemonic: env.SUI_SIGNER_MNEMONIC,
Expand Down
2 changes: 2 additions & 0 deletions packages/btcindexer/src/btcindexer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ function mkMockD1() {
const SUI_CLIENT_CONFIG: SuiClientConfig = {
suiNetwork: "testnet",
suiPackageId: "0xPACKAGE",
suiModule: "test",
suiFunction: "mint",
suiNbtcObjectId: "0xNBTC",
suiLightClientObjectId: "0xLIGHTCLIENT",
suiSignerMnemonic:
Expand Down
58 changes: 58 additions & 0 deletions packages/btcindexer/src/sui-client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import "dotenv/config";
import { describe, it, assert } from "vitest";
import { Indexer } from "./btcindexer";
import { SuiClient, SuiClientConfig } from "./sui-client";
import { Block, networks } from "bitcoinjs-lib";

const REGTEST_DATA = {
BLOCK_HEX:
"000000305c2f30d99ad69f247638613dcca7f455159e252878ea6fe10bbc4574a0076914d98ada655d950ac6507d14584fa679d12fb5203c384e52ef292d063fe29b1b645c4b6d68ffff7f200200000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04022f0100ffffffff02de82814a0000000016001477174bfb906c0e52d750eac4b40fd86746ad50550000000000000000266a24aa21a9ed27611410788b35b819e10a0227f40f9bbc70df824e3a30879552f004b48451210120000000000000000000000000000000000000000000000000000000000000000000000000020000000001017fec0755f3524b89ad45383343f992a0d5cb797a695b59e30f2fc80794f001050000000000fdffffff032202089200000000160014b125723e78c2d779e3e299dfd95d72e9a067a0b780f0fa02000000001600144cc99479ada301056d78a8f3676cfb404d696abe00000000000000000d6a0b3078313233343536373839024730440220755610ff6b6fdea530c20d11b7765816beb75e16ce78fa200a7da25e251a7eb9022078e78bed1cc38822cd5dce3982e23c3cd401415ae72050b00c5f8b3441a2c178012103ef55b72bddf4960ddbb12a9a04f61f91fb613aa99b472115f25a5f8686e6c3f200000000",
TX_ID: "2060dfd3cdbffb7db6c968357f3c9df91b52a4cef5c02fad0b0836b0f25cc4ca",
BLOCK_HEIGHT: 303,
};

const SUI_CLIENT_CONFIG: SuiClientConfig = {
suiNetwork: "devnet",
suiPackageId: "0x7a03af034ade1d5b4072ba4fdb9650bd5ce0cd4dcab40f0563540be0ebbe824b",
suiModule: "indexer_test",
suiFunction: "mint",
suiNbtcObjectId: "0xd93cc7f6d91100990f9fa8ca11d533a69254e2f716ab69a22c6cc4e9a49a9374",
suiLightClientObjectId:
"0xd93cc7f6d91100990f9fa8ca11d533a69254e2f716ab69a22c6cc4e9a49a9374",
suiSignerMnemonic:
"april tonight combine album kit burst detect outside label quiz undo such",
};

// NOTE: skip to prevent this test from running in CI
describe.skip("Sui Contract Integration", () => {
it("should successfully call the mint function on devnet", { timeout: 60000 }, async () => {
const suiClient = new SuiClient(SUI_CLIENT_CONFIG);
const indexer = new Indexer(
{} as any,

Check failure on line 31 in packages/btcindexer/src/sui-client.test.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
"bcrt1qfnyeg7dd5vqs2mtc4rekwm8mgpxkj647p39zhw",
"fallback",
networks.regtest,
suiClient,
);
const block = Block.fromHex(REGTEST_DATA.BLOCK_HEX);
const txIndex = block.transactions?.findIndex(
(tx) => tx.getId() === REGTEST_DATA.TX_ID,
);
assert(txIndex);
const targetTx = block.transactions?.[txIndex ?? -1];
assert(targetTx);

const tree = indexer.constructMerkleTree(block);
assert(tree);
const proofResult = indexer.getTxProof(tree, targetTx);
assert(proofResult);

const success = await suiClient.tryMintNbtc(
targetTx,
REGTEST_DATA.BLOCK_HEIGHT,
txIndex,
proofResult,
);
assert.isTrue(success);
});
});
21 changes: 16 additions & 5 deletions packages/btcindexer/src/sui-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ProofResult } from "./btcindexer";
export interface SuiClientConfig {
suiNetwork: "testnet" | "mainnet" | "devnet";
suiPackageId: string;
suiModule: string;
suiFunction: string;
suiNbtcObjectId: string;
suiLightClientObjectId: string;
suiSignerMnemonic: string;
Expand All @@ -17,13 +19,17 @@ export class SuiClient {
private client: Client;
private signer: Ed25519Keypair;
private packageId: string;
private module: string;
private function: string;
private nbtcObjectId: string;
private lightClientObjectId: string;

constructor(config: SuiClientConfig) {
this.client = new Client({ url: getFullnodeUrl(config.suiNetwork) });
this.signer = Ed25519Keypair.deriveKeypair(config.suiSignerMnemonic);
this.packageId = config.suiPackageId;
this.module = config.suiModule;
this.function = config.suiFunction;
this.nbtcObjectId = config.suiNbtcObjectId;
this.lightClientObjectId = config.suiLightClientObjectId;
}
Expand All @@ -35,9 +41,12 @@ export class SuiClient {
proof: ProofResult,
): Promise<void> {
const tx = new SuiTransaction();
const target = `${this.packageId}::nbtc::mint` as const;
const target = `${this.packageId}::${this.module}::${this.function}` as const;
const serializedTx = serializeBtcTx(transaction);

// NOTE: the contract is expecting the proofs to be in big-endian format, while the bitcon-js lib operates internally on little-endian.
const proofBigEndian = proof.proofPath.map((p) => Array.from(Buffer.from(p).reverse()));

tx.moveCall({
target: target,
arguments: [
Expand All @@ -49,15 +58,15 @@ export class SuiClient {
tx.pure.u32(serializedTx.outputCount),
tx.pure.vector("u8", serializedTx.outputs),
tx.pure.vector("u8", serializedTx.lockTime),
tx.pure.vector(
"vector<u8>",
proof.proofPath.map((p) => Array.from(p)),
),
tx.pure.vector("vector<u8>", proofBigEndian),
tx.pure.u64(blockHeight),
tx.pure.u64(txIndex),
],
});

// TODO: should we move it to config or set it as a constant
tx.setGasBudget(1000000000);

const result = await this.client.signAndExecuteTransaction({
signer: this.signer,
transaction: tx,
Expand All @@ -66,6 +75,8 @@ export class SuiClient {
},
});

console.log(result.effects);

if (result.effects?.status.status !== "success") {
throw new Error(`Mint transaction failed: ${result.effects?.status.error}`);
}
Expand Down
Loading