@misofm/sdk 0.15.10 → 0.16.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.
Files changed (145) hide show
  1. package/README.md +153 -56
  2. package/dist/client.d.ts +175 -47
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +302 -47
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.d.ts +11 -11
  7. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.d.ts.map +1 -1
  8. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.js +9 -9
  9. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.js.map +1 -1
  10. package/dist/contracts/miso_record/deps/std/type_name.d.ts.map +1 -0
  11. package/dist/contracts/miso_record/deps/std/type_name.js.map +1 -0
  12. package/dist/contracts/miso_record/deps/sui/vec_set.d.ts +21 -0
  13. package/dist/contracts/miso_record/deps/sui/vec_set.d.ts.map +1 -0
  14. package/dist/contracts/miso_record/deps/sui/vec_set.js +20 -0
  15. package/dist/contracts/miso_record/deps/sui/vec_set.js.map +1 -0
  16. package/dist/contracts/miso_record/pressing.d.ts +327 -0
  17. package/dist/contracts/miso_record/pressing.d.ts.map +1 -0
  18. package/dist/contracts/miso_record/pressing.js +345 -0
  19. package/dist/contracts/miso_record/pressing.js.map +1 -0
  20. package/dist/contracts/miso_record/record.d.ts +190 -0
  21. package/dist/contracts/miso_record/record.d.ts.map +1 -0
  22. package/dist/contracts/miso_record/record.js +226 -0
  23. package/dist/contracts/miso_record/record.js.map +1 -0
  24. package/dist/contracts/miso_record_shop/deps/std/type_name.d.ts +18 -0
  25. package/dist/contracts/miso_record_shop/deps/std/type_name.d.ts.map +1 -0
  26. package/dist/contracts/miso_record_shop/deps/std/type_name.js +20 -0
  27. package/dist/contracts/miso_record_shop/deps/std/type_name.js.map +1 -0
  28. package/dist/contracts/miso_record_shop/listing.d.ts +387 -0
  29. package/dist/contracts/miso_record_shop/listing.d.ts.map +1 -0
  30. package/dist/contracts/miso_record_shop/listing.js +380 -0
  31. package/dist/contracts/miso_record_shop/listing.js.map +1 -0
  32. package/dist/contracts/miso_record_shop/witness.d.ts +7 -0
  33. package/dist/contracts/miso_record_shop/witness.d.ts.map +1 -0
  34. package/dist/contracts/miso_record_shop/witness.js +9 -0
  35. package/dist/contracts/miso_record_shop/witness.js.map +1 -0
  36. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.d.ts +10 -12
  37. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.d.ts.map +1 -1
  38. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.js +8 -10
  39. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.js.map +1 -1
  40. package/dist/contracts/vault/vault.d.ts +149 -23
  41. package/dist/contracts/vault/vault.d.ts.map +1 -1
  42. package/dist/contracts/vault/vault.js +144 -18
  43. package/dist/contracts/vault/vault.js.map +1 -1
  44. package/dist/contracts.d.ts +3 -3
  45. package/dist/contracts.d.ts.map +1 -1
  46. package/dist/contracts.js +5 -4
  47. package/dist/contracts.js.map +1 -1
  48. package/dist/deployments.d.ts +47 -11
  49. package/dist/deployments.d.ts.map +1 -1
  50. package/dist/deployments.js +48 -9
  51. package/dist/deployments.js.map +1 -1
  52. package/dist/index.d.ts +2 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +2 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/mix.d.ts +144 -0
  57. package/dist/mix.d.ts.map +1 -0
  58. package/dist/mix.js +656 -0
  59. package/dist/mix.js.map +1 -0
  60. package/dist/pressing.d.ts +72 -156
  61. package/dist/pressing.d.ts.map +1 -1
  62. package/dist/pressing.js +269 -261
  63. package/dist/pressing.js.map +1 -1
  64. package/dist/publication.d.ts +5 -2
  65. package/dist/publication.d.ts.map +1 -1
  66. package/dist/publication.js +63 -34
  67. package/dist/publication.js.map +1 -1
  68. package/dist/read/catalog.d.ts +8 -5
  69. package/dist/read/catalog.d.ts.map +1 -1
  70. package/dist/read/catalog.js +47 -35
  71. package/dist/read/catalog.js.map +1 -1
  72. package/dist/read/config.d.ts +6 -4
  73. package/dist/read/config.d.ts.map +1 -1
  74. package/dist/read/config.js +1 -2
  75. package/dist/read/config.js.map +1 -1
  76. package/dist/read/index.d.ts +1 -1
  77. package/dist/read/index.d.ts.map +1 -1
  78. package/dist/read/index.js +1 -1
  79. package/dist/read/index.js.map +1 -1
  80. package/dist/read/internal/scalars.d.ts.map +1 -1
  81. package/dist/read/internal/scalars.js +4 -3
  82. package/dist/read/internal/scalars.js.map +1 -1
  83. package/dist/read/internal/walrus.d.ts.map +1 -1
  84. package/dist/read/internal/walrus.js +2 -1
  85. package/dist/read/internal/walrus.js.map +1 -1
  86. package/dist/read/receipts.d.ts +21 -12
  87. package/dist/read/receipts.d.ts.map +1 -1
  88. package/dist/read/receipts.js +159 -56
  89. package/dist/read/receipts.js.map +1 -1
  90. package/dist/read/types.d.ts +40 -26
  91. package/dist/read/types.d.ts.map +1 -1
  92. package/dist/read/wallet.d.ts +3 -4
  93. package/dist/read/wallet.d.ts.map +1 -1
  94. package/dist/read/wallet.js +72 -53
  95. package/dist/read/wallet.js.map +1 -1
  96. package/dist/vault.d.ts +71 -15
  97. package/dist/vault.d.ts.map +1 -1
  98. package/dist/vault.js +135 -29
  99. package/dist/vault.js.map +1 -1
  100. package/package.json +10 -3
  101. package/src/client.ts +404 -69
  102. package/src/contracts/composition_royalty_pool/composition_royalty_pool.ts +15 -15
  103. package/src/contracts/miso_record/deps/sui/vec_set.ts +21 -0
  104. package/src/contracts/miso_record/pressing.ts +522 -0
  105. package/src/contracts/miso_record/record.ts +338 -0
  106. package/src/contracts/miso_record_shop/deps/std/type_name.ts +22 -0
  107. package/src/contracts/miso_record_shop/listing.ts +602 -0
  108. package/src/contracts/miso_record_shop/witness.ts +11 -0
  109. package/src/contracts/recording_royalty_pool/recording_royalty_pool.ts +14 -16
  110. package/src/contracts/vault/vault.ts +226 -21
  111. package/src/contracts.ts +5 -4
  112. package/src/deployments.ts +134 -38
  113. package/src/index.ts +2 -0
  114. package/src/mix.ts +910 -0
  115. package/src/pressing.ts +428 -423
  116. package/src/publication.ts +69 -36
  117. package/src/read/catalog.ts +49 -34
  118. package/src/read/config.ts +7 -7
  119. package/src/read/index.ts +9 -1
  120. package/src/read/internal/scalars.ts +4 -2
  121. package/src/read/internal/walrus.ts +2 -1
  122. package/src/read/receipts.ts +181 -66
  123. package/src/read/types.ts +41 -24
  124. package/src/read/wallet.ts +70 -57
  125. package/src/vault.ts +228 -41
  126. package/dist/contracts/miso_pressing/certificate.d.ts +0 -89
  127. package/dist/contracts/miso_pressing/certificate.d.ts.map +0 -1
  128. package/dist/contracts/miso_pressing/certificate.js +0 -108
  129. package/dist/contracts/miso_pressing/certificate.js.map +0 -1
  130. package/dist/contracts/miso_pressing/deps/std/type_name.d.ts.map +0 -1
  131. package/dist/contracts/miso_pressing/deps/std/type_name.js.map +0 -1
  132. package/dist/contracts/miso_pressing/listing.d.ts +0 -434
  133. package/dist/contracts/miso_pressing/listing.d.ts.map +0 -1
  134. package/dist/contracts/miso_pressing/listing.js +0 -401
  135. package/dist/contracts/miso_pressing/listing.js.map +0 -1
  136. package/dist/contracts/miso_pressing/pressing.d.ts +0 -334
  137. package/dist/contracts/miso_pressing/pressing.d.ts.map +0 -1
  138. package/dist/contracts/miso_pressing/pressing.js +0 -298
  139. package/dist/contracts/miso_pressing/pressing.js.map +0 -1
  140. package/src/contracts/miso_pressing/certificate.ts +0 -164
  141. package/src/contracts/miso_pressing/listing.ts +0 -592
  142. package/src/contracts/miso_pressing/pressing.ts +0 -399
  143. /package/dist/contracts/{miso_pressing → miso_record}/deps/std/type_name.d.ts +0 -0
  144. /package/dist/contracts/{miso_pressing → miso_record}/deps/std/type_name.js +0 -0
  145. /package/src/contracts/{miso_pressing → miso_record}/deps/std/type_name.ts +0 -0
