From 8639647cde2fbb118719a4fe945b9bae4dd87f63 Mon Sep 17 00:00:00 2001 From: DenisIvanov26 Date: Wed, 27 Mar 2024 11:29:26 -0500 Subject: [PATCH 1/3] utxo tx fields utxo types remove env --- .gitignore | 2 +- package-lock.json | 131 +++++------------ package.json | 5 +- src.ts/providers/abstract-signer.ts | 15 +- src.ts/providers/formatting.ts | 6 +- src.ts/providers/provider.ts | 33 ++--- src.ts/transaction/transaction.ts | 22 ++- src.ts/utils/ProtoBuf/proto_common.ts | 16 +-- src.ts/utils/proto-decode.ts | 1 + src.ts/wallet/base-crypto.ts | 196 ++++++++++++++++++++++++++ src.ts/wallet/base-wallet.ts | 23 ++- src.ts/wallet/hdwallet.ts | 1 - src.ts/wallet/musig-crypto.ts | 82 +++++++++++ transactions.json.gz | 0 14 files changed, 400 insertions(+), 133 deletions(-) create mode 100644 src.ts/wallet/base-crypto.ts create mode 100644 src.ts/wallet/musig-crypto.ts delete mode 100644 transactions.json.gz diff --git a/.gitignore b/.gitignore index 7e058352..2dcfd5e5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ output/** **/*.tgz dist/*.gz /*.env -.idea/** +.idea/** \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 05c774f0..8fd47e76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@adraffy/ens-normalize": "1.10.0", + "@brandonblack/musig": "^0.0.1-alpha.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", @@ -45,89 +46,18 @@ "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==" }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/helper-validator-identifier": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", @@ -138,14 +68,15 @@ } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -228,6 +159,11 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@brandonblack/musig": { + "version": "0.0.1-alpha.1", + "resolved": "https://registry.npmjs.org/@brandonblack/musig/-/musig-0.0.1-alpha.1.tgz", + "integrity": "sha512-00RbByQG85lSzrkDjCblzrUc2n1LJAPPrEMHS4oMg+QckE0kzjd26JytT6yx6tNU2+aOXfK7O4kGW/sKVL67cw==" + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -554,12 +490,12 @@ "dev": true }, "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -571,12 +507,15 @@ "dev": true }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/brace-expansion": { @@ -956,9 +895,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -1115,9 +1054,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -1706,6 +1645,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", diff --git a/package.json b/package.json index 14944972..1822c0ec 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@adraffy/ens-normalize": "1.10.0", + "@brandonblack/musig": "^0.0.1-alpha.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", @@ -23,8 +24,8 @@ "description": "A complete and compact Quai library, for dapps, wallets and any other tools.", "devDependencies": { "@rollup/plugin-node-resolve": "15.0.2", - "@types/google-protobuf": "^3.15.12", "@types/expect": "^24.3.0", + "@types/google-protobuf": "^3.15.12", "@types/mocha": "^9.1.1", "@types/semver": "7.5.0", "axios": "^1.6.7", @@ -129,4 +130,4 @@ }, "sideEffects": false, "version": "v0.1.0-pre" -} \ No newline at end of file +} diff --git a/src.ts/providers/abstract-signer.ts b/src.ts/providers/abstract-signer.ts index d8d2f4c9..56a2d13e 100644 --- a/src.ts/providers/abstract-signer.ts +++ b/src.ts/providers/abstract-signer.ts @@ -91,18 +91,24 @@ export abstract class AbstractSigner

> { + + // } + async populateTransaction(tx: TransactionRequest): Promise> { + console.log("populateTransaction") const provider = checkProvider(this, "populateTransaction"); const pop = await populate(this, tx); - if (pop.nonce == null) { - pop.nonce = await this.getNonce("pending"); - } if (pop.type == null) { pop.type = await getTxType(pop.from ?? null, pop.to ?? null); } + if (pop.nonce == null) { + pop.nonce = await this.getNonce("pending"); + } + if (pop.gasLimit == null) { if (pop.type == 0 ) pop.gasLimit = await this.estimateGas(pop); else { @@ -152,9 +158,12 @@ export abstract class AbstractSigner

{ + console.log('sendTransaction', tx) const provider = checkProvider(this, "sendTransaction"); const pop = await this.populateTransaction(tx); + console.log("populated tx", pop) delete pop.from; + const txObj = Transaction.from(pop); const signedTx = await this.signTransaction(txObj); const result = await provider.broadcastTransaction(signedTx); diff --git a/src.ts/providers/formatting.ts b/src.ts/providers/formatting.ts index 5bea400a..c5d08274 100644 --- a/src.ts/providers/formatting.ts +++ b/src.ts/providers/formatting.ts @@ -6,7 +6,7 @@ import type { Signature } from "../crypto/index.js"; import type { AccessList } from "../transaction/index.js"; - +import type { UTXOTransactionInput, UTXOTransactionOutput } from "../transaction/utxo.js"; ////////////////////// // Block @@ -380,6 +380,10 @@ export interface TransactionResponseParams { * The transaction access list. */ accessList: null | AccessList; + + UTXOoutputs ?: UTXOTransactionOutput[]; + + UTXOinputs ?: UTXOTransactionInput[]; }; diff --git a/src.ts/providers/provider.ts b/src.ts/providers/provider.ts index fdd1f737..eacba88f 100644 --- a/src.ts/providers/provider.ts +++ b/src.ts/providers/provider.ts @@ -12,7 +12,7 @@ import type { AccessList, AccessListish, TransactionLike } from "../transaction/ import type { ContractRunner } from "./contracts.js"; import type { Network } from "./network.js"; - +import type { UTXOTransactionInput, UTXOTransactionOutput } from "../transaction/utxo.js"; const BN_0 = BigInt(0); @@ -113,7 +113,6 @@ export class FeeData { } } - /** * A **TransactionRequest** is a transactions with potentially various * properties not defined, or with less strict types for its values. @@ -203,16 +202,9 @@ export interface TransactionRequest { */ blockTag?: BlockTag; - /** - * When using ``call``, this enables CCIP-read, which permits the - * provider to be redirected to web-based content during execution, - * which is then further validated by the contract. - * - * There are potential security implications allowing CCIP-read, as - * it could be used to expose the IP address or user activity during - * the fetch to unexpected parties. - */ - enableCcipRead?: boolean; + inputs?: null | Array; + + outputs?: null | Array; }; /** @@ -304,16 +296,9 @@ export interface PreparedTransactionRequest { */ blockTag?: BlockTag; - /** - * When using ``call``, this enables CCIP-read, which permits the - * provider to be redirected to web-based content during execution, - * which is then further validated by the contract. - * - * There are potential security implications allowing CCIP-read, as - * it could be used to expose the IP address or user activity during - * the fetch to unexpected parties. - */ - enableCcipRead?: boolean; + inputs?: null | Array; + + outputs?: null | Array; } /** @@ -1361,6 +1346,10 @@ export class TransactionResponse implements TransactionLike, Transaction */ readonly accessList!: null | AccessList; + readonly inputs ?: Array ; + + readonly outputs ?: Array ; + #startBlock: number; /** diff --git a/src.ts/transaction/transaction.ts b/src.ts/transaction/transaction.ts index e0695845..69f05989 100644 --- a/src.ts/transaction/transaction.ts +++ b/src.ts/transaction/transaction.ts @@ -12,7 +12,7 @@ import { computeAddress, recoverAddress } from "./address.js"; import type { BigNumberish, BytesLike } from "../utils/index.js"; import type { SignatureLike } from "../crypto/index.js"; import type { AccessList, AccessListish } from "./index.js"; - +import type { UTXOTransactionInput, UTXOTransactionOutput } from "./utxo.js"; export interface TransactionLike { /** @@ -84,6 +84,11 @@ export interface TransactionLike { * The access list for berlin and london transactions. */ accessList?: null | AccessListish; + + + UTXOinputs?: null | Array; + + UTXOoutputs?: null | Array; } function handleNumber(_value: string, param: string): number { @@ -181,6 +186,11 @@ function _serialize(tx: TransactionLike, sig?: Signature): string { type: (tx.type || 0), } + if (tx.type == 2){ + formattedTx.tx_ins = tx.UTXOinputs + formattedTx.tx_outs = tx.UTXOoutputs + } + if (sig) { formattedTx.v = formatNumber(sig.yParity, "yParity"), formattedTx.r = toBeArray(sig.r), @@ -217,6 +227,8 @@ export class Transaction implements TransactionLike { #sig: null | Signature; #accessList: null | AccessList; #hash: null | string; + #UTXOinputs: null | UTXOTransactionInput[]; + #UTXOoutputs: null | UTXOTransactionOutput[]; /** * The transaction type. @@ -368,6 +380,12 @@ export class Transaction implements TransactionLike { this.#accessList = (value == null) ? null: accessListify(value); } + + get UTXOinputs(): null | UTXOTransactionInput[] { return this.#UTXOinputs; } + set UTXOinputs(value: null | UTXOTransactionInput[]) { this.#UTXOinputs = value; } + + get UTXOoutputs(): null | UTXOTransactionOutput[] { return this.#UTXOoutputs; } + set UTXOoutputs(value: null | UTXOTransactionOutput[]) { this.#UTXOoutputs = value; } /** @@ -387,6 +405,8 @@ export class Transaction implements TransactionLike { this.#sig = null; this.#accessList = null; this.#hash = null; + this.#UTXOinputs = null; + this.#UTXOoutputs = null; } /** diff --git a/src.ts/utils/ProtoBuf/proto_common.ts b/src.ts/utils/ProtoBuf/proto_common.ts index 3c406530..a2313e4f 100644 --- a/src.ts/utils/ProtoBuf/proto_common.ts +++ b/src.ts/utils/ProtoBuf/proto_common.ts @@ -6,12 +6,12 @@ import * as pb_1 from "google-protobuf"; export namespace common { export class ProtoLocation extends pb_1.Message { - one_of_decls: number[][] = []; + #one_of_decls: number[][] = []; constructor(data?: any[] | { value?: Uint8Array; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("value" in data && data.value != undefined) { this.value = data.value; @@ -73,12 +73,12 @@ export namespace common { } } export class ProtoHash extends pb_1.Message { - one_of_decls: number[][] = []; + #one_of_decls: number[][] = []; constructor(data?: any[] | { value?: Uint8Array; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("value" in data && data.value != undefined) { this.value = data.value; @@ -140,12 +140,12 @@ export namespace common { } } export class ProtoHashes extends pb_1.Message { - one_of_decls: number[][] = []; + #one_of_decls: number[][] = []; constructor(data?: any[] | { hashes?: ProtoHash[]; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1], this.one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("hashes" in data && data.hashes != undefined) { this.hashes = data.hashes; @@ -207,12 +207,12 @@ export namespace common { } } export class ProtoAddress extends pb_1.Message { - one_of_decls: number[][] = []; + #one_of_decls: number[][] = []; constructor(data?: any[] | { value?: Uint8Array; }) { super(); - pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.one_of_decls); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); if (!Array.isArray(data) && typeof data == "object") { if ("value" in data && data.value != undefined) { this.value = data.value; diff --git a/src.ts/utils/proto-decode.ts b/src.ts/utils/proto-decode.ts index 27706c60..8ed43803 100644 --- a/src.ts/utils/proto-decode.ts +++ b/src.ts/utils/proto-decode.ts @@ -7,5 +7,6 @@ function _decode(object: any): any { } export function decodeProto(object: Uint8Array): string{ + console.log('Test decode') return _decode(object); } \ No newline at end of file diff --git a/src.ts/wallet/base-crypto.ts b/src.ts/wallet/base-crypto.ts new file mode 100644 index 00000000..14202bb9 --- /dev/null +++ b/src.ts/wallet/base-crypto.ts @@ -0,0 +1,196 @@ +// BigInt / Uint8Array versions of Crypto functions that do not require point +// math. If your JS interpreter has BigInt, you can use all of these. If not, +// you'll need to either shim it in or override more of these functions. + +// Idea from noble-secp256k1, be nice to bad JS parsers +const _0n = BigInt(0); +const _1n = BigInt(1); +const _2n = BigInt(2); +const _3n = BigInt(3); +const _5n = BigInt(5); +const _7n = BigInt(7); +const _64n = BigInt(64); +const _64mask = BigInt('0xFFFFFFFFFFFFFFFF'); + +const CURVE = { + b: BigInt(7), + P: BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'), + n: BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'), +}; + +// Big Endian +function read32b(bytes: Uint8Array): bigint { + if (bytes.length !== 32) throw new Error(`Expected 32-bytes, not ${bytes.length}`); + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length); + let b = view.getBigUint64(0); + for (let offs = 8; offs < bytes.length; offs += 8) { + b <<= _64n; + b += view.getBigUint64(offs); + } + return b; +} + +function write32b(num: bigint, dest: Uint8Array = new Uint8Array(32)): Uint8Array { + // All input values are modulo P or n, so no bounds checking needed + const view = new DataView(dest.buffer, dest.byteOffset, dest.length); + for (let offs = 24; offs >= 0; offs -= 8) { + view.setBigUint64(offs, num & _64mask); + num >>= _64n; + } + return dest; +} + +export function readScalar(bytes: Uint8Array): bigint { + const a = read32b(bytes); + if (a >= CURVE.n) throw new Error('Expected value mod n'); + return a; +} + +export function readSecret(bytes: Uint8Array): bigint { + const a = readScalar(bytes); + if (a === 0n) throw new Error('Expected non-zero'); + return a; +} + +// The short Weierstrass form curve equation simplifes to y^2 = x^3 + 7. +function secp256k1Right(x: bigint): bigint { + const x2 = (x * x) % CURVE.P; + const x3 = (x2 * x) % CURVE.P; + return (x3 + CURVE.b) % CURVE.P; +} + +// For prime P, the Jacobi Symbol of 'a' is 1 if and only if 'a' is a quadratic +// residue mod P, ie. there exists a value 'x' for whom x^2 = a. +function jacobiSymbol(a: bigint): -1 | 0 | 1 { + if (a === _0n) return 0; // Vanishingly improbable + + let p = CURVE.P; + let sign = 1; + // This algorithm is fairly heavily optimized, so don't simplify it w/o benchmarking + for (;;) { + let and3; + // Handle runs of zeros efficiently w/o flipping sign each time + for (and3 = a & _3n; and3 === _0n; a >>= _2n, and3 = a & _3n); + // If there's one more zero, shift it off and flip the sign + if (and3 === _2n) { + a >>= _1n; + const pand7 = p & _7n; + if (pand7 === _3n || pand7 === _5n) sign = -sign; + } + if (a === _1n) break; + if ((_3n & a) === _3n && (_3n & p) === _3n) sign = -sign; + [a, p] = [p % a, a]; + } + return sign > 0 ? 1 : -1; +} + +export function isPoint(p: Uint8Array): boolean { + if (p.length < 33) return false; + + const t = p[0]; + if (p.length === 33) { + return (t === 0x02 || t === 0x03) && isXOnlyPoint(p.subarray(1)); + } + + if (t !== 0x04 || p.length !== 65) return false; + + const x = read32b(p.subarray(1, 33)); + if (x === _0n) return false; + if (x >= CURVE.P) return false; + + const y = read32b(p.subarray(33)); + if (y === _0n) return false; + if (y >= CURVE.P) return false; + + const left = (y * y) % CURVE.P; + const right = secp256k1Right(x); + return left === right; +} + +export function isXOnlyPoint(p: Uint8Array): boolean { + if (p.length !== 32) return false; + const x = read32b(p); + if (x === _0n) return false; + if (x >= CURVE.P) return false; + const y2 = secp256k1Right(x); + return jacobiSymbol(y2) === 1; // If sqrt(y^2) exists, x is on the curve. +} + +export function scalarAdd(a: Uint8Array, b: Uint8Array): Uint8Array { + const aN = readScalar(a); + const bN = readScalar(b); + const sum = (aN + bN) % CURVE.n; + return write32b(sum); +} + +export function scalarMultiply(a: Uint8Array, b: Uint8Array): Uint8Array { + const aN = readScalar(a); + const bN = readScalar(b); + const product = (aN * bN) % CURVE.n; + return write32b(product); +} + +export function scalarNegate(a: Uint8Array): Uint8Array { + const aN = readScalar(a); + const negated = aN === _0n ? _0n : CURVE.n - aN; + return write32b(negated); +} + +export function scalarMod(a: Uint8Array): Uint8Array { + const aN = read32b(a); + const remainder = aN % CURVE.n; + return write32b(remainder); +} + +export function isScalar(t: Uint8Array): boolean { + try { + readScalar(t); + return true; + } catch { + return false; + } +} + +export function isSecret(s: Uint8Array): boolean { + try { + readSecret(s); + return true; + } catch { + return false; + } +} + +export function pointNegate(p: Uint8Array): Uint8Array { + // hasEvenY does basic structure check, so start there + const even = hasEvenY(p); + // `from` because node.Buffer.slice doesn't copy but looks like a Uint8Array + const negated = Uint8Array.from(p); + if (p.length === 33) { + negated[0] = even ? 3 : 2; + } else if (p.length === 65) { + const y = read32b(p.subarray(33)); + if (y >= CURVE.P) throw new Error('Expected Y coordinate mod P'); + const minusY = y === _0n ? _0n : CURVE.P - y; + write32b(minusY, negated.subarray(33)); + } + return negated; +} + +export function pointX(p: Uint8Array): Uint8Array { + if (p.length === 32) return p; + hasEvenY(p); // hasEvenY throws if not well structured + return p.slice(1, 33); +} + +export function hasEvenY(p: Uint8Array): boolean { + if (p.length === 33) { + if (p[0] === 2) return true; + else if (p[0] === 3) return false; + else throw new Error('Wrong first byte to be a point'); + } + if (p.length === 65) { + if (p[0] !== 4) throw new Error('Wrong first byte to be point'); + return p[64] % 2 === 0; + } + throw new Error('Wrong length to be a point'); +} \ No newline at end of file diff --git a/src.ts/wallet/base-wallet.ts b/src.ts/wallet/base-wallet.ts index 6e7ae5cf..daa7acaa 100644 --- a/src.ts/wallet/base-wallet.ts +++ b/src.ts/wallet/base-wallet.ts @@ -11,6 +11,10 @@ import type { TypedDataDomain, TypedDataField } from "../hash/index.js"; import type { Provider, TransactionRequest } from "../providers/index.js"; import type { TransactionLike } from "../transaction/index.js"; +// import { MuSigFactory } from "@brandonblack/musig" +// import { nobleCrypto } from "./musig-crypto.js"; +// import { UTXOTransaction } from "../transaction/utxo.js"; +// import { schnorr } from "@noble/curves/secp256k1"; /** * The **BaseWallet** is a stream-lined implementation of a @@ -73,7 +77,8 @@ export class BaseWallet extends AbstractSigner { return new BaseWallet(this.#signingKey, provider); } - async signTransaction(tx: TransactionRequest): Promise { + async signTransaction(tx: TransactionRequest ): Promise { + console.log("signTransaction") // Replace any Addressable or ENS name with an address const { to, from } = await resolveProperties({ to: (tx.to ? resolveAddress(tx.to, this.provider): undefined), @@ -96,6 +101,22 @@ export class BaseWallet extends AbstractSigner { return btx.serialized; } + // async signUTXOTransaction(tx: UTXOTransaction, pk: Uint8Array): Promise { + // const factory = MuSigFactory(nobleCrypto); + + // //const transactionHash = tx.serialize() + + // // Check if there is only one private key + // if (pk.length === 1) { + // // Single key scenario: Perform a simple Schnorr signature + // const publicKey = factory.getXOnlyPubkey(pk[0]); + // const signature = schnorr.sign(transactionHash, BigInt(pk[0]), publicKey); + + // // Attach the signature to the transaction + // transaction.signature = signature; + // } + // } + async signMessage(message: string | Uint8Array): Promise { return this.signMessageSync(message); } diff --git a/src.ts/wallet/hdwallet.ts b/src.ts/wallet/hdwallet.ts index bab29cc5..4b8536ba 100644 --- a/src.ts/wallet/hdwallet.ts +++ b/src.ts/wallet/hdwallet.ts @@ -460,7 +460,6 @@ export class HDNodeWallet extends BaseWallet { // newPath = this.path.replace(pathComponents[pathComponents.length - 1], addrIndex.toString()); // else throw new Error(`Invalid or uncomplete path: ${newPath} ${this.path}`); newWallet = this.derivePath(addrIndex.toString()); - console.log(newWallet.address) if (getShardForAddress(newWallet.address) == shard && ((newWallet.coinType == 969) == isUTXOAddress(newWallet.address))) zoneIndex--; addrIndex++; diff --git a/src.ts/wallet/musig-crypto.ts b/src.ts/wallet/musig-crypto.ts new file mode 100644 index 00000000..15016dc6 --- /dev/null +++ b/src.ts/wallet/musig-crypto.ts @@ -0,0 +1,82 @@ +import { sha256 } from '@noble/hashes/sha256'; +import { secp256k1, schnorr } from '@noble/curves/secp256k1'; +import * as baseCrypto from './base-crypto'; + + +export const nobleCrypto = { + ...baseCrypto, + pointMultiplyUnsafe: (p: Uint8Array, a: Uint8Array, compress: boolean): Uint8Array | null => { + try { + const product = secp256k1.ProjectivePoint.fromHex(p).multiplyAndAddUnsafe( + secp256k1.ProjectivePoint.ZERO, + BigInt(`0x${Buffer.from(a).toString('hex')}`), + BigInt(1) + ); + if (!product) return null; + return product.toRawBytes(compress); + } catch { + return null; + } + }, + pointMultiplyAndAddUnsafe: ( + p1: Uint8Array, + a: Uint8Array, + p2: Uint8Array, + compress: boolean + ): Uint8Array | null => { + try { + const p2p = secp256k1.ProjectivePoint.fromHex(p2); + const p = secp256k1.ProjectivePoint.fromHex(p1).multiplyAndAddUnsafe( + p2p, + BigInt(`0x${Buffer.from(a).toString('hex')}`), + BigInt(1) + ); + if (!p) return null; + return p.toRawBytes(compress); + } catch { + return null; + } + }, + pointAdd: (a: Uint8Array, b: Uint8Array, compress: boolean): Uint8Array | null => { + try { + return secp256k1.ProjectivePoint.fromHex(a) + .add(secp256k1.ProjectivePoint.fromHex(b)) + .toRawBytes(compress); + } catch { + return null; + } + }, + pointAddTweak: (p: Uint8Array, tweak: Uint8Array, compress: boolean): Uint8Array | null => { + try { + const P = secp256k1.ProjectivePoint.fromHex(p); + const t = baseCrypto.readSecret(tweak); + const Q = secp256k1.ProjectivePoint.BASE.multiplyAndAddUnsafe(P, t, 1n); + if (!Q) throw new Error('Tweaked point at infinity'); + return Q.toRawBytes(compress); + } catch { + return null; + } + }, + pointCompress: (p: Uint8Array, compress = true): Uint8Array => + secp256k1.ProjectivePoint.fromHex(p).toRawBytes(compress), + liftX: (p: Uint8Array): Uint8Array | null => { + try { + return secp256k1.ProjectivePoint.fromHex(p).toRawBytes(false); + } catch { + return null; + } + }, + getPublicKey: (s: Uint8Array, compress: boolean): Uint8Array | null => { + try { + return secp256k1.getPublicKey(s, compress); + } catch { + return null; + } + }, + taggedHash: schnorr.utils.taggedHash, + sha256: (...messages: Uint8Array[]): Uint8Array => { + const h = sha256.create(); + for (const message of messages) h.update(message); + return h.digest(); + }, +}; \ No newline at end of file diff --git a/transactions.json.gz b/transactions.json.gz deleted file mode 100644 index e69de29b..00000000 From a321c01c113496d452d5022bf84d1a81718428f9 Mon Sep 17 00:00:00 2001 From: DenisIvanov26 Date: Fri, 29 Mar 2024 14:30:46 -0500 Subject: [PATCH 2/3] remvoe musig files --- src.ts/wallet/base-crypto.ts | 196 ---------------------------------- src.ts/wallet/musig-crypto.ts | 82 -------------- 2 files changed, 278 deletions(-) delete mode 100644 src.ts/wallet/base-crypto.ts delete mode 100644 src.ts/wallet/musig-crypto.ts diff --git a/src.ts/wallet/base-crypto.ts b/src.ts/wallet/base-crypto.ts deleted file mode 100644 index 14202bb9..00000000 --- a/src.ts/wallet/base-crypto.ts +++ /dev/null @@ -1,196 +0,0 @@ -// BigInt / Uint8Array versions of Crypto functions that do not require point -// math. If your JS interpreter has BigInt, you can use all of these. If not, -// you'll need to either shim it in or override more of these functions. - -// Idea from noble-secp256k1, be nice to bad JS parsers -const _0n = BigInt(0); -const _1n = BigInt(1); -const _2n = BigInt(2); -const _3n = BigInt(3); -const _5n = BigInt(5); -const _7n = BigInt(7); -const _64n = BigInt(64); -const _64mask = BigInt('0xFFFFFFFFFFFFFFFF'); - -const CURVE = { - b: BigInt(7), - P: BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'), - n: BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'), -}; - -// Big Endian -function read32b(bytes: Uint8Array): bigint { - if (bytes.length !== 32) throw new Error(`Expected 32-bytes, not ${bytes.length}`); - const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length); - let b = view.getBigUint64(0); - for (let offs = 8; offs < bytes.length; offs += 8) { - b <<= _64n; - b += view.getBigUint64(offs); - } - return b; -} - -function write32b(num: bigint, dest: Uint8Array = new Uint8Array(32)): Uint8Array { - // All input values are modulo P or n, so no bounds checking needed - const view = new DataView(dest.buffer, dest.byteOffset, dest.length); - for (let offs = 24; offs >= 0; offs -= 8) { - view.setBigUint64(offs, num & _64mask); - num >>= _64n; - } - return dest; -} - -export function readScalar(bytes: Uint8Array): bigint { - const a = read32b(bytes); - if (a >= CURVE.n) throw new Error('Expected value mod n'); - return a; -} - -export function readSecret(bytes: Uint8Array): bigint { - const a = readScalar(bytes); - if (a === 0n) throw new Error('Expected non-zero'); - return a; -} - -// The short Weierstrass form curve equation simplifes to y^2 = x^3 + 7. -function secp256k1Right(x: bigint): bigint { - const x2 = (x * x) % CURVE.P; - const x3 = (x2 * x) % CURVE.P; - return (x3 + CURVE.b) % CURVE.P; -} - -// For prime P, the Jacobi Symbol of 'a' is 1 if and only if 'a' is a quadratic -// residue mod P, ie. there exists a value 'x' for whom x^2 = a. -function jacobiSymbol(a: bigint): -1 | 0 | 1 { - if (a === _0n) return 0; // Vanishingly improbable - - let p = CURVE.P; - let sign = 1; - // This algorithm is fairly heavily optimized, so don't simplify it w/o benchmarking - for (;;) { - let and3; - // Handle runs of zeros efficiently w/o flipping sign each time - for (and3 = a & _3n; and3 === _0n; a >>= _2n, and3 = a & _3n); - // If there's one more zero, shift it off and flip the sign - if (and3 === _2n) { - a >>= _1n; - const pand7 = p & _7n; - if (pand7 === _3n || pand7 === _5n) sign = -sign; - } - if (a === _1n) break; - if ((_3n & a) === _3n && (_3n & p) === _3n) sign = -sign; - [a, p] = [p % a, a]; - } - return sign > 0 ? 1 : -1; -} - -export function isPoint(p: Uint8Array): boolean { - if (p.length < 33) return false; - - const t = p[0]; - if (p.length === 33) { - return (t === 0x02 || t === 0x03) && isXOnlyPoint(p.subarray(1)); - } - - if (t !== 0x04 || p.length !== 65) return false; - - const x = read32b(p.subarray(1, 33)); - if (x === _0n) return false; - if (x >= CURVE.P) return false; - - const y = read32b(p.subarray(33)); - if (y === _0n) return false; - if (y >= CURVE.P) return false; - - const left = (y * y) % CURVE.P; - const right = secp256k1Right(x); - return left === right; -} - -export function isXOnlyPoint(p: Uint8Array): boolean { - if (p.length !== 32) return false; - const x = read32b(p); - if (x === _0n) return false; - if (x >= CURVE.P) return false; - const y2 = secp256k1Right(x); - return jacobiSymbol(y2) === 1; // If sqrt(y^2) exists, x is on the curve. -} - -export function scalarAdd(a: Uint8Array, b: Uint8Array): Uint8Array { - const aN = readScalar(a); - const bN = readScalar(b); - const sum = (aN + bN) % CURVE.n; - return write32b(sum); -} - -export function scalarMultiply(a: Uint8Array, b: Uint8Array): Uint8Array { - const aN = readScalar(a); - const bN = readScalar(b); - const product = (aN * bN) % CURVE.n; - return write32b(product); -} - -export function scalarNegate(a: Uint8Array): Uint8Array { - const aN = readScalar(a); - const negated = aN === _0n ? _0n : CURVE.n - aN; - return write32b(negated); -} - -export function scalarMod(a: Uint8Array): Uint8Array { - const aN = read32b(a); - const remainder = aN % CURVE.n; - return write32b(remainder); -} - -export function isScalar(t: Uint8Array): boolean { - try { - readScalar(t); - return true; - } catch { - return false; - } -} - -export function isSecret(s: Uint8Array): boolean { - try { - readSecret(s); - return true; - } catch { - return false; - } -} - -export function pointNegate(p: Uint8Array): Uint8Array { - // hasEvenY does basic structure check, so start there - const even = hasEvenY(p); - // `from` because node.Buffer.slice doesn't copy but looks like a Uint8Array - const negated = Uint8Array.from(p); - if (p.length === 33) { - negated[0] = even ? 3 : 2; - } else if (p.length === 65) { - const y = read32b(p.subarray(33)); - if (y >= CURVE.P) throw new Error('Expected Y coordinate mod P'); - const minusY = y === _0n ? _0n : CURVE.P - y; - write32b(minusY, negated.subarray(33)); - } - return negated; -} - -export function pointX(p: Uint8Array): Uint8Array { - if (p.length === 32) return p; - hasEvenY(p); // hasEvenY throws if not well structured - return p.slice(1, 33); -} - -export function hasEvenY(p: Uint8Array): boolean { - if (p.length === 33) { - if (p[0] === 2) return true; - else if (p[0] === 3) return false; - else throw new Error('Wrong first byte to be a point'); - } - if (p.length === 65) { - if (p[0] !== 4) throw new Error('Wrong first byte to be point'); - return p[64] % 2 === 0; - } - throw new Error('Wrong length to be a point'); -} \ No newline at end of file diff --git a/src.ts/wallet/musig-crypto.ts b/src.ts/wallet/musig-crypto.ts deleted file mode 100644 index 15016dc6..00000000 --- a/src.ts/wallet/musig-crypto.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { sha256 } from '@noble/hashes/sha256'; -import { secp256k1, schnorr } from '@noble/curves/secp256k1'; -import * as baseCrypto from './base-crypto'; - - -export const nobleCrypto = { - ...baseCrypto, - pointMultiplyUnsafe: (p: Uint8Array, a: Uint8Array, compress: boolean): Uint8Array | null => { - try { - const product = secp256k1.ProjectivePoint.fromHex(p).multiplyAndAddUnsafe( - secp256k1.ProjectivePoint.ZERO, - BigInt(`0x${Buffer.from(a).toString('hex')}`), - BigInt(1) - ); - if (!product) return null; - return product.toRawBytes(compress); - } catch { - return null; - } - }, - pointMultiplyAndAddUnsafe: ( - p1: Uint8Array, - a: Uint8Array, - p2: Uint8Array, - compress: boolean - ): Uint8Array | null => { - try { - const p2p = secp256k1.ProjectivePoint.fromHex(p2); - const p = secp256k1.ProjectivePoint.fromHex(p1).multiplyAndAddUnsafe( - p2p, - BigInt(`0x${Buffer.from(a).toString('hex')}`), - BigInt(1) - ); - if (!p) return null; - return p.toRawBytes(compress); - } catch { - return null; - } - }, - pointAdd: (a: Uint8Array, b: Uint8Array, compress: boolean): Uint8Array | null => { - try { - return secp256k1.ProjectivePoint.fromHex(a) - .add(secp256k1.ProjectivePoint.fromHex(b)) - .toRawBytes(compress); - } catch { - return null; - } - }, - pointAddTweak: (p: Uint8Array, tweak: Uint8Array, compress: boolean): Uint8Array | null => { - try { - const P = secp256k1.ProjectivePoint.fromHex(p); - const t = baseCrypto.readSecret(tweak); - const Q = secp256k1.ProjectivePoint.BASE.multiplyAndAddUnsafe(P, t, 1n); - if (!Q) throw new Error('Tweaked point at infinity'); - return Q.toRawBytes(compress); - } catch { - return null; - } - }, - pointCompress: (p: Uint8Array, compress = true): Uint8Array => - secp256k1.ProjectivePoint.fromHex(p).toRawBytes(compress), - liftX: (p: Uint8Array): Uint8Array | null => { - try { - return secp256k1.ProjectivePoint.fromHex(p).toRawBytes(false); - } catch { - return null; - } - }, - getPublicKey: (s: Uint8Array, compress: boolean): Uint8Array | null => { - try { - return secp256k1.getPublicKey(s, compress); - } catch { - return null; - } - }, - taggedHash: schnorr.utils.taggedHash, - sha256: (...messages: Uint8Array[]): Uint8Array => { - const h = sha256.create(); - for (const message of messages) h.update(message); - return h.digest(); - }, -}; \ No newline at end of file From 5041057310144bc26b631a02711c167937644c73 Mon Sep 17 00:00:00 2001 From: DenisIvanov26 Date: Fri, 29 Mar 2024 15:05:06 -0500 Subject: [PATCH 3/3] camelcase rename --- src.ts/providers/formatting.ts | 4 ++-- src.ts/transaction/transaction.ts | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src.ts/providers/formatting.ts b/src.ts/providers/formatting.ts index c5d08274..1d783219 100644 --- a/src.ts/providers/formatting.ts +++ b/src.ts/providers/formatting.ts @@ -381,9 +381,9 @@ export interface TransactionResponseParams { */ accessList: null | AccessList; - UTXOoutputs ?: UTXOTransactionOutput[]; + outputsUTXO ?: UTXOTransactionOutput[]; - UTXOinputs ?: UTXOTransactionInput[]; + inputsUTXO ?: UTXOTransactionInput[]; }; diff --git a/src.ts/transaction/transaction.ts b/src.ts/transaction/transaction.ts index 69f05989..77bf1b00 100644 --- a/src.ts/transaction/transaction.ts +++ b/src.ts/transaction/transaction.ts @@ -86,9 +86,9 @@ export interface TransactionLike { accessList?: null | AccessListish; - UTXOinputs?: null | Array; + inputsUTXO?: null | Array; - UTXOoutputs?: null | Array; + outputsUTXO?: null | Array; } function handleNumber(_value: string, param: string): number { @@ -187,8 +187,8 @@ function _serialize(tx: TransactionLike, sig?: Signature): string { } if (tx.type == 2){ - formattedTx.tx_ins = tx.UTXOinputs - formattedTx.tx_outs = tx.UTXOoutputs + formattedTx.tx_ins = tx.inputsUTXO + formattedTx.tx_outs = tx.outputsUTXO } if (sig) { @@ -227,8 +227,8 @@ export class Transaction implements TransactionLike { #sig: null | Signature; #accessList: null | AccessList; #hash: null | string; - #UTXOinputs: null | UTXOTransactionInput[]; - #UTXOoutputs: null | UTXOTransactionOutput[]; + #inputsUTXO: null | UTXOTransactionInput[]; + #outputsUTXO: null | UTXOTransactionOutput[]; /** * The transaction type. @@ -381,11 +381,11 @@ export class Transaction implements TransactionLike { } - get UTXOinputs(): null | UTXOTransactionInput[] { return this.#UTXOinputs; } - set UTXOinputs(value: null | UTXOTransactionInput[]) { this.#UTXOinputs = value; } + get inputsUTXO(): null | UTXOTransactionInput[] { return this.#inputsUTXO; } + set inputsUTXO(value: null | UTXOTransactionInput[]) { this.#inputsUTXO = value; } - get UTXOoutputs(): null | UTXOTransactionOutput[] { return this.#UTXOoutputs; } - set UTXOoutputs(value: null | UTXOTransactionOutput[]) { this.#UTXOoutputs = value; } + get outputsUTXO(): null | UTXOTransactionOutput[] { return this.#outputsUTXO; } + set outputsUTXO(value: null | UTXOTransactionOutput[]) { this.#outputsUTXO = value; } /** @@ -405,8 +405,8 @@ export class Transaction implements TransactionLike { this.#sig = null; this.#accessList = null; this.#hash = null; - this.#UTXOinputs = null; - this.#UTXOoutputs = null; + this.#inputsUTXO = null; + this.#outputsUTXO = null; } /**