Skip to content

Commit 3f1015e

Browse files
OttoAllmendingerllm-git
andcommitted
fix(wasm-utxo): add proper TypeScript type assertions
Improve type safety by adding explicit type assertions and proper type handling for node and object structures. This fixes potential TypeScript errors with JSON stringification of nodes, unknown types, and array indexing. Also improves error message display by properly serializing objects to strings. Issue: BTC-2786 Co-authored-by: llm-git <[email protected]>
1 parent 3400438 commit 3f1015e

15 files changed

+52
-41
lines changed

packages/wasm-utxo/js/ast/formatNode.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,16 @@ function formatN(n: Node | Node[]): string {
8888
if (n && typeof n === "object") {
8989
const entries = Object.entries(n);
9090
if (entries.length !== 1) {
91-
throw new Error(`Invalid node: ${n}`);
91+
throw new Error(`Invalid node: ${JSON.stringify(n)}`);
9292
}
93-
const [name, value] = entries[0];
93+
const [name, value] = entries[0] as [string, Node | Node[]];
9494
if (name === "tr" && Array.isArray(value)) {
95-
const [key, tree] = value;
95+
const [key, tree] = value as [Node, TapTree];
9696
return formatN({ tr: formatN([key, formatTr(tree)]) });
9797
}
9898
return `${name}(${formatN(value)})`;
9999
}
100-
throw new Error(`Invalid node: ${n}`);
100+
throw new Error(`Invalid node: ${JSON.stringify(n)}`);
101101
}
102102

103103
export type TapTreeNode = TapTree;