@@ -22,6 +22,9 @@ import {
22
22
  import type { MisoClient } from "./client.ts";
23
23
  import { int, u64 } from "./internal/scalars.ts";
24
24
  import * as vaultContract from "../contracts/vault/vault.ts";
25
+ import * as recordContract from "../contracts/miso_record/record.ts";
26
+ import { deriveRecordId } from "../pressing.ts";
27
+ import { requireRecordSalesDeployment } from "../deployments.ts";
25
28
  import type {
26
29
  Balance,
27
30
  OwnedParty,
@@ -125,29 +128,14 @@ export function classifyVaultedWorkAdminCapType(
125
128
 
126
129
  // ── Records ──────────────────────────────────────────────────────────────────
127
130
 
128
- function coerceNumber(v: unknown): number | null {
129
- if (typeof v === "number" && Number.isFinite(v)) return v;
130
- if (typeof v === "bigint") return Number(v);
131
- if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))) return Number(v);
132
- return null;
133
- }
134
-
135
- function record(value: unknown): Record<string, unknown> | null {
136
- return typeof value === "object" && value !== null && !Array.isArray(value)
137
- ? (value as Record<string, unknown>)
138
- : null;
139
- }
140
-
141
131
  /**
142
- * A wallet record is trusted only when both halves of its concrete type are the
143
- * currently configured protocol packages. Checking the parsed tag (rather than
144
- * a prefix/suffix) rejects retired namespaces, extra type parameters, and an
145
- * arbitrary certificate that anyone can use with `record::new`.
132
+ * A wallet record is trusted only when it is the exact, non-generic Record type
133
+ * from the configured package. Checking the parsed tag (rather than a prefix or
134
+ * suffix) rejects retired namespaces and legacy/arbitrary generic wrappers.
146
135
  */
