@mysten-incubation/hashi 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/dist/bitcoin.d.mts +140 -0
  3. package/dist/bitcoin.mjs +272 -0
  4. package/dist/client.d.mts +318 -0
  5. package/dist/client.mjs +522 -0
  6. package/dist/constants.mjs +60 -0
  7. package/dist/contracts/hashi/bitcoin_state.mjs +28 -0
  8. package/dist/contracts/hashi/committee.mjs +40 -0
  9. package/dist/contracts/hashi/committee_set.mjs +34 -0
  10. package/dist/contracts/hashi/config.mjs +28 -0
  11. package/dist/contracts/hashi/config_value.mjs +21 -0
  12. package/dist/contracts/hashi/deposit.mjs +67 -0
  13. package/dist/contracts/hashi/deposit_queue.mjs +33 -0
  14. package/dist/contracts/hashi/deps/sui/bag.mjs +42 -0
  15. package/dist/contracts/hashi/deps/sui/balance.mjs +20 -0
  16. package/dist/contracts/hashi/deps/sui/group_ops.mjs +16 -0
  17. package/dist/contracts/hashi/deps/sui/object_bag.mjs +25 -0
  18. package/dist/contracts/hashi/deps/sui/package.mjs +26 -0
  19. package/dist/contracts/hashi/deps/sui/table.mjs +37 -0
  20. package/dist/contracts/hashi/deps/sui/vec_map.mjs +36 -0
  21. package/dist/contracts/hashi/deps/sui/vec_set.mjs +25 -0
  22. package/dist/contracts/hashi/hashi.mjs +29 -0
  23. package/dist/contracts/hashi/proposals.mjs +18 -0
  24. package/dist/contracts/hashi/treasury.mjs +28 -0
  25. package/dist/contracts/hashi/utxo.mjs +56 -0
  26. package/dist/contracts/hashi/utxo_pool.mjs +35 -0
  27. package/dist/contracts/hashi/withdraw.mjs +91 -0
  28. package/dist/contracts/hashi/withdrawal_queue.mjs +131 -0
  29. package/dist/contracts/utils/index.d.mts +8 -0
  30. package/dist/contracts/utils/index.mjs +118 -0
  31. package/dist/errors.d.mts +118 -0
  32. package/dist/errors.mjs +118 -0
  33. package/dist/index.d.mts +5 -0
  34. package/dist/index.mjs +5 -0
  35. package/dist/types.d.mts +137 -0
  36. package/dist/util.mjs +50 -0
  37. package/package.json +64 -0