packages/wasm-utxo/js/ast/fromWasmNode.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,16 @@ function fromUnknown(v: unknown): Node | Node[] {
8686
return node("and_v", value);
8787
case "AndB":
8888
return node("and_b", value);
89-
case "AndOr":
89+
case "AndOr": {
9090
if (!Array.isArray(value)) {
9191
throw new Error(`Invalid AndOr node: ${JSON.stringify(value)}`);
9292
}
93-
const [cond, success, failure] = value;
93+
const [cond, success, failure] = value as [unknown, unknown, unknown];
9494
if (failure === false) {
9595
return node("and_n", [cond, success]);
9696
}
9797
return node("andor", [cond, success, failure]);
98+
}
9899

99100
// Disjunctions
100101
case "OrB":

packages/wasm-utxo/js/fixedScriptWallet.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ export class BitGoPsbt {
112112
walletKeys: WalletKeys,
113113
replayProtection: ReplayProtection,
114114
): ParsedTransaction {
115-
return this.wasm.parse_transaction_with_wallet_keys(walletKeys, replayProtection);
115+
return this.wasm.parse_transaction_with_wallet_keys(
116+
walletKeys,
117+
replayProtection,
118+
) as ParsedTransaction;
116119
}
117120

118121
/**
@@ -127,7 +130,7 @@ export class BitGoPsbt {
127130
* @note This method does NOT validate wallet inputs. It only parses outputs.
128131
*/
129132
parseOutputsWithWalletKeys(walletKeys: WalletKeys): ParsedOutput[] {
130-
return this.wasm.parse_outputs_with_wallet_keys(walletKeys);
133+
return this.wasm.parse_outputs_with_wallet_keys(walletKeys) as ParsedOutput[];
131134
}
132135

133136
/**

packages/wasm-utxo/js/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ declare module "./wasm/wasm_utxo.js" {
2727
node(): unknown;
2828
}
2929

30+
// eslint-disable-next-line @typescript-eslint/no-namespace
3031
namespace WrapDescriptor {
3132
function fromString(descriptor: string, pkType: DescriptorPkType): WrapDescriptor;
3233
function fromStringDetectType(descriptor: string): WrapDescriptor;
@@ -37,6 +38,7 @@ declare module "./wasm/wasm_utxo.js" {
3738
node(): unknown;
3839
}
3940

41+
// eslint-disable-next-line @typescript-eslint/no-namespace
4042
namespace WrapMiniscript {
4143
function fromString(miniscript: string, ctx: ScriptContext): WrapMiniscript;
4244
function fromBitcoinScript(script: Uint8Array, ctx: ScriptContext): WrapMiniscript;

packages/wasm-utxo/test/address/utxolibCompat.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ async function getFixtures(name: string, addressFormat?: AddressFormat): Promise
7373
const filename = addressFormat ? `${name}-${addressFormat}` : name;
7474
const fixturePath = path.join(__dirname, "..", "fixtures", "address", `${filename}.json`);
7575
const fixtures = await fs.readFile(fixturePath, "utf8");
76-
return JSON.parse(fixtures);
76+
return JSON.parse(fixtures) as Fixture[];
7777
}
7878

7979
function runTest(network: utxolib.Network, addressFormat?: AddressFormat) {
@@ -85,9 +85,9 @@ function runTest(network: utxolib.Network, addressFormat?: AddressFormat) {
8585
fixtures = await getFixtures(name, addressFormat);
8686
});
8787

88-
it("should convert to utxolib compatible network", async function () {
88+
it("should convert to utxolib compatible network", function () {
8989
for (const fixture of fixtures) {
90-
const [_type, script, addressRef] = fixture;
90+
const [, script, addressRef] = fixture;
9191
const scriptBuf = Buffer.from(script, "hex");
9292
const address = utxolibCompat.fromOutputScript(scriptBuf, network, addressFormat);
9393
assert.strictEqual(address, addressRef);
@@ -96,11 +96,11 @@ function runTest(network: utxolib.Network, addressFormat?: AddressFormat) {
9696
}
9797
});
9898

99-
it("should convert using coin name", async function () {
99+
it("should convert using coin name", function () {
100100
const coinName = getCoinNameForNetwork(name);
101101

102102
for (const fixture of fixtures) {
103-
const [_type, script, addressRef] = fixture;
103+
const [, script, addressRef] = fixture;
104104
const scriptBuf = Buffer.from(script, "hex");
105105

106106
// Test encoding (script -> address)

packages/wasm-utxo/test/descriptorUtil.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { DescriptorNode, MiniscriptNode, formatNode } from "../js/ast/index.js";
55

66
async function assertEqualJSON(path: string, value: unknown): Promise<void> {
77
try {
8-
const data = JSON.parse(await fs.readFile(path, "utf8"));
8+
const data: unknown = JSON.parse(await fs.readFile(path, "utf8"));
99
assert.deepStrictEqual(data, value);
10-
} catch (e: any) {
11-
if (e.code === "ENOENT") {
10+
} catch (e: unknown) {
11+
if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT") {
1212
await fs.writeFile(path, JSON.stringify(value, null, 2));
1313
throw new Error("Expected file not found, wrote it instead");
1414
}

packages/wasm-utxo/test/fixedScript/fixtureUtil.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export type Fixture = {
8989
psbtInputsFinalized: PsbtInput[] | null;
9090
outputs: Output[];
9191
psbtOutputs: PsbtOutput[];
92-
extractedTransaction: any | null;
92+
extractedTransaction: string | null;
9393
};
9494

9595
/**

packages/wasm-utxo/test/fixedScript/verifySignature.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ function getExpectedSignatures(
4747
// Regular multisig uses user + bitgo
4848
return { user: true, backup: false, bitgo: true };
4949
default:
50-
throw new Error(`Unknown signature stage: ${signatureStage}`);
50+
throw new Error(`Unknown signature stage: ${String(signatureStage)}`);
5151
}
5252
}
5353

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import * as fs from "fs/promises";
22
export async function getFixture(path: string, defaultValue: unknown): Promise<unknown> {
33
try {
4-
return JSON.parse(await fs.readFile(path, "utf8"));
4+
return JSON.parse(await fs.readFile(path, "utf8")) as unknown;
55
} catch (e) {
6-
if (e.code === "ENOENT") {
6+
if (
7+
typeof e === "object" &&
8+
e !== null &&
9+
"code" in e &&
10+
(e as { code: unknown }).code === "ENOENT"
11+
) {
712
await fs.writeFile(path, JSON.stringify(defaultValue, null, 2));
813
throw new Error(`Fixture not found at ${path}, created a new one`);
914
}
15+
throw e;
1016
}
1117
}

packages/wasm-utxo/test/psbt.util.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,14 @@ function matchPath(path: (string | number)[], pattern: (string | number | symbol
7979
return true;
8080
}
8181

82-
function normalizeBip32Derivation(v: unknown) {
82+
function normalizeBip32Derivation(v: unknown): {
83+
masterFingerprint: Buffer;
84+
path: string;
85+
}[] {
8386
if (!Array.isArray(v)) {
8487
throw new Error("Expected bip32Derivation to be an array");
8588
}
86-
return (
87-
[...v] as {
88-
masterFingerprint: Buffer;
89-
path: string;
90-
}[]
91-
)
89+
return (v as { masterFingerprint: Buffer; path: string }[])
9290
.map((e) => {
9391
let { path } = e;
9492
if (path.startsWith("m/")) {
@@ -102,7 +100,7 @@ function normalizeBip32Derivation(v: unknown) {
102100
.sort((a, b) => a.masterFingerprint.toString().localeCompare(b.masterFingerprint.toString()));
103101
}
104102

105-
function toPlainObject(v: unknown, path: (string | number)[]) {
103+
function toPlainObject(v: unknown, path: (string | number)[]): unknown {
106104
// psbts have fun getters and other types of irregular properties that we mash into shape here
107105
if (v === null || v === undefined) {
108106
return v;

0 commit comments

Comments
 (0)