147
136
  function isCanonicalRecordType(
148
137
  type: string,
149
138
  recordPackageId: string,
150
- pressingPackageId: string,
151
139
  ): boolean {
152
140
  let tag: ReturnType<typeof parseStructTag>;
153
141
  try {
@@ -160,34 +148,11 @@ function isCanonicalRecordType(
160
148
  tag.address !== normalizeSuiAddress(recordPackageId) ||
161
149
  tag.module !== "record" ||
162
150
  tag.name !== "Record" ||
163
- tag.typeParams.length !== 1
151
+ tag.typeParams.length !== 0
164
152
  ) {
165
153
  return false;
166
154
  }
167
-
168
- const certificate = tag.typeParams[0];
169
- return (
170
- certificate !== undefined &&
171
- typeof certificate !== "string" &&
172
- certificate.address === normalizeSuiAddress(pressingPackageId) &&
173
- certificate.module === "certificate" &&
174
- certificate.name === "Certificate" &&
175
- certificate.typeParams.length === 0
176
- );
177
- }
178
-
179
- /**
180
- * This copy's number in its pressing run. The current Record keeps issuance
181
- * details inside its embedded Certificate, so the canonical JSON shape is
182
- * `{ release_id, certificate: { number } }`.
183
- */
184
- function readRecordNumber(json: Record<string, unknown>): number | null {
185
- return coerceNumber(record(json.certificate)?.number);
186
- }
187
-
188
- function readReleaseId(json: Record<string, unknown>): string | null {
189
- const r = json.release_id;
190
- return typeof r === "string" && r ? r : null;
155
+ return true;
191
156
  }
192
157
 
193
158
  /**
@@ -199,8 +164,8 @@ function readReleaseId(json: Record<string, unknown>): string | null {
199
164
  export async function getOwnedRecords(client: MisoClient, owner: string): Promise<OwnedRecord[]> {
200
165
  const out: OwnedRecord[] = [];
201
166
  let cursor: string | null = null;
202
- const recordType = `${client.config.protocol.record}::record::Record`;
203
- const pressingPackageId = client.config.protocol.pressing;
167
+ const sales = requireRecordSalesDeployment(client.config.recordSales);
168
+ const recordType = `${sales.recordPackageId}::record::Record`;
204
169
 
205
170
  for (let page = 0; page < MAX_PAGES; page++) {
206
171
  // Annotated: `cursor` is both an input and assigned from the result, which
@@ -211,18 +176,32 @@ export async function getOwnedRecords(client: MisoClient, owner: string): Promis
211
176
  type: recordType,
212
177
  cursor,
213
178
  limit: 50,
214
- include: { json: true },
179
+ include: { content: true },
215
180
  });
216
181
  for (const obj of res.objects) {
217
- if (!isCanonicalRecordType(obj.type, client.config.protocol.record, pressingPackageId)) {
182
+ if (!isCanonicalRecordType(obj.type, sales.recordPackageId)) {
218
183
  continue;
219
184
  }
220
- const json = (obj.json ?? {}) as Record<string, unknown>;
185
+ if (!obj.content) throw new Error(`Record ${obj.objectId} has no BCS content`);
186
+ const record = recordContract.Record.parse(obj.content);
187
+ if (normalizeSuiAddress(record.id) !== normalizeSuiAddress(obj.objectId)) {
188
+ throw new Error(`Record ${obj.objectId} has mismatched embedded UID ${record.id}`);
189
+ }
190
+ const derived = deriveRecordId(record.pressing_id, record.number, sales.recordPackageId);
191
+ if (normalizeSuiAddress(derived) !== normalizeSuiAddress(obj.objectId)) {
192
+ throw new Error(`Record ${obj.objectId} is not derived from its Pressing and number`);
193
+ }
221
194
  out.push({
222
195
  id: obj.objectId,
223
196
  type: obj.type,
224
- releaseId: readReleaseId(json),
225
- number: readRecordNumber(json),
197
+ releaseId: record.release_id,
198
+ pressingId: record.pressing_id,
199
+ edition: record.edition,
200
+ number: record.number,
201
+ purchaseCurrency: normalizeStructTag(record.purchase_currency.name),
202
+ purchasePrice: record.purchase_price,
203
+ purchasedBy: record.purchased_by,
204
+ purchasedTimestampMs: record.purchased_timestamp_ms,
226
205
  });
227
206
  }
228
207
  if (!res.hasNextPage) break;
@@ -406,7 +385,7 @@ async function resolveVaultedReleaseCaps(
406
385
  const vault = vaultContract.Vault(networkContracts.release.ReleaseAdminCap).parse(
407
386
  object.content,
408
387
  );
409
- const releaseId = vault.cap.value?.release_id;
388
+ const releaseId = vault.cap?.value?.release_id;
410
389
  if (releaseId) releasesByVault.set(object.objectId, releaseId);
411
390
  } catch {
412
391
  // Batch catalog discovery is best-effort per authority, matching the
@@ -615,20 +594,54 @@ export async function getWorkByCap(client: MisoClient, capId: string): Promise<W
615
594
 
616
595
  // ── Balance ──────────────────────────────────────────────────────────────────
617
596
 
597
+ const decimalsByClient = new WeakMap<MisoClient, Map<string, Promise<number>>>();
598
+
599
+ /** Resolve once per client/type. Failed lookups are evicted so a transient
600
+ * fullnode error cannot poison a long-lived API worker. */
601
+ async function coinDecimals(client: MisoClient, coinType: string): Promise<number> {
602
+ let cache = decimalsByClient.get(client);
603
+ if (!cache) {
604
+ cache = new Map();
605
+ decimalsByClient.set(client, cache);
606
+ }
607
+ const key = normalizeStructTag(coinType);
608
+ const cached = cache.get(key);
609
+ if (cached) return cached;
610
+
611
+ const pending = client.protocol.core.getCoinMetadata({ coinType: key }).then(({ coinMetadata }) => {
612
+ const decimals = coinMetadata?.decimals;
613
+ if (!Number.isSafeInteger(decimals) || decimals! < 0 || decimals! > 18) {
614
+ throw new Error(`Coin metadata for ${key} has no supported decimal precision`);
615
+ }
616
+ return decimals!;
617
+ });
618
+ cache.set(key, pending);
619
+ try {
620
+ return await pending;
621
+ } catch (error) {
622
+ if (cache.get(key) === pending) cache.delete(key);
623
+ throw error;
624
+ }
625
+ }
626
+
618
627
  /**
619
- * A wallet's spendable balance in one currency. `core.getBalance` totals coin
620
- * OBJECTS and the address balance, so funds that arrived either way are counted —
621
- * which matters because `balance::send_funds` (how the app transfers dollars)
622
- * credits the address balance, not a coin.
628
+ * A wallet's balance in one currency. Keep the aggregate and both Sui storage
629
+ * classes: callers using a `FundsWithdrawal` must never mistake coin-object
630
+ * value for immediately withdrawable address balance.
623
631
  */
624
632
  export async function getBalance(client: MisoClient, address: string, coinType?: string): Promise<Balance> {
625
633
  const type = coinType ?? client.config.money.usdCoinType;
626
- const res = await client.protocol.core.getBalance({ owner: address, coinType: type });
634
+ const [res, decimals] = await Promise.all([
635
+ client.protocol.core.getBalance({ owner: address, coinType: type }),
636
+ coinDecimals(client, type),
637
+ ]);
627
638
  return {
628
639
  address: normalizeSuiAddress(address),
629
640
  coinType: type,
630
641
  balance: u64(res.balance.balance),
631
- decimals: type === client.config.money.usdCoinType ? client.config.money.usdDecimals : 9,
642
+ coinBalance: u64(res.balance.coinBalance),
643
+ addressBalance: u64(res.balance.addressBalance),
644
+ decimals,
632
645
  };
633
646
  }
634
647
 
package/src/vault.ts CHANGED
@@ -17,7 +17,7 @@ import type {
17
17
  TransactionArgument,
18
18
  TransactionObjectArgument,
19
19
  } from "@mysten/sui/transactions";
20
- import { normalizeStructTag } from "@mysten/sui/utils";
20
+ import { deriveObjectID, normalizeStructTag } from "@mysten/sui/utils";
21
21
  import * as vault from "./contracts/vault/vault.ts";
22
22
  import * as compositionRoyaltyPool from "./contracts/composition_royalty_pool/composition_royalty_pool.ts";
23
23
  import * as recordingRoyaltyPool from "./contracts/recording_royalty_pool/recording_royalty_pool.ts";
@@ -30,6 +30,9 @@ import * as routedStake from "./contracts/routed_stake/routed_stake.ts";
30
30
  /** An object id resolved lazily when a transaction thunk is applied. */
31
31
  export type ObjectInput = string | TransactionObjectArgument;
32
32
 
33
+ /** The framework singleton read by `balance::settled_funds_value`. */
34
+ export const SUI_ACCUMULATOR_ROOT_OBJECT_ID = "0xacc";
35
+
33
36
  function object(tx: Transaction, value: ObjectInput): TransactionObjectArgument {
34
37
  return typeof value === "string" ? tx.object(value) : value;
35
38
  }
@@ -145,6 +148,8 @@ export function invokeWithAdminCap(
145
148
  export interface CustodyNewAdminCapParams {
146
149
  /** The freshly-created raw protocol cap, consumed into the Vault. */
147
150
  readonly adminCap: TransactionObjectArgument;
151
+ /** Shared singleton from which canonical Vault IDs are derived. */
152
+ readonly vaultRegistry: ObjectInput;
148
153
  readonly capType: string;
149
154
  readonly vaultPackageId: string;
150
155
  /** Recipient of the only owner-held authority: VaultAdminCap. */
@@ -162,6 +167,7 @@ export type AdminCapCustody =
162
167
  | {
163
168
  readonly kind: "vault";
164
169
  readonly owner: string | TransactionArgument;
170
+ readonly vaultRegistry: ObjectInput;
165
171
  readonly capType: string;
166
172
  readonly vaultPackageId: string;
167
173
  readonly configure?: CustodyNewAdminCapParams["configure"];
@@ -179,6 +185,7 @@ export function disposeNewAdminCap(
179
185
  }
180
186
  custodyNewAdminCap(tx, {
181
187
  adminCap,
188
+ vaultRegistry: custody.vaultRegistry,
182
189
  capType: custody.capType,
183
190
  vaultPackageId: custody.vaultPackageId,
184
191
  owner: custody.owner,
@@ -186,23 +193,60 @@ export function disposeNewAdminCap(
186
193
  });
187
194
  }
188
195
 
189
- /** Destroy a vault only while deliberately disposing of its returned raw cap. */
190
- export function destroyVault(
196
+ /** Withdraw the raw capability while leaving its canonical Vault shell intact. */
197
+ export function withdrawVaultCapability(
191
198
  tx: Transaction,
192
199
  params: {
193
200
  readonly vault: ObjectInput;
194
201
  readonly vaultAdminCap: ObjectInput;
195
202
  readonly capType: string;
196
203
  readonly vaultPackageId: string;
197
- readonly disposition: AdminCapCustody;
198
204
  },
199
- ): void {
200
- const cap = tx.add(vault.destroy({
205
+ ): TransactionObjectArgument {
206
+ return tx.add(vault.withdrawCap({
201
207
  package: params.vaultPackageId,
202
208
  typeArguments: [params.capType],
203
209
  arguments: [object(tx, params.vault), object(tx, params.vaultAdminCap)],
204
210
  }));
205
- disposeNewAdminCap(tx, cap, params.disposition);
211
+ }
212
+
213
+ /** Restore the one exact capability permanently assigned to a Vault. */
214
+ export function restoreVaultCapability(
215
+ tx: Transaction,
216
+ params: {
217
+ readonly vault: ObjectInput;
218
+ readonly vaultAdminCap: ObjectInput;
219
+ readonly adminCap: ObjectInput;
220
+ readonly capType: string;
221
+ readonly vaultPackageId: string;
222
+ },
223
+ ): void {
224
+ tx.add(vault.restoreCap({
225
+ package: params.vaultPackageId,
226
+ typeArguments: [params.capType],
227
+ arguments: [
228
+ object(tx, params.vault),
229
+ object(tx, params.vaultAdminCap),
230
+ object(tx, params.adminCap),
231
+ ],
232
+ }));
233
+ }
234
+
235
+ /** Transfer the key-only VaultAdminCap through the Vault module. */
236
+ export function transferVaultAdminCap(
237
+ tx: Transaction,
238
+ params: {
239
+ readonly vaultAdminCap: ObjectInput;
240
+ readonly owner: string | TransactionArgument;
241
+ readonly capType: string;
242
+ readonly vaultPackageId: string;
243
+ },
244
+ ): void {
245
+ tx.add(vault.transferAdminCap({
246
+ package: params.vaultPackageId,
247
+ typeArguments: [params.capType],
248
+ arguments: [object(tx, params.vaultAdminCap), params.owner],
249
+ }));
206
250
  }
207
251
 
208
252
  /**
@@ -217,7 +261,7 @@ export function custodyNewAdminCap(
217
261
  vault._new({
218
262
  package: params.vaultPackageId,
219
263
  typeArguments: [params.capType],
220
- arguments: [params.adminCap],
264
+ arguments: [object(tx, params.vaultRegistry), params.adminCap],
221
265
  }),
222
266
  );
223
267
  const vaultObject = requiredVaultResult(created, 0, "vault::_new");
@@ -230,7 +274,43 @@ export function custodyNewAdminCap(
230
274
  arguments: [vaultObject],
231
275
  }),
232
276
  );
233
- tx.transferObjects([vaultAdminCap], params.owner);
277
+ transferVaultAdminCap(tx, {
278
+ vaultAdminCap,
279
+ owner: params.owner,
280
+ capType: params.capType,
281
+ vaultPackageId: params.vaultPackageId,
282
+ });
283
+ }
284
+
285
+ export interface VaultIdParams {
286
+ readonly vaultRegistryId: string;
287
+ readonly capId: string;
288
+ readonly capType: string;
289
+ readonly vaultPackageId: string;
290
+ }
291
+
292
+ /** Derive the canonical Vault ID without an RPC lookup. */
293
+ export function deriveVaultId(params: VaultIdParams): string {
294
+ const keyType = normalizeStructTag(
295
+ `${params.vaultPackageId}::vault::VaultKey<${params.capType}>`,
296
+ );
297
+ return deriveObjectID(
298
+ params.vaultRegistryId,
299
+ keyType,
300
+ vault.VaultKey.serialize([params.capId]).toBytes(),
301
+ );
302
+ }
303
+
304
+ /** Derive the canonical VaultAdminCap ID from its Vault ID. */
305
+ export function deriveVaultAdminCapId(
306
+ vaultId: string,
307
+ vaultPackageId: string,
308
+ ): string {
309
+ return deriveObjectID(
310
+ vaultId,
311
+ `${vaultPackageId}::vault::VaultAdminCapKey`,
312
+ vault.VaultAdminCapKey.serialize([false]).toBytes(),
313
+ );
234
314
  }
235
315
 
236
316
  export interface CompositionRoyaltyPoolPluginParams {
@@ -299,7 +379,6 @@ export interface CompositionRoyaltyPoolCrankParams {
299
379
  readonly vault: TransactionObjectArgument;
300
380
  readonly composition: TransactionObjectArgument;
301
381
  readonly pool: TransactionObjectArgument;
302
- readonly accumulatorRoot: TransactionObjectArgument;
303
382
  readonly compositionShareType: string;
304
383
  readonly currencyType: string;
305
384
  readonly pluginPackageId: string;
@@ -308,6 +387,9 @@ export interface CompositionRoyaltyPoolCrankParams {
308
387
  /** JSON-safe input for an on-chain u64. Numbers are rejected to prevent rounding. */
309
388
  export type U64Input = bigint | string | number;
310
389
 
390
+ /** An exact scalar or the result of an earlier PTB command returning `u64`. */
391
+ export type U64Argument = U64Input | TransactionArgument;
392
+
311
393
  /** Validate an SDK scalar before serializing it as a Move u64. */
312
394
  export function asU64(name: string, value: U64Input): bigint {
313
395
  if (typeof value === "number" && (!Number.isSafeInteger(value) || value < 0)) {
@@ -323,20 +405,79 @@ export function asU64(name: string, value: U64Input): bigint {
323
405
  return parsed;
324
406
  }
325
407
 
326
- /** Permissionless crank: sweep settled address funds into the canonical pool. */
327
- export function sweepCompositionRoyaltyPool(
408
+ function asU64Argument(name: string, value: U64Argument): bigint | TransactionArgument {
409
+ if (
410
+ typeof value === "bigint" ||
411
+ typeof value === "string" ||
412
+ typeof value === "number"
413
+ ) {
414
+ return asU64(name, value);
415
+ }
416
+ return value;
417
+ }
418
+
419
+ /** Read the commit-settled accumulator balance for an address inside this PTB. */
420
+ export function settledFundsValue(
421
+ tx: Transaction,
422
+ params: {
423
+ readonly address: string | TransactionArgument;
424
+ readonly currencyType: string;
425
+ readonly accumulatorRoot?: ObjectInput;
426
+ },
427
+ ): TransactionArgument {
428
+ return tx.moveCall({
429
+ target: "0x2::balance::settled_funds_value",
430
+ typeArguments: [params.currencyType],
431
+ arguments: [
432
+ object(tx, params.accumulatorRoot ?? SUI_ACCUMULATOR_ROOT_OBJECT_ID),
433
+ typeof params.address === "string"
434
+ ? tx.pure.address(params.address)
435
+ : params.address,
436
+ ],
437
+ });
438
+ }
439
+
440
+ /** Permissionless crank: redeem an exact Composition amount into its pool. */
441
+ export function redeemAndDepositCompositionRoyaltyPool(
328
442
  tx: Transaction,
329
- params: CompositionRoyaltyPoolCrankParams,
443
+ params: CompositionRoyaltyPoolCrankParams & {
444
+ readonly value: U64Argument;
445
+ },
330
446
  ): void {
331
447
  tx.add(
332
- compositionRoyaltyPool.sweepAndDeposit({
448
+ compositionRoyaltyPool.redeemAndDeposit({
333
449
  package: params.pluginPackageId,
334
450
  typeArguments: [params.compositionShareType, params.currencyType],
335
- arguments: [params.vault, params.composition, params.pool, params.accumulatorRoot],
451
+ arguments: [
452
+ params.vault,
453
+ params.composition,
454
+ params.pool,
455
+ asU64Argument("value", params.value),
456
+ ],
336
457
  }),
337
458
  );
338
459
  }
339
460
 
461
+ /** Redeem exactly the framework-reported settled Composition funds. */
462
+ export function settleCompositionRoyaltyPool(
463
+ tx: Transaction,
464
+ params: Omit<CompositionRoyaltyPoolCrankParams, "composition"> & {
465
+ readonly compositionId: string;
466
+ readonly accumulatorRoot?: ObjectInput;
467
+ },
468
+ ): void {
469
+ const value = settledFundsValue(tx, {
470
+ address: params.compositionId,
471
+ currencyType: params.currencyType,
472
+ accumulatorRoot: params.accumulatorRoot,
473
+ });
474
+ redeemAndDepositCompositionRoyaltyPool(tx, {
475
+ ...params,
476
+ composition: tx.object(params.compositionId),
477
+ value,
478
+ });
479
+ }
480
+
340
481
  /** Permissionless crank: receive selected Composition-owned coins into the pool. */
341
482
  export function receiveCompositionRoyaltyPool(
342
483
  tx: Transaction,
@@ -435,7 +576,7 @@ export function receivePartyWalletBalance(
435
576
  /** Redeem an exact Party accumulator amount and return its Balance. */
436
577
  export function redeemPartyWalletBalance(
437
578
  tx: Transaction,
438
- params: PartyWalletFundsParams & { readonly value: U64Input },
579
+ params: PartyWalletFundsParams & { readonly value: U64Argument },
439
580
  ): TransactionArgument {
440
581
  return tx.add(
441
582
  partyWallet.redeemBalance({
@@ -445,31 +586,30 @@ export function redeemPartyWalletBalance(
445
586
  params.vault,
446
587
  params.party,
447
588
  params.vaultAdminCap,
448
- asU64("value", params.value),
589
+ asU64Argument("value", params.value),
449
590
  ],
450
591
  }),
451
592
  );
452
593
  }
453
594
 
454
- /** Sweep the Party's currently settled accumulator funds and return its Balance. */
455
- export function sweepPartyWalletBalance(
595
+ /** Redeem exactly the framework-reported settled Party funds. */
596
+ export function settlePartyWalletBalance(
456
597
  tx: Transaction,
457
- params: PartyWalletFundsParams & {
458
- readonly accumulatorRoot: TransactionObjectArgument;
598
+ params: Omit<PartyWalletFundsParams, "party"> & {
599
+ readonly partyId: string;
600
+ readonly accumulatorRoot?: ObjectInput;
459
601
  },
460
602
  ): TransactionArgument {
461
- return tx.add(
462
- partyWallet.sweepBalance({
463
- package: params.pluginPackageId,
464
- typeArguments: [params.currencyType],
465
- arguments: [
466
- params.vault,
467
- params.party,
468
- params.accumulatorRoot,
469
- params.vaultAdminCap,
470
- ],
471
- }),
472
- );
603
+ const value = settledFundsValue(tx, {
604
+ address: params.partyId,
605
+ currencyType: params.currencyType,
606
+ accumulatorRoot: params.accumulatorRoot,
607
+ });
608
+ return redeemPartyWalletBalance(tx, {
609
+ ...params,
610
+ party: tx.object(params.partyId),
611
+ value,
612
+ });
473
613
  }
474
614
 
475
615
  export function uninstallRecordingRoyaltyPoolPlugin(
@@ -525,31 +665,57 @@ export interface RecordingRoyaltyPoolCrankParams {
525
665
  readonly vault: TransactionObjectArgument;
526
666
  readonly recording: TransactionObjectArgument;
527
667
  readonly pool: TransactionObjectArgument;
528
- readonly accumulatorRoot: TransactionObjectArgument;
529
668
  readonly recordingShareType: string;
530
669
  readonly compositionShareType: string;
531
670
  readonly currencyType: string;
532
671
  readonly pluginPackageId: string;
533
672
  }
534
673
 
535
- /** Permissionless crank: sweep settled address funds into the canonical pool. */
536
- export function sweepRecordingRoyaltyPool(
674
+ /** Permissionless crank: redeem an exact Recording amount into its pool. */
675
+ export function redeemAndDepositRecordingRoyaltyPool(
537
676
  tx: Transaction,
538
- params: RecordingRoyaltyPoolCrankParams,
677
+ params: RecordingRoyaltyPoolCrankParams & {
678
+ readonly value: U64Argument;
679
+ },
539
680
  ): void {
540
681
  tx.add(
541
- recordingRoyaltyPool.sweepAndDeposit({
682
+ recordingRoyaltyPool.redeemAndDeposit({
542
683
  package: params.pluginPackageId,
543
684
  typeArguments: [
544
685
  params.recordingShareType,
545
686
  params.compositionShareType,
546
687
  params.currencyType,
547
688
  ],
548
- arguments: [params.vault, params.recording, params.pool, params.accumulatorRoot],
689
+ arguments: [
690
+ params.vault,
691
+ params.recording,
692
+ params.pool,
693
+ asU64Argument("value", params.value),
694
+ ],
549
695
  }),
550
696
  );
551
697
  }
552
698
 
699
+ /** Redeem exactly the framework-reported settled Recording funds. */
700
+ export function settleRecordingRoyaltyPool(
701
+ tx: Transaction,
702
+ params: Omit<RecordingRoyaltyPoolCrankParams, "recording"> & {
703
+ readonly recordingId: string;
704
+ readonly accumulatorRoot?: ObjectInput;
705
+ },
706
+ ): void {
707
+ const value = settledFundsValue(tx, {
708
+ address: params.recordingId,
709
+ currencyType: params.currencyType,
710
+ accumulatorRoot: params.accumulatorRoot,
711
+ });
712
+ redeemAndDepositRecordingRoyaltyPool(tx, {
713
+ ...params,
714
+ recording: tx.object(params.recordingId),
715
+ value,
716
+ });
717
+ }
718
+
553
719
  /** Permissionless crank: receive selected Recording-owned coins into the pool. */
554
720
  export function receiveRecordingRoyaltyPool(
555
721
  tx: Transaction,
@@ -604,18 +770,39 @@ export function redeemAndDistributeReleaseRevenue(
604
770
  params: Omit<ReleaseRevenueDistributorPluginParams, "vaultAdminCap"> & {
605
771
  readonly release: TransactionObjectArgument;
606
772
  readonly currencyType: string;
607
- readonly value: U64Input;
773
+ readonly value: U64Argument;
608
774
  },
609
775
  ): void {
610
776
  tx.add(
611
777
  releaseRevenueDistributor.redeemAndDistribute({
612
778
  package: params.pluginPackageId,
613
779
  typeArguments: [params.currencyType],
614
- arguments: [params.vault, params.release, asU64("value", params.value)],
780
+ arguments: [params.vault, params.release, asU64Argument("value", params.value)],
615
781
  }),
616
782
  );
617
783
  }
618
784
 
785
+ /** Redeem exactly the framework-reported settled Release funds and route them. */
786
+ export function settleAndDistributeReleaseRevenue(
787
+ tx: Transaction,
788
+ params: Omit<ReleaseRevenueDistributorPluginParams, "vaultAdminCap"> & {
789
+ readonly releaseId: string;
790
+ readonly currencyType: string;
791
+ readonly accumulatorRoot?: ObjectInput;
792
+ },
793
+ ): void {
794
+ const value = settledFundsValue(tx, {
795
+ address: params.releaseId,
796
+ currencyType: params.currencyType,
797
+ accumulatorRoot: params.accumulatorRoot,
798
+ });
799
+ redeemAndDistributeReleaseRevenue(tx, {
800
+ ...params,
801
+ release: tx.object(params.releaseId),
802
+ value,
803
+ });
804
+ }
805
+
619
806
  /** Permissionless crank: receive release-owned coins and route them by track BPS. */
620
807
  export function receiveAndDistributeReleaseRevenue(
621
808
  tx: Transaction,