Skip to content

Commit

Permalink
Merge pull request #47 from babylonchain/feat/37-unit-test-withdraw-m…
Browse files Browse the repository at this point in the history
…ethods

chores / 37 unit test withdraw methods
  • Loading branch information
jeremy-babylonlabs authored Jun 28, 2024
2 parents ed9feb1 + 2dfe307 commit ef08878
Show file tree
Hide file tree
Showing 6 changed files with 518 additions and 203 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"scripts": {
"generate-types": "dts-bundle-generator -o ./dist/index.d.ts ./src/index.ts",
"build": "node build.js && npm run generate-types",
"format": "prettier --check \"src/**/*.ts\"",
"format:fix": "prettier --write \"src/**/*.ts\"",
"format": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
"format:fix": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
"lint": "eslint ./src --fix",
"prepare": "husky",
"prepublishOnly": "npm run build",
Expand Down
107 changes: 82 additions & 25 deletions tests/helper/dataGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import ECPairFactory from "ecpair";
import * as ecc from "@bitcoin-js/tiny-secp256k1-asmjs";
import * as bitcoin from 'bitcoinjs-lib';
import * as bitcoin from "bitcoinjs-lib";
import ECPairFactory, { ECPairInterface } from "ecpair";
import { StakingScriptData, stakingTransaction } from "../../src";
import { StakingScripts } from "../../src/types/StakingScripts";
import { StakingScriptData } from "../../src";
import { UTXO } from "../../src/types/UTXO";

bitcoin.initEccLib(ecc);
const ECPair = ECPairFactory(ecc);

export const DEFAULT_TEST_FEE_RATE = 10;

export interface KeyPair {
privateKey: string;
publicKey: string;
publicKeyNoCoord: string;
keyPair: ECPairInterface;
}

class DataGenerator {
private network: bitcoin.networks.Network;

Expand All @@ -22,24 +32,24 @@ class DataGenerator {
return randomBuffer.toString("hex");
};

generateRandomKeyPair = (isNoCoordPk = false) => {
generateRandomKeyPair = (): KeyPair => {
const keyPair = ECPair.makeRandom({ network: this.network });
const { privateKey, publicKey } = keyPair;
if (!privateKey || !publicKey) {
throw new Error("Failed to generate random key pair");
}
let pk = publicKey.toString("hex");

pk = isNoCoordPk ? pk.slice(2) : pk;
pk = pk.slice(2);

return {
privateKey: privateKey.toString("hex"),
publicKey: pk,
publicKey: publicKey.toString("hex"),
publicKeyNoCoord: pk,
keyPair,
};
};

// Generate a random staking term (number of blocks to stake)
// ranged from 1 to 65535
generateRandomStakingTerm = () => {
return Math.floor(Math.random() * 65535) + 1;
};
Expand All @@ -52,12 +62,11 @@ class DataGenerator {
return Math.floor(Math.random() * 1000) + 1;
};

// Convenant committee are a list of public keys that are used to sign a covenant
generateRandomCovenantCommittee = (size: number): Buffer[] => {
const committe: Buffer[] = [];
for (let i = 0; i < size; i++) {
const keyPair = this.generateRandomKeyPair(true);
committe.push(Buffer.from(keyPair.publicKey, "hex"));
const keyPair = this.generateRandomKeyPair();
committe.push(Buffer.from(keyPair.publicKeyNoCoord, "hex"));
}
return committe;
};
Expand Down Expand Up @@ -86,43 +95,50 @@ class DataGenerator {
};

getTaprootAddress = (publicKey: string) => {
// Remove the prefix if it exists
if (publicKey.length == 66) {
publicKey = publicKey.slice(2);
}
const internalPubkey = Buffer.from(publicKey, "hex");
const { address } = bitcoin.payments.p2tr({
const { address, output: scriptPubKey } = bitcoin.payments.p2tr({
internalPubkey,
network: this.network,
});
if (!address) {
throw new Error("Failed to generate taproot address from public key");
if (!address || !scriptPubKey) {
throw new Error(
"Failed to generate taproot address or script from public key",
);
}
return address;
return {
address,
scriptPubKey: scriptPubKey.toString("hex"),
};
};

getNativeSegwitAddress = (publicKey: string) => {
const internalPubkey = Buffer.from(publicKey, "hex");
const { address } = bitcoin.payments.p2wpkh({
const { address, output: scriptPubKey } = bitcoin.payments.p2wpkh({
pubkey: internalPubkey,
network: this.network,
});
if (!address) {
if (!address || !scriptPubKey) {
throw new Error(
"Failed to generate native segwit address from public key",
"Failed to generate native segwit address or script from public key",
);
}
return address;
return {
address,
scriptPubKey: scriptPubKey.toString("hex"),
};
};

getNetwork = () => {
return this.network;
};

generateMockStakingScripts = (): StakingScripts => {
const finalityProviderPk = this.generateRandomKeyPair(true).publicKey;
const finalityProviderPk = this.generateRandomKeyPair().publicKeyNoCoord;
const stakingTxTimelock = this.generateRandomStakingTerm();
const publicKeyNoCoord = this.generateRandomKeyPair(true).publicKey;
const publicKeyNoCoord = this.generateRandomKeyPair().publicKeyNoCoord;
const committeeSize = Math.floor(Math.random() * 10) + 1;
const globalParams = this.generateRandomGlobalParams(
stakingTxTimelock,
Expand Down Expand Up @@ -150,7 +166,6 @@ class DataGenerator {
throw new Error(error?.message || "Cannot build staking script data");
}

// Build scripts
let scripts;
try {
scripts = stakingScriptData.buildScripts();
Expand All @@ -161,17 +176,29 @@ class DataGenerator {
return scripts;
};

getAddressAndScriptPubKey = (publicKey: string) => {
return {
taproot: this.getTaprootAddress(publicKey),
nativeSegwit: this.getNativeSegwitAddress(publicKey),
};
};

generateRandomUTXOs = (
minAvailableBalance: number,
numberOfUTXOs: number,
publicKey?: string,
): UTXO[] => {
const utxos = [];
let sum = 0;
for (let i = 0; i < numberOfUTXOs; i++) {
const { nativeSegwit } = this.getAddressAndScriptPubKey(
publicKey ? publicKey : this.generateRandomKeyPair().publicKey,
);

utxos.push({
txid: this.generateRandomTxId(),
vout: Math.floor(Math.random() * 10),
scriptPubKey: this.generateRandomKeyPair().publicKey,
scriptPubKey: nativeSegwit.scriptPubKey,
value: Math.floor(Math.random() * 9000) + minAvailableBalance,
});
sum += utxos[i].value;
Expand All @@ -181,6 +208,36 @@ class DataGenerator {
}
return utxos;
};

generateRandomStakingTransaction = (
network: bitcoin.Network,
feeRate: number,
keyPair: KeyPair,
address: string,
stakingScripts: StakingScripts,
) => {
const randomAmount = Math.floor(Math.random() * 100000000) + 1000;

const utxos = this.generateRandomUTXOs(
Math.floor(Math.random() * 1000000) + randomAmount,
Math.floor(Math.random() * 10) + 1,
keyPair.publicKey,
);

const { psbt } = stakingTransaction(
stakingScripts,
randomAmount,
address,
utxos,
network,
feeRate,
);

return psbt
.signAllInputs(keyPair.keyPair)
.finalizeAllInputs()
.extractTransaction();
};
}

export default DataGenerator;
export default DataGenerator;
2 changes: 1 addition & 1 deletion tests/helper/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { default as DataGenerator } from "./dataGenerator";
export { default as testingNetworks } from "./testingNetworks";
export { default as testingNetworks } from "./testingNetworks";
9 changes: 6 additions & 3 deletions tests/helper/testingNetworks.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import * as bitcoin from "bitcoinjs-lib";
import DataGenerator from "./dataGenerator";

interface NetworkConfig {
export interface NetworkConfig {
networkName: string;
network: bitcoin.Network;
dataGenerator: DataGenerator;
}

const createNetworkConfig = (networkName: string, network: bitcoin.Network): NetworkConfig => ({
const createNetworkConfig = (
networkName: string,
network: bitcoin.Network,
): NetworkConfig => ({
networkName,
network,
dataGenerator: new DataGenerator(network),
Expand All @@ -18,4 +21,4 @@ const testingNetworks: NetworkConfig[] = [
createNetworkConfig("testnet", bitcoin.networks.testnet),
];

export default testingNetworks;
export default testingNetworks;
Loading

0 comments on commit ef08878

Please sign in to comment.