Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
34 changes: 34 additions & 0 deletions packages/wasm-utxo/js/fixedScriptWallet/BitGoPsbt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ export type ParseOutputsOptions = {
payGoPubkeys?: ECPairArg[];
};

export type HydrationUnspent = {
chain: number;
index: number;
value: bigint;
};

export class BitGoPsbt implements IPsbtWithAddress {
protected constructor(protected _wasm: WasmBitGoPsbt) {}

Expand Down Expand Up @@ -185,6 +191,34 @@ export class BitGoPsbt implements IPsbtWithAddress {
return new BitGoPsbt(wasm);
}

/**
* Convert a half-signed legacy transaction to a psbt-lite.
*
* Extracts partial signatures from scriptSig/witness and creates a PSBT
* with proper wallet metadata (bip32Derivation, scripts, witnessUtxo).
* Only supports p2sh, p2shP2wsh, and p2wsh inputs (not taproot).
*
* @param txBytes - The serialized half-signed legacy transaction
* @param network - Network name
* @param walletKeys - The wallet's root keys
* @param unspents - Chain, index, and value for each input
*/
static fromHalfSignedLegacyTransaction(
txBytes: Uint8Array,
network: NetworkName,
walletKeys: WalletKeysArg,
unspents: HydrationUnspent[],
): BitGoPsbt {
const keys = RootWalletKeys.from(walletKeys);
const wasm = WasmBitGoPsbt.from_half_signed_legacy_transaction(
txBytes,
network,
keys.wasm,
unspents,
);
return new BitGoPsbt(wasm);
}

/**
* Add an input to the PSBT
*
Expand Down
1 change: 1 addition & 0 deletions packages/wasm-utxo/js/fixedScriptWallet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export {
type AddWalletOutputOptions,
type ParseTransactionOptions,
type ParseOutputsOptions,
type HydrationUnspent,
} from "./BitGoPsbt.js";

// Zcash-specific PSBT subclass
Expand Down
33 changes: 32 additions & 1 deletion packages/wasm-utxo/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,41 @@ declare module "./wasm/wasm_utxo.js" {
interface PsbtOutputDataWithAddress extends PsbtOutputData {
address: string;
}

/** Outpoint referencing a previous transaction output */
interface TxOutPoint {
txid: string;
vout: number;
}

/** Raw transaction input data returned by Transaction.getInputs() */
interface TxInputData {
previousOutput: TxOutPoint;
sequence: number;
scriptSig: Uint8Array;
witness: Uint8Array[];
}

/** Raw transaction output data returned by Transaction.getOutputs() */
interface TxOutputData {
script: Uint8Array;
value: bigint;
}

/** Transaction output data with resolved address */
interface TxOutputDataWithAddress extends TxOutputData {
address: string;
}
}

export { WrapDescriptor as Descriptor } from "./wasm/wasm_utxo.js";
export { WrapMiniscript as Miniscript } from "./wasm/wasm_utxo.js";
export { Psbt } from "./descriptorWallet/Psbt.js";
export { DashTransaction, Transaction, ZcashTransaction } from "./transaction.js";
export {
DashTransaction,
Transaction,
ZcashTransaction,
type ITransaction,
type ITransactionCommon,
} from "./transaction.js";
export { hasPsbtMagic, type IPsbt, type IPsbtWithAddress } from "./psbt.js";
9 changes: 2 additions & 7 deletions packages/wasm-utxo/js/psbt.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import type { PsbtInputData, PsbtOutputData, PsbtOutputDataWithAddress } from "./wasm/wasm_utxo.js";
import type { BIP32 } from "./bip32.js";
import type { ITransactionCommon } from "./transaction.js";

