Skip to content

Commit

Permalink
feat: add unit test for creating and signing vault related transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Polybius93 committed Jun 3, 2024
1 parent 51e2ab0 commit fc4a968
Show file tree
Hide file tree
Showing 8 changed files with 1,790 additions and 73 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/code-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,12 @@ jobs:

- name: Commit Message
uses: wagoid/commitlint-github-action@v4

test-unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/provision

- name: Unit Test
run: yarn test
8 changes: 8 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/?(*.)+(spec|test).ts'],
moduleNameMapper: {
'^(\\.\\.?\\/.+)\\.js$': '$1',
},
};
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "dlc-btc-lib",
"version": "1.0.3",
"version": "1.0.4",
"description": "This library provides a comprehensive set of interfaces and functions for minting dlcBTC tokens on supported blockchains.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -20,7 +20,7 @@
"clean": "rm -rf dist && rm -rf node_modules",
"build": "tsc",
"start": "node dist/example.js",
"test": "ts-node index.ts",
"test": "jest",
"lint": "concurrently -g 'yarn lint:eslint' 'yarn lint:prettier' 'yarn run lint:typecheck'",
"lint:eslint": "eslint \"src/**/*.{js,ts}\"",
"lint:eslint:fix": "eslint --fix \"src/**/*.{js,ts}\"",
Expand All @@ -39,21 +39,25 @@
"author": "DLC.Link",
"license": "ISC",
"devDependencies": {
"@babel/preset-typescript": "^7.24.6",
"@ledgerhq/hw-transport-node-hid": "^6.28.6",
"@ledgerhq/hw-transport-webusb": "^6.28.6",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/jest": "^29.5.12",
"@types/prompts": "^2.4.9",
"concurrently": "^8.2.2",
"eslint": "^9.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"lint": "^0.8.19",
"ls-lint": "^0.1.2",
"prettier": "^3.2.5",
"prettier-eslint": "^16.3.0",
"ts-jest": "^29.1.4",
"ts-node": "^10.9.2",
"typecheck": "^0.1.2",
"typescript": "4.7.4",
"typescript": "^5.4.5",
"typescript-eslint": "^7.7.0"
},
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/dlc-handlers/software-wallet-dlc-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class SoftwareWalletDLCHandler {
const taprootMultisigPayment = createTaprootMultisigPayment(
unspendableDerivedPublicKey,
attestorDerivedPublicKey,
Buffer.from(this.taprootDerivedPublicKey),
Buffer.from(this.taprootDerivedPublicKey, 'hex'),
this.bitcoinNetwork
);

Expand Down
2 changes: 2 additions & 0 deletions src/functions/bitcoin/psbt-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export function createClosingTransaction(
},
];

console.log('inputs', inputs);

