@mysten-incubation/hashi 0.3.0 → 0.4.0
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.
- package/CHANGELOG.md +16 -0
- package/README.md +1 -1
- package/dist/bitcoin.d.mts +15 -8
- package/dist/bitcoin.mjs +71 -27
- package/dist/client.d.mts +37 -11
- package/dist/client.mjs +90 -15
- package/dist/constants.mjs +2 -2
- package/dist/contracts/hashi/bitcoin_state.mjs +8 -0
- package/dist/contracts/hashi/committee.mjs +10 -3
- package/dist/contracts/hashi/committee_set.mjs +32 -3
- package/dist/contracts/hashi/config.mjs +10 -10
- package/dist/contracts/hashi/config_value.mjs +10 -0
- package/dist/contracts/hashi/deposit.mjs +18 -9
- package/dist/contracts/hashi/deposit_queue.mjs +11 -3
- package/dist/contracts/hashi/hashi.mjs +12 -2
- package/dist/contracts/hashi/mpc_signing.mjs +56 -0
- package/dist/contracts/hashi/proposals.mjs +6 -0
- package/dist/contracts/hashi/treasury.mjs +10 -4
- package/dist/contracts/hashi/utxo.mjs +7 -0
- package/dist/contracts/hashi/utxo_pool.mjs +10 -3
- package/dist/contracts/hashi/versioning.mjs +28 -0
- package/dist/contracts/hashi/withdraw.mjs +17 -1
- package/dist/contracts/hashi/withdrawal_queue.mjs +44 -24
- package/dist/errors.d.mts +28 -1
- package/dist/errors.mjs +17 -1
- package/dist/guardian.d.mts +26 -0
- package/dist/guardian.mjs +101 -0
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +3 -2
- package/dist/types.d.mts +64 -3
- package/package.json +1 -1
|
@@ -1,23 +1,51 @@
|
|
|
1
1
|
import { MoveStruct } from "../utils/index.mjs";
|
|
2
|
-
import { Bag } from "./deps/sui/bag.mjs";
|
|
3
2
|
import { Element } from "./deps/sui/group_ops.mjs";
|
|
3
|
+
import { Config } from "./config.mjs";
|
|
4
|
+
import { CommitteeSignature } from "./committee.mjs";
|
|
5
|
+
import { Bag } from "./deps/sui/bag.mjs";
|
|
4
6
|
import { bcs } from "@mysten/sui/bcs";
|
|
5
7
|
|
|
6
8
|
//#region src/contracts/hashi/committee_set.ts
|
|
7
9
|
/**************************************************************
|
|
8
10
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
9
11
|
**************************************************************/
|
|
12
|
+
/**
|
|
13
|
+
* Registry of Hashi committee state: registered member metadata (`MemberInfo`),
|
|
14
|
+
* per-epoch `Committee`s, the current epoch, the MPC threshold public key, and the
|
|
15
|
+
* pending epoch change while a reconfiguration is in flight. Members register (and
|
|
16
|
+
* rotate keys/metadata) here between epochs; `start_reconfig` builds the next
|
|
17
|
+
* committee from Sui's active validator set, and `end_reconfig` activates it —
|
|
18
|
+
* storing the outgoing committee's handoff certificate for non-initial reconfigs.
|
|
19
|
+
*/
|
|
10
20
|
const $moduleName = "@local-pkg/hashi::committee_set";
|
|
21
|
+
const PendingEpochChange = new MoveStruct({
|
|
22
|
+
name: `${$moduleName}::PendingEpochChange`,
|
|
23
|
+
fields: {
|
|
24
|
+
epoch: bcs.u64(),
|
|
25
|
+
committee_handoff_cert: bcs.option(CommitteeSignature)
|
|
26
|
+
}
|
|
27
|
+
});
|
|
11
28
|
const CommitteeSet = new MoveStruct({
|
|
12
29
|
name: `${$moduleName}::CommitteeSet`,
|
|
13
30
|
fields: {
|
|
14
31
|
members: Bag,
|
|
15
32
|
epoch: bcs.u64(),
|
|
16
33
|
committees: Bag,
|
|
17
|
-
pending_epoch_change: bcs.option(
|
|
34
|
+
pending_epoch_change: bcs.option(PendingEpochChange),
|
|
18
35
|
mpc_public_key: bcs.vector(bcs.u8())
|
|
19
36
|
}
|
|
20
37
|
});
|
|
38
|
+
const CommitteeHandoffKey = new MoveStruct({
|
|
39
|
+
name: `${$moduleName}::CommitteeHandoffKey`,
|
|
40
|
+
fields: { epoch: bcs.u64() }
|
|
41
|
+
});
|
|
42
|
+
const CommitteeHandoff = new MoveStruct({
|
|
43
|
+
name: `${$moduleName}::CommitteeHandoff`,
|
|
44
|
+
fields: {
|
|
45
|
+
next_epoch: bcs.u64(),
|
|
46
|
+
cert: CommitteeSignature
|
|
47
|
+
}
|
|
48
|
+
});
|
|
21
49
|
const MemberInfo = new MoveStruct({
|
|
22
50
|
name: `${$moduleName}::MemberInfo`,
|
|
23
51
|
fields: {
|
|
@@ -26,7 +54,8 @@ const MemberInfo = new MoveStruct({
|
|
|
26
54
|
next_epoch_public_key: Element,
|
|
27
55
|
endpoint_url: bcs.string(),
|
|
28
56
|
tls_public_key: bcs.vector(bcs.u8()),
|
|
29
|
-
next_epoch_encryption_public_key: bcs.vector(bcs.u8())
|
|
57
|
+
next_epoch_encryption_public_key: bcs.vector(bcs.u8()),
|
|
58
|
+
extra_fields: Config
|
|
30
59
|
}
|
|
31
60
|
});
|
|
32
61
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { MoveStruct } from "../utils/index.mjs";
|
|
2
2
|
import { VecMap } from "./deps/sui/vec_map.mjs";
|
|
3
3
|
import { Value } from "./config_value.mjs";
|
|
4
|
-
import { VecSet } from "./deps/sui/vec_set.mjs";
|
|
5
|
-
import { UpgradeCap } from "./deps/sui/package.mjs";
|
|
6
4
|
import { bcs } from "@mysten/sui/bcs";
|
|
7
5
|
|
|
8
6
|
//#region src/contracts/hashi/config.ts
|
|
@@ -10,18 +8,20 @@ import { bcs } from "@mysten/sui/bcs";
|
|
|
10
8
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
11
9
|
**************************************************************/
|
|
12
10
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* A general-purpose, typed key-value configuration store: a map from string keys
|
|
12
|
+
* to `config_value::Value`s, with domain-specific accessors layered on top (pause
|
|
13
|
+
* state, guardian, emergency thresholds). Chain-specific configuration (e.g. BTC
|
|
14
|
+
* fee parameters) lives in separate modules that use get/upsert.
|
|
15
|
+
*
|
|
16
|
+
* `Config` has `copy, drop, store` and carries no policy of its own (no
|
|
17
|
+
* versioning, no upgrade authority — those live in `versioning`), so it can be
|
|
18
|
+
* embedded by value wherever a bag of settings is needed: it backs the package's
|
|
19
|
+
* global config and is also pinned per-epoch onto a `Committee`.
|
|
16
20
|
*/
|
|
17
21
|
const $moduleName = "@local-pkg/hashi::config";
|
|
18
22
|
const Config = new MoveStruct({
|
|
19
23
|
name: `${$moduleName}::Config`,
|
|
20
|
-
fields: {
|
|
21
|
-
config: VecMap(bcs.string(), Value),
|
|
22
|
-
enabled_versions: VecSet(bcs.u64()),
|
|
23
|
-
upgrade_cap: bcs.option(UpgradeCap)
|
|
24
|
-
}
|
|
24
|
+
fields: { config: VecMap(bcs.string(), Value) }
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
//#endregion
|
|
@@ -5,11 +5,21 @@ import { bcs } from "@mysten/sui/bcs";
|
|
|
5
5
|
/**************************************************************
|
|
6
6
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
7
7
|
**************************************************************/
|
|
8
|
+
/**
|
|
9
|
+
* Typed value wrapper for config entries: the `Value` enum carries one of the
|
|
10
|
+
* primitive types a configuration entry can hold, with a public constructor per
|
|
11
|
+
* variant and package-level helpers for variant checks (`is_*`) and extraction
|
|
12
|
+
* (`as_*`, aborting on a type mismatch). Storing typed values — rather than raw
|
|
13
|
+
* bytes — lets `config::is_valid_config_update` reject governance updates that
|
|
14
|
+
* would change an entry's type.
|
|
15
|
+
*/
|
|
8
16
|
const $moduleName = "@local-pkg/hashi::config_value";
|
|
9
17
|
const Value = new MoveEnum({
|
|
10
18
|
name: `${$moduleName}::Value`,
|
|
11
19
|
fields: {
|
|
12
20
|
U64: bcs.u64(),
|
|
21
|
+
U128: bcs.u128(),
|
|
22
|
+
U256: bcs.u256(),
|
|
13
23
|
Address: bcs.Address,
|
|
14
24
|
String: bcs.string(),
|
|
15
25
|
Bool: bcs.bool(),
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { MoveStruct, normalizeMoveArguments } from "../utils/index.mjs";
|
|
2
|
-
import { Utxo, UtxoId } from "./utxo.mjs";
|
|
3
2
|
import { CommitteeSignature } from "./committee.mjs";
|
|
3
|
+
import { Utxo, UtxoId } from "./utxo.mjs";
|
|
4
4
|
import { bcs } from "@mysten/sui/bcs";
|
|
5
5
|
|
|
6
6
|
//#region src/contracts/hashi/deposit.ts
|
|
7
7
|
/**************************************************************
|
|
8
8
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
9
9
|
**************************************************************/
|
|
10
|
+
/**
|
|
11
|
+
* User-facing Bitcoin deposit flow. A depositor registers the UTXO they sent to
|
|
12
|
+
* the bridge's address, the committee approves it with a certificate over
|
|
13
|
+
* `(request_id, utxo)`, and — after a configurable time delay in which a faulty
|
|
14
|
+
* approval can be caught and the service paused — the deposit is confirmed: hBTC
|
|
15
|
+
* is minted to the recipient encoded in the UTXO's derivation path and the UTXO
|
|
16
|
+
* joins the active pool. Requests that are never confirmed can be
|
|
17
|
+
* garbage-collected once they expire.
|
|
18
|
+
*/
|
|
10
19
|
const $moduleName = "@local-pkg/hashi::deposit";
|
|
11
20
|
const DepositConfirmationMessage = new MoveStruct({
|
|
12
21
|
name: `${$moduleName}::DepositConfirmationMessage`,
|
|
@@ -15,8 +24,8 @@ const DepositConfirmationMessage = new MoveStruct({
|
|
|
15
24
|
utxo: Utxo
|
|
16
25
|
}
|
|
17
26
|
});
|
|
18
|
-
const
|
|
19
|
-
name: `${$moduleName}::
|
|
27
|
+
const DepositRequested = new MoveStruct({
|
|
28
|
+
name: `${$moduleName}::DepositRequested`,
|
|
20
29
|
fields: {
|
|
21
30
|
request_id: bcs.Address,
|
|
22
31
|
utxo_id: UtxoId,
|
|
@@ -27,8 +36,8 @@ const DepositRequestedEvent = new MoveStruct({
|
|
|
27
36
|
sui_tx_digest: bcs.vector(bcs.u8())
|
|
28
37
|
}
|
|
29
38
|
});
|
|
30
|
-
const
|
|
31
|
-
name: `${$moduleName}::
|
|
39
|
+
const DepositApproved = new MoveStruct({
|
|
40
|
+
name: `${$moduleName}::DepositApproved`,
|
|
32
41
|
fields: {
|
|
33
42
|
request_id: bcs.Address,
|
|
34
43
|
utxo: Utxo,
|
|
@@ -36,15 +45,15 @@ const DepositApprovedEvent = new MoveStruct({
|
|
|
36
45
|
approval_timestamp_ms: bcs.u64()
|
|
37
46
|
}
|
|
38
47
|
});
|
|
39
|
-
const
|
|
40
|
-
name: `${$moduleName}::
|
|
48
|
+
const DepositConfirmed = new MoveStruct({
|
|
49
|
+
name: `${$moduleName}::DepositConfirmed`,
|
|
41
50
|
fields: {
|
|
42
51
|
request_id: bcs.Address,
|
|
43
52
|
utxo: Utxo
|
|
44
53
|
}
|
|
45
54
|
});
|
|
46
|
-
const
|
|
47
|
-
name: `${$moduleName}::
|
|
55
|
+
const ExpiredDepositDeleted = new MoveStruct({
|
|
56
|
+
name: `${$moduleName}::ExpiredDepositDeleted`,
|
|
48
57
|
fields: { request_id: bcs.Address }
|
|
49
58
|
});
|
|
50
59
|
function deposit(options) {
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { MoveStruct } from "../utils/index.mjs";
|
|
2
|
+
import { CommitteeSignature } from "./committee.mjs";
|
|
2
3
|
import { ObjectBag } from "./deps/sui/object_bag.mjs";
|
|
3
4
|
import { Utxo } from "./utxo.mjs";
|
|
4
|
-
import { CommitteeSignature } from "./committee.mjs";
|
|
5
5
|
import { bcs } from "@mysten/sui/bcs";
|
|
6
6
|
|
|
7
7
|
//#region src/contracts/hashi/deposit_queue.ts
|
|
8
8
|
/**************************************************************
|
|
9
9
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
10
10
|
**************************************************************/
|
|
11
|
+
/**
|
|
12
|
+
* Storage and bookkeeping for Bitcoin deposit requests. Active requests sit in an
|
|
13
|
+
* ObjectBag awaiting committee approval and confirmation; confirmed requests move
|
|
14
|
+
* to a processed bag, and requests that were never confirmed can be deleted once
|
|
15
|
+
* they pass the maximum age. The state transitions themselves (certificate
|
|
16
|
+
* verification, minting, time-delay enforcement) are driven by `hashi::deposit`.
|
|
17
|
+
*/
|
|
11
18
|
const $moduleName = "@local-pkg/hashi::deposit_queue";
|
|
12
19
|
const DepositRequestQueue = new MoveStruct({
|
|
13
20
|
name: `${$moduleName}::DepositRequestQueue`,
|
|
@@ -21,11 +28,12 @@ const DepositRequest = new MoveStruct({
|
|
|
21
28
|
fields: {
|
|
22
29
|
id: bcs.Address,
|
|
23
30
|
sender: bcs.Address,
|
|
24
|
-
|
|
31
|
+
created_timestamp_ms: bcs.u64(),
|
|
25
32
|
sui_tx_digest: bcs.vector(bcs.u8()),
|
|
26
33
|
utxo: Utxo,
|
|
27
34
|
approval_cert: bcs.option(CommitteeSignature),
|
|
28
|
-
|
|
35
|
+
approved_timestamp_ms: bcs.option(bcs.u64()),
|
|
36
|
+
confirmed_timestamp_ms: bcs.option(bcs.u64())
|
|
29
37
|
}
|
|
30
38
|
});
|
|
31
39
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { MoveStruct } from "../utils/index.mjs";
|
|
2
|
+
import { Config } from "./config.mjs";
|
|
2
3
|
import { Bag } from "./deps/sui/bag.mjs";
|
|
3
4
|
import { CommitteeSet } from "./committee_set.mjs";
|
|
4
|
-
import {
|
|
5
|
+
import { Versioning } from "./versioning.mjs";
|
|
5
6
|
import { Treasury } from "./treasury.mjs";
|
|
6
7
|
import { Proposals } from "./proposals.mjs";
|
|
7
8
|
import { bcs } from "@mysten/sui/bcs";
|
|
@@ -10,7 +11,15 @@ import { bcs } from "@mysten/sui/bcs";
|
|
|
10
11
|
/**************************************************************
|
|
11
12
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
12
13
|
**************************************************************/
|
|
13
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* The root shared object of the bridge. `Hashi` aggregates every subsystem —
|
|
16
|
+
* committee set, config, versioning, treasury, governance proposals, and TOB
|
|
17
|
+
* certificate storage — and hangs per-chain state (e.g. `BitcoinState`) off its
|
|
18
|
+
* `UID` as dynamic fields. It also provides the package-wide guards (pause,
|
|
19
|
+
* reconfig, committee-signature verification) that entry functions in other
|
|
20
|
+
* modules call through, and the one-time `finish_publish` launch switch that hands
|
|
21
|
+
* the package `UpgradeCap` into on-chain custody.
|
|
22
|
+
*/
|
|
14
23
|
const $moduleName = "@local-pkg/hashi::hashi";
|
|
15
24
|
const Hashi = new MoveStruct({
|
|
16
25
|
name: `${$moduleName}::Hashi`,
|
|
@@ -18,6 +27,7 @@ const Hashi = new MoveStruct({
|
|
|
18
27
|
id: bcs.Address,
|
|
19
28
|
committee_set: CommitteeSet,
|
|
20
29
|
config: Config,
|
|
30
|
+
versioning: Versioning,
|
|
21
31
|
treasury: Treasury,
|
|
22
32
|
proposals: Proposals,
|
|
23
33
|
tob: Bag,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { MoveEnum, MoveStruct } from "../utils/index.mjs";
|
|
2
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
3
|
+
|
|
4
|
+
//#region src/contracts/hashi/mpc_signing.ts
|
|
5
|
+
/**************************************************************
|
|
6
|
+
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
7
|
+
**************************************************************/
|
|
8
|
+
/**
|
|
9
|
+
* Durable, out-of-order accumulator for a withdrawal's per-input threshold Schnorr
|
|
10
|
+
* signatures. This is the MPC-protocol side of incremental signing: the dangerous
|
|
11
|
+
* presignature / nonce bookkeeping lives here, behind a module boundary, and is
|
|
12
|
+
* embedded (field-private) inside the BTC `WithdrawalTransaction` rather than
|
|
13
|
+
* stored as a separate object.
|
|
14
|
+
*
|
|
15
|
+
* Each input occupies one slot that is either:
|
|
16
|
+
*
|
|
17
|
+
* - `Pending(presig_index)` — awaiting its signature; carries the presignature
|
|
18
|
+
* index it will consume (valid within `epoch`), or
|
|
19
|
+
* - `Signed(bytes)` — the completed per-input MPC signature.
|
|
20
|
+
*
|
|
21
|
+
* Signatures are filled in any order (`record`), survive leader timeouts /
|
|
22
|
+
* rotation / restart because they live on chain, and survive committee
|
|
23
|
+
* reconfiguration: on an epoch change only the still-`Pending` slots are
|
|
24
|
+
* reassigned fresh presignatures (`reallocate`); `Signed` slots are final and
|
|
25
|
+
* epoch-independent (the committee group key is stable across rotation).
|
|
26
|
+
*
|
|
27
|
+
* NONCE SAFETY (a violation leaks the group secret share):
|
|
28
|
+
*
|
|
29
|
+
* - every `Pending` index is unique within (batch, epoch) — `new` / `reallocate`
|
|
30
|
+
* assign distinct offsets from a freshly allocated block;
|
|
31
|
+
* - indices are globally disjoint within an epoch — the allocator is monotonic
|
|
32
|
+
* (see `hashi::allocate_presigs`);
|
|
33
|
+
* - a stale-epoch index is never used after a reconfig — `reallocate` overwrites
|
|
34
|
+
* EVERY `Pending` slot before any signing happens in the new epoch, and the
|
|
35
|
+
* caller must `reallocate` whenever `epoch` is stale;
|
|
36
|
+
* - a `Signed` slot holds no index, so there is nothing stale to reuse.
|
|
37
|
+
*/
|
|
38
|
+
const $moduleName = "@local-pkg/hashi::mpc_signing";
|
|
39
|
+
/** Per-input signing slot. */
|
|
40
|
+
const MpcSig = new MoveEnum({
|
|
41
|
+
name: `${$moduleName}::MpcSig`,
|
|
42
|
+
fields: {
|
|
43
|
+
Pending: bcs.u64(),
|
|
44
|
+
Signed: bcs.vector(bcs.u8())
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const SigningBatch = new MoveStruct({
|
|
48
|
+
name: `${$moduleName}::SigningBatch`,
|
|
49
|
+
fields: {
|
|
50
|
+
signatures: bcs.vector(MpcSig),
|
|
51
|
+
epoch: bcs.u64()
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { SigningBatch };
|
|
@@ -5,6 +5,12 @@ import { ObjectBag } from "./deps/sui/object_bag.mjs";
|
|
|
5
5
|
/**************************************************************
|
|
6
6
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
7
7
|
**************************************************************/
|
|
8
|
+
/**
|
|
9
|
+
* Container for the package's governance proposals, hung off `Hashi`. Active and
|
|
10
|
+
* executed proposals live in two separate object bags so that each set can be
|
|
11
|
+
* enumerated directly, and executed proposals are archived indefinitely to keep
|
|
12
|
+
* historical governance actions inspectable.
|
|
13
|
+
*/
|
|
8
14
|
const $moduleName = "@local-pkg/hashi::proposals";
|
|
9
15
|
const Proposals = new MoveStruct({
|
|
10
16
|
name: `${$moduleName}::Proposals`,
|
|
@@ -6,6 +6,12 @@ import { bcs } from "@mysten/sui/bcs";
|
|
|
6
6
|
/**************************************************************
|
|
7
7
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
8
8
|
**************************************************************/
|
|
9
|
+
/**
|
|
10
|
+
* Custody of the coin capabilities for bridge-issued assets. `Treasury` holds the
|
|
11
|
+
* `TreasuryCap` and `MetadataCap` of each registered coin type in an `ObjectBag`
|
|
12
|
+
* keyed by cap type, and exposes package-only mint/burn that emit
|
|
13
|
+
* `Minted`/`Burned` events for off-chain watchers.
|
|
14
|
+
*/
|
|
9
15
|
const $moduleName = "@local-pkg/hashi::treasury";
|
|
10
16
|
const Treasury = new MoveStruct({
|
|
11
17
|
name: `${$moduleName}::Treasury`,
|
|
@@ -15,12 +21,12 @@ const Key = new MoveStruct({
|
|
|
15
21
|
name: `${$moduleName}::Key<phantom T>`,
|
|
16
22
|
fields: { dummy_field: bcs.bool() }
|
|
17
23
|
});
|
|
18
|
-
const
|
|
19
|
-
name: `${$moduleName}::
|
|
24
|
+
const Minted = new MoveStruct({
|
|
25
|
+
name: `${$moduleName}::Minted<phantom T>`,
|
|
20
26
|
fields: { amount: bcs.u64() }
|
|
21
27
|
});
|
|
22
|
-
const
|
|
23
|
-
name: `${$moduleName}::
|
|
28
|
+
const Burned = new MoveStruct({
|
|
29
|
+
name: `${$moduleName}::Burned<phantom T>`,
|
|
24
30
|
fields: { amount: bcs.u64() }
|
|
25
31
|
});
|
|
26
32
|
|
|
@@ -5,6 +5,13 @@ import { bcs } from "@mysten/sui/bcs";
|
|
|
5
5
|
/**************************************************************
|
|
6
6
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
7
7
|
**************************************************************/
|
|
8
|
+
/**
|
|
9
|
+
* Bitcoin UTXO value types shared by the deposit and withdrawal flows. A `UtxoId`
|
|
10
|
+
* identifies an outpoint (txid:vout) and a `Utxo` pairs it with its satoshi amount
|
|
11
|
+
* and an optional derivation path (the Sui address a deposit mints to). The
|
|
12
|
+
* constructors are `public` so PTBs can assemble UTXOs when calling into the
|
|
13
|
+
* bridge; everything else is package-only.
|
|
14
|
+
*/
|
|
8
15
|
const $moduleName = "@local-pkg/hashi::utxo";
|
|
9
16
|
const UtxoId = new MoveStruct({
|
|
10
17
|
name: `${$moduleName}::UtxoId`,
|
|
@@ -7,6 +7,13 @@ import { bcs } from "@mysten/sui/bcs";
|
|
|
7
7
|
/**************************************************************
|
|
8
8
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
9
9
|
**************************************************************/
|
|
10
|
+
/**
|
|
11
|
+
* On-chain bookkeeping for the bridge's Bitcoin UTXO set. Confirmed deposit
|
|
12
|
+
* outputs and unconfirmed withdrawal change outputs live in `utxo_records` from
|
|
13
|
+
* insertion until the withdrawal that spends them confirms on Bitcoin, after which
|
|
14
|
+
* their IDs move to `spent_utxos` — kept permanently as replay protection so an
|
|
15
|
+
* already-spent outpoint can never be re-inserted.
|
|
16
|
+
*/
|
|
10
17
|
const $moduleName = "@local-pkg/hashi::utxo_pool";
|
|
11
18
|
const UtxoPool = new MoveStruct({
|
|
12
19
|
name: `${$moduleName}::UtxoPool`,
|
|
@@ -20,12 +27,12 @@ const UtxoRecord = new MoveStruct({
|
|
|
20
27
|
fields: {
|
|
21
28
|
utxo: Utxo,
|
|
22
29
|
produced_by: bcs.option(bcs.Address),
|
|
23
|
-
|
|
30
|
+
spent_by: bcs.option(bcs.Address),
|
|
24
31
|
spent_epoch: bcs.option(bcs.u64())
|
|
25
32
|
}
|
|
26
33
|
});
|
|
27
|
-
const
|
|
28
|
-
name: `${$moduleName}::
|
|
34
|
+
const UtxoSpent = new MoveStruct({
|
|
35
|
+
name: `${$moduleName}::UtxoSpent`,
|
|
29
36
|
fields: {
|
|
30
37
|
utxo_id: UtxoId,
|
|
31
38
|
spent_epoch: bcs.u64()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MoveStruct } from "../utils/index.mjs";
|
|
2
|
+
import { VecSet } from "./deps/sui/vec_set.mjs";
|
|
3
|
+
import { UpgradeCap } from "./deps/sui/package.mjs";
|
|
4
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
5
|
+
|
|
6
|
+
//#region src/contracts/hashi/versioning.ts
|
|
7
|
+
/**************************************************************
|
|
8
|
+
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
9
|
+
**************************************************************/
|
|
10
|
+
/**
|
|
11
|
+
* Package version gating and upgrade authority.
|
|
12
|
+
*
|
|
13
|
+
* Holds the set of package versions allowed to run and custodies the package
|
|
14
|
+
* `UpgradeCap`. The two live together because they are one lifecycle: committing
|
|
15
|
+
* an upgrade through the cap auto-enables the new version. Every entry function
|
|
16
|
+
* gates on `assert_version_enabled` so a disabled version cannot be executed.
|
|
17
|
+
*/
|
|
18
|
+
const $moduleName = "@local-pkg/hashi::versioning";
|
|
19
|
+
const Versioning = new MoveStruct({
|
|
20
|
+
name: `${$moduleName}::Versioning`,
|
|
21
|
+
fields: {
|
|
22
|
+
enabled_versions: VecSet(bcs.u64()),
|
|
23
|
+
upgrade_cap: bcs.option(UpgradeCap)
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { Versioning };
|
|
@@ -7,7 +7,15 @@ import { bcs } from "@mysten/sui/bcs";
|
|
|
7
7
|
/**************************************************************
|
|
8
8
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
9
9
|
**************************************************************/
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* User-facing Bitcoin withdrawal flow. A user escrows hBTC against a target
|
|
12
|
+
* Bitcoin address; the committee approves the request, batches one or more
|
|
13
|
+
* requests into a withdrawal transaction (burning the hBTC and locking the input
|
|
14
|
+
* UTXOs), accumulates per-input MPC signatures incrementally, finalizes with the
|
|
15
|
+
* one-shot guardian signatures, and confirms once the transaction lands on
|
|
16
|
+
* Bitcoin. A not-yet-committed request can be cancelled by its requester after a
|
|
17
|
+
* cooldown, refunding the hBTC.
|
|
18
|
+
*/
|
|
11
19
|
const $moduleName = "@local-pkg/hashi::withdraw";
|
|
12
20
|
const RequestApprovalMessage = new MoveStruct({
|
|
13
21
|
name: `${$moduleName}::RequestApprovalMessage`,
|
|
@@ -31,6 +39,14 @@ const WithdrawalSignedMessage = new MoveStruct({
|
|
|
31
39
|
guardian_signatures: bcs.vector(bcs.vector(bcs.u8()))
|
|
32
40
|
}
|
|
33
41
|
});
|
|
42
|
+
const MpcInputSignaturesMessage = new MoveStruct({
|
|
43
|
+
name: `${$moduleName}::MpcInputSignaturesMessage`,
|
|
44
|
+
fields: {
|
|
45
|
+
withdrawal_id: bcs.Address,
|
|
46
|
+
indices: bcs.vector(bcs.u64()),
|
|
47
|
+
signatures: bcs.vector(bcs.vector(bcs.u8()))
|
|
48
|
+
}
|
|
49
|
+
});
|
|
34
50
|
const WithdrawalConfirmationMessage = new MoveStruct({
|
|
35
51
|
name: `${$moduleName}::WithdrawalConfirmationMessage`,
|
|
36
52
|
fields: { withdrawal_id: bcs.Address }
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { MoveEnum, MoveStruct } from "../utils/index.mjs";
|
|
2
|
+
import { CommitteeSignature } from "./committee.mjs";
|
|
2
3
|
import { ObjectBag } from "./deps/sui/object_bag.mjs";
|
|
3
4
|
import { Utxo, UtxoId } from "./utxo.mjs";
|
|
4
5
|
import { Balance } from "./deps/sui/balance.mjs";
|
|
6
|
+
import { SigningBatch } from "./mpc_signing.mjs";
|
|
5
7
|
import { bcs } from "@mysten/sui/bcs";
|
|
6
8
|
|
|
7
9
|
//#region src/contracts/hashi/withdrawal_queue.ts
|
|
8
10
|
/**************************************************************
|
|
9
11
|
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
|
|
10
12
|
**************************************************************/
|
|
13
|
+
/**
|
|
14
|
+
* Storage and state machine for Bitcoin withdrawals. Holds `WithdrawalRequest`
|
|
15
|
+
* objects as they move from Requested through Approved, Processing, Signed, and
|
|
16
|
+
* Confirmed, plus the `WithdrawalTransaction` objects that batch them: each
|
|
17
|
+
* transaction tracks its input UTXOs, withdrawal and change outputs, and the
|
|
18
|
+
* incrementally collected MPC and guardian signatures. Certificate verification
|
|
19
|
+
* and funds movement are driven by `hashi::withdraw`.
|
|
20
|
+
*/
|
|
11
21
|
const $moduleName = "@local-pkg/hashi::withdrawal_queue";
|
|
12
22
|
const WithdrawalRequestQueue = new MoveStruct({
|
|
13
23
|
name: `${$moduleName}::WithdrawalRequestQueue`,
|
|
@@ -42,8 +52,10 @@ const WithdrawalRequest = new MoveStruct({
|
|
|
42
52
|
sender: bcs.Address,
|
|
43
53
|
btc_amount: bcs.u64(),
|
|
44
54
|
bitcoin_address: bcs.vector(bcs.u8()),
|
|
45
|
-
|
|
55
|
+
created_timestamp_ms: bcs.u64(),
|
|
46
56
|
status: WithdrawalStatus,
|
|
57
|
+
approval_cert: bcs.option(CommitteeSignature),
|
|
58
|
+
approved_timestamp_ms: bcs.option(bcs.u64()),
|
|
47
59
|
withdrawal_txn_id: bcs.option(bcs.Address),
|
|
48
60
|
sui_tx_digest: bcs.vector(bcs.u8()),
|
|
49
61
|
btc: Balance
|
|
@@ -57,13 +69,13 @@ const WithdrawalTransaction = new MoveStruct({
|
|
|
57
69
|
request_ids: bcs.vector(bcs.Address),
|
|
58
70
|
inputs: bcs.vector(Utxo),
|
|
59
71
|
withdrawal_outputs: bcs.vector(OutputUtxo),
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
change_outputs: bcs.vector(OutputUtxo),
|
|
73
|
+
created_timestamp_ms: bcs.u64(),
|
|
74
|
+
signed_timestamp_ms: bcs.option(bcs.u64()),
|
|
75
|
+
confirmed_timestamp_ms: bcs.option(bcs.u64()),
|
|
62
76
|
randomness: bcs.vector(bcs.u8()),
|
|
63
|
-
|
|
64
|
-
guardian_signatures: bcs.option(bcs.vector(bcs.vector(bcs.u8())))
|
|
65
|
-
presig_start_index: bcs.u64(),
|
|
66
|
-
epoch: bcs.u64()
|
|
77
|
+
signing: SigningBatch,
|
|
78
|
+
guardian_signatures: bcs.option(bcs.vector(bcs.vector(bcs.u8())))
|
|
67
79
|
}
|
|
68
80
|
});
|
|
69
81
|
const CommittedRequestInfo = new MoveStruct({
|
|
@@ -73,8 +85,8 @@ const CommittedRequestInfo = new MoveStruct({
|
|
|
73
85
|
bitcoin_address: bcs.vector(bcs.u8())
|
|
74
86
|
}
|
|
75
87
|
});
|
|
76
|
-
const
|
|
77
|
-
name: `${$moduleName}::
|
|
88
|
+
const WithdrawalRequested = new MoveStruct({
|
|
89
|
+
name: `${$moduleName}::WithdrawalRequested`,
|
|
78
90
|
fields: {
|
|
79
91
|
request_id: bcs.Address,
|
|
80
92
|
btc_amount: bcs.u64(),
|
|
@@ -84,25 +96,33 @@ const WithdrawalRequestedEvent = new MoveStruct({
|
|
|
84
96
|
sui_tx_digest: bcs.vector(bcs.u8())
|
|
85
97
|
}
|
|
86
98
|
});
|
|
87
|
-
const
|
|
88
|
-
name: `${$moduleName}::
|
|
99
|
+
const WithdrawalApproved = new MoveStruct({
|
|
100
|
+
name: `${$moduleName}::WithdrawalApproved`,
|
|
89
101
|
fields: { request_id: bcs.Address }
|
|
90
102
|
});
|
|
91
|
-
const
|
|
92
|
-
name: `${$moduleName}::
|
|
103
|
+
const WithdrawalPickedForProcessing = new MoveStruct({
|
|
104
|
+
name: `${$moduleName}::WithdrawalPickedForProcessing`,
|
|
93
105
|
fields: {
|
|
94
106
|
withdrawal_txn_id: bcs.Address,
|
|
95
107
|
txid: bcs.Address,
|
|
96
108
|
request_ids: bcs.vector(bcs.Address),
|
|
97
109
|
inputs: bcs.vector(Utxo),
|
|
98
110
|
withdrawal_outputs: bcs.vector(OutputUtxo),
|
|
99
|
-
|
|
111
|
+
change_outputs: bcs.vector(OutputUtxo),
|
|
100
112
|
timestamp_ms: bcs.u64(),
|
|
101
113
|
randomness: bcs.vector(bcs.u8())
|
|
102
114
|
}
|
|
103
115
|
});
|
|
104
|
-
const
|
|
105
|
-
name: `${$moduleName}::
|
|
116
|
+
const WithdrawalInputsSigned = new MoveStruct({
|
|
117
|
+
name: `${$moduleName}::WithdrawalInputsSigned`,
|
|
118
|
+
fields: {
|
|
119
|
+
withdrawal_txn_id: bcs.Address,
|
|
120
|
+
signed_count: bcs.u64(),
|
|
121
|
+
num_inputs: bcs.u64()
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
const WithdrawalSigned = new MoveStruct({
|
|
125
|
+
name: `${$moduleName}::WithdrawalSigned`,
|
|
106
126
|
fields: {
|
|
107
127
|
withdrawal_txn_id: bcs.Address,
|
|
108
128
|
request_ids: bcs.vector(bcs.Address),
|
|
@@ -110,26 +130,26 @@ const WithdrawalSignedEvent = new MoveStruct({
|
|
|
110
130
|
guardian_signatures: bcs.vector(bcs.vector(bcs.u8()))
|
|
111
131
|
}
|
|
112
132
|
});
|
|
113
|
-
const
|
|
114
|
-
name: `${$moduleName}::
|
|
133
|
+
const WithdrawalPresigsReassigned = new MoveStruct({
|
|
134
|
+
name: `${$moduleName}::WithdrawalPresigsReassigned`,
|
|
115
135
|
fields: {
|
|
116
136
|
withdrawal_txn_id: bcs.Address,
|
|
117
137
|
epoch: bcs.u64(),
|
|
118
138
|
presig_start_index: bcs.u64()
|
|
119
139
|
}
|
|
120
140
|
});
|
|
121
|
-
const
|
|
122
|
-
name: `${$moduleName}::
|
|
141
|
+
const WithdrawalConfirmed = new MoveStruct({
|
|
142
|
+
name: `${$moduleName}::WithdrawalConfirmed`,
|
|
123
143
|
fields: {
|
|
124
144
|
withdrawal_txn_id: bcs.Address,
|
|
125
145
|
txid: bcs.Address,
|
|
126
|
-
|
|
146
|
+
change_utxo_ids: bcs.vector(UtxoId),
|
|
127
147
|
request_ids: bcs.vector(bcs.Address),
|
|
128
|
-
|
|
148
|
+
change_utxo_amounts: bcs.vector(bcs.u64())
|
|
129
149
|
}
|
|
130
150
|
});
|
|
131
|
-
const
|
|
132
|
-
name: `${$moduleName}::
|
|
151
|
+
const WithdrawalCancelled = new MoveStruct({
|
|
152
|
+
name: `${$moduleName}::WithdrawalCancelled`,
|
|
133
153
|
fields: {
|
|
134
154
|
request_id: bcs.Address,
|
|
135
155
|
requester_address: bcs.Address,
|
package/dist/errors.d.mts
CHANGED
|
@@ -36,6 +36,33 @@ declare class HashiFetchError extends Error {
|
|
|
36
36
|
cause?: unknown;
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Stable discriminator for `HashiGuardianError`, so callers can `switch` on
|
|
41
|
+
* `code` rather than string-parse the message: `not-configured` (no guardian URL
|
|
42
|
+
* resolvable), `unreachable` (`fetch` threw), `http-error` (non-2xx),
|
|
43
|
+
* `malformed-response` (bad JSON or limiter field), `not-initialized` (no limiter yet).
|
|
44
|
+
*/
|
|
45
|
+
type GuardianErrorCode = "not-configured" | "unreachable" | "http-error" | "malformed-response" | "not-initialized";
|
|
46
|
+
/**
|
|
47
|
+
* Thrown by the `client.hashi.guardian.*` methods when the guardian `/info`
|
|
48
|
+
* endpoint can't be resolved, reached, parsed, or is not yet initialized.
|
|
49
|
+
* `code` is a stable discriminator for programmatic handling; `url` is the
|
|
50
|
+
* `/info` endpoint that failed (`null` for `not-configured`); `status` carries
|
|
51
|
+
* the HTTP status for `http-error`.
|
|
52
|
+
*/
|
|
53
|
+
declare class HashiGuardianError extends Error {
|
|
54
|
+
readonly code: GuardianErrorCode;
|
|
55
|
+
readonly url: string | null;
|
|
56
|
+
readonly status?: number;
|
|
57
|
+
constructor(details: {
|
|
58
|
+
message: string;
|
|
59
|
+
code: GuardianErrorCode;
|
|
60
|
+
url?: string | null;
|
|
61
|
+
status?: number;
|
|
62
|
+
}, options?: {
|
|
63
|
+
cause?: unknown;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
39
66
|
/**
|
|
40
67
|
* One amount that failed a client-side minimum check. `vout` is present for
|
|
41
68
|
* deposit-UTXO violations (so callers can map each offender back to a Bitcoin
|
|
@@ -115,4 +142,4 @@ declare class InvalidBitcoinAddressError extends Error {
|
|
|
115
142
|
});
|
|
116
143
|
}
|
|
117
144
|
//#endregion
|
|
118
|
-
export { AmountBelowMinimumError, AmountViolation, HashiConfigError, HashiFetchError, HashiPausedError, InvalidBitcoinAddressCode, InvalidBitcoinAddressError, InvalidParamsError };
|
|
145
|
+
export { AmountBelowMinimumError, AmountViolation, GuardianErrorCode, HashiConfigError, HashiFetchError, HashiGuardianError, HashiPausedError, InvalidBitcoinAddressCode, InvalidBitcoinAddressError, InvalidParamsError };
|