/** Common interface for PSBT types */
export interface IPsbt {
inputCount(): number;
outputCount(): number;
getInputs(): PsbtInputData[];
getOutputs(): PsbtOutputData[];
export interface IPsbt extends ITransactionCommon<PsbtInputData, PsbtOutputData> {
getGlobalXpubs(): BIP32[];
version(): number;
lockTime(): number;
unsignedTxId(): string;
addInputAtIndex(
index: number,
Expand Down
135 changes: 112 additions & 23 deletions packages/wasm-utxo/js/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import { WasmDashTransaction, WasmTransaction, WasmZcashTransaction } from "./wasm/wasm_utxo.js";
import {
WasmDashTransaction,
WasmTransaction,
WasmZcashTransaction,
type TxInputData,
type TxOutputData,
type TxOutputDataWithAddress,
} from "./wasm/wasm_utxo.js";
import type { CoinName } from "./coinName.js";

/**
* Common interface for all transaction types
*/
export interface ITransaction {
/** Common read-only interface shared by transactions and PSBTs */
export interface ITransactionCommon<TInput, TOutput> {
inputCount(): number;
outputCount(): number;
version(): number;
lockTime(): number;
getInputs(): TInput[];
getOutputs(): TOutput[];
}

/** Common interface for all transaction types */
export interface ITransaction extends ITransactionCommon<TxInputData, TxOutputData> {
toBytes(): Uint8Array;
getId(): string;
getOutputsWithAddress(coin: CoinName): TxOutputDataWithAddress[];
}

/**
Expand All @@ -27,9 +44,7 @@ export class Transaction implements ITransaction {
return new Transaction(WasmTransaction.from_bytes(bytes));
}

/**
* @internal Create from WASM instance directly (avoids re-parsing bytes)
*/
/** @internal Create from WASM instance directly (avoids re-parsing bytes) */
static fromWasm(wasm: WasmTransaction): Transaction {
return new Transaction(wasm);
}
Expand Down Expand Up @@ -84,9 +99,35 @@ export class Transaction implements ITransaction {
return this._wasm.get_vsize();
}

/**
* @internal
*/
inputCount(): number {
return this._wasm.input_count();
}

outputCount(): number {
return this._wasm.output_count();
}

version(): number {
return this._wasm.version();
}

lockTime(): number {
return this._wasm.lock_time();
}

getInputs(): TxInputData[] {
return this._wasm.get_inputs() as TxInputData[];
}

getOutputs(): TxOutputData[] {
return this._wasm.get_outputs() as TxOutputData[];
}

getOutputsWithAddress(coin: CoinName): TxOutputDataWithAddress[] {
return this._wasm.get_outputs_with_address(coin) as TxOutputDataWithAddress[];
}

/** @internal */
get wasm(): WasmTransaction {
return this._wasm;
}
Expand All @@ -104,9 +145,7 @@ export class ZcashTransaction implements ITransaction {
return new ZcashTransaction(WasmZcashTransaction.from_bytes(bytes));
}

/**
* @internal Create from WASM instance directly (avoids re-parsing bytes)
*/
/** @internal Create from WASM instance directly (avoids re-parsing bytes) */
static fromWasm(wasm: WasmZcashTransaction): ZcashTransaction {
return new ZcashTransaction(wasm);
}
Expand All @@ -127,9 +166,35 @@ export class ZcashTransaction implements ITransaction {
return this._wasm.get_txid();
}

/**
* @internal
*/
inputCount(): number {
return this._wasm.input_count();
}

outputCount(): number {
return this._wasm.output_count();
}

version(): number {
return this._wasm.version();
}

lockTime(): number {
return this._wasm.lock_time();
}

getInputs(): TxInputData[] {
return this._wasm.get_inputs() as TxInputData[];
}

getOutputs(): TxOutputData[] {
return this._wasm.get_outputs() as TxOutputData[];
}

getOutputsWithAddress(coin: CoinName): TxOutputDataWithAddress[] {
return this._wasm.get_outputs_with_address(coin) as TxOutputDataWithAddress[];
}

/** @internal */
get wasm(): WasmZcashTransaction {
return this._wasm;
}
Expand All @@ -147,9 +212,7 @@ export class DashTransaction implements ITransaction {
return new DashTransaction(WasmDashTransaction.from_bytes(bytes));
}

/**
* @internal Create from WASM instance directly (avoids re-parsing bytes)
*/
/** @internal Create from WASM instance directly (avoids re-parsing bytes) */
static fromWasm(wasm: WasmDashTransaction): DashTransaction {
return new DashTransaction(wasm);
}
Expand All @@ -170,9 +233,35 @@ export class DashTransaction implements ITransaction {
return this._wasm.get_txid();
}

/**
* @internal
*/
inputCount(): number {
return this._wasm.input_count();
}

outputCount(): number {
return this._wasm.output_count();
}

version(): number {
return this._wasm.version();
}

lockTime(): number {
return this._wasm.lock_time();
}

getInputs(): TxInputData[] {
return this._wasm.get_inputs() as TxInputData[];
}

getOutputs(): TxOutputData[] {
return this._wasm.get_outputs() as TxOutputData[];
}

getOutputsWithAddress(coin: CoinName): TxOutputDataWithAddress[] {
return this._wasm.get_outputs_with_address(coin) as TxOutputDataWithAddress[];
}

/** @internal */
get wasm(): WasmDashTransaction {
return this._wasm;
}
Expand Down
Loading
Loading