const outputs = [
{
address: feeAddress,
Expand Down
60 changes: 60 additions & 0 deletions tests/mocks/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { regtest } from 'bitcoinjs-lib/src/networks.js';
import { BigNumber } from 'ethers';

import { RawVault } from '../../src/models/ethereum-models.js';

// Bitcoin
export const TEST_BITCOIN_NETWORK = regtest;
export const TEST_BITCOIN_ADDRESS = 'bcrt1q4htslvp40rf6epd2hqyfww2mkprzy0yjmagsy5';
export const TEST_BITCOIN_EXTENDED_PRIVATE_KEY =
'tprv8ZgxMBicQKsPeJ7iQfVEb34R3JoSyJ1J9z6wv1yXJkd1NMTRbmQiLkcZXgqQ277LMtszhnp2L2VmmHhFzoLD12fjyXcAvfnvs6qTJMMcKFq';
export const TEST_BITCOIN_WALLET_ACCOUNT_INDEX = 0;
export const TEST_BITCOIN_BLOCKCHAIN_API = 'https://devnet.dlc.link/electrs';
export const TEST_BITCOIN_BLOCKCHAIN_FEE_RECOMMENDATION_API =
'https://devnet.dlc.link/electrs/fee-estimates';
export const TEST_BITCOIN_AMOUNT = 0.01;

// Ethereum
export const TEST_ETHEREUM_PRIVATE_KEY = '';
export const TEST_ETHEREUM_NODE_API = 'https://sepolia-rollup.arbitrum.io/rpc';
export const TEST_ETHEREUM_READ_ONLY_NODE_API = 'https://sepolia-rollup.arbitrum.io/rpc';
export const TEST_ETHEREUM_GITHUB_DEPLOYMENT_PLAN_ROOT_URL =
'https://raw.githubusercontent.com/DLC-link/dlc-solidity';
export const TEST_ETHEREUM_DEVNET_GITHUB_DEPLOYMENT_PLAN_BRANCH = 'dev';
export const TEST_ETHEREUM_TESTNET_GITHUB_DEPLOYMENT_PLAN_BRANCH = 'testnet-rolling';
export const TEST_ETHEREUM_ATTESTOR_CHAIN_ID = 'evm-arbsepolia';

// Attestor
export const TEST_REGTEST_ATTESTOR_APIS = [
'https://devnet.dlc.link/attestor-1',
'https://devnet.dlc.link/attestor-2',
'https://devnet.dlc.link/attestor-3',
];

// export const TEST_TESTNET_ATTESTOR_APIS = [
// 'https://testnet.dlc.link/attestor-1',
// 'https://testnet.dlc.link/attestor-2',
// 'https://testnet.dlc.link/attestor-3',
// ];
// export const TEST_TESTNET_BITCOIN_BLOCKCHAIN_API = 'https://testnet.dlc.link/electrs';

// export const TEST_TESTNET_ATTESTOR_GROUP_PUBLIC_KEY_V1 =
// '0c0bf55fa1ab72462467b973b13e556b07d2fdd8d7a30cdfc10f337e23c7ac00';

export const TEST_REGTEST_ATTESTOR_EXTENDED_GROUP_PUBLIC_KEY =
'tpubDDqN2CmTDKaGeqXMayfCZEvjZqntifi4r1ztmRWsGuE1VE4bosR3mBKQwVaCxZcmg8R1nHDMDzDmzjoccBMgwZV1hhz51tAXVnhjABCQcwA';

export const TEST_VAULT: RawVault = {
uuid: '0x400ca1a687f9c8241566d334fcb4b33efab8e540b943be1455143284c5afc962',
protocolContract: '0x6e692DB944162f8b4250aA25eCEe80608457D7a7',
timestamp: BigNumber.from('0x665da025'),
valueLocked: BigNumber.from('0x0f4240'),
creator: '0x0DD4f29E21F10cb2E485cf9bDAb9F2dD1f240Bfa',
status: 0,
fundingTxId: '',
closingTxId: '',
btcFeeRecipient: '031131cd88bcea8c1d84da8e034bb24c2f6e748c571922dc363e7e088f5df0436c',
btcMintFeeBasisPoints: BigNumber.from('0x64'),
btcRedeemFeeBasisPoints: BigNumber.from('0x64'),
taprootPubKey: '',
};
105 changes: 105 additions & 0 deletions tests/unit/sign-transactions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Transaction, p2wpkh } from '@scure/btc-signer';

import { PrivateKeyDLCHandler } from '../../src/index.js';
import {
TEST_BITCOIN_BLOCKCHAIN_API,
TEST_BITCOIN_BLOCKCHAIN_FEE_RECOMMENDATION_API,
TEST_BITCOIN_EXTENDED_PRIVATE_KEY,
TEST_BITCOIN_NETWORK,
TEST_BITCOIN_WALLET_ACCOUNT_INDEX,
TEST_REGTEST_ATTESTOR_EXTENDED_GROUP_PUBLIC_KEY,
TEST_VAULT,
} from '../mocks/constants.js';

describe('Create and Sign Vault related Transactions', () => {
let dlcHandler: PrivateKeyDLCHandler;
let fundingTransaction: Transaction;
let signedFundingTransaction: Transaction;
let closingTransaction: Transaction;
let partiallySignedClosingTransaction: Transaction;

it('should initialize a Private Key DLC Handler', async () => {
dlcHandler = new PrivateKeyDLCHandler(
TEST_BITCOIN_EXTENDED_PRIVATE_KEY,
TEST_BITCOIN_WALLET_ACCOUNT_INDEX,
TEST_BITCOIN_NETWORK,
TEST_BITCOIN_BLOCKCHAIN_API,
TEST_BITCOIN_BLOCKCHAIN_FEE_RECOMMENDATION_API
);
});

it('should create a funding transaction', async () => {
fundingTransaction = await dlcHandler.createFundingPSBT(
TEST_VAULT,
TEST_REGTEST_ATTESTOR_EXTENDED_GROUP_PUBLIC_KEY
);

const vaultAmount = TEST_VAULT.valueLocked.toBigInt();
const feeAmount = vaultAmount / TEST_VAULT.btcMintFeeBasisPoints.toBigInt();

const feeRecipientScript = p2wpkh(
Buffer.from(TEST_VAULT.btcFeeRecipient, 'hex'),
TEST_BITCOIN_NETWORK
).script;
const multisigScript = dlcHandler.payment?.taprootMultisigPayment.script;

const outputs = Array.from({ length: fundingTransaction.outputsLength }, (_, index) =>
fundingTransaction.getOutput(index)
);

const multisigOutput = outputs.find(output => output.script === multisigScript);
const feeOutput = outputs.find(
output => output.script?.toString() === feeRecipientScript.toString()
);

expect(fundingTransaction).toBeDefined();
expect(multisigOutput?.amount === vaultAmount).toBeTruthy();
expect(feeOutput?.amount === feeAmount).toBeTruthy();
});

it('should sign a funding transaction', async () => {
signedFundingTransaction = dlcHandler.signPSBT(fundingTransaction, 'funding');

expect(signedFundingTransaction.isFinal).toBeTruthy();
});

it('should create a closing transaction', async () => {
closingTransaction = await dlcHandler.createClosingPSBT(
TEST_VAULT,
signedFundingTransaction.id
);

const vaultAmount = TEST_VAULT.valueLocked.toBigInt();
const feeAmount = vaultAmount / TEST_VAULT.btcMintFeeBasisPoints.toBigInt();

const feeRecipientScript = p2wpkh(
Buffer.from(TEST_VAULT.btcFeeRecipient, 'hex'),
TEST_BITCOIN_NETWORK
).script;
const userScript = dlcHandler.payment?.nativeSegwitPayment.script;

const outputs = Array.from({ length: fundingTransaction.outputsLength }, (_, index) =>
fundingTransaction.getOutput(index)
);

const userOutput = outputs.find(output => output.script?.toString() === userScript?.toString());
const feeOutput = outputs.find(
output => output.script?.toString() === feeRecipientScript.toString()
);

expect(closingTransaction).toBeDefined();
expect(userOutput).toBeDefined();
expect(feeOutput?.amount === feeAmount).toBeTruthy();
expect(
closingTransaction.getInput(0).witnessUtxo?.script.toString() ==
dlcHandler.payment?.taprootMultisigPayment.script.toString()
).toBeTruthy();
});

it('should sign a closing transaction', async () => {
partiallySignedClosingTransaction = dlcHandler.signPSBT(closingTransaction, 'closing');

expect(closingTransaction.isFinal).toBeFalsy();
expect(partiallySignedClosingTransaction).toBeDefined();
});
});
Loading

0 comments on commit fc4a968

Please sign in to comment.