@@ -0,0 +1,131 @@
1
+ import { MoveEnum, MoveStruct } from "../utils/index.mjs";
2
+ import { ObjectBag } from "./deps/sui/object_bag.mjs";
3
+ import { Utxo, UtxoId } from "./utxo.mjs";
4
+ import { Balance } from "./deps/sui/balance.mjs";
5
+ import { bcs } from "@mysten/sui/bcs";
6
+
7
+ //#region src/contracts/hashi/withdrawal_queue.ts
8
+ /**************************************************************
9
+ * THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
10
+ **************************************************************/
11
+ const $moduleName = "@local-pkg/hashi::withdrawal_queue";
12
+ const WithdrawalRequestQueue = new MoveStruct({
13
+ name: `${$moduleName}::WithdrawalRequestQueue`,
14
+ fields: {
15
+ requests: ObjectBag,
16
+ processed: ObjectBag,
17
+ withdrawal_txns: ObjectBag,
18
+ confirmed_txns: ObjectBag
19
+ }
20
+ });
21
+ const OutputUtxo = new MoveStruct({
22
+ name: `${$moduleName}::OutputUtxo`,
23
+ fields: {
24
+ amount: bcs.u64(),
25
+ bitcoin_address: bcs.vector(bcs.u8())
26
+ }
27
+ });
28
+ const WithdrawalStatus = new MoveEnum({
29
+ name: `${$moduleName}::WithdrawalStatus`,
30
+ fields: {
31
+ Requested: null,
32
+ Approved: null,
33
+ Processing: null,
34
+ Signed: null,
35
+ Confirmed: null
36
+ }
37
+ });
38
+ const WithdrawalRequest = new MoveStruct({
39
+ name: `${$moduleName}::WithdrawalRequest`,
40
+ fields: {
41
+ id: bcs.Address,
42
+ sender: bcs.Address,
43
+ btc_amount: bcs.u64(),
44
+ bitcoin_address: bcs.vector(bcs.u8()),
45
+ timestamp_ms: bcs.u64(),
46
+ status: WithdrawalStatus,
47
+ withdrawal_txn_id: bcs.option(bcs.Address),
48
+ sui_tx_digest: bcs.vector(bcs.u8()),
49
+ btc: Balance
50
+ }
51
+ });
52
+ const WithdrawalTransaction = new MoveStruct({
53
+ name: `${$moduleName}::WithdrawalTransaction`,
54
+ fields: {
55
+ id: bcs.Address,
56
+ txid: bcs.Address,
57
+ request_ids: bcs.vector(bcs.Address),
58
+ inputs: bcs.vector(Utxo),
59
+ withdrawal_outputs: bcs.vector(OutputUtxo),
60
+ change_output: bcs.option(OutputUtxo),
61
+ timestamp_ms: bcs.u64(),
62
+ randomness: bcs.vector(bcs.u8()),
63
+ signatures: bcs.option(bcs.vector(bcs.vector(bcs.u8()))),
64
+ presig_start_index: bcs.u64(),
65
+ epoch: bcs.u64()
66
+ }
67
+ });
68
+ const CommittedRequestInfo = new MoveStruct({
69
+ name: `${$moduleName}::CommittedRequestInfo`,
70
+ fields: {
71
+ btc_amount: bcs.u64(),
72
+ bitcoin_address: bcs.vector(bcs.u8())
73
+ }
74
+ });
75
+ const WithdrawalRequestedEvent = new MoveStruct({
76
+ name: `${$moduleName}::WithdrawalRequestedEvent`,
77
+ fields: {
78
+ request_id: bcs.Address,
79
+ btc_amount: bcs.u64(),
80
+ bitcoin_address: bcs.vector(bcs.u8()),
81
+ timestamp_ms: bcs.u64(),
82
+ requester_address: bcs.Address,
83
+ sui_tx_digest: bcs.vector(bcs.u8())
84
+ }
85
+ });
86
+ const WithdrawalApprovedEvent = new MoveStruct({
87
+ name: `${$moduleName}::WithdrawalApprovedEvent`,
88
+ fields: { request_id: bcs.Address }
89
+ });
90
+ const WithdrawalPickedForProcessingEvent = new MoveStruct({
91
+ name: `${$moduleName}::WithdrawalPickedForProcessingEvent`,
92
+ fields: {
93
+ withdrawal_txn_id: bcs.Address,
94
+ txid: bcs.Address,
95
+ request_ids: bcs.vector(bcs.Address),
96
+ inputs: bcs.vector(Utxo),
97
+ withdrawal_outputs: bcs.vector(OutputUtxo),
98
+ change_output: bcs.option(OutputUtxo),
99
+ timestamp_ms: bcs.u64(),
100
+ randomness: bcs.vector(bcs.u8())
101
+ }
102
+ });
103
+ const WithdrawalSignedEvent = new MoveStruct({
104
+ name: `${$moduleName}::WithdrawalSignedEvent`,
105
+ fields: {
106
+ withdrawal_txn_id: bcs.Address,
107
+ request_ids: bcs.vector(bcs.Address),
108
+ signatures: bcs.vector(bcs.vector(bcs.u8()))
109
+ }
110
+ });
111
+ const WithdrawalConfirmedEvent = new MoveStruct({
112
+ name: `${$moduleName}::WithdrawalConfirmedEvent`,
113
+ fields: {
114
+ withdrawal_txn_id: bcs.Address,
115
+ txid: bcs.Address,
116
+ change_utxo_id: bcs.option(UtxoId),
117
+ request_ids: bcs.vector(bcs.Address),
118
+ change_utxo_amount: bcs.option(bcs.u64())
119
+ }
120
+ });
121
+ const WithdrawalCancelledEvent = new MoveStruct({
122
+ name: `${$moduleName}::WithdrawalCancelledEvent`,
123
+ fields: {
124
+ request_id: bcs.Address,
125
+ requester_address: bcs.Address,
126
+ btc_amount: bcs.u64()
127
+ }
128
+ });
129
+
130
+ //#endregion
131
+ export { OutputUtxo, WithdrawalRequest, WithdrawalRequestQueue, WithdrawalTransaction };
@@ -0,0 +1,8 @@
1
+ import { BcsEnum, BcsStruct } from "@mysten/sui/bcs";
2
+ import { TransactionArgument } from "@mysten/sui/transactions";
3
+ import { ClientWithCoreApi, SuiClientTypes } from "@mysten/sui/client";
4
+
5
+ //#region src/contracts/utils/index.d.ts
6
+ type RawTransactionArgument<T> = T | TransactionArgument;
7
+ //#endregion
8
+ export { RawTransactionArgument };
@@ -0,0 +1,118 @@
1
+ import { BcsEnum, BcsStruct, TypeTagSerializer, bcs } from "@mysten/sui/bcs";
2
+ import { normalizeSuiAddress } from "@mysten/sui/utils";
3
+ import { isArgument } from "@mysten/sui/transactions";
4
+
5
+ //#region src/contracts/utils/index.ts
6
+ const MOVE_STDLIB_ADDRESS = normalizeSuiAddress("0x1");
7
+ const SUI_FRAMEWORK_ADDRESS = normalizeSuiAddress("0x2");
8
+ function getPureBcsSchema(typeTag) {
9
+ const parsedTag = typeof typeTag === "string" ? TypeTagSerializer.parseFromStr(typeTag) : typeTag;
10
+ if ("u8" in parsedTag) return bcs.U8;
11
+ else if ("u16" in parsedTag) return bcs.U16;
12
+ else if ("u32" in parsedTag) return bcs.U32;
13
+ else if ("u64" in parsedTag) return bcs.U64;
14
+ else if ("u128" in parsedTag) return bcs.U128;
15
+ else if ("u256" in parsedTag) return bcs.U256;
16
+ else if ("address" in parsedTag) return bcs.Address;
17
+ else if ("bool" in parsedTag) return bcs.Bool;
18
+ else if ("vector" in parsedTag) {
19
+ const type = getPureBcsSchema(parsedTag.vector);
20
+ return type ? bcs.vector(type) : null;
21
+ } else if ("struct" in parsedTag) {
22
+ const structTag = parsedTag.struct;
23
+ const pkg = normalizeSuiAddress(structTag.address);
24
+ if (pkg === MOVE_STDLIB_ADDRESS) {
25
+ if ((structTag.module === "ascii" || structTag.module === "string") && structTag.name === "String") return bcs.String;
26
+ if (structTag.module === "option" && structTag.name === "Option") {
27
+ const type = getPureBcsSchema(structTag.typeParams[0]);
28
+ return type ? bcs.option(type) : null;
29
+ }
30
+ }
31
+ if (pkg === SUI_FRAMEWORK_ADDRESS && structTag.module === "object" && (structTag.name === "ID" || structTag.name === "UID")) return bcs.Address;
32
+ }
33
+ return null;
34
+ }
35
+ function normalizeMoveArguments(args, argTypes, parameterNames) {
36
+ const argLen = Array.isArray(args) ? args.length : Object.keys(args).length;
37
+ if (parameterNames && argLen !== parameterNames.length) throw new Error(`Invalid number of arguments, expected ${parameterNames.length}, got ${argLen}`);
38
+ const normalizedArgs = [];
39
+ let index = 0;
40
+ for (const [i, argType] of argTypes.entries()) {
41
+ if (argType === "0x2::clock::Clock") {
42
+ normalizedArgs.push((tx) => tx.object.clock());
43
+ continue;
44
+ }
45
+ if (argType === "0x2::random::Random") {
46
+ normalizedArgs.push((tx) => tx.object.random());
47
+ continue;
48
+ }
49
+ if (argType === "0x2::deny_list::DenyList") {
50
+ normalizedArgs.push((tx) => tx.object.denyList());
51
+ continue;
52
+ }
53
+ if (argType === "0x3::sui_system::SuiSystemState") {
54
+ normalizedArgs.push((tx) => tx.object.system());
55
+ continue;
56
+ }
57
+ let arg;
58
+ if (Array.isArray(args)) {
59
+ if (index >= args.length) throw new Error(`Invalid number of arguments, expected at least ${index + 1}, got ${args.length}`);
60
+ arg = args[index];
61
+ } else {
62
+ if (!parameterNames) throw new Error(`Expected arguments to be passed as an array`);
63
+ const name = parameterNames[index];
64
+ arg = args[name];
65
+ if (arg === void 0) throw new Error(`Parameter ${name} is required`);
66
+ }
67
+ index += 1;
68
+ if (typeof arg === "function" || isArgument(arg)) {
69
+ normalizedArgs.push(arg);
70
+ continue;
71
+ }
72
+ const type = argTypes[i];
73
+ const bcsType = type === null ? null : getPureBcsSchema(type);
74
+ if (bcsType) {
75
+ const bytes = bcsType.serialize(arg);
76
+ normalizedArgs.push((tx) => tx.pure(bytes));
77
+ continue;
78
+ } else if (typeof arg === "string") {
79
+ normalizedArgs.push((tx) => tx.object(arg));
80
+ continue;
81
+ }
82
+ throw new Error(`Invalid argument ${stringify(arg)} for type ${type}`);
83
+ }
84
+ return normalizedArgs;
85
+ }
86
+ var MoveStruct = class extends BcsStruct {
87
+ async get({ objectId, ...options }) {
88
+ const [res] = await this.getMany({
89
+ ...options,
90
+ objectIds: [objectId]
91
+ });
92
+ return res;
93
+ }
94
+ async getMany({ client, ...options }) {
95
+ return (await client.core.getObjects({
96
+ ...options,
97
+ include: {
98
+ ...options.include,
99
+ content: true
100
+ }
101
+ })).objects.map((obj) => {
102
+ if (obj instanceof Error) throw obj;
103
+ return {
104
+ ...obj,
105
+ json: this.parse(obj.content)
106
+ };
107
+ });
108
+ }
109
+ };
110
+ var MoveEnum = class extends BcsEnum {};
111
+ function stringify(val) {
112
+ if (typeof val === "object") return JSON.stringify(val, (val$1) => val$1);
113
+ if (typeof val === "bigint") return val.toString();
114
+ return val;
115
+ }
116
+
117
+ //#endregion
118
+ export { MoveEnum, MoveStruct, normalizeMoveArguments };
@@ -0,0 +1,118 @@
1
+ //#region src/errors.d.ts
2
+ /**
3
+ * Custom error classes thrown by the Hashi SDK. Consumers can `instanceof`-check
4
+ * these to distinguish SDK-structured failures (missing/malformed on-chain data,
5
+ * chain-fetch failures) from generic runtime errors.
6
+ */
7
+ /**
8
+ * Thrown when a governance config entry on-chain is missing, has an unexpected
9
+ * variant, or has a payload that cannot be decoded to the expected type.
10
+ * Carries the offending `key` and `expectedVariant` as structured fields so
11
+ * callers can react programmatically without string-parsing the message.
12
+ */
13
+ declare class HashiConfigError extends Error {
14
+ readonly key: string;
15
+ readonly expectedVariant: string;
16
+ readonly actualVariant?: string;
17
+ constructor(message: string, details: {
18
+ key: string;
19
+ expectedVariant: string;
20
+ actualVariant?: string;
21
+ }, options?: {
22
+ cause?: unknown;
23
+ });
24
+ static missing(key: string, expectedVariant: string): HashiConfigError;
25
+ static wrongVariant(key: string, expectedVariant: string, actualVariant: string): HashiConfigError;
26
+ static malformedPayload(key: string, expectedVariant: string, detail: string, cause?: unknown): HashiConfigError;
27
+ }
28
+ /**
29
+ * Thrown when fetching the Hashi shared object fails or returns an
30
+ * unexpectedly shaped response. Wraps the underlying Sui-client error via
31
+ * `cause` so callers can still access the network-layer detail.
32
+ */
33
+ declare class HashiFetchError extends Error {
34
+ readonly hashiObjectId: string;
35
+ constructor(message: string, hashiObjectId: string, options?: {
36
+ cause?: unknown;
37
+ });
38
+ }
39
+ /**
40
+ * One amount that failed a client-side minimum check. `vout` is present for
41
+ * deposit-UTXO violations (so callers can map each offender back to a Bitcoin
42
+ * output) and absent for withdrawal violations, where there is a single
43
+ * top-level amount and no output index.
44
+ */
45
+ interface AmountViolation {
46
+ readonly amount: bigint;
47
+ readonly minimum: bigint;
48
+ readonly vout?: number;
49
+ }
50
+ /**
51
+ * Thrown by `HashiClient.deposit()` and `HashiClient.requestWithdrawal()` when
52
+ * one or more amounts are below the live on-chain minimum. Deposits may carry
53
+ * multiple violations (one per offending UTXO) so callers can fix the whole
54
+ * batch in one round-trip; withdrawals always carry exactly one. Raised after
55
+ * the governance snapshot is fetched but before any PTB is built — mirrors
56
+ * the Move-side `EBelowMinimumDeposit` / `EBelowMinimumWithdrawal` aborts.
57
+ */
58
+ declare class AmountBelowMinimumError extends Error {
59
+ readonly violations: readonly AmountViolation[];
60
+ constructor(details: {
61
+ violations: readonly AmountViolation[];
62
+ });
63
+ }
64
+ /**
65
+ * Thrown by user-facing entry points when `paused` is `true` in the governance
66
+ * config snapshot. Mirrors the Move-side `ESystemPaused` abort in
67
+ * `hashi::assert_unpaused` so the SDK can fail early with a typed error
68
+ * instead of a gas-burning on-chain abort.
69
+ */
70
+ declare class HashiPausedError extends Error {
71
+ readonly operation?: string;
72
+ constructor(details?: {
73
+ operation?: string;
74
+ }, options?: {
75
+ cause?: unknown;
76
+ });
77
+ }
78
+ /**
79
+ * Thrown by `HashiClient` direct methods when the caller-supplied params
80
+ * don't meet structural preconditions (empty `utxos`, duplicate `vout`,
81
+ * malformed hex). Raised before any chain read so even a paused or
82
+ * unreachable protocol surfaces the client-side bug first.
83
+ */
84
+ declare class InvalidParamsError extends Error {
85
+ readonly reason: string;
86
+ readonly detail?: string;
87
+ constructor(details: {
88
+ reason: string;
89
+ detail?: string;
90
+ }, options?: {
91
+ cause?: unknown;
92
+ });
93
+ }
94
+ /**
95
+ * Stable discriminator for `InvalidBitcoinAddressError`. Callers can switch on
96
+ * `code` to surface targeted UX (e.g. "wrong network" → prompt the user to
97
+ * switch, "bad-checksum" → flag a typo) without string-parsing the message.
98
+ */
99
+ type InvalidBitcoinAddressCode = "malformed" | "bad-checksum" | "wrong-network" | "unsupported-version" | "bad-program-length";
100
+ /**
101
+ * Thrown when a user-supplied Bitcoin address cannot be decoded into a
102
+ * witness program that the Hashi withdrawal path accepts. `code` is a stable
103
+ * discriminator suitable for programmatic handling; `address` echoes the
104
+ * offending input back so callers can display it.
105
+ */
106
+ declare class InvalidBitcoinAddressError extends Error {
107
+ readonly address: string;
108
+ readonly code: InvalidBitcoinAddressCode;
109
+ constructor(details: {
110
+ address: string;
111
+ code: InvalidBitcoinAddressCode;
112
+ message: string;
113
+ }, options?: {
114
+ cause?: unknown;
115
+ });
116
+ }
117
+ //#endregion
118
+ export { AmountBelowMinimumError, AmountViolation, HashiConfigError, HashiFetchError, HashiPausedError, InvalidBitcoinAddressCode, InvalidBitcoinAddressError, InvalidParamsError };
@@ -0,0 +1,118 @@
1
+ //#region src/errors.ts
2
+ /**
3
+ * Custom error classes thrown by the Hashi SDK. Consumers can `instanceof`-check
4
+ * these to distinguish SDK-structured failures (missing/malformed on-chain data,
5
+ * chain-fetch failures) from generic runtime errors.
6
+ */
7
+ /**
8
+ * Thrown when a governance config entry on-chain is missing, has an unexpected
9
+ * variant, or has a payload that cannot be decoded to the expected type.
10
+ * Carries the offending `key` and `expectedVariant` as structured fields so
11
+ * callers can react programmatically without string-parsing the message.
12
+ */
13
+ var HashiConfigError = class HashiConfigError extends Error {
14
+ constructor(message, details, options) {
15
+ super(message, options);
16
+ this.name = "HashiConfigError";
17
+ this.key = details.key;
18
+ this.expectedVariant = details.expectedVariant;
19
+ this.actualVariant = details.actualVariant;
20
+ }
21
+ static missing(key, expectedVariant) {
22
+ return new HashiConfigError(`Config key "${key}" not found on-chain.`, {
23
+ key,
24
+ expectedVariant
25
+ });
26
+ }
27
+ static wrongVariant(key, expectedVariant, actualVariant) {
28
+ return new HashiConfigError(`Config key "${key}" is ${actualVariant}, expected ${expectedVariant}.`, {
29
+ key,
30
+ expectedVariant,
31
+ actualVariant
32
+ });
33
+ }
34
+ static malformedPayload(key, expectedVariant, detail, cause) {
35
+ return new HashiConfigError(`Config key "${key}" ${expectedVariant} payload is malformed: ${detail}.`, {
36
+ key,
37
+ expectedVariant,
38
+ actualVariant: expectedVariant
39
+ }, { cause });
40
+ }
41
+ };
42
+ /**
43
+ * Thrown when fetching the Hashi shared object fails or returns an
44
+ * unexpectedly shaped response. Wraps the underlying Sui-client error via
45
+ * `cause` so callers can still access the network-layer detail.
46
+ */
47
+ var HashiFetchError = class extends Error {
48
+ constructor(message, hashiObjectId, options) {
49
+ super(message, options);
50
+ this.name = "HashiFetchError";
51
+ this.hashiObjectId = hashiObjectId;
52
+ }
53
+ };
54
+ /**
55
+ * Thrown by `HashiClient.deposit()` and `HashiClient.requestWithdrawal()` when
56
+ * one or more amounts are below the live on-chain minimum. Deposits may carry
57
+ * multiple violations (one per offending UTXO) so callers can fix the whole
58
+ * batch in one round-trip; withdrawals always carry exactly one. Raised after
59
+ * the governance snapshot is fetched but before any PTB is built — mirrors
60
+ * the Move-side `EBelowMinimumDeposit` / `EBelowMinimumWithdrawal` aborts.
61
+ */
62
+ var AmountBelowMinimumError = class extends Error {
63
+ constructor(details) {
64
+ const { violations } = details;
65
+ const head = violations[0];
66
+ let summary;
67
+ if (violations.length === 1) summary = head.vout === void 0 ? `Amount ${head.amount} sats is below the protocol minimum of ${head.minimum} sats.` : `UTXO at vout ${head.vout} has amount ${head.amount} sats, below the protocol minimum of ${head.minimum} sats.`;
68
+ else summary = `${violations.length} UTXOs are below the protocol minimum (${head.minimum} sats): ${violations.map((v) => v.vout === void 0 ? `${v.amount} sats` : `vout ${v.vout} = ${v.amount} sats`).join(", ")}.`;
69
+ super(summary);
70
+ this.name = "AmountBelowMinimumError";
71
+ this.violations = violations;
72
+ }
73
+ };
74
+ /**
75
+ * Thrown by user-facing entry points when `paused` is `true` in the governance
76
+ * config snapshot. Mirrors the Move-side `ESystemPaused` abort in
77
+ * `hashi::assert_unpaused` so the SDK can fail early with a typed error
78
+ * instead of a gas-burning on-chain abort.
79
+ */
80
+ var HashiPausedError = class extends Error {
81
+ constructor(details, options) {
82
+ const op = details?.operation;
83
+ super(op ? `Hashi protocol is currently paused; cannot ${op}.` : "Hashi protocol is currently paused.", options);
84
+ this.name = "HashiPausedError";
85
+ this.operation = op;
86
+ }
87
+ };
88
+ /**
89
+ * Thrown by `HashiClient` direct methods when the caller-supplied params
90
+ * don't meet structural preconditions (empty `utxos`, duplicate `vout`,
91
+ * malformed hex). Raised before any chain read so even a paused or
92
+ * unreachable protocol surfaces the client-side bug first.
93
+ */
94
+ var InvalidParamsError = class extends Error {
95
+ constructor(details, options) {
96
+ super(details.detail ? `${details.reason}: ${details.detail}` : details.reason, options);
97
+ this.name = "InvalidParamsError";
98
+ this.reason = details.reason;
99
+ this.detail = details.detail;
100
+ }
101
+ };
102
+ /**
103
+ * Thrown when a user-supplied Bitcoin address cannot be decoded into a
104
+ * witness program that the Hashi withdrawal path accepts. `code` is a stable
105
+ * discriminator suitable for programmatic handling; `address` echoes the
106
+ * offending input back so callers can display it.
107
+ */
108
+ var InvalidBitcoinAddressError = class extends Error {
109
+ constructor(details, options) {
110
+ super(details.message, options);
111
+ this.name = "InvalidBitcoinAddressError";
112
+ this.address = details.address;
113
+ this.code = details.code;
114
+ }
115
+ };
116
+
117
+ //#endregion
118
+ export { AmountBelowMinimumError, HashiConfigError, HashiFetchError, HashiPausedError, InvalidBitcoinAddressError, InvalidParamsError };
@@ -0,0 +1,5 @@
1
+ import { BitcoinNetwork, CancelWithdrawalParams, DepositHistoryItem, DepositParams, GovernanceConfig, HashiClientOptions, NetworkConfig, SuiNetwork, TransactionHistoryItem, UtxoId, UtxoOutput, UtxoUsageResult, WithdrawalHistoryItem, WithdrawalParams, WithdrawalStatus } from "./types.mjs";
2
+ import { HashiClient, hashi } from "./client.mjs";
3
+ import { AmountBelowMinimumError, AmountViolation, HashiConfigError, HashiFetchError, HashiPausedError, InvalidBitcoinAddressCode, InvalidBitcoinAddressError, InvalidParamsError } from "./errors.mjs";
4
+ import { arkworksToSec1Compressed, bitcoinAddressToWitnessProgram, deriveChildPubkey, generateDepositAddress, taprootScriptPathAddress } from "./bitcoin.mjs";
5
+ export { AmountBelowMinimumError, type AmountViolation, type BitcoinNetwork, type CancelWithdrawalParams, type DepositHistoryItem, type DepositParams, type GovernanceConfig, HashiClient, type HashiClientOptions, HashiConfigError, HashiFetchError, HashiPausedError, type InvalidBitcoinAddressCode, InvalidBitcoinAddressError, InvalidParamsError, type NetworkConfig, type SuiNetwork, type TransactionHistoryItem, type UtxoId, type UtxoOutput, type UtxoUsageResult, type WithdrawalHistoryItem, type WithdrawalParams, type WithdrawalStatus, arkworksToSec1Compressed, bitcoinAddressToWitnessProgram, deriveChildPubkey, generateDepositAddress, hashi, taprootScriptPathAddress };
package/dist/index.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import { AmountBelowMinimumError, HashiConfigError, HashiFetchError, HashiPausedError, InvalidBitcoinAddressError, InvalidParamsError } from "./errors.mjs";
2
+ import { arkworksToSec1Compressed, bitcoinAddressToWitnessProgram, deriveChildPubkey, generateDepositAddress, taprootScriptPathAddress } from "./bitcoin.mjs";
3
+ import { HashiClient, hashi } from "./client.mjs";
4
+
5
+ export { AmountBelowMinimumError, HashiClient, HashiConfigError, HashiFetchError, HashiPausedError, InvalidBitcoinAddressError, InvalidParamsError, arkworksToSec1Compressed, bitcoinAddressToWitnessProgram, deriveChildPubkey, generateDepositAddress, hashi, taprootScriptPathAddress };
@@ -0,0 +1,137 @@
1
+ //#region src/types.d.ts
2
+ type BitcoinNetwork = "mainnet" | "testnet" | "signet" | "regtest";
3
+ type SuiNetwork = "devnet" | "testnet" | "mainnet" | "localnet";
4
+ interface NetworkConfig {
5
+ hashiObjectId: string;
6
+ packageId: string;
7
+ bitcoinNetwork: BitcoinNetwork;
8
+ }
9
+ interface HashiClientOptions<Name = "HashiClient"> {
10
+ name?: Name;
11
+ /** Sui network — determines Hashi object IDs and default Bitcoin network. */
12
+ network: SuiNetwork;
13
+ /** Override the auto-resolved Hashi shared object ID (for custom/local deployments). */
14
+ hashiObjectId?: string;
15
+ /** Override the auto-resolved Hashi package ID (for custom/local deployments). */
16
+ packageId?: string;
17
+ /** Override the auto-resolved Bitcoin network for address encoding. */
18
+ bitcoinNetwork?: BitcoinNetwork;
19
+ }
20
+ /**
21
+ * Frozen snapshot of every governance-controlled protocol parameter, returned
22
+ * by `HashiClient.view.all()`. Fields are `readonly` because the snapshot is
23
+ * a point-in-time read from chain — mutating it locally cannot change on-chain
24
+ * state. `depositMinimum` is a Move-side alias of `bitcoinDepositMinimum`;
25
+ * `worstCaseNetworkFee` is derived as `bitcoinWithdrawalMinimum - 546` (the
26
+ * dust relay floor) and is always ≥ 1.
27
+ */
28
+ interface GovernanceConfig {
29
+ readonly paused: boolean;
30
+ readonly bitcoinChainId: string;
31
+ readonly bitcoinDepositMinimum: bigint;
32
+ readonly bitcoinWithdrawalMinimum: bigint;
33
+ readonly bitcoinConfirmationThreshold: bigint;
34
+ readonly withdrawalCancellationCooldownMs: bigint;
35
+ readonly depositMinimum: bigint;
36
+ readonly worstCaseNetworkFee: bigint;
37
+ }
38
+ /**
39
+ * A single UTXO output within a Bitcoin transaction used to fund a deposit.
40
+ * `vout` is the output index (Bitcoin u32); `amountSats` must be ≥ the
41
+ * on-chain deposit minimum (enforced at deposit time).
42
+ */
43
+ interface UtxoOutput {
44
+ readonly vout: number;
45
+ readonly amountSats: bigint;
46
+ }
47
+ /** Parameters for `HashiClient.deposit()` — one Bitcoin txid, one or more outputs paying the deposit address. */
48
+ interface DepositParams {
49
+ /**
50
+ * 0x-prefixed 32-byte Bitcoin txid of the funding transaction, in
51
+ * **display byte order** — the form mempool.space, blockstream.info,
52
+ * and `bitcoin-cli` show. The SDK reverses to internal byte order
53
+ * before recording on-chain (see `reverseTxidBytes` in `util.ts`).
54
+ */
55
+ readonly txid: string;
56
+ /** UTXOs from `txid` that paid the deposit address (one per output to the address). */
57
+ readonly utxos: readonly UtxoOutput[];
58
+ /**
59
+ * Sui address that derived the deposit address and will receive the minted
60
+ * hBTC. Becomes the `derivation_path` of every `Utxo` built in the PTB.
61
+ */
62
+ readonly recipient: string;
63
+ }
64
+ /** Parameters for `HashiClient.requestWithdrawal()`. */
65
+ interface WithdrawalParams {
66
+ /** Amount in satoshis to withdraw. Must be ≥ the on-chain withdrawal minimum. */
67
+ readonly amountSats: bigint;
68
+ /**
69
+ * Recipient Bitcoin address. Bech32 for P2WPKH (`bc1q…`, `tb1q…`) or
70
+ * bech32m for P2TR (`bc1p…`, `tb1p…`). Decoded client-side into a witness
71
+ * program and must match the client's configured Bitcoin network.
72
+ */
73
+ readonly bitcoinAddress: string;
74
+ }
75
+ /** Parameters for `HashiClient.cancelWithdrawal()`. */
76
+ interface CancelWithdrawalParams {
77
+ /** 0x-prefixed 32-byte object ID of the pending withdrawal request. */
78
+ readonly requestId: string;
79
+ }
80
+ /**
81
+ * Identifies a single Bitcoin UTXO by its funding transaction and output
82
+ * index. `txid` is in **display byte order** — the form mempool.space,
83
+ * blockstream.info, and `bitcoin-cli` show.
84
+ */
85
+ interface UtxoId {
86
+ /** 0x-prefixed 32-byte Bitcoin txid in display byte order. */
87
+ readonly txid: string;
88
+ /** Output index within the Bitcoin transaction (u32). */
89
+ readonly vout: number;
90
+ }
91
+ /**
92
+ * Result of checking a single UTXO against the on-chain `UtxoPool` bags.
93
+ * `inActivePool` means the UTXO is live (confirmed deposit, not yet
94
+ * consumed by a withdrawal); `inSpentPool` means it was consumed.
95
+ */
96
+ interface UtxoUsageResult {
97
+ readonly utxoId: UtxoId;
98
+ readonly inActivePool: boolean;
99
+ readonly inSpentPool: boolean;
100
+ /** Convenience: `inActivePool || inSpentPool`. */
101
+ readonly isUsed: boolean;
102
+ }
103
+ /** Discriminated union of deposit and withdrawal history entries. */
104
+ type TransactionHistoryItem = DepositHistoryItem | WithdrawalHistoryItem;
105
+ interface DepositHistoryItem {
106
+ readonly kind: "deposit";
107
+ readonly requestId: string;
108
+ readonly sender: string;
109
+ readonly timestampMs: bigint;
110
+ readonly suiTxDigest: string;
111
+ readonly amountSats: bigint;
112
+ /** Bitcoin txid of the funding transaction, in display byte order. */
113
+ readonly btcTxid: string;
114
+ /** Output index within the funding transaction. */
115
+ readonly btcVout: number;
116
+ /** `true` once the committee has approved the deposit. */
117
+ readonly approved: boolean;
118
+ readonly approvalTimestampMs: bigint | null;
119
+ }
120
+ type WithdrawalStatus = "Requested" | "Approved" | "Processing" | "Signed" | "Confirmed";
121
+ interface WithdrawalHistoryItem {
122
+ readonly kind: "withdrawal";
123
+ readonly requestId: string;
124
+ readonly sender: string;
125
+ readonly btcAmountSats: bigint;
126
+ /** Raw witness program bytes of the destination Bitcoin address. */
127
+ readonly bitcoinAddress: Uint8Array;
128
+ readonly timestampMs: bigint;
129
+ readonly suiTxDigest: string;
130
+ readonly status: WithdrawalStatus;
131
+ /** Object ID of the linked `WithdrawalTransaction`, if one exists. */
132
+ readonly withdrawalTxnId: string | null;
133
+ /** Bitcoin txid from the `WithdrawalTransaction`, in display byte order. `null` until the committee commits. */
134
+ readonly btcTxid: string | null;
135
+ }
136
+ //#endregion
137
+ export { BitcoinNetwork, CancelWithdrawalParams, DepositHistoryItem, DepositParams, GovernanceConfig, HashiClientOptions, NetworkConfig, SuiNetwork, TransactionHistoryItem, UtxoId, UtxoOutput, UtxoUsageResult, WithdrawalHistoryItem, WithdrawalParams, WithdrawalStatus };