@totemsdk/omnia-vtxo 0.4.0 → 0.5.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/dist/anchor.d.ts CHANGED
@@ -11,8 +11,11 @@ import { type OmniaTxDraft, type StateValue } from '@totemsdk/omnia';
11
11
  import type { ChainStateProvider } from '@totemsdk/chain-provider';
12
12
  export interface BatchAnchorParams {
13
13
  operatorPublicKeyDigest: string;
14
- ownerPublicKeyDigest: string;
15
- /** Absolute block height after which the owner may exit unilaterally (STATE(102)). */
14
+ /** Holder WOTS public-key digests (one per pool share). */
15
+ holders: string[];
16
+ /** Committed share per holder (aligned with `holders`); Σ = pool capacity. */
17
+ shares: bigint[];
18
+ /** Absolute block height after which holders may exit unilaterally (STATE(102)). */
16
19
  exitBlock: number;
17
20
  /** The epoch's Merkle root (32-byte hex). */
18
21
  root: string;
@@ -25,8 +28,8 @@ export interface BatchAnchorParams {
25
28
  amount: bigint;
26
29
  tokenId: string;
27
30
  }
28
- /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock. */
29
- export declare function poolStateVariables(root: string, epoch: number, exitBlock: number): StateValue[];
31
+ /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock, STATE(300+k)=share k. */
32
+ export declare function poolStateVariables(root: string, epoch: number, exitBlock: number, shares?: bigint[]): StateValue[];
30
33
  /** Build the batch-anchor draft (input = pool coin, output = pool state output). */
31
34
  export declare function buildBatchAnchorDraft(params: BatchAnchorParams): OmniaTxDraft;
32
35
  export declare function batchAnchorDigest(draft: OmniaTxDraft): Uint8Array;
package/dist/anchor.js CHANGED
@@ -10,20 +10,24 @@
10
10
  import { computeOmniaTxDigest, omniaDraftToMinimaBytes, } from '@totemsdk/omnia';
11
11
  import { serializeTxBody, mineTxPoW, TX_POW_MIN_DIFFICULTY } from '@totemsdk/txpow';
12
12
  import { concatBytes } from '@totemsdk/core';
13
- import { buildAndHashPoolScript } from './pool-script.js';
14
- /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock. */
15
- export function poolStateVariables(root, epoch, exitBlock) {
13
+ import { buildAndHashPoolScript, POOL_SHARE_PORT_BASE } from './pool-script.js';
14
+ /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock, STATE(300+k)=share k. */
15
+ export function poolStateVariables(root, epoch, exitBlock, shares = []) {
16
16
  return [
17
17
  { port: 100, value: root, type: 'string' },
18
18
  { port: 101, value: BigInt(epoch), type: 'number' },
19
19
  { port: 102, value: BigInt(exitBlock), type: 'number' },
20
+ ...shares.map((share, k) => ({ port: POOL_SHARE_PORT_BASE + k, value: share, type: 'number' })),
20
21
  ];
21
22
  }
22
23
  /** Build the batch-anchor draft (input = pool coin, output = pool state output). */
23
24
  export function buildBatchAnchorDraft(params) {
25
+ if (params.holders.length !== params.shares.length) {
26
+ throw new Error('anchorBatch: holders and shares must be the same length');
27
+ }
24
28
  const { script, address } = buildAndHashPoolScript({
25
29
  operatorPublicKeyDigest: params.operatorPublicKeyDigest,
26
- ownerPublicKeyDigest: params.ownerPublicKeyDigest,
30
+ holders: params.holders,
27
31
  exitBlock: params.exitBlock,
28
32
  });
29
33
  // The input must be the operator's own pool output, not a foreign script.
@@ -33,7 +37,7 @@ export function buildBatchAnchorDraft(params) {
33
37
  if (params.fundingAddress !== address) {
34
38
  throw new Error('anchorBatch: fundingAddress does not match the pool address');
35
39
  }
36
- const stateVariables = poolStateVariables(params.root, params.epoch, params.exitBlock);
40
+ const stateVariables = poolStateVariables(params.root, params.epoch, params.exitBlock, params.shares);
37
41
  return {
38
42
  type: 'settlement',
39
43
  inputs: [{
@@ -11,8 +11,11 @@ import { type OmniaTxDraft, type StateValue } from '@totemsdk/omnia';
11
11
  import type { ChainStateProvider } from '@totemsdk/chain-provider';
12
12
  export interface BatchAnchorParams {
13
13
  operatorPublicKeyDigest: string;
14
- ownerPublicKeyDigest: string;
15
- /** Absolute block height after which the owner may exit unilaterally (STATE(102)). */
14
+ /** Holder WOTS public-key digests (one per pool share). */
15
+ holders: string[];
16
+ /** Committed share per holder (aligned with `holders`); Σ = pool capacity. */
17
+ shares: bigint[];
18
+ /** Absolute block height after which holders may exit unilaterally (STATE(102)). */
16
19
  exitBlock: number;
17
20
  /** The epoch's Merkle root (32-byte hex). */
18
21
  root: string;
@@ -25,8 +28,8 @@ export interface BatchAnchorParams {
25
28
  amount: bigint;
26
29
  tokenId: string;
27
30
  }
28
- /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock. */
29
- export declare function poolStateVariables(root: string, epoch: number, exitBlock: number): StateValue[];
31
+ /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock, STATE(300+k)=share k. */
32
+ export declare function poolStateVariables(root: string, epoch: number, exitBlock: number, shares?: bigint[]): StateValue[];
30
33
  /** Build the batch-anchor draft (input = pool coin, output = pool state output). */
31
34
  export declare function buildBatchAnchorDraft(params: BatchAnchorParams): OmniaTxDraft;
32
35
  export declare function batchAnchorDigest(draft: OmniaTxDraft): Uint8Array;
@@ -18,19 +18,23 @@ const omnia_1 = require("@totemsdk/omnia");
18
18
  const txpow_1 = require("@totemsdk/txpow");
19
19
  const core_1 = require("@totemsdk/core");
20
20
  const pool_script_js_1 = require("./pool-script.js");
21
- /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock. */
22
- function poolStateVariables(root, epoch, exitBlock) {
21
+ /** Pool output state: STATE(100)=root, STATE(101)=epoch, STATE(102)=exitBlock, STATE(300+k)=share k. */
22
+ function poolStateVariables(root, epoch, exitBlock, shares = []) {
23
23
  return [
24
24
  { port: 100, value: root, type: 'string' },
25
25
  { port: 101, value: BigInt(epoch), type: 'number' },
26
26
  { port: 102, value: BigInt(exitBlock), type: 'number' },
27
+ ...shares.map((share, k) => ({ port: pool_script_js_1.POOL_SHARE_PORT_BASE + k, value: share, type: 'number' })),
27
28
  ];
28
29
  }
29
30
  /** Build the batch-anchor draft (input = pool coin, output = pool state output). */
30
31
  function buildBatchAnchorDraft(params) {
32
+ if (params.holders.length !== params.shares.length) {
33
+ throw new Error('anchorBatch: holders and shares must be the same length');
34
+ }
31
35
  const { script, address } = (0, pool_script_js_1.buildAndHashPoolScript)({
32
36
  operatorPublicKeyDigest: params.operatorPublicKeyDigest,
33
- ownerPublicKeyDigest: params.ownerPublicKeyDigest,
37
+ holders: params.holders,
34
38
  exitBlock: params.exitBlock,
35
39
  });
36
40
  // The input must be the operator's own pool output, not a foreign script.
@@ -40,7 +44,7 @@ function buildBatchAnchorDraft(params) {
40
44
  if (params.fundingAddress !== address) {
41
45
  throw new Error('anchorBatch: fundingAddress does not match the pool address');
42
46
  }
43
- const stateVariables = poolStateVariables(params.root, params.epoch, params.exitBlock);
47
+ const stateVariables = poolStateVariables(params.root, params.epoch, params.exitBlock, params.shares);
44
48
  return {
45
49
  type: 'settlement',
46
50
  inputs: [{
@@ -1,21 +1,20 @@
1
1
  /**
2
- * VTXO exit transaction (RFC-038 V2 — owner-unilateral).
2
+ * VTXO exit transaction (RFC-038 V3 — per-share, owner-signed).
3
3
  *
4
- * The exit spends the pool's on-chain coin and pays the VTXO's owner, carrying
5
- * the exit delay in STATE(110). It is signed with the **owner's** key (not the
6
- * operator's): the pool script's `IF @BLOCK GT EXITBLOCK THEN RETURN
7
- * SIGNEDBY(OWNER)` branch authorizes it after the exit window, so the owner can
8
- * broadcast it without any operator signature or liveness. The digest is signed
9
- * (injected signer) and, when a chain provider is supplied, mined + broadcast
10
- * (injected miner).
4
+ * The exit spends the pool's on-chain coin and pays the exiting holder **only
5
+ * its committed share** (`shares[holderIndex]`), returning the remainder to the
6
+ * pool with that holder's share state zeroed. It is signed with the holder's key
7
+ * — the pool script's `IF @BLOCK GT EXITBLOCK … IF SIGNEDBY(holder) … VERIFYOUT(0
8
+ * holder SHARE @TOKENID FALSE)` branch authorizes it, so the holder can broadcast
9
+ * without any operator signature or liveness, and cannot take more than its share.
11
10
  *
12
- * The caller must pass the owner signer; the operator cannot construct a valid
13
- * exit witness for itself.
11
+ * The caller must pass the holder signer; neither the operator nor another holder
12
+ * can build a valid witness for this holder's share.
14
13
  */
15
14
  import { type OmniaTxDraft } from '@totemsdk/omnia';
16
15
  import type { ChainStateProvider } from '@totemsdk/chain-provider';
17
16
  import type { OmniaVtxo } from './types.js';
18
- /** State port carrying the exit delay on the owner's output. */
17
+ /** State port carrying an optional exit delay on the holder's output. */
19
18
  export declare const EXIT_DELAY_PORT = 110;
20
19
  export interface ExitTxParams {
21
20
  vtxo: OmniaVtxo;
@@ -23,12 +22,19 @@ export interface ExitTxParams {
23
22
  fundingCoinId: string;
24
23
  fundingAddress: string;
25
24
  fundingScript: string;
26
- /** Raw base-unit amount to pay the owner (the VTXO amount, pre-scaled). */
25
+ /** Total pool amount (raw base units). */
27
26
  amount: bigint;
28
- /** Exit delay carried as STATE(102). */
29
- exitDelayBlocks: number;
27
+ /** Pool holders + committed shares (aligned arrays). */
28
+ holders: string[];
29
+ shares: bigint[];
30
+ /** Index of the exiting holder (must match `vtxo.owner`). */
31
+ holderIndex: number;
32
+ /** Pool state, needed to rebuild the remainder output's state. */
33
+ root: string;
34
+ epoch: number;
35
+ exitBlock: number;
30
36
  }
31
- /** Draft that spends the pool coin to the VTXO owner with the exit delay encoded. */
37
+ /** Draft that spends the pool coin: output 0 = holder's share, remainder = pool. */
32
38
  export declare function buildExitTransactionDraft(params: ExitTxParams): OmniaTxDraft;
33
39
  export declare function exitTransactionDigest(draft: OmniaTxDraft): Uint8Array;
34
40
  export declare function exitTransactionHex(draft: OmniaTxDraft): string;
@@ -44,14 +50,13 @@ export interface ExitTxDeps {
44
50
  export interface ExitTxResult {
45
51
  vtxoId: string;
46
52
  owner: string;
47
- amount: string;
48
- exitDelayBlocks: number;
53
+ share: string;
49
54
  draftType: 'vtxo-exit';
50
55
  txHex: string;
51
56
  digest: string;
52
57
  witnessHex: string;
53
58
  txpowId?: string;
54
59
  }
55
- /** Build, sign (and optionally mine + broadcast) a VTXO exit transaction. */
60
+ /** Build, sign (and optionally mine + broadcast) a per-share VTXO exit transaction. */
56
61
  export declare function buildExitTransaction(params: ExitTxParams, deps: ExitTxDeps): Promise<ExitTxResult>;
57
62
  export {};
@@ -1,17 +1,16 @@
1
1
  "use strict";
2
2
  /**
3
- * VTXO exit transaction (RFC-038 V2 — owner-unilateral).
3
+ * VTXO exit transaction (RFC-038 V3 — per-share, owner-signed).
4
4
  *
5
- * The exit spends the pool's on-chain coin and pays the VTXO's owner, carrying
6
- * the exit delay in STATE(110). It is signed with the **owner's** key (not the
7
- * operator's): the pool script's `IF @BLOCK GT EXITBLOCK THEN RETURN
8
- * SIGNEDBY(OWNER)` branch authorizes it after the exit window, so the owner can
9
- * broadcast it without any operator signature or liveness. The digest is signed
10
- * (injected signer) and, when a chain provider is supplied, mined + broadcast
11
- * (injected miner).
5
+ * The exit spends the pool's on-chain coin and pays the exiting holder **only
6
+ * its committed share** (`shares[holderIndex]`), returning the remainder to the
7
+ * pool with that holder's share state zeroed. It is signed with the holder's key
8
+ * — the pool script's `IF @BLOCK GT EXITBLOCK … IF SIGNEDBY(holder) … VERIFYOUT(0
9
+ * holder SHARE @TOKENID FALSE)` branch authorizes it, so the holder can broadcast
10
+ * without any operator signature or liveness, and cannot take more than its share.
12
11
  *
13
- * The caller must pass the owner signer; the operator cannot construct a valid
14
- * exit witness for itself.
12
+ * The caller must pass the holder signer; neither the operator nor another holder
13
+ * can build a valid witness for this holder's share.
15
14
  */
16
15
  Object.defineProperty(exports, "__esModule", { value: true });
17
16
  exports.EXIT_DELAY_PORT = void 0;
@@ -22,13 +21,34 @@ exports.buildExitTransaction = buildExitTransaction;
22
21
  const omnia_1 = require("@totemsdk/omnia");
23
22
  const txpow_1 = require("@totemsdk/txpow");
24
23
  const core_1 = require("@totemsdk/core");
25
- /** State port carrying the exit delay on the owner's output. */
24
+ const anchor_js_1 = require("./anchor.js");
25
+ /** State port carrying an optional exit delay on the holder's output. */
26
26
  exports.EXIT_DELAY_PORT = 110;
27
- /** Draft that spends the pool coin to the VTXO owner with the exit delay encoded. */
27
+ /** Draft that spends the pool coin: output 0 = holder's share, remainder = pool. */
28
28
  function buildExitTransactionDraft(params) {
29
- const stateVariables = [
30
- { port: exports.EXIT_DELAY_PORT, value: BigInt(params.exitDelayBlocks), type: 'number' },
31
- ];
29
+ const share = params.shares[params.holderIndex];
30
+ if (share === undefined)
31
+ throw new Error('exit: holderIndex out of range');
32
+ if (share <= 0n)
33
+ throw new Error('exit: holder share must be positive');
34
+ const outputs = [{
35
+ address: params.vtxo.owner,
36
+ amount: share,
37
+ tokenId: params.vtxo.tokenId,
38
+ storeState: false,
39
+ stateVariables: [],
40
+ }];
41
+ const carriesState = params.amount > share;
42
+ if (carriesState) {
43
+ const remaining = params.shares.map((s, i) => (i === params.holderIndex ? 0n : s));
44
+ outputs.push({
45
+ address: params.fundingAddress,
46
+ amount: params.amount - share,
47
+ tokenId: params.vtxo.tokenId,
48
+ storeState: true,
49
+ stateVariables: (0, anchor_js_1.poolStateVariables)(params.root, params.epoch, params.exitBlock, remaining),
50
+ });
51
+ }
32
52
  return {
33
53
  type: 'settlement',
34
54
  inputs: [{
@@ -38,15 +58,9 @@ function buildExitTransactionDraft(params) {
38
58
  tokenId: params.vtxo.tokenId,
39
59
  scriptHex: params.fundingScript,
40
60
  }],
41
- outputs: [{
42
- address: params.vtxo.owner,
43
- amount: params.amount,
44
- tokenId: params.vtxo.tokenId,
45
- storeState: false,
46
- stateVariables,
47
- }],
48
- storeState: false,
49
- stateVariables,
61
+ outputs,
62
+ storeState: carriesState,
63
+ stateVariables: [],
50
64
  };
51
65
  }
52
66
  function exitTransactionDigest(draft) {
@@ -55,7 +69,7 @@ function exitTransactionDigest(draft) {
55
69
  function exitTransactionHex(draft) {
56
70
  return (0, omnia_1.serializeTxDraft)(draft);
57
71
  }
58
- /** Build, sign (and optionally mine + broadcast) a VTXO exit transaction. */
72
+ /** Build, sign (and optionally mine + broadcast) a per-share VTXO exit transaction. */
59
73
  async function buildExitTransaction(params, deps) {
60
74
  const draft = buildExitTransactionDraft(params);
61
75
  const digest = exitTransactionDigest(draft);
@@ -63,8 +77,7 @@ async function buildExitTransaction(params, deps) {
63
77
  const result = {
64
78
  vtxoId: params.vtxo.vtxoId,
65
79
  owner: params.vtxo.owner,
66
- amount: params.vtxo.amount.toString(),
67
- exitDelayBlocks: params.exitDelayBlocks,
80
+ share: params.shares[params.holderIndex].toString(),
68
81
  draftType: 'vtxo-exit',
69
82
  txHex: exitTransactionHex(draft),
70
83
  digest: Buffer.from(digest).toString('hex'),
@@ -1,33 +1,37 @@
1
1
  /**
2
- * VTXO pool on-chain script (RFC-038 V2 — non-custodial).
2
+ * VTXO pool on-chain script (RFC-038 V3 — per-share non-custodial).
3
3
  *
4
4
  * The pool is an on-chain state output holding `totalCapacity`. An epoch's batch
5
- * root is committed as STATE(100), the epoch number in STATE(101), and the
6
- * owner's absolute exit-eligibility block in STATE(102).
5
+ * root is committed as STATE(100), the epoch number in STATE(101), the absolute
6
+ * exit-eligibility block in STATE(102), and each holder's committed share in
7
+ * STATE(300+k).
7
8
  *
8
- * Custody (RFC-044 / CUSTODY-POLICY §2):
9
- * - **Unilateral owner exit.** After `@BLOCK GT EXITBLOCK` the owner alone may
10
- * spend (`RETURN SIGNEDBY(OWNER)`) — no operator signature or liveness. This
11
- * is exercised by the pre-signed exit tx (`exit-tx.ts`).
9
+ * Custody (RFC-039 / CUSTODY-POLICY §2):
10
+ * - **Per-share unilateral exit.** After `@BLOCK GT EXITBLOCK` each holder may
11
+ * withdraw **only its own committed share** (`STATE(300+k)`), to its own key,
12
+ * zeroing that share and returning the remainder to the pool. A holder cannot
13
+ * pay itself more than its share, so one holder can never rug the others.
12
14
  * - **Cooperative update.** Before the exit window the pool may only move by
13
- * `MULTISIG(2 OPERATOR OWNER)`, epoch-monotone (`ASSERT EPOCH GT
15
+ * `MULTISIG(operator + all holders)`, epoch-monotone (`ASSERT EPOCH GT
14
16
  * PREVSTATE(101)`), with the exit block immutable (`ASSERT SAMESTATE(102
15
- * 102)`) so the operator can never push the owner's escape clock, and the
16
- * value confined to the same script address (`ASSERT VERIFYOUT(@INPUT
17
- * @ADDRESS @AMOUNT @TOKENID TRUE)`) so the operator can never pay itself.
17
+ * 102)`) so no one can push the escape clock, and value confined to the same
18
+ * script address (`ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)`)
19
+ * so the operator can never pay itself.
18
20
  *
19
- * The operator holds no unilateral path: it cannot move funds, cannot advance
20
- * the exit block, and cannot stop the owner's exit. It is a liveness-only peer.
21
+ * The operator holds no unilateral path: it cannot move funds, cannot advance the
22
+ * exit block, and cannot stop a holder's exit. It is a liveness-only peer.
21
23
  */
24
+ /** State port base for per-holder shares: holder k ⇒ port 200+k (ports are bytes, ≤255). */
25
+ export declare const POOL_SHARE_PORT_BASE = 200;
22
26
  export interface PoolScriptParams {
23
27
  /** Operator WOTS public-key digest (64 hex). */
24
28
  operatorPublicKeyDigest: string;
25
- /** Pool owner WOTS public-key digest (64 hex). */
26
- ownerPublicKeyDigest: string;
27
- /** Absolute block height after which the owner may exit unilaterally. */
29
+ /** Holder WOTS public-key digests (64 hex), one per beneficial owner. */
30
+ holders: string[];
31
+ /** Absolute block height after which holders may exit unilaterally. */
28
32
  exitBlock: number;
29
33
  }
30
- /** Non-custodial, epoch-monotone, owner-escapable state-carrying pool script. */
34
+ /** Per-share-constrained, epoch-monotone, state-carrying pool script. */
31
35
  export declare function buildPoolScript(params: PoolScriptParams): string;
32
36
  export declare function poolScriptAddress(script: string): string;
33
37
  export declare function buildAndHashPoolScript(params: PoolScriptParams): {
@@ -1,30 +1,35 @@
1
1
  "use strict";
2
2
  /**
3
- * VTXO pool on-chain script (RFC-038 V2 — non-custodial).
3
+ * VTXO pool on-chain script (RFC-038 V3 — per-share non-custodial).
4
4
  *
5
5
  * The pool is an on-chain state output holding `totalCapacity`. An epoch's batch
6
- * root is committed as STATE(100), the epoch number in STATE(101), and the
7
- * owner's absolute exit-eligibility block in STATE(102).
6
+ * root is committed as STATE(100), the epoch number in STATE(101), the absolute
7
+ * exit-eligibility block in STATE(102), and each holder's committed share in
8
+ * STATE(300+k).
8
9
  *
9
- * Custody (RFC-044 / CUSTODY-POLICY §2):
10
- * - **Unilateral owner exit.** After `@BLOCK GT EXITBLOCK` the owner alone may
11
- * spend (`RETURN SIGNEDBY(OWNER)`) — no operator signature or liveness. This
12
- * is exercised by the pre-signed exit tx (`exit-tx.ts`).
10
+ * Custody (RFC-039 / CUSTODY-POLICY §2):
11
+ * - **Per-share unilateral exit.** After `@BLOCK GT EXITBLOCK` each holder may
12
+ * withdraw **only its own committed share** (`STATE(300+k)`), to its own key,
13
+ * zeroing that share and returning the remainder to the pool. A holder cannot
14
+ * pay itself more than its share, so one holder can never rug the others.
13
15
  * - **Cooperative update.** Before the exit window the pool may only move by
14
- * `MULTISIG(2 OPERATOR OWNER)`, epoch-monotone (`ASSERT EPOCH GT
16
+ * `MULTISIG(operator + all holders)`, epoch-monotone (`ASSERT EPOCH GT
15
17
  * PREVSTATE(101)`), with the exit block immutable (`ASSERT SAMESTATE(102
16
- * 102)`) so the operator can never push the owner's escape clock, and the
17
- * value confined to the same script address (`ASSERT VERIFYOUT(@INPUT
18
- * @ADDRESS @AMOUNT @TOKENID TRUE)`) so the operator can never pay itself.
18
+ * 102)`) so no one can push the escape clock, and value confined to the same
19
+ * script address (`ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)`)
20
+ * so the operator can never pay itself.
19
21
  *
20
- * The operator holds no unilateral path: it cannot move funds, cannot advance
21
- * the exit block, and cannot stop the owner's exit. It is a liveness-only peer.
22
+ * The operator holds no unilateral path: it cannot move funds, cannot advance the
23
+ * exit block, and cannot stop a holder's exit. It is a liveness-only peer.
22
24
  */
23
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.POOL_SHARE_PORT_BASE = void 0;
24
27
  exports.buildPoolScript = buildPoolScript;
25
28
  exports.poolScriptAddress = poolScriptAddress;
26
29
  exports.buildAndHashPoolScript = buildAndHashPoolScript;
27
30
  const core_1 = require("@totemsdk/core");
31
+ /** State port base for per-holder shares: holder k ⇒ port 200+k (ports are bytes, ≤255). */
32
+ exports.POOL_SHARE_PORT_BASE = 200;
28
33
  function pkHex(digest, label) {
29
34
  const raw = digest.replace(/^0x/i, '');
30
35
  if (!/^[0-9a-fA-F]{64}$/.test(raw)) {
@@ -32,24 +37,48 @@ function pkHex(digest, label) {
32
37
  }
33
38
  return '0X' + raw.toUpperCase();
34
39
  }
35
- /** Non-custodial, epoch-monotone, owner-escapable state-carrying pool script. */
40
+ /** Per-share-constrained, epoch-monotone, state-carrying pool script. */
36
41
  function buildPoolScript(params) {
37
- const owner = pkHex(params.ownerPublicKeyDigest, 'owner');
38
42
  const operator = pkHex(params.operatorPublicKeyDigest, 'operator');
43
+ if (!Array.isArray(params.holders) || params.holders.length < 1) {
44
+ throw new Error('pool requires at least one holder');
45
+ }
46
+ const holders = params.holders.map((h, i) => pkHex(h, `holder[${i}]`));
39
47
  if (!Number.isInteger(params.exitBlock) || params.exitBlock < 0) {
40
48
  throw new Error(`exitBlock must be a non-negative integer, got ${JSON.stringify(params.exitBlock)}`);
41
49
  }
42
- return [
50
+ const lines = [
43
51
  'LET EPOCH=STATE(101)',
44
52
  'LET EXITBLOCK=STATE(102)',
45
53
  'IF @BLOCK GT EXITBLOCK THEN',
46
- ` RETURN SIGNEDBY(${owner})`,
47
- 'ENDIF',
48
- 'ASSERT EPOCH GT PREVSTATE(101)',
49
- 'ASSERT SAMESTATE(102 102)',
50
- 'ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)',
51
- `RETURN MULTISIG(2 ${operator} ${owner})`,
52
- ].join('\n');
54
+ ];
55
+ holders.forEach((holder, k) => {
56
+ const port = exports.POOL_SHARE_PORT_BASE + k;
57
+ lines.push(` LET SHARE${k}=STATE(${port})`);
58
+ lines.push(` IF SIGNEDBY(${holder}) THEN`);
59
+ lines.push(` IF SHARE${k} GT 0 THEN`);
60
+ lines.push(` ASSERT VERIFYOUT(0 ${holder} SHARE${k} @TOKENID FALSE)`);
61
+ for (let j = 0; j < holders.length; j++) {
62
+ if (j === k)
63
+ continue;
64
+ lines.push(` ASSERT STATE(${exports.POOL_SHARE_PORT_BASE + j}) EQ PREVSTATE(${exports.POOL_SHARE_PORT_BASE + j})`);
65
+ }
66
+ lines.push(` ASSERT STATE(${port}) EQ 0`);
67
+ // Remainder (other holders' shares) stays in the pool; skip it when the
68
+ // withdrawing holder's share is the whole pool (no room for another output).
69
+ lines.push(` IF @AMOUNT GT SHARE${k} THEN`);
70
+ lines.push(` RETURN VERIFYOUT(@INPUT @ADDRESS @AMOUNT SUB SHARE${k} @TOKENID TRUE)`);
71
+ lines.push(' ENDIF');
72
+ lines.push(' RETURN TRUE');
73
+ lines.push(' ENDIF');
74
+ lines.push(' ENDIF');
75
+ });
76
+ lines.push('ENDIF');
77
+ lines.push('ASSERT EPOCH GT PREVSTATE(101)');
78
+ lines.push('ASSERT SAMESTATE(102 102)');
79
+ lines.push('ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)');
80
+ lines.push(`RETURN MULTISIG(${holders.length + 1} ${operator} ${holders.join(' ')})`);
81
+ return lines.join('\n');
53
82
  }
54
83
  function poolScriptAddress(script) {
55
84
  return (0, core_1.computeScriptAddress)(script);
package/dist/exit-tx.d.ts CHANGED
@@ -1,21 +1,20 @@
1
1
  /**
2
- * VTXO exit transaction (RFC-038 V2 — owner-unilateral).
2
+ * VTXO exit transaction (RFC-038 V3 — per-share, owner-signed).
3
3
  *
4
- * The exit spends the pool's on-chain coin and pays the VTXO's owner, carrying
5
- * the exit delay in STATE(110). It is signed with the **owner's** key (not the
6
- * operator's): the pool script's `IF @BLOCK GT EXITBLOCK THEN RETURN
7
- * SIGNEDBY(OWNER)` branch authorizes it after the exit window, so the owner can
8
- * broadcast it without any operator signature or liveness. The digest is signed
9
- * (injected signer) and, when a chain provider is supplied, mined + broadcast
10
- * (injected miner).
4
+ * The exit spends the pool's on-chain coin and pays the exiting holder **only
5
+ * its committed share** (`shares[holderIndex]`), returning the remainder to the
6
+ * pool with that holder's share state zeroed. It is signed with the holder's key
7
+ * — the pool script's `IF @BLOCK GT EXITBLOCK … IF SIGNEDBY(holder) … VERIFYOUT(0
8
+ * holder SHARE @TOKENID FALSE)` branch authorizes it, so the holder can broadcast
9
+ * without any operator signature or liveness, and cannot take more than its share.
11
10
  *
12
- * The caller must pass the owner signer; the operator cannot construct a valid
13
- * exit witness for itself.
11
+ * The caller must pass the holder signer; neither the operator nor another holder
12
+ * can build a valid witness for this holder's share.
14
13
  */
15
14
  import { type OmniaTxDraft } from '@totemsdk/omnia';
16
15
  import type { ChainStateProvider } from '@totemsdk/chain-provider';
17
16
  import type { OmniaVtxo } from './types.js';
18
- /** State port carrying the exit delay on the owner's output. */
17
+ /** State port carrying an optional exit delay on the holder's output. */
19
18
  export declare const EXIT_DELAY_PORT = 110;
20
19
  export interface ExitTxParams {
21
20
  vtxo: OmniaVtxo;
@@ -23,12 +22,19 @@ export interface ExitTxParams {
23
22
  fundingCoinId: string;
24
23
  fundingAddress: string;
25
24
  fundingScript: string;
26
- /** Raw base-unit amount to pay the owner (the VTXO amount, pre-scaled). */
25
+ /** Total pool amount (raw base units). */
27
26
  amount: bigint;
28
- /** Exit delay carried as STATE(102). */
29
- exitDelayBlocks: number;
27
+ /** Pool holders + committed shares (aligned arrays). */
28
+ holders: string[];
29
+ shares: bigint[];
30
+ /** Index of the exiting holder (must match `vtxo.owner`). */
31
+ holderIndex: number;
32
+ /** Pool state, needed to rebuild the remainder output's state. */
33
+ root: string;
34
+ epoch: number;
35
+ exitBlock: number;
30
36
  }
31
- /** Draft that spends the pool coin to the VTXO owner with the exit delay encoded. */
37
+ /** Draft that spends the pool coin: output 0 = holder's share, remainder = pool. */
32
38
  export declare function buildExitTransactionDraft(params: ExitTxParams): OmniaTxDraft;
33
39
  export declare function exitTransactionDigest(draft: OmniaTxDraft): Uint8Array;
34
40
  export declare function exitTransactionHex(draft: OmniaTxDraft): string;
@@ -44,14 +50,13 @@ export interface ExitTxDeps {
44
50
  export interface ExitTxResult {
45
51
  vtxoId: string;
46
52
  owner: string;
47
- amount: string;
48
- exitDelayBlocks: number;
53
+ share: string;
49
54
  draftType: 'vtxo-exit';
50
55
  txHex: string;
51
56
  digest: string;
52
57
  witnessHex: string;
53
58
  txpowId?: string;
54
59
  }
55
- /** Build, sign (and optionally mine + broadcast) a VTXO exit transaction. */
60
+ /** Build, sign (and optionally mine + broadcast) a per-share VTXO exit transaction. */
56
61
  export declare function buildExitTransaction(params: ExitTxParams, deps: ExitTxDeps): Promise<ExitTxResult>;
57
62
  export {};
package/dist/exit-tx.js CHANGED
@@ -1,27 +1,47 @@
1
1
  /**
2
- * VTXO exit transaction (RFC-038 V2 — owner-unilateral).
2
+ * VTXO exit transaction (RFC-038 V3 — per-share, owner-signed).
3
3
  *
4
- * The exit spends the pool's on-chain coin and pays the VTXO's owner, carrying
5
- * the exit delay in STATE(110). It is signed with the **owner's** key (not the
6
- * operator's): the pool script's `IF @BLOCK GT EXITBLOCK THEN RETURN
7
- * SIGNEDBY(OWNER)` branch authorizes it after the exit window, so the owner can
8
- * broadcast it without any operator signature or liveness. The digest is signed
9
- * (injected signer) and, when a chain provider is supplied, mined + broadcast
10
- * (injected miner).
4
+ * The exit spends the pool's on-chain coin and pays the exiting holder **only
5
+ * its committed share** (`shares[holderIndex]`), returning the remainder to the
6
+ * pool with that holder's share state zeroed. It is signed with the holder's key
7
+ * — the pool script's `IF @BLOCK GT EXITBLOCK … IF SIGNEDBY(holder) … VERIFYOUT(0
8
+ * holder SHARE @TOKENID FALSE)` branch authorizes it, so the holder can broadcast
9
+ * without any operator signature or liveness, and cannot take more than its share.
11
10
  *
12
- * The caller must pass the owner signer; the operator cannot construct a valid
13
- * exit witness for itself.
11
+ * The caller must pass the holder signer; neither the operator nor another holder
12
+ * can build a valid witness for this holder's share.
14
13
  */
15
14
  import { computeOmniaTxDigest, omniaDraftToMinimaBytes, serializeTxDraft, } from '@totemsdk/omnia';
16
15
  import { serializeTxBody, mineTxPoW, TX_POW_MIN_DIFFICULTY } from '@totemsdk/txpow';
17
16
  import { concatBytes } from '@totemsdk/core';
18
- /** State port carrying the exit delay on the owner's output. */
17
+ import { poolStateVariables } from './anchor.js';
18
+ /** State port carrying an optional exit delay on the holder's output. */
19
19
  export const EXIT_DELAY_PORT = 110;
20
- /** Draft that spends the pool coin to the VTXO owner with the exit delay encoded. */
20
+ /** Draft that spends the pool coin: output 0 = holder's share, remainder = pool. */
21
21
  export function buildExitTransactionDraft(params) {
22
- const stateVariables = [
23
- { port: EXIT_DELAY_PORT, value: BigInt(params.exitDelayBlocks), type: 'number' },
24
- ];
22
+ const share = params.shares[params.holderIndex];
23
+ if (share === undefined)
24
+ throw new Error('exit: holderIndex out of range');
25
+ if (share <= 0n)
26
+ throw new Error('exit: holder share must be positive');
27
+ const outputs = [{
28
+ address: params.vtxo.owner,
29
+ amount: share,
30
+ tokenId: params.vtxo.tokenId,
31
+ storeState: false,
32
+ stateVariables: [],
33
+ }];
34
+ const carriesState = params.amount > share;
35
+ if (carriesState) {
36
+ const remaining = params.shares.map((s, i) => (i === params.holderIndex ? 0n : s));
37
+ outputs.push({
38
+ address: params.fundingAddress,
39
+ amount: params.amount - share,
40
+ tokenId: params.vtxo.tokenId,
41
+ storeState: true,
42
+ stateVariables: poolStateVariables(params.root, params.epoch, params.exitBlock, remaining),
43
+ });
44
+ }
25
45
  return {
26
46
  type: 'settlement',
27
47
  inputs: [{
@@ -31,15 +51,9 @@ export function buildExitTransactionDraft(params) {
31
51
  tokenId: params.vtxo.tokenId,
32
52
  scriptHex: params.fundingScript,
33
53
  }],
34
- outputs: [{
35
- address: params.vtxo.owner,
36
- amount: params.amount,
37
- tokenId: params.vtxo.tokenId,
38
- storeState: false,
39
- stateVariables,
40
- }],
41
- storeState: false,
42
- stateVariables,
54
+ outputs,
55
+ storeState: carriesState,
56
+ stateVariables: [],
43
57
  };
44
58
  }
45
59
  export function exitTransactionDigest(draft) {
@@ -48,7 +62,7 @@ export function exitTransactionDigest(draft) {
48
62
  export function exitTransactionHex(draft) {
49
63
  return serializeTxDraft(draft);
50
64
  }
51
- /** Build, sign (and optionally mine + broadcast) a VTXO exit transaction. */
65
+ /** Build, sign (and optionally mine + broadcast) a per-share VTXO exit transaction. */
52
66
  export async function buildExitTransaction(params, deps) {
53
67
  const draft = buildExitTransactionDraft(params);
54
68
  const digest = exitTransactionDigest(draft);
@@ -56,8 +70,7 @@ export async function buildExitTransaction(params, deps) {
56
70
  const result = {
57
71
  vtxoId: params.vtxo.vtxoId,
58
72
  owner: params.vtxo.owner,
59
- amount: params.vtxo.amount.toString(),
60
- exitDelayBlocks: params.exitDelayBlocks,
73
+ share: params.shares[params.holderIndex].toString(),
61
74
  draftType: 'vtxo-exit',
62
75
  txHex: exitTransactionHex(draft),
63
76
  digest: Buffer.from(digest).toString('hex'),
@@ -1,33 +1,37 @@
1
1
  /**
2
- * VTXO pool on-chain script (RFC-038 V2 — non-custodial).
2
+ * VTXO pool on-chain script (RFC-038 V3 — per-share non-custodial).
3
3
  *
4
4
  * The pool is an on-chain state output holding `totalCapacity`. An epoch's batch
5
- * root is committed as STATE(100), the epoch number in STATE(101), and the
6
- * owner's absolute exit-eligibility block in STATE(102).
5
+ * root is committed as STATE(100), the epoch number in STATE(101), the absolute
6
+ * exit-eligibility block in STATE(102), and each holder's committed share in
7
+ * STATE(300+k).
7
8
  *
8
- * Custody (RFC-044 / CUSTODY-POLICY §2):
9
- * - **Unilateral owner exit.** After `@BLOCK GT EXITBLOCK` the owner alone may
10
- * spend (`RETURN SIGNEDBY(OWNER)`) — no operator signature or liveness. This
11
- * is exercised by the pre-signed exit tx (`exit-tx.ts`).
9
+ * Custody (RFC-039 / CUSTODY-POLICY §2):
10
+ * - **Per-share unilateral exit.** After `@BLOCK GT EXITBLOCK` each holder may
11
+ * withdraw **only its own committed share** (`STATE(300+k)`), to its own key,
12
+ * zeroing that share and returning the remainder to the pool. A holder cannot
13
+ * pay itself more than its share, so one holder can never rug the others.
12
14
  * - **Cooperative update.** Before the exit window the pool may only move by
13
- * `MULTISIG(2 OPERATOR OWNER)`, epoch-monotone (`ASSERT EPOCH GT
15
+ * `MULTISIG(operator + all holders)`, epoch-monotone (`ASSERT EPOCH GT
14
16
  * PREVSTATE(101)`), with the exit block immutable (`ASSERT SAMESTATE(102
15
- * 102)`) so the operator can never push the owner's escape clock, and the
16
- * value confined to the same script address (`ASSERT VERIFYOUT(@INPUT
17
- * @ADDRESS @AMOUNT @TOKENID TRUE)`) so the operator can never pay itself.
17
+ * 102)`) so no one can push the escape clock, and value confined to the same
18
+ * script address (`ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)`)
19
+ * so the operator can never pay itself.
18
20
  *
19
- * The operator holds no unilateral path: it cannot move funds, cannot advance
20
- * the exit block, and cannot stop the owner's exit. It is a liveness-only peer.
21
+ * The operator holds no unilateral path: it cannot move funds, cannot advance the
22
+ * exit block, and cannot stop a holder's exit. It is a liveness-only peer.
21
23
  */
24
+ /** State port base for per-holder shares: holder k ⇒ port 200+k (ports are bytes, ≤255). */
25
+ export declare const POOL_SHARE_PORT_BASE = 200;
22
26
  export interface PoolScriptParams {
23
27
  /** Operator WOTS public-key digest (64 hex). */
24
28
  operatorPublicKeyDigest: string;
25
- /** Pool owner WOTS public-key digest (64 hex). */
26
- ownerPublicKeyDigest: string;
27
- /** Absolute block height after which the owner may exit unilaterally. */
29
+ /** Holder WOTS public-key digests (64 hex), one per beneficial owner. */
30
+ holders: string[];
31
+ /** Absolute block height after which holders may exit unilaterally. */
28
32
  exitBlock: number;
29
33
  }
30
- /** Non-custodial, epoch-monotone, owner-escapable state-carrying pool script. */
34
+ /** Per-share-constrained, epoch-monotone, state-carrying pool script. */
31
35
  export declare function buildPoolScript(params: PoolScriptParams): string;
32
36
  export declare function poolScriptAddress(script: string): string;
33
37
  export declare function buildAndHashPoolScript(params: PoolScriptParams): {
@@ -1,25 +1,29 @@
1
1
  /**
2
- * VTXO pool on-chain script (RFC-038 V2 — non-custodial).
2
+ * VTXO pool on-chain script (RFC-038 V3 — per-share non-custodial).
3
3
  *
4
4
  * The pool is an on-chain state output holding `totalCapacity`. An epoch's batch
5
- * root is committed as STATE(100), the epoch number in STATE(101), and the
6
- * owner's absolute exit-eligibility block in STATE(102).
5
+ * root is committed as STATE(100), the epoch number in STATE(101), the absolute
6
+ * exit-eligibility block in STATE(102), and each holder's committed share in
7
+ * STATE(300+k).
7
8
  *
8
- * Custody (RFC-044 / CUSTODY-POLICY §2):
9
- * - **Unilateral owner exit.** After `@BLOCK GT EXITBLOCK` the owner alone may
10
- * spend (`RETURN SIGNEDBY(OWNER)`) — no operator signature or liveness. This
11
- * is exercised by the pre-signed exit tx (`exit-tx.ts`).
9
+ * Custody (RFC-039 / CUSTODY-POLICY §2):
10
+ * - **Per-share unilateral exit.** After `@BLOCK GT EXITBLOCK` each holder may
11
+ * withdraw **only its own committed share** (`STATE(300+k)`), to its own key,
12
+ * zeroing that share and returning the remainder to the pool. A holder cannot
13
+ * pay itself more than its share, so one holder can never rug the others.
12
14
  * - **Cooperative update.** Before the exit window the pool may only move by
13
- * `MULTISIG(2 OPERATOR OWNER)`, epoch-monotone (`ASSERT EPOCH GT
15
+ * `MULTISIG(operator + all holders)`, epoch-monotone (`ASSERT EPOCH GT
14
16
  * PREVSTATE(101)`), with the exit block immutable (`ASSERT SAMESTATE(102
15
- * 102)`) so the operator can never push the owner's escape clock, and the
16
- * value confined to the same script address (`ASSERT VERIFYOUT(@INPUT
17
- * @ADDRESS @AMOUNT @TOKENID TRUE)`) so the operator can never pay itself.
17
+ * 102)`) so no one can push the escape clock, and value confined to the same
18
+ * script address (`ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)`)
19
+ * so the operator can never pay itself.
18
20
  *
19
- * The operator holds no unilateral path: it cannot move funds, cannot advance
20
- * the exit block, and cannot stop the owner's exit. It is a liveness-only peer.
21
+ * The operator holds no unilateral path: it cannot move funds, cannot advance the
22
+ * exit block, and cannot stop a holder's exit. It is a liveness-only peer.
21
23
  */
22
24
  import { computeScriptAddress } from '@totemsdk/core';
25
+ /** State port base for per-holder shares: holder k ⇒ port 200+k (ports are bytes, ≤255). */
26
+ export const POOL_SHARE_PORT_BASE = 200;
23
27
  function pkHex(digest, label) {
24
28
  const raw = digest.replace(/^0x/i, '');
25
29
  if (!/^[0-9a-fA-F]{64}$/.test(raw)) {
@@ -27,24 +31,48 @@ function pkHex(digest, label) {
27
31
  }
28
32
  return '0X' + raw.toUpperCase();
29
33
  }
30
- /** Non-custodial, epoch-monotone, owner-escapable state-carrying pool script. */
34
+ /** Per-share-constrained, epoch-monotone, state-carrying pool script. */
31
35
  export function buildPoolScript(params) {
32
- const owner = pkHex(params.ownerPublicKeyDigest, 'owner');
33
36
  const operator = pkHex(params.operatorPublicKeyDigest, 'operator');
37
+ if (!Array.isArray(params.holders) || params.holders.length < 1) {
38
+ throw new Error('pool requires at least one holder');
39
+ }
40
+ const holders = params.holders.map((h, i) => pkHex(h, `holder[${i}]`));
34
41
  if (!Number.isInteger(params.exitBlock) || params.exitBlock < 0) {
35
42
  throw new Error(`exitBlock must be a non-negative integer, got ${JSON.stringify(params.exitBlock)}`);
36
43
  }
37
- return [
44
+ const lines = [
38
45
  'LET EPOCH=STATE(101)',
39
46
  'LET EXITBLOCK=STATE(102)',
40
47
  'IF @BLOCK GT EXITBLOCK THEN',
41
- ` RETURN SIGNEDBY(${owner})`,
42
- 'ENDIF',
43
- 'ASSERT EPOCH GT PREVSTATE(101)',
44
- 'ASSERT SAMESTATE(102 102)',
45
- 'ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)',
46
- `RETURN MULTISIG(2 ${operator} ${owner})`,
47
- ].join('\n');
48
+ ];
49
+ holders.forEach((holder, k) => {
50
+ const port = POOL_SHARE_PORT_BASE + k;
51
+ lines.push(` LET SHARE${k}=STATE(${port})`);
52
+ lines.push(` IF SIGNEDBY(${holder}) THEN`);
53
+ lines.push(` IF SHARE${k} GT 0 THEN`);
54
+ lines.push(` ASSERT VERIFYOUT(0 ${holder} SHARE${k} @TOKENID FALSE)`);
55
+ for (let j = 0; j < holders.length; j++) {
56
+ if (j === k)
57
+ continue;
58
+ lines.push(` ASSERT STATE(${POOL_SHARE_PORT_BASE + j}) EQ PREVSTATE(${POOL_SHARE_PORT_BASE + j})`);
59
+ }
60
+ lines.push(` ASSERT STATE(${port}) EQ 0`);
61
+ // Remainder (other holders' shares) stays in the pool; skip it when the
62
+ // withdrawing holder's share is the whole pool (no room for another output).
63
+ lines.push(` IF @AMOUNT GT SHARE${k} THEN`);
64
+ lines.push(` RETURN VERIFYOUT(@INPUT @ADDRESS @AMOUNT SUB SHARE${k} @TOKENID TRUE)`);
65
+ lines.push(' ENDIF');
66
+ lines.push(' RETURN TRUE');
67
+ lines.push(' ENDIF');
68
+ lines.push(' ENDIF');
69
+ });
70
+ lines.push('ENDIF');
71
+ lines.push('ASSERT EPOCH GT PREVSTATE(101)');
72
+ lines.push('ASSERT SAMESTATE(102 102)');
73
+ lines.push('ASSERT VERIFYOUT(@INPUT @ADDRESS @AMOUNT @TOKENID TRUE)');
74
+ lines.push(`RETURN MULTISIG(${holders.length + 1} ${operator} ${holders.join(' ')})`);
75
+ return lines.join('\n');
48
76
  }
49
77
  export function poolScriptAddress(script) {
50
78
  return computeScriptAddress(script);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totemsdk/omnia-vtxo",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Virtual UTXO / payment-pool claim layer for Omnia — cash-like off-chain balance primitive for Totem Edge",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/cjs/index.d.ts",
@@ -25,9 +25,9 @@
25
25
  ],
26
26
  "dependencies": {
27
27
  "@totemsdk/chain-provider": "^0.2.1",
28
- "@totemsdk/omnia": "^2.0.0",
29
- "@totemsdk/storage": "^0.1.0",
28
+ "@totemsdk/omnia": "^2.0.1",
30
29
  "@totemsdk/txpow": "^1.0.2",
30
+ "@totemsdk/storage": "^0.1.0",
31
31
  "@totemsdk/core": "^1.2.11",
32
32
  "@totemsdk/wots-lease": "^1.0.1"
33
33
  },