New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

sbtc-bridge-lib

Package Overview
Dependencies
Maintainers
1
Versions
127
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sbtc-bridge-lib - npm Package Compare versions

Comparing version 1.0.93 to 1.0.94

tests/old_withdraw.test.ts

19

dist/deposit_utils.d.ts
import * as btc from '@scure/btc-signer';
import type { Transaction } from '@scure/btc-signer';
import type { BridgeTransactionType, DepositPayloadUIType } from './types/sbtc_types.js';

@@ -6,4 +7,4 @@ export declare const revealPayment = 10001;

/**
*
* @param network
* buildOpReturnDepositTransaction:Transaction
* @param network (devnet|testnet|mainnet)
* @param uiPayload:DepositPayloadUIType

@@ -13,12 +14,12 @@ * @param btcFeeRates current rates

* @param stacksAddress the stacks address to materialise sBTC
* @returns
* @returns Transaction from @scure/btc-signer
*/
export declare function buildOpReturnDepositTransaction(network: string, uiPayload: DepositPayloadUIType, btcFeeRates: any, addressInfo: any): btc.Transaction;
export declare function buildOpReturnDepositTransaction(network: string, uiPayload: DepositPayloadUIType, btcFeeRates: any, addressInfo: any): Transaction;
/**
* @param network
* @param uiPayload:DepositPayloadUIType
* @param btcFeeRates current rates
* @param addressInfo the utxos to spend from
* @param commitTxAddress the commitment address - contains the taproot data and the payload
* @returns transaction object
* @param uiPayload
* @param btcFeeRates
* @param addressInfo
* @param commitTxAddress
* @returns Transaction from @scure/btc-signer
*/

@@ -25,0 +26,0 @@ export declare function buildOpDropDepositTransaction(network: string, uiPayload: DepositPayloadUIType, btcFeeRates: any, addressInfo: any, commitTxAddress: string): btc.Transaction;

@@ -12,4 +12,4 @@ import * as btc from '@scure/btc-signer';

/**
*
* @param network
* buildOpReturnDepositTransaction:Transaction
* @param network (devnet|testnet|mainnet)
* @param uiPayload:DepositPayloadUIType

@@ -19,3 +19,3 @@ * @param btcFeeRates current rates

* @param stacksAddress the stacks address to materialise sBTC
* @returns
* @returns Transaction from @scure/btc-signer
*/

@@ -40,7 +40,7 @@ export function buildOpReturnDepositTransaction(network, uiPayload, btcFeeRates, addressInfo) {

* @param network
* @param uiPayload:DepositPayloadUIType
* @param btcFeeRates current rates
* @param addressInfo the utxos to spend from
* @param commitTxAddress the commitment address - contains the taproot data and the payload
* @returns transaction object
* @param uiPayload
* @param btcFeeRates
* @param addressInfo
* @param commitTxAddress
* @returns Transaction from @scure/btc-signer
*/

@@ -47,0 +47,0 @@ export function buildOpDropDepositTransaction(network, uiPayload, btcFeeRates, addressInfo, commitTxAddress) {

@@ -18,3 +18,3 @@ import type { PayloadType } from './types/sbtc_types.js';

export declare function bigUint64ToAmount(buf: Uint8Array): number;
export declare function parseWithdrawalPayload(network: string, d1: Uint8Array, scriptPubKey: string): PayloadType;
export declare function parseWithdrawalPayload(network: string, d1: Uint8Array, bitcoinAddress: string): PayloadType;
export declare enum PrincipalType {

@@ -24,4 +24,27 @@ STANDARD = "05",

}
/**
*
* @param net
* @param address
* @returns
*/
export declare function buildDepositPayloadOpReturn(net: any, address: string): Uint8Array;
/**
*
* @param net
* @param amountSats
* @param address
* @param opDrop
* @param memo
* @returns
*/
export declare function buildDepositPayload(net: any, amountSats: number, address: string, opDrop: boolean, memo: string | undefined): Uint8Array;
/**
*
* @param net
* @param amount
* @param signature
* @param opDrop
* @returns
*/
export declare function buildWithdrawalPayload(net: any, amount: number, signature: Uint8Array, opDrop: boolean): Uint8Array;

@@ -75,2 +98,8 @@ /**

export declare function readDepositValue(outputs: Array<any>): number;
/**
*
* @param network
* @param txHex
* @returns
*/
export declare function parsePayloadFromTransaction(network: string, txHex: string): PayloadType;

@@ -119,4 +148,17 @@ export declare function parsePayloadFromOutput(network: string, out0: any, scriptPubKey: string): PayloadType;

*/
/**
*
* @param network
* @param amount
* @param bitcoinAddress
* @returns
*/
export declare function getDataToSign(network: string, amount: number, bitcoinAddress: string): Uint8Array;
export declare function getStacksSimpleHashOfDataToSign(network: string, amount: number, bitcoinAddress: string): string;
/**
*
* @param messageHash
* @param signature
* @returns
*/
export declare function getStacksAddressFromSignature(messageHash: Uint8Array, signature: string): {

@@ -140,2 +182,7 @@ tp2pkh: string;

export declare function fromStorable(script: any): any;
/**
*
* @param script
* @returns
*/
export declare function toStorable(script: any): {

@@ -142,0 +189,0 @@ address: any;

@@ -129,10 +129,10 @@ import * as secp from '@noble/secp256k1';

}
export function parseWithdrawalPayload(network, d1, scriptPubKey) {
export function parseWithdrawalPayload(network, d1, bitcoinAddress) {
const magicOp = getMagicAndOpCode(d1);
if (magicOp.magic) {
return parseWithdrawalPayloadNoMagic(network, d1.subarray(2), scriptPubKey);
return parseWithdrawalPayloadNoMagic(network, d1.subarray(2), bitcoinAddress);
}
return parseWithdrawalPayloadNoMagic(network, d1, scriptPubKey);
return parseWithdrawalPayloadNoMagic(network, d1, bitcoinAddress);
}
function parseWithdrawalPayloadNoMagic(network, d1, scriptPubKey) {
function parseWithdrawalPayloadNoMagic(network, d1, bitcoinAddress) {
//console.log('parseWithdrawalPayloadNoMagic: d1: ', hex.encode(d1))

@@ -150,7 +150,8 @@ const opcode = hex.encode(d1.subarray(0, 1)).toUpperCase();

//if (signature.startsWith('00')) signature = reverseSigBits(signature)
//console.log('parseWithdrawalPayloadNoMagic signature: ', signature)
const msgHash = getStacksSimpleHashOfDataToSign(network, amountSats, scriptPubKey);
//console.log('parseWithdrawalPayloadNoMagic msgHash: ' + msgHash)
console.log('parseWithdrawalPayloadNoMagic bitcoinAddress: ', bitcoinAddress);
console.log('parseWithdrawalPayloadNoMagic signature: ', signature);
const msgHash = getStacksSimpleHashOfDataToSign(network, amountSats, bitcoinAddress);
console.log('parseWithdrawalPayloadNoMagic msgHash: ' + msgHash);
const pubKey = getPubkeySignature(hex.decode(msgHash), signature);
//console.log('parseWithdrawalPayloadNoMagic pubKey: ' + hex.encode(pubKey))
console.log('parseWithdrawalPayloadNoMagic pubKey: ' + hex.encode(pubKey));
const v = verifyMessageSignature({ signature, message: msgHash, publicKey: hex.encode(pubKey) });

@@ -175,2 +176,8 @@ //console.log('parseWithdrawalPayloadNoMagic v: ' + v)

})(PrincipalType || (PrincipalType = {}));
/**
*
* @param net
* @param address
* @returns
*/
export function buildDepositPayloadOpReturn(net, address) {

@@ -198,2 +205,11 @@ const magicBuf = (typeof net === 'object' && net.bech32 === 'tb') ? hex.decode(MAGIC_BYTES_TESTNET) : hex.decode(MAGIC_BYTES_MAINNET);

}
/**
*
* @param net
* @param amountSats
* @param address
* @param opDrop
* @param memo
* @returns
*/
export function buildDepositPayload(net, amountSats, address, opDrop, memo) {

@@ -237,2 +253,10 @@ const magicBuf = (typeof net === 'object' && net.bech32 === 'tb') ? hex.decode(MAGIC_BYTES_TESTNET) : hex.decode(MAGIC_BYTES_MAINNET);

}
/**
*
* @param net
* @param amount
* @param signature
* @param opDrop
* @returns
*/
export function buildWithdrawalPayload(net, amount, signature, opDrop) {

@@ -304,2 +328,8 @@ const magicBuf = (net === btc.TEST_NETWORK) ? hex.decode(MAGIC_BYTES_TESTNET) : hex.decode(MAGIC_BYTES_MAINNET);

}
/**
*
* @param network
* @param txHex
* @returns
*/
export function parsePayloadFromTransaction(network, txHex) {

@@ -378,2 +408,9 @@ const tx = btc.Transaction.fromRaw(hex.decode(txHex), { allowUnknowInput: true, allowUnknowOutput: true, allowUnknownOutputs: true, allowUnknownInputs: true });

*/
/**
*
* @param network
* @param amount
* @param bitcoinAddress
* @returns
*/
export function getDataToSign(network, amount, bitcoinAddress) {

@@ -391,2 +428,4 @@ const net = (network === 'testnet') ? btc.TEST_NETWORK : btc.NETWORK;

const msgHash = hashMessage(hex.encode(dataToSign));
console.log('getStacksSimpleHashOfDataToSign:dataToSign: ' + hex.encode(dataToSign));
console.log('getStacksSimpleHashOfDataToSign:msgHash: ' + hex.encode(msgHash));
return hex.encode(msgHash);

@@ -406,36 +445,16 @@ }

function getPubkeySignature(messageHash, signature) {
//console.log('getStacksAddressFromSignature: messageHash: ' + hex.encode(messageHash))
//console.log('getStacksAddressFromSignature: signature: ' + signature)
let pubkey;
try {
//console.log('=============================================================')
const recBits = (signature.substring(signature.length - 2));
//let signature = signature.substring(2)
//console.log('getPubkeySignature1: recBits: ' + ' ' + recBits)
// works for Hiro sig but not unit test sig ?
const sigM = recoverSignature({ signature: signature, mode: 'rsv' }); // vrs to rsv
let sig = new secp.Signature(sigM.signature.r, sigM.signature.s);
sig = sig.addRecoveryBit(Number(recBits)); // sometime 0 sometiimes 1 ??
//console.log('getPubkeySignature1: recovery: ', sig)
const pubkeyM = sig.recoverPublicKey(messageHash);
//console.log('getPubkeySignature11: Hiro: messageHash: ' + hex.encode(messageHash))
pubkey = hex.decode(pubkeyM.toHex());
//console.log('getPubkeySignature11: Hiro: pubkey: ' + hex.encode(pubkey))
}
catch (err) {
//console.log('=============================================================')
//console.log('getPubkeySignature2: error: ' + ' ' + err.message)
const recBits = (signature.substring(0, 2));
const sigM = recoverSignature({ signature: signature, mode: 'rsv' }); // vrs to rsv
//console.log('getPubkeySignature2: sigM: ', sigM)
let sig = new secp.Signature(sigM.signature.r, sigM.signature.s);
sig = sig.addRecoveryBit(Number(recBits)); // sometime 0 sometiimes 1 ??
//console.log('getPubkeySignature2: recovery: ', sig)
const pubkeyM = sig.recoverPublicKey(messageHash);
//console.log('getPubkeySignature2: Hiro: messageHash: ' + hex.encode(messageHash))
pubkey = hex.decode(pubkeyM.toHex());
//console.log('getPubkeySignature2: Hiro: pubkey: ' + hex.encode(pubkey))
}
const sigM = recoverSignature({ signature: signature, mode: 'vrs' }); // vrs to rsv
let sig = new secp.Signature(sigM.signature.r, sigM.signature.s);
sig = sig.addRecoveryBit(0);
const pubkeyM = sig.recoverPublicKey(messageHash);
const pubkey = hex.decode(pubkeyM.toHex());
console.log(pubkeyM.toHex());
return pubkey;
}
/**
*
* @param messageHash
* @param signature
* @returns
*/
export function getStacksAddressFromSignature(messageHash, signature) {

@@ -452,3 +471,3 @@ const pubkey = getPubkeySignature(messageHash, signature);

};
//console.log('getStacksAddressFromSignature: addresses: ', addresses)
console.log('getStacksAddressFromSignature: addresses: ', addresses);
return addresses;

@@ -495,2 +514,7 @@ }

}
/**
*
* @param script
* @returns
*/
export function toStorable(script) {

@@ -497,0 +521,0 @@ //const copied = JSON.parse(JSON.stringify(script));

@@ -88,5 +88,22 @@ import * as btc from '@scure/btc-signer';

export declare function addInputs(network: string, amount: number, revealPayment: number, transaction: btc.Transaction, feeCalc: boolean, utxos: Array<UTXO>, paymentPublicKey: string): void;
/**
* getAddressFromOutScript converts a script to an address
* @param network:string
* @param script: Uint8Array
* @returns address as string
*/
export declare function getAddressFromOutScript(network: string, script: Uint8Array): string;
export declare function inputAmt(tx: btc.Transaction): number;
/**
*
* @param pubkey
* @returns
*/
export declare function toXOnly(pubkey: string): string;
export declare function getPegWalletAddressFromPublicKey(network: string, sbtcWalletPublicKey: string): string;
/**
*
* @param network
* @param sbtcWalletPublicKey
* @returns
*/
export declare function getPegWalletAddressFromPublicKey(network: string, sbtcWalletPublicKey: string): string | undefined;

@@ -288,2 +288,8 @@ import * as secp from '@noble/secp256k1';

}
/**
* getAddressFromOutScript converts a script to an address
* @param network:string
* @param script: Uint8Array
* @returns address as string
*/
export function getAddressFromOutScript(network, script) {

@@ -357,6 +363,19 @@ const net = (network === 'testnet') ? btc.TEST_NETWORK : btc.NETWORK;

}
/**
*
* @param pubkey
* @returns
*/
export function toXOnly(pubkey) {
return hex.encode(hex.decode(pubkey).subarray(1, 33));
}
/**
*
* @param network
* @param sbtcWalletPublicKey
* @returns
*/
export function getPegWalletAddressFromPublicKey(network, sbtcWalletPublicKey) {
if (!sbtcWalletPublicKey)
return;
let net = (network === 'testnet') ? btc.TEST_NETWORK : btc.NETWORK;

@@ -363,0 +382,0 @@ if (network === 'development' || network === 'simnet') {

@@ -5,3 +5,20 @@ import * as btc from '@scure/btc-signer';

export declare const dust = 500;
/**
*
* @param network
* @param uiPayload
* @param addressInfo
* @param btcFeeRates
* @returns Transaction from @scure/btc-signer
*/
export declare function buildOpReturnWithdrawTransaction(network: string, uiPayload: WithdrawPayloadUIType, addressInfo: any, btcFeeRates: any): btc.Transaction;
/**
*
* @param network
* @param uiPayload
* @param addressInfo
* @param btcFeeRates
* @param originator
* @returns
*/
export declare function buildOpDropWithdrawTransaction(network: string, uiPayload: WithdrawPayloadUIType, addressInfo: any, btcFeeRates: any, originator: string): btc.Transaction;

@@ -8,0 +25,0 @@ export declare function calculateWithdrawFees(network: string, opDrop: boolean, addressInfo: any, amount: number, feeInfo: {

@@ -11,2 +11,10 @@ import * as btc from '@scure/btc-signer';

export const dust = 500;
/**
*
* @param network
* @param uiPayload
* @param addressInfo
* @param btcFeeRates
* @returns Transaction from @scure/btc-signer
*/
export function buildOpReturnWithdrawTransaction(network, uiPayload, addressInfo, btcFeeRates) {

@@ -28,2 +36,11 @@ if (!uiPayload.signature)

}
/**
*
* @param network
* @param uiPayload
* @param addressInfo
* @param btcFeeRates
* @param originator
* @returns
*/
export function buildOpDropWithdrawTransaction(network, uiPayload, addressInfo, btcFeeRates, originator) {

@@ -30,0 +47,0 @@ if (!uiPayload.signature)

{
"name": "sbtc-bridge-lib",
"version": "1.0.93",
"version": "1.0.94",
"description": "Library for sBTC Bridge web client and API apps ",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -1,29 +0,168 @@

# sbtc-bridge-lib
# SBTC SDK Documentation
![ci](https://github.com/stacks-network/sbtc-bridge-web)
Decentralised protocol for depositing and withdrawing bitcoin on the Stacks blockchain.
This library is intended to be used by app developers to build sBTC applications.
## Introduction
For more information on the sBTC project see;
Library and utility functions for the sBTC Bridge.
- [sBTC.tech](https://sbtc.tech)
- [sBTC bridge web app](https://bridge.sbtc.tech?net=testnet)
- [npm registry](https://www.npmjs.com/package/sbtc-bridge-lib)
[sbtc.tech](https://sbtc.tech).
## The sBTC Library Install
## Build
The sbtc-bridge-lib can be installed via npm registry;
```bash
npm install
npx tsc
npm install sbtc-bridge-lib
```
## Test
### Build & Publish
```bash
npm run test
npm install sbtc-bridge-lib
npm install
npx tsc
npm publish
```
## Publish
### The sBTC Library Modules
```bash
npm publish
```
- deposit_utils.ts
- payload_utils.ts
- wallet_utils.ts
- withdraw_utils.ts
#### deposit_utils.ts
**buildOpReturnDepositTransaction**
Builds the PSBT the user signs to initiate deposit via op_return
- @param network (devnet|testnet|mainnet)
- @param uiPayload:DepositPayloadUIType
- @param btcFeeRates current rates
- @param addressInfo the utxos to spend from
- @param stacksAddress the stacks address to materialise sBTC
- @returns Transaction from @scure/btc-signer
**buildOpDropDepositTransaction**
Builds the PSBT the user signs to initiate deposit via op_drop
- @param network
- @param uiPayload:DepositPayloadUIType
- @param btcFeeRates
- @param addressInfo
- @param commitTxAddress
- @returns Transaction from @scure/btc-signer
#### withdraw_utils.ts
**buildOpReturnWithdrawTransaction**
Builds the PSBT the user signs to initiate withdrawal via op_return
- @param network
- @param uiPayload:WithdrawPayloadUIType
- @param btcFeeRates
- @param addressInfo
- @param commitTxAddress
- @returns Transaction from @scure/btc-signer
**buildOpDropWithdrawTransaction**
Builds the PSBT the user signs to initiate withdrawal via op_drop
- @param network
- @param uiPayload :WithdrawPayloadUIType
- @param addressInfo
- @param btcFeeRates
- @param originator
- @returns Transaction from @scure/btc-signer
#### payload_utils.ts
**buildDepositPayload**
Builds the data to be transmitted in a deposit request
- @param net
- @param amountSats
- @param address
- @param opDrop
- @param memo
- @returns Uint8Array
**buildWithdrawalPayload**
Builds the data to be transmitted in a withdraw request
- @param net
- @param amount
- @param signature
- @param opDrop
- @returns Uint8Array
**parsePayloadFromTransaction**
Takes raw transaction hex extracts the sBTC data and returns it in a PayloadType
- @param network
- @param txHex
- @returns PayloadType
**getDataToSign**
The data the user needs to sign to issue a withdrawal request
- @param network
- @param amount
- @param bitcoinAddress
- @returns Uint8Array
**getStacksAddressFromSignature**
- @param messageHash
- @param signature
- @returns string
**toStorable**
Converts taproot script and leaf data structure to hex for easy storage.
- @param script
- @returns CommitmentScriptDataType
**fromStorable**
Creates a deep clone of the taproot script path data.
- @param script
- @returns CommitmentScriptDataType
#### wallet_utils.ts
**getAddressFromOutScript**
getAddressFromOutScript converts a script to an address
- @param network:string
- @param script: Uint8Array
- @returns address as string
**toXOnly**
converts compressed public key to x-only form for schnorr compatibility
- @param pubkey
- @returns pubkey as string
**getPegWalletAddressFromPublicKey**
Converts the sBTC peg wallet public key to a taproot segwit v2 address.
- @param network
- @param sbtcWalletPublicKey
- @returns address as string

@@ -5,2 +5,3 @@ import * as btc from '@scure/btc-signer';

import { hex } from '@scure/base';
import type { Transaction } from '@scure/btc-signer'
import type { BridgeTransactionType, DepositPayloadUIType, UTXO } from './types/sbtc_types.js'

@@ -15,5 +16,6 @@ import { toStorable, buildDepositPayload } from './payload_utils.js'

export const dust = 500;
/**
*
* @param network
* buildOpReturnDepositTransaction:Transaction
* @param network (devnet|testnet|mainnet)
* @param uiPayload:DepositPayloadUIType

@@ -23,5 +25,5 @@ * @param btcFeeRates current rates

* @param stacksAddress the stacks address to materialise sBTC
* @returns
* @returns Transaction from @scure/btc-signer
*/
export function buildOpReturnDepositTransaction(network:string, uiPayload:DepositPayloadUIType, btcFeeRates:any, addressInfo:any) {
export function buildOpReturnDepositTransaction(network:string, uiPayload:DepositPayloadUIType, btcFeeRates:any, addressInfo:any):Transaction {
const net = (network === 'testnet') ? btc.TEST_NETWORK : btc.NETWORK;

@@ -32,3 +34,3 @@ const sbtcWalletAddress = getPegWalletAddressFromPublicKey(network, uiPayload.sbtcWalletPublicKey)

const txFees = calculateDepositFees(network, false, uiPayload.amountSats, btcFeeRates.feeInfo, addressInfo, sbtcWalletAddress, data)
const txFees = calculateDepositFees(network, false, uiPayload.amountSats, btcFeeRates.feeInfo, addressInfo, sbtcWalletAddress!, data)
const tx = new btc.Transaction({ allowUnknowInput: true, allowUnknowOutput: true, allowUnknownInputs:true, allowUnknownOutputs:true });

@@ -38,3 +40,3 @@ // no reveal fee for op_return

tx.addOutput({ script: btc.Script.encode(['RETURN', data]), amount: BigInt(0) });
tx.addOutputAddress(sbtcWalletAddress, BigInt(uiPayload.amountSats), net);
tx.addOutputAddress(sbtcWalletAddress!, BigInt(uiPayload.amountSats), net);
const changeAmount = inputAmt(tx) - (uiPayload.amountSats + txFees[1]);

@@ -47,7 +49,7 @@ if (changeAmount > 0) tx.addOutputAddress(uiPayload.bitcoinAddress, BigInt(changeAmount), net);

* @param network
* @param uiPayload:DepositPayloadUIType
* @param btcFeeRates current rates
* @param addressInfo the utxos to spend from
* @param commitTxAddress the commitment address - contains the taproot data and the payload
* @returns transaction object
* @param uiPayload
* @param btcFeeRates
* @param addressInfo
* @param commitTxAddress
* @returns Transaction from @scure/btc-signer
*/

@@ -54,0 +56,0 @@ export function buildOpDropDepositTransaction (network:string, uiPayload:DepositPayloadUIType, btcFeeRates:any, addressInfo:any, commitTxAddress:string) {

@@ -146,11 +146,11 @@ import * as secp from '@noble/secp256k1';

export function parseWithdrawalPayload(network:string, d1:Uint8Array, scriptPubKey:string):PayloadType {
export function parseWithdrawalPayload(network:string, d1:Uint8Array, bitcoinAddress:string):PayloadType {
const magicOp = getMagicAndOpCode(d1);
if (magicOp.magic) {
return parseWithdrawalPayloadNoMagic(network, d1.subarray(2), scriptPubKey);
return parseWithdrawalPayloadNoMagic(network, d1.subarray(2), bitcoinAddress);
}
return parseWithdrawalPayloadNoMagic(network, d1, scriptPubKey);
return parseWithdrawalPayloadNoMagic(network, d1, bitcoinAddress);
}
function parseWithdrawalPayloadNoMagic(network:string, d1:Uint8Array, scriptPubKey:string):PayloadType {
function parseWithdrawalPayloadNoMagic(network:string, d1:Uint8Array, bitcoinAddress:string):PayloadType {
//console.log('parseWithdrawalPayloadNoMagic: d1: ', hex.encode(d1))

@@ -168,8 +168,9 @@ const opcode = hex.encode(d1.subarray(0,1)).toUpperCase();

//if (signature.startsWith('00')) signature = reverseSigBits(signature)
//console.log('parseWithdrawalPayloadNoMagic signature: ', signature)
console.log('parseWithdrawalPayloadNoMagic bitcoinAddress: ', bitcoinAddress)
console.log('parseWithdrawalPayloadNoMagic signature: ', signature)
const msgHash = getStacksSimpleHashOfDataToSign(network, amountSats, scriptPubKey);
//console.log('parseWithdrawalPayloadNoMagic msgHash: ' + msgHash)
const msgHash = getStacksSimpleHashOfDataToSign(network, amountSats, bitcoinAddress);
console.log('parseWithdrawalPayloadNoMagic msgHash: ' + msgHash)
const pubKey = getPubkeySignature(hex.decode(msgHash), signature)
//console.log('parseWithdrawalPayloadNoMagic pubKey: ' + hex.encode(pubKey))
console.log('parseWithdrawalPayloadNoMagic pubKey: ' + hex.encode(pubKey))
const v = verifyMessageSignature({ signature, message: msgHash, publicKey: hex.encode(pubKey) })

@@ -196,2 +197,8 @@ //console.log('parseWithdrawalPayloadNoMagic v: ' + v)

/**
*
* @param net
* @param address
* @returns
*/
export function buildDepositPayloadOpReturn(net:any, address:string):Uint8Array {

@@ -220,2 +227,11 @@ const magicBuf = (typeof net === 'object' && net.bech32 === 'tb') ? hex.decode(MAGIC_BYTES_TESTNET) : hex.decode(MAGIC_BYTES_MAINNET);

/**
*
* @param net
* @param amountSats
* @param address
* @param opDrop
* @param memo
* @returns
*/
export function buildDepositPayload(net:any, amountSats:number, address:string, opDrop:boolean, memo:string|undefined):Uint8Array {

@@ -260,2 +276,10 @@ const magicBuf = (typeof net === 'object' && net.bech32 === 'tb') ? hex.decode(MAGIC_BYTES_TESTNET) : hex.decode(MAGIC_BYTES_MAINNET);

/**
*
* @param net
* @param amount
* @param signature
* @param opDrop
* @returns
*/
export function buildWithdrawalPayload(net:any, amount:number, signature:Uint8Array, opDrop:boolean):Uint8Array {

@@ -327,2 +351,8 @@ const magicBuf = (net === btc.TEST_NETWORK) ? hex.decode(MAGIC_BYTES_TESTNET) : hex.decode(MAGIC_BYTES_MAINNET);

/**
*
* @param network
* @param txHex
* @returns
*/
export function parsePayloadFromTransaction(network:string, txHex:string):PayloadType {

@@ -403,2 +433,9 @@ const tx:btc.Transaction = btc.Transaction.fromRaw(hex.decode(txHex), {allowUnknowInput:true, allowUnknowOutput: true, allowUnknownOutputs: true, allowUnknownInputs: true})

/**
*
* @param network
* @param amount
* @param bitcoinAddress
* @returns
*/
export function getDataToSign(network:string, amount:number, bitcoinAddress:string):Uint8Array {

@@ -417,2 +454,4 @@ const net = (network === 'testnet') ? btc.TEST_NETWORK : btc.NETWORK;

const msgHash = hashMessage(hex.encode(dataToSign));
console.log('getStacksSimpleHashOfDataToSign:dataToSign: ' + hex.encode(dataToSign))
console.log('getStacksSimpleHashOfDataToSign:msgHash: ' + hex.encode(msgHash))
return hex.encode(msgHash);

@@ -434,38 +473,17 @@ }

function getPubkeySignature(messageHash:Uint8Array, signature:string) {
//console.log('getStacksAddressFromSignature: messageHash: ' + hex.encode(messageHash))
//console.log('getStacksAddressFromSignature: signature: ' + signature)
let pubkey;
try {
//console.log('=============================================================')
const recBits = (signature.substring(signature.length - 2));
//let signature = signature.substring(2)
//console.log('getPubkeySignature1: recBits: ' + ' ' + recBits)
// works for Hiro sig but not unit test sig ?
const sigM = recoverSignature({ signature: signature, mode: 'rsv' }); // vrs to rsv
let sig = new secp.Signature(sigM.signature.r, sigM.signature.s);
sig = sig.addRecoveryBit(Number(recBits)); // sometime 0 sometiimes 1 ??
//console.log('getPubkeySignature1: recovery: ', sig)
const pubkeyM = sig.recoverPublicKey(messageHash);
//console.log('getPubkeySignature11: Hiro: messageHash: ' + hex.encode(messageHash))
pubkey = hex.decode(pubkeyM.toHex());
//console.log('getPubkeySignature11: Hiro: pubkey: ' + hex.encode(pubkey))
} catch (err:any) {
//console.log('=============================================================')
//console.log('getPubkeySignature2: error: ' + ' ' + err.message)
const recBits = (signature.substring(0, 2));
const sigM = recoverSignature({ signature: signature, mode: 'rsv' }); // vrs to rsv
//console.log('getPubkeySignature2: sigM: ', sigM)
let sig = new secp.Signature(sigM.signature.r, sigM.signature.s);
sig = sig.addRecoveryBit(Number(recBits)); // sometime 0 sometiimes 1 ??
//console.log('getPubkeySignature2: recovery: ', sig)
const pubkeyM = sig.recoverPublicKey(messageHash);
//console.log('getPubkeySignature2: Hiro: messageHash: ' + hex.encode(messageHash))
pubkey = hex.decode(pubkeyM.toHex());
//console.log('getPubkeySignature2: Hiro: pubkey: ' + hex.encode(pubkey))
}
return pubkey
const sigM = recoverSignature({ signature: signature, mode: 'vrs' }); // vrs to rsv
let sig = new secp.Signature(sigM.signature.r, sigM.signature.s);
sig = sig.addRecoveryBit(0);
const pubkeyM = sig.recoverPublicKey(messageHash);
const pubkey = hex.decode(pubkeyM.toHex());
console.log(pubkeyM.toHex())
return pubkey;
}
/**
*
* @param messageHash
* @param signature
* @returns
*/
export function getStacksAddressFromSignature(messageHash:Uint8Array, signature:string) {

@@ -483,3 +501,3 @@ const pubkey = getPubkeySignature(messageHash, signature)

}
//console.log('getStacksAddressFromSignature: addresses: ', addresses)
console.log('getStacksAddressFromSignature: addresses: ', addresses)
return addresses;

@@ -530,3 +548,8 @@ }

}
/**
*
* @param script
* @returns
*/
export function toStorable(script:any) {

@@ -533,0 +556,0 @@ //const copied = JSON.parse(JSON.stringify(script));

@@ -32,3 +32,3 @@ import * as btc from '@scure/btc-signer';

if (!script.tapInternalKey) throw new Error('Incorrect data passed')
const sbtcWalletAddrScript = btc.Address(net).decode(outAddr)
const sbtcWalletAddrScript = btc.Address(net).decode(outAddr!)
if (sbtcWalletAddrScript.type !== 'tr') throw new Error('Taproot required')

@@ -136,3 +136,3 @@ //const fromBtcAddressScript = btc.Address(net).decode(peginRequest.uiPayload.bitcoinAddress);

*/
tx.addOutputAddress(outAddr, BigInt(amount), net);
tx.addOutputAddress(outAddr!, BigInt(amount), net);

@@ -139,0 +139,0 @@ /**

@@ -281,3 +281,9 @@ import * as secp from '@noble/secp256k1';

export function getAddressFromOutScript(network:string, script: Uint8Array) {
/**
* getAddressFromOutScript converts a script to an address
* @param network:string
* @param script: Uint8Array
* @returns address as string
*/
export function getAddressFromOutScript(network:string, script: Uint8Array):string {
const net = (network === 'testnet') ? btc.TEST_NETWORK : btc.NETWORK;

@@ -353,2 +359,7 @@ const outputScript = btc.OutScript.decode(script);

/**
*
* @param pubkey
* @returns
*/
export function toXOnly(pubkey: string): string {

@@ -358,3 +369,10 @@ return hex.encode(hex.decode(pubkey).subarray(1, 33))

/**
*
* @param network
* @param sbtcWalletPublicKey
* @returns
*/
export function getPegWalletAddressFromPublicKey (network:string, sbtcWalletPublicKey:string) {
if (!sbtcWalletPublicKey) return
let net = (network === 'testnet') ? btc.TEST_NETWORK : btc.NETWORK;

@@ -361,0 +379,0 @@ if (network === 'development' || network === 'simnet') {

@@ -16,2 +16,10 @@ import * as btc from '@scure/btc-signer';

/**
*
* @param network
* @param uiPayload
* @param addressInfo
* @param btcFeeRates
* @returns Transaction from @scure/btc-signer
*/
export function buildOpReturnWithdrawTransaction(network:string, uiPayload:WithdrawPayloadUIType, addressInfo:any, btcFeeRates:any) {

@@ -22,3 +30,3 @@ if (!uiPayload.signature) throw new Error('Signature of output 2 scriptPubKey is required');

const data = buildData(network, uiPayload.amountSats, uiPayload.signature, false)
const txFees = calculateWithdrawFees(network, false, addressInfo, uiPayload.amountSats, btcFeeRates, sbtcWalletAddress, uiPayload.bitcoinAddress, uiPayload.paymentPublicKey, data)
const txFees = calculateWithdrawFees(network, false, addressInfo, uiPayload.amountSats, btcFeeRates, sbtcWalletAddress!, uiPayload.bitcoinAddress, uiPayload.paymentPublicKey, data)
const tx = new btc.Transaction({ allowUnknowOutput: true, allowUnknownInputs:true, allowUnknownOutputs:true });

@@ -33,2 +41,11 @@ addInputs(network, uiPayload.amountSats, 0, tx, false, addressInfo.utxos, uiPayload.paymentPublicKey);

/**
*
* @param network
* @param uiPayload
* @param addressInfo
* @param btcFeeRates
* @param originator
* @returns
*/
export function buildOpDropWithdrawTransaction (network:string, uiPayload:WithdrawPayloadUIType, addressInfo:any, btcFeeRates:any, originator:string) {

@@ -38,3 +55,3 @@ if (!uiPayload.signature) throw new Error('Signature of output 2 scriptPubKey is required');

const sbtcWalletAddress = getPegWalletAddressFromPublicKey(network, uiPayload.sbtcWalletPublicKey)
const txFees = calculateWithdrawFees(network, true, addressInfo, uiPayload.amountSats, btcFeeRates, sbtcWalletAddress, uiPayload.bitcoinAddress, uiPayload.paymentPublicKey, undefined)
const txFees = calculateWithdrawFees(network, true, addressInfo, uiPayload.amountSats, btcFeeRates, sbtcWalletAddress!, uiPayload.bitcoinAddress, uiPayload.paymentPublicKey, undefined)
const tx = new btc.Transaction({ allowUnknowOutput: true, allowUnknownInputs:true, allowUnknownOutputs:true });

@@ -41,0 +58,0 @@ addInputs(network, uiPayload.amountSats, revealPayment, tx, false, addressInfo.utxos, uiPayload.paymentPublicKey);

@@ -6,3 +6,3 @@ import { beforeAll, beforeEach, expect, describe, it } from 'vitest'

buildWithdrawalPayload, parseWithdrawalPayload,
getStacksSimpleHashOfDataToSign, getStacksAddressFromSignature
getStacksSimpleHashOfDataToSign, getStacksAddressFromSignature, PayloadType, parsePayloadFromTransaction, getDataToSign
} from '../src/index';

@@ -16,2 +16,4 @@ import { sbtcWallets } from '../src/index';

import * as secp from '@noble/secp256k1';
import { dust } from '../src/withdraw_utils';
import { getStacksAddressFromPubkey } from '../src/payload_utils';

@@ -60,29 +62,31 @@ describe('bitcoin rpc suite - requires bitcoin core running on testnet', () => {

})
it.concurrent('Check parsing and building withdrawal payload 1', async () => {
const sig = {
publicKey: "032dea00ee2172e11fc18fc3c3ab2712038bf95d7b89330d0195624cc20764e414",
signature: "00b9710b4fda0bcf7a066d49f29ed76032c28862e5c496c5c9803501baa6130eb915e992eef765daaebf06acba5efa49ae8e0a438c5f22b03088c9d94dd061ca30"
}
const getDataToSign = '3600000000000003200014764ad6983a6455cca54cd6a4f7b0da71ba6a0bab';
const message = '3600000000000003200014764ad6983a6455cca54cd6a4f7b0da71ba6a0bab'
const messageHash = 'b37a0c9bf56598e9d39da2eaf6762c99fd403c61605148a34c505c62271880cc'
getStacksAddressFromPubkey(hex.decode(sig.publicKey))
const fromAddress = 'tb1qwe9ddxp6v32uef2v66j00vx6wxax5zat223tms'
const stacksAddress = 'ST1NXBK3K5YYMD6FD41MVNP3JS1GABZ8TRVX023PT';
const amount = 800;
const payload = buildWithdrawalPayload(btc.TEST_NETWORK, amount, hex.decode(sig.signature), false);
//assert(hex.encode(payload) === data);
//const tx = new btc.Transaction({ allowUnknowOutput: true, allowUnknownInputs:true, allowUnknownOutputs:true });
//tx.addOutputAddress(fromAddress, BigInt(dust), btc.TEST_NETWORK);
/**
*/
it.concurrent('Check parsing and building withdrawal payload 1', async () => {
const fromAddress = 'tb1qp8r7ln235zx6nd8rsdzkgkrxc238p6eecys2m9'
const stacksAddress = 'ST1R1061ZT6KPJXQ7PAXPFB6ZAZ6ZWW28G8HXK9G5';
const amount = 942;
//const amountBuf = '00000000000003ae' // 8 bytes
//const messageHash = '00000000000003ae001409c7efcd51a08da9b4e38345645866c2a270eb39'
//const publicKey = "02e30e89dc85db23273fed237c21d4ca495de4fbffbdf8a90d90e902847fb411c7"
let signature = "885b122df0a9a4abb9bc7911dc6d7af5b36a54063fa32476fbfe5ba0a0d039803bb6de6bd3058c4c494d3a6f1c925afd55dc2daa5672d164816457ab8c0ef6e600"
//Sats (be, buf=1): 942 amountToBigUint64:00000000000003ae bigUint64ToAmount:942
//data = concat(magicBuf, opCodeBuf, amountBuf, signature)
const data = '54323e00000000000003ae885b122df0a9a4abb9bc7911dc6d7af5b36a54063fa32476fbfe5ba0a0d039803bb6de6bd3058c4c494d3a6f1c925afd55dc2daa5672d164816457ab8c0ef6e600'
// 00000000000003ae
//let signature = await secp.signAsync(dataToSignHash, privKey); // sync methods below
//signature = signature.addRecoveryBit(1);
//assert(secp.verify(signature, dataToSignHash, pubKey));
//const payload = buildWithdrawalPayload(btc.TEST_NETWORK, 5000, signature.toCompactRawBytes(), false);
const payload = buildWithdrawalPayload(btc.TEST_NETWORK, amount, hex.decode(signature), false);
assert(hex.encode(payload) === data);
const parsedPayload = parseWithdrawalPayload('testnet', payload, fromAddress, 0);
const parsedPayload = parseWithdrawalPayload('testnet', payload, fromAddress);
//console.log('parsedPayload1: ', parsedPayload);
assert(parsedPayload.amountSats === amount);
assert(parsedPayload.opcode === '3E');
assert(parsedPayload.signature === signature);
assert(parsedPayload.stacksAddress === stacksAddress);
assert(parsedPayload.signature === sig.signature);
expect(parsedPayload.stacksAddress).equals(stacksAddress);
})

@@ -94,55 +98,32 @@

const amount = 942;
const data = '54323e00000000000003ae885b122df0a9a4abb9bc7911dc6d7af5b36a54063fa32476fbfe5ba0a0d039803bb6de6bd3058c4c494d3a6f1c925afd55dc2daa5672d164816457ab8c0ef6e600'
let signature = '885b122df0a9a4abb9bc7911dc6d7af5b36a54063fa32476fbfe5ba0a0d039803bb6de6bd3058c4c494d3a6f1c925afd55dc2daa5672d164816457ab8c0ef6e600'
const payload = buildWithdrawalPayload(btc.TEST_NETWORK, amount, hex.decode(signature), false);
const parsedPayload = parseWithdrawalPayload('testnet', payload, fromAddress, 0);
//console.log('parsedPayload: ', parsedPayload);
expect(data).equals(hex.encode(payload));
assert(parsedPayload.amountSats === amount);
assert(parsedPayload.opcode === '3E');
assert(parsedPayload.stacksAddress === stacksAddress);
assert(parsedPayload.signature === signature);
})
const sig = {
publicKey: "02e30e89dc85db23273fed237c21d4ca495de4fbffbdf8a90d90e902847fb411c7",
signature: "00251c10f7e9a650409416fd70a4c9f3467723f3bdbcc6a534c1d11776c6da76df57dfddfb524c01776af0443da6fd7be5e189ec4d42290ee80db2a1e7f08dda5e"
}
const getDataToSign = '360000000000000258001409c7efcd51a08da9b4e38345645866c2a270eb39';
const message = '3600000000000003200014764ad6983a6455cca54cd6a4f7b0da71ba6a0bab'
const messageHash = 'b37a0c9bf56598e9d39da2eaf6762c99fd403c61605148a34c505c62271880cc'
it.concurrent('Check parsing and building withdrawal payload 3', async () => {
const fromAddress = 'tb1qp8r7ln235zx6nd8rsdzkgkrxc238p6eecys2m9'
const stacksAddress = 'ST1R1061ZT6KPJXQ7PAXPFB6ZAZ6ZWW28G8HXK9G5';
const amount = 242;
const data = '54323e00000000000000f221a7ac825846d024fe29d0db9d9b48b0d520d01398dc4edf0aab15f9b38da27718ddce8a5c6f8bf730858d9619455a68c03338d729b1f623aa1ddb84ee383e6a00'
let signature = '21a7ac825846d024fe29d0db9d9b48b0d520d01398dc4edf0aab15f9b38da27718ddce8a5c6f8bf730858d9619455a68c03338d729b1f623aa1ddb84ee383e6a00'
const payload = buildWithdrawalPayload(btc.TEST_NETWORK, amount, hex.decode(signature), false);
//console.log('payload: ', hex.encode(payload));
const parsedPayload = parseWithdrawalPayload('testnet', hex.decode(data), fromAddress, 0);
//console.log('parsedPayload: ', parsedPayload);
//console.log('data : ', data);
expect(data).equals(hex.encode(payload));
const payload = buildWithdrawalPayload(btc.TEST_NETWORK, amount, hex.decode(sig.signature), false);
const parsedPayload = parseWithdrawalPayload('testnet', payload, fromAddress);
//console.log('parsedPayload1: ', parsedPayload);
assert(parsedPayload.amountSats === amount);
assert(parsedPayload.opcode === '3E');
assert(parsedPayload.stacksAddress === stacksAddress);
assert(parsedPayload.signature === signature);
assert(parsedPayload.signature === sig.signature);
expect(parsedPayload.stacksAddress).equals(stacksAddress);
})
it.concurrent('Check parsing and building withdrawal payload 4', async () => {
const fromAddress = 'mu5o1rDdfP6g8NKa1RweQDo1zQT58KWjdR'
const stacksAddress = 'ST2ACZ7DAH6EH20V36ES9SJEERBX7VWGWV0YB91PG';
const amount = 100;
const msgHash = 'ccfa2c7c2a3a4d3928729119d27e4959b77772e457f6d256119ee2211504d1ad'
expect(msgHash).equals(getStacksSimpleHashOfDataToSign('testnet', amount, fromAddress))
const data = '54323e0000000000000064084a912d26cb8f26652efc53d717a6b6dbdb64042cfbaa06e20b60fef67d144f36643bbba7ed178255497a058774e39fe39493f444f5ca3428d821356a6bfcf501'
let signature = '084a912d26cb8f26652efc53d717a6b6dbdb64042cfbaa06e20b60fef67d144f36643bbba7ed178255497a058774e39fe39493f444f5ca3428d821356a6bfcf501'
const payload = buildWithdrawalPayload(btc.TEST_NETWORK, amount, hex.decode(signature), false);
//console.log('payload: ', hex.encode(payload));
const parsedPayload = parseWithdrawalPayload('testnet', hex.decode(data), fromAddress, 1);
//console.log('parsedPayload: ', parsedPayload);
//console.log('data : ', data);
expect(data).equals(hex.encode(payload));
assert(parsedPayload.amountSats === amount);
assert(parsedPayload.opcode === '3E');
assert(parsedPayload.stacksAddress === stacksAddress);
assert(parsedPayload.signature === signature);
it.concurrent('Parse deposit op_return', async () => {
const txHex = '02000000000101b45477dbbb0529da2113432a3a4956de86225db8cbe7d5542e7789cd6a440f6c0100000000ffffffff0300000000000000004f6a4c4c54323e0000000000000315019d9f202861ef9e2d8ec332aac3f60d922ba7d1a98adf46f9416756e6f750639f4a949af7ff0c7b30dc24c0db2bdd7ea70cf3e9096108eb4023b2eca79d35a494f40100000000000016001409c7efcd51a08da9b4e38345645866c2a270eb39d14305000000000016001409c7efcd51a08da9b4e38345645866c2a270eb3902483045022100de9e244dd9bd6f307e979547e088736f54fde25d250e435fe867ddf4948f4d0202207762316984993ef5a8cefad1723eee8f07200437b87f3c141a39c3b150cffd27012103665ca3afcd61141e97aa9706d180514e28ef8fa29e0425e82a78e5e3b25f2b3600000000';
const payload:PayloadType = parsePayloadFromTransaction('testnet', txHex);
console.log('Parse deposit op_return:', payload)
expect(payload.stacksAddress).equals('ST1R1061ZT6KPJXQ7PAXPFB6ZAZ6ZWW28G8HXK9G5')
expect(payload.amountSats).equals(100)
expect(payload.opcode).equals('3C')
expect(payload.sbtcWallet).equals('tb1p68eyfa7nprcegz4xdj5q9msjy69xgshzckvy64cmwegfzu77v2wslah8ww')
expect(payload.prinType).equals(0)
})
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc