@misofm/sdk 0.15.7 → 0.15.9

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 (51) hide show
  1. package/README.md +8 -3
  2. package/dist/client.d.ts +22 -2
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +15 -1
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts/vault/vault.d.ts +149 -23
  7. package/dist/contracts/vault/vault.d.ts.map +1 -1
  8. package/dist/contracts/vault/vault.js +144 -18
  9. package/dist/contracts/vault/vault.js.map +1 -1
  10. package/dist/deployments.d.ts +10 -7
  11. package/dist/deployments.d.ts.map +1 -1
  12. package/dist/deployments.js +8 -7
  13. package/dist/deployments.js.map +1 -1
  14. package/dist/publication.d.ts.map +1 -1
  15. package/dist/publication.js +8 -4
  16. package/dist/publication.js.map +1 -1
  17. package/dist/read/catalog.d.ts.map +1 -1
  18. package/dist/read/catalog.js +24 -13
  19. package/dist/read/catalog.js.map +1 -1
  20. package/dist/read/config.d.ts +2 -0
  21. package/dist/read/config.d.ts.map +1 -1
  22. package/dist/read/config.js +1 -0
  23. package/dist/read/config.js.map +1 -1
  24. package/dist/read/internal/walrus.d.ts +2 -0
  25. package/dist/read/internal/walrus.d.ts.map +1 -1
  26. package/dist/read/internal/walrus.js +5 -0
  27. package/dist/read/internal/walrus.js.map +1 -1
  28. package/dist/read/types.d.ts +2 -0
  29. package/dist/read/types.d.ts.map +1 -1
  30. package/dist/read/wallet.js +1 -1
  31. package/dist/read/wallet.js.map +1 -1
  32. package/dist/recording-extensions.d.ts +14 -1
  33. package/dist/recording-extensions.d.ts.map +1 -1
  34. package/dist/recording-extensions.js +65 -0
  35. package/dist/recording-extensions.js.map +1 -1
  36. package/dist/vault.d.ts +31 -4
  37. package/dist/vault.d.ts.map +1 -1
  38. package/dist/vault.js +41 -7
  39. package/dist/vault.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/client.ts +22 -1
  42. package/src/contracts/vault/vault.ts +226 -21
  43. package/src/deployments.ts +10 -7
  44. package/src/publication.ts +9 -5
  45. package/src/read/catalog.ts +31 -13
  46. package/src/read/config.ts +3 -0
  47. package/src/read/internal/walrus.ts +9 -0
  48. package/src/read/types.ts +2 -0
  49. package/src/read/wallet.ts +1 -1
  50. package/src/recording-extensions.ts +104 -1
  51. package/src/vault.ts +86 -9
@@ -6,32 +6,38 @@
6
6
  /**
7
7
  * Generic capability custody and plugin authorization.
8
8
  *
9
- * `Vault<Cap>` holds a capability in a Sui `Referent`. An authorized plugin
10
- * receives the whole capability temporarily, paired with a hot-potato `Borrow`
11
- * receipt that forces the same capability back into the same vault before the
12
- * transaction can finish. Plugin authorization is represented by a typed dynamic
13
- * field in the vault's `Bag`.
9
+ * `Vault<Cap>` is a permanent, deterministically addressed shell that can hold one
10
+ * exact capability in a Sui `Referent`. An authorized plugin receives the whole
11
+ * capability temporarily, paired with a hot-potato `Borrow` receipt that forces
12
+ * the same capability back into the same vault before the transaction can finish.
13
+ * Plugin authorization is represented by a typed dynamic field in the vault's
14
+ * `Bag`.
14
15
  */
15
16
 
16
- import { type BcsType, bcs } from '@mysten/sui/bcs';
17
17
  import { MoveStruct, MoveTuple, normalizeMoveArguments, type RawTransactionArgument } from '../utils/index.js';
18
+ import { bcs, type BcsType } from '@mysten/sui/bcs';
18
19
  import { type Transaction, type TransactionArgument } from '@mysten/sui/transactions';
19
20
  import * as borrow from './deps/sui/borrow.js';
20
21
  import * as bag from './deps/sui/bag.js';
21
22
  const $moduleName = '@local-pkg/vault::vault';
23
+ export const VaultRegistry = new MoveStruct({ name: `${$moduleName}::VaultRegistry`, fields: {
24
+ id: bcs.Address
25
+ } });
22
26
  /**
23
27
  * Custodies one capability and the typed authorization records for plugins.
24
28
  *
25
- * `Vault` intentionally lacks `store`: only this module can share or destroy it.
26
- * The wrapped capability is never exposed except through a hot-potato borrow that
27
- * requires its exact return.
29
+ * `Vault` intentionally lacks `store`: only this module can share it, and no
30
+ * production API can delete it. `cap_id` permanently binds the shell to the exact
31
+ * capability from which its ID was derived. An empty Vault can only be restored
32
+ * with that same capability object.
28
33
  */
29
34
  export function Vault<Cap extends BcsType<any>>(...typeParameters: [
30
35
  Cap
31
36
  ]) {
32
37
  return new MoveStruct({ name: `${$moduleName}::Vault<${typeParameters[0].name as Cap['name']}>`, fields: {
33
38
  id: bcs.Address,
34
- cap: borrow.Referent(typeParameters[0]),
39
+ cap_id: bcs.Address,
40
+ cap: bcs.option(borrow.Referent(typeParameters[0])),
35
41
  authorized_plugins: bag.Bag
36
42
  } });
37
43
  }
@@ -39,11 +45,16 @@ export const VaultAdminCap = new MoveStruct({ name: `${$moduleName}::VaultAdminC
39
45
  id: bcs.Address,
40
46
  vault_id: bcs.Address
41
47
  } });
48
+ export const VaultKey = new MoveTuple({ name: `${$moduleName}::VaultKey<phantom Cap>`, fields: [bcs.Address] });
49
+ export const VaultAdminCapKey = new MoveTuple({ name: `${$moduleName}::VaultAdminCapKey`, fields: [bcs.bool()] });
42
50
  export const AuthorizedPluginKey = new MoveTuple({ name: `${$moduleName}::AuthorizedPluginKey<phantom Witness>`, fields: [bcs.bool()] });
51
+ export const VaultRegistryCreatedEvent = new MoveStruct({ name: `${$moduleName}::VaultRegistryCreatedEvent`, fields: {
52
+ registry_id: bcs.Address
53
+ } });
43
54
  export const VaultCreatedEvent = new MoveStruct({ name: `${$moduleName}::VaultCreatedEvent<phantom Cap>`, fields: {
44
55
  vault_id: bcs.Address,
45
56
  vault_admin_cap_id: bcs.Address,
46
- wrapped_cap_id: bcs.Address,
57
+ cap_id: bcs.Address,
47
58
  authorized_plugins_id: bcs.Address
48
59
  } });
49
60
  export const PluginAuthorizedEvent = new MoveStruct({ name: `${$moduleName}::PluginAuthorizedEvent<phantom Cap, phantom Witness>`, fields: {
@@ -52,29 +63,39 @@ export const PluginAuthorizedEvent = new MoveStruct({ name: `${$moduleName}::Plu
52
63
  export const PluginRevokedEvent = new MoveStruct({ name: `${$moduleName}::PluginRevokedEvent<phantom Cap, phantom Witness>`, fields: {
53
64
  vault_id: bcs.Address
54
65
  } });
55
- export const VaultDestroyedEvent = new MoveStruct({ name: `${$moduleName}::VaultDestroyedEvent<phantom Cap>`, fields: {
66
+ export const VaultCapabilityWithdrawnEvent = new MoveStruct({ name: `${$moduleName}::VaultCapabilityWithdrawnEvent<phantom Cap>`, fields: {
56
67
  vault_id: bcs.Address,
57
- wrapped_cap_id: bcs.Address
68
+ cap_id: bcs.Address
69
+ } });
70
+ export const VaultCapabilityRestoredEvent = new MoveStruct({ name: `${$moduleName}::VaultCapabilityRestoredEvent<phantom Cap>`, fields: {
71
+ vault_id: bcs.Address,
72
+ cap_id: bcs.Address
58
73
  } });
59
74
  export interface NewArguments<Cap extends BcsType<any>> {
75
+ registry: RawTransactionArgument<string>;
60
76
  cap: RawTransactionArgument<Cap>;
61
77
  }
62
78
  export interface NewOptions<Cap extends BcsType<any>> {
63
79
  package?: string;
64
80
  arguments: NewArguments<Cap> | [
81
+ registry: RawTransactionArgument<string>,
65
82
  cap: RawTransactionArgument<Cap>
66
83
  ];
67
84
  typeArguments: [
68
85
  string
69
86
  ];
70
87
  }
71
- /** Custody `cap` and create its vault-specific administrator capability. */
88
+ /**
89
+ * Custody `cap` in its canonical permanent Vault and create the canonical
90
+ * vault-specific administrator capability.
91
+ */
72
92
  export function _new<Cap extends BcsType<any>>(options: NewOptions<Cap>) {
73
93
  const packageAddress = options.package ?? '@local-pkg/vault';
74
94
  const argumentsTypes = [
95
+ null,
75
96
  `${options.typeArguments[0]}`
76
97
  ] satisfies (string | null)[];
77
- const parameterNames = ["cap"];
98
+ const parameterNames = ["registry", "cap"];
78
99
  return (tx: Transaction) => tx.moveCall({
79
100
  package: packageAddress,
80
101
  module: 'vault',
@@ -110,13 +131,46 @@ export function share(options: ShareOptions) {
110
131
  typeArguments: options.typeArguments
111
132
  });
112
133
  }
113
- export interface DestroyArguments {
134
+ export interface TransferAdminCapArguments {
135
+ adminCap: RawTransactionArgument<string>;
136
+ recipient: RawTransactionArgument<string>;
137
+ }
138
+ export interface TransferAdminCapOptions {
139
+ package?: string;
140
+ arguments: TransferAdminCapArguments | [
141
+ adminCap: RawTransactionArgument<string>,
142
+ recipient: RawTransactionArgument<string>
143
+ ];
144
+ typeArguments: [
145
+ string
146
+ ];
147
+ }
148
+ /**
149
+ * Transfer exclusive administration without exposing public freeze, share, or
150
+ * wrapping operations for the VaultAdminCap.
151
+ */
152
+ export function transferAdminCap(options: TransferAdminCapOptions) {
153
+ const packageAddress = options.package ?? '@local-pkg/vault';
154
+ const argumentsTypes = [
155
+ null,
156
+ 'address'
157
+ ] satisfies (string | null)[];
158
+ const parameterNames = ["adminCap", "recipient"];
159
+ return (tx: Transaction) => tx.moveCall({
160
+ package: packageAddress,
161
+ module: 'vault',
162
+ function: 'transfer_admin_cap',
163
+ arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
164
+ typeArguments: options.typeArguments
165
+ });
166
+ }
167
+ export interface WithdrawCapArguments {
114
168
  self: RawTransactionArgument<string>;
115
169
  adminCap: RawTransactionArgument<string>;
116
170
  }
117
- export interface DestroyOptions {
171
+ export interface WithdrawCapOptions {
118
172
  package?: string;
119
- arguments: DestroyArguments | [
173
+ arguments: WithdrawCapArguments | [
120
174
  self: RawTransactionArgument<string>,
121
175
  adminCap: RawTransactionArgument<string>
122
176
  ];
@@ -124,8 +178,11 @@ export interface DestroyOptions {
124
178
  string
125
179
  ];
126
180
  }
127
- /** Destroy an empty vault and return the exact capability it custodied. */
128
- export function destroy(options: DestroyOptions) {
181
+ /**
182
+ * Withdraw the exact capability while leaving its canonical Vault and
183
+ * VaultAdminCap intact. Every plugin must be revoked first.
184
+ */
185
+ export function withdrawCap(options: WithdrawCapOptions) {
129
186
  const packageAddress = options.package ?? '@local-pkg/vault';
130
187
  const argumentsTypes = [
131
188
  null,
@@ -135,7 +192,43 @@ export function destroy(options: DestroyOptions) {
135
192
  return (tx: Transaction) => tx.moveCall({
136
193
  package: packageAddress,
137
194
  module: 'vault',
138
- function: 'destroy',
195
+ function: 'withdraw_cap',
196
+ arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
197
+ typeArguments: options.typeArguments
198
+ });
199
+ }
200
+ export interface RestoreCapArguments<Cap extends BcsType<any>> {
201
+ self: RawTransactionArgument<string>;
202
+ adminCap: RawTransactionArgument<string>;
203
+ cap: RawTransactionArgument<Cap>;
204
+ }
205
+ export interface RestoreCapOptions<Cap extends BcsType<any>> {
206
+ package?: string;
207
+ arguments: RestoreCapArguments<Cap> | [
208
+ self: RawTransactionArgument<string>,
209
+ adminCap: RawTransactionArgument<string>,
210
+ cap: RawTransactionArgument<Cap>
211
+ ];
212
+ typeArguments: [
213
+ string
214
+ ];
215
+ }
216
+ /**
217
+ * Restore the exact capability used to derive this permanent Vault. Restoring
218
+ * always starts from a clean plugin-authorization slate.
219
+ */
220
+ export function restoreCap<Cap extends BcsType<any>>(options: RestoreCapOptions<Cap>) {
221
+ const packageAddress = options.package ?? '@local-pkg/vault';
222
+ const argumentsTypes = [
223
+ null,
224
+ null,
225
+ `${options.typeArguments[0]}`
226
+ ] satisfies (string | null)[];
227
+ const parameterNames = ["self", "adminCap", "cap"];
228
+ return (tx: Transaction) => tx.moveCall({
229
+ package: packageAddress,
230
+ module: 'vault',
231
+ function: 'restore_cap',
139
232
  arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
140
233
  typeArguments: options.typeArguments
141
234
  });
@@ -315,6 +408,59 @@ export function putBack<Cap extends BcsType<any>>(options: PutBackOptions<Cap>)
315
408
  typeArguments: options.typeArguments
316
409
  });
317
410
  }
411
+ export interface VaultAddressArguments {
412
+ registry: RawTransactionArgument<string>;
413
+ capId: RawTransactionArgument<string>;
414
+ }
415
+ export interface VaultAddressOptions {
416
+ package?: string;
417
+ arguments: VaultAddressArguments | [
418
+ registry: RawTransactionArgument<string>,
419
+ capId: RawTransactionArgument<string>
420
+ ];
421
+ typeArguments: [
422
+ string
423
+ ];
424
+ }
425
+ /** Derive the canonical Vault address for `cap_id` in this registry. */
426
+ export function vaultAddress(options: VaultAddressOptions) {
427
+ const packageAddress = options.package ?? '@local-pkg/vault';
428
+ const argumentsTypes = [
429
+ null,
430
+ '0x2::object::ID'
431
+ ] satisfies (string | null)[];
432
+ const parameterNames = ["registry", "capId"];
433
+ return (tx: Transaction) => tx.moveCall({
434
+ package: packageAddress,
435
+ module: 'vault',
436
+ function: 'vault_address',
437
+ arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
438
+ typeArguments: options.typeArguments
439
+ });
440
+ }
441
+ export interface VaultAdminCapAddressArguments {
442
+ vaultId: RawTransactionArgument<string>;
443
+ }
444
+ export interface VaultAdminCapAddressOptions {
445
+ package?: string;
446
+ arguments: VaultAdminCapAddressArguments | [
447
+ vaultId: RawTransactionArgument<string>
448
+ ];
449
+ }
450
+ /** Derive the canonical VaultAdminCap address for a Vault ID. */
451
+ export function vaultAdminCapAddress(options: VaultAdminCapAddressOptions) {
452
+ const packageAddress = options.package ?? '@local-pkg/vault';
453
+ const argumentsTypes = [
454
+ '0x2::object::ID'
455
+ ] satisfies (string | null)[];
456
+ const parameterNames = ["vaultId"];
457
+ return (tx: Transaction) => tx.moveCall({
458
+ package: packageAddress,
459
+ module: 'vault',
460
+ function: 'vault_admin_cap_address',
461
+ arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
462
+ });
463
+ }
318
464
  export interface VaultIdArguments {
319
465
  self: RawTransactionArgument<string>;
320
466
  }
@@ -341,6 +487,65 @@ export function vaultId(options: VaultIdOptions) {
341
487
  typeArguments: options.typeArguments
342
488
  });
343
489
  }
490
+ export interface CapIdArguments {
491
+ self: RawTransactionArgument<string>;
492
+ }
493
+ export interface CapIdOptions {
494
+ package?: string;
495
+ arguments: CapIdArguments | [
496
+ self: RawTransactionArgument<string>
497
+ ];
498
+ typeArguments: [
499
+ string
500
+ ];
501
+ }
502
+ /** The exact capability object permanently assigned to this Vault. */
503
+ export function capId(options: CapIdOptions) {
504
+ const packageAddress = options.package ?? '@local-pkg/vault';
505
+ const argumentsTypes = [
506
+ null
507
+ ] satisfies (string | null)[];
508
+ const parameterNames = ["self"];
509
+ return (tx: Transaction) => tx.moveCall({
510
+ package: packageAddress,
511
+ module: 'vault',
512
+ function: 'cap_id',
513
+ arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
514
+ typeArguments: options.typeArguments
515
+ });
516
+ }
517
+ export interface IsOccupiedArguments {
518
+ self: RawTransactionArgument<string>;
519
+ }
520
+ export interface IsOccupiedOptions {
521
+ package?: string;
522
+ arguments: IsOccupiedArguments | [
523
+ self: RawTransactionArgument<string>
524
+ ];
525
+ typeArguments: [
526
+ string
527
+ ];
528
+ }
529
+ /**
530
+ * Whether the permanent outer capability slot is occupied.
531
+ *
532
+ * This is the persistent-state custody view. It remains true during a
533
+ * transaction-local lease even though the inner Referent is temporarily empty.
534
+ */
535
+ export function isOccupied(options: IsOccupiedOptions) {
536
+ const packageAddress = options.package ?? '@local-pkg/vault';
537
+ const argumentsTypes = [
538
+ null
539
+ ] satisfies (string | null)[];
540
+ const parameterNames = ["self"];
541
+ return (tx: Transaction) => tx.moveCall({
542
+ package: packageAddress,
543
+ module: 'vault',
544
+ function: 'is_occupied',
545
+ arguments: normalizeMoveArguments(options.arguments, argumentsTypes, parameterNames),
546
+ typeArguments: options.typeArguments
547
+ });
548
+ }
344
549
  export interface AuthorizedPluginsIdArguments {
345
550
  self: RawTransactionArgument<string>;
346
551
  }
@@ -57,6 +57,8 @@ export interface MisoPlatformDeployment {
57
57
  };
58
58
  readonly objects: {
59
59
  readonly releaseRegistry: string;
60
+ /** Shared parent used to derive canonical Vault object ids. */
61
+ readonly vaultRegistry: string;
60
62
  /** Shared parent used to derive canonical Genre object ids. */
61
63
  readonly genreRegistry: string;
62
64
  };
@@ -68,7 +70,7 @@ export interface MisoPlatformDeployment {
68
70
  /**
69
71
  * Platform deployments bundled with this SDK release.
70
72
  *
71
- * IDs come only from the verified output of the Ledger-backed deployment run.
73
+ * IDs come only from verified immutable deployment output.
72
74
  * Consumers may still pass an explicit complete deployment for custom networks.
73
75
  */
74
76
  export const MISO_PLATFORM_DEPLOYMENTS = {
@@ -85,12 +87,12 @@ export const MISO_PLATFORM_DEPLOYMENTS = {
85
87
  recordingCredits: "0x7096a47b0ba12063c037d6d417bffade758665a3f313574c8ba218823cfb159a",
86
88
  releaseCredits: "0xbe293700ef758c95b69838df6cfa8377b9cad1dd59cbf933974f68b1766d87b5",
87
89
  royaltyPool: "0x8021942b5e91c5ef5e383ad481102ee96f52dd77b9b3dbcdf06bb133cd7c91ed",
88
- vault: "0x7075ce4bfc2c738e774c94f1eeb7dc532a5f11ead9b4e3815d90dc16053eae9c",
89
- vaultCompositionRoyaltyPoolPlugin: "0xdd259821c97e887ec7ca20459ef98e3afbb36d2d613b537fbc0027e02c0eb378",
90
- vaultRecordingRoyaltyPoolPlugin: "0xbb873a4e285a8e987d8b5e53919f35172071493872a342ca4c02a941c2af44e3",
91
- vaultPartyWalletPlugin: "0xfb600cc71773f4b9a22921ba16906b4ccfef791540402dbd556b555ca7a305f7",
90
+ vault: "0xfe396139d500e4381adefea72da2e0157c54ee5c38cc8bdcbc4edd551d043230",
91
+ vaultCompositionRoyaltyPoolPlugin: "0xbfd9b6c9d3e5635c0beb5472b45566b92f509ed67ae4a661bf928c359f3b438f",
92
+ vaultRecordingRoyaltyPoolPlugin: "0x1643c188790a7e756310ce779b279159356a9bf7fe8237edf1e5b24a15422615",
93
+ vaultPartyWalletPlugin: "0x0d869fe4291fec02821aed40c38349bac8547f0c690316f2a1a2273ac1f317ed",
92
94
  routedStake: "0x7a55b1841043efea865d65a6601e057400a79a0aa7bb11e781a25dbe622cbe5f",
93
- vaultCompositionRoutedStakePlugin: "0x59a5aa190ed14c754ef292a23320bd5749bbb781c4990dcd4a8ad1dff60797d4",
95
+ vaultCompositionRoutedStakePlugin: "0xf86994ebd0dabecda1b14efc02a2e71b3219a7c043841ad8097dc3683bd088dd",
94
96
  coverArt: "0x2dae28058b89df93224bacfb9af42fd3ab41f001c2c815fd57fd575024d9a50b",
95
97
  releaseCoverArt: "0x649b18f2bb3d94f6a611a8e4ad3a29dcf8b7bba3f684056d60897a8a5e835106",
96
98
  genre: "0x5091d30e893105abe24adf75223f587361034e90516c6e509897bb86d18d2387",
@@ -98,7 +100,7 @@ export const MISO_PLATFORM_DEPLOYMENTS = {
98
100
  releaseDspLink: "0x2b8e1d7be7a3cbc07e6167c5b5c6511059791b4a2116c1fa97d65cfd871d0bda",
99
101
  releaseGenre: "0x7882367d45efff41ef0cb9e937029a3f8a3cdf5908d83beeb5cbc0cff178d290",
100
102
  releaseKind: "0x3e74c960d9446ae2ebf228456ddc1b099d2090501c9cbcd284a999aa2e774e12",
101
- vaultReleaseRevenueDistributorPlugin: "0x23b214507e4b4c344916d10367eaceea1f0dd233b609d99329bb98d55d3c1363",
103
+ vaultReleaseRevenueDistributorPlugin: "0x2172dc326fbf226b6cf6eed610f217fb0ff2682d1938e8089f4d6ce21a4999b5",
102
104
  recordingAdvisory: "0x28e0e72c5b892fc888a9007afa59ebe04ed8e47f12632ddb42cd685d09c4af2e",
103
105
  recordingLanguage: "0x4b284a9435cf4f48e3785e4485d16be2fcbcef5beaa2b44b6556d9c1028e2c0d",
104
106
  recordingMasterReference: "0x2b06ab58f2d5a915b42fc5879d52241fc72e804b3da782fa752b2d2f242170c0",
@@ -107,6 +109,7 @@ export const MISO_PLATFORM_DEPLOYMENTS = {
107
109
  },
108
110
  objects: {
109
111
  releaseRegistry: "0xf5941ae9640f6f24b75e921da16c95fd23d776b9e6518c275a50a5ce6337c8ba",
112
+ vaultRegistry: "0xee17744a0c6f71bbde98d0c2b4cab58929000fd2f65e28a4676164d34758584b",
110
113
  genreRegistry: "0xa83f9c7a340b5b5b6387d1d5933019b45bcedebbae85bbb89bab855a56e90816",
111
114
  },
112
115
  legacy: {
@@ -277,6 +277,7 @@ function custody(
277
277
  return {
278
278
  kind: "vault",
279
279
  owner: selected.owner,
280
+ vaultRegistry: p.deployment.objects.vaultRegistry,
280
281
  capType,
281
282
  vaultPackageId: p.deployment.packages.vault,
282
283
  configure,
@@ -410,6 +411,7 @@ function publishComposition(
410
411
  }
411
412
  custodyNewAdminCap(tx, {
412
413
  adminCap: parts.adminCap,
414
+ vaultRegistry: p.deployment.objects.vaultRegistry,
413
415
  capType: compositionCapType(p, node.shareType),
414
416
  vaultPackageId: p.deployment.packages.vault,
415
417
  owner: node.custody.owner,
@@ -479,6 +481,7 @@ function publishRecording(
479
481
  }
480
482
  custodyNewAdminCap(tx, {
481
483
  adminCap: parts.adminCap,
484
+ vaultRegistry: p.deployment.objects.vaultRegistry,
482
485
  capType: recordingCapType(p, node.shareType),
483
486
  vaultPackageId: p.deployment.packages.vault,
484
487
  owner: node.custody.owner,
@@ -542,6 +545,7 @@ function publishReleaseObject(
542
545
  }
543
546
  custodyNewAdminCap(tx, {
544
547
  adminCap,
548
+ vaultRegistry: p.deployment.objects.vaultRegistry,
545
549
  capType: releaseCapType(p),
546
550
  vaultPackageId: p.deployment.packages.vault,
547
551
  owner: node.custody.owner,
@@ -928,12 +932,12 @@ function findByShareType(
928
932
  return matches[0]!.objectId;
929
933
  }
930
934
 
931
- function vaultsByWrappedCap(result: PlatformExecResult) {
935
+ function vaultsByCap(result: PlatformExecResult) {
932
936
  const out = new Map<string, { vaultId: string; vaultAdminCapId: string }>();
933
937
  for (const event of result.events) {
934
938
  if (!event.eventType.includes("::vault::VaultCreatedEvent<")) continue;
935
939
  const parsed = parseVaultCreatedEvent(event.bcs);
936
- out.set(parsed.wrapped_cap_id, {
940
+ out.set(parsed.cap_id, {
937
941
  vaultId: parsed.vault_id,
938
942
  vaultAdminCapId: parsed.vault_admin_cap_id,
939
943
  });
@@ -943,7 +947,7 @@ function vaultsByWrappedCap(result: PlatformExecResult) {
943
947
 
944
948
  function authorityOut(
945
949
  result: PlatformExecResult,
946
- vaults: ReturnType<typeof vaultsByWrappedCap>,
950
+ vaults: ReturnType<typeof vaultsByCap>,
947
951
  selected: PublicationCustody,
948
952
  adminCapId: string,
949
953
  capType: string,
@@ -951,7 +955,7 @@ function authorityOut(
951
955
  ): PublicationAuthorityOut {
952
956
  if (selected.kind === "direct") return { kind: "direct", adminCapId };
953
957
  const found = vaults.get(adminCapId);
954
- if (!found) throw new Error(`No VaultCreatedEvent wrapped admin cap ${adminCapId} in ${result.digest}`);
958
+ if (!found) throw new Error(`No VaultCreatedEvent for admin cap ${adminCapId} in ${result.digest}`);
955
959
  return { kind: "vault", ...found, capType, vaultPackageId };
956
960
  }
957
961
 
@@ -960,7 +964,7 @@ export function parseAtomicPublicationResult(
960
964
  p: AtomicPublicationParams,
961
965
  result: PlatformExecResult,
962
966
  ): AtomicPublicationResult {
963
- const vaults = vaultsByWrappedCap(result);
967
+ const vaults = vaultsByCap(result);
964
968
  const createdCompositions = allCreatedByType(result, "::composition::Composition<");
965
969
  const createdRecordings = allCreatedByType(result, "::recording::Recording<");
966
970
  const createdPools = allCreatedByType(result, "::pool::RoyaltyPool<");
@@ -35,13 +35,18 @@ import {
35
35
  parseReleaseKindContent,
36
36
  releaseKindFieldId,
37
37
  } from "../release-extensions.ts";
38
+ import { getRecordingMasterReferencesByIds } from "../recording-extensions.ts";
38
39
  import { getTrackCreditsByRecordingIds } from "../catalog.ts";
39
40
  import { getReleaseById, getReleasesByIds, isNotFound } from "@misonetwork/sdk";
40
41
  import type { Release } from "@misonetwork/sdk";
41
42
  import type { MisoClient } from "./client.ts";
42
43
  import { getRecordingTitles, parseReleaseObject } from "./works.ts";
43
44
  import { int, u64 } from "./internal/scalars.ts";
44
- import { quiltPatchId, u256ToB64Url } from "./internal/walrus.ts";
45
+ import {
46
+ quiltPatchId,
47
+ u256ToB64Url,
48
+ walrusBlobReadUrl,
49
+ } from "./internal/walrus.ts";
45
50
  import type {
46
51
  Cover,
47
52
  CoverImage,
@@ -67,8 +72,7 @@ import type {
67
72
  /** Aggregator URL for a cover image ref, whichever Walrus variant it is. */
68
73
  function imageUrl(aggregator: string, ref: CoverImageRef): string {
69
74
  const base = aggregator.replace(/\/$/, "");
70
- if (ref.kind === "blob")
71
- return `${base}/v1/blobs/${u256ToB64Url(ref.blobId)}`;
75
+ if (ref.kind === "blob") return walrusBlobReadUrl(base, ref.blobId);
72
76
  const patch = quiltPatchId(
73
77
  ref.quiltId,
74
78
  ref.version,
@@ -206,15 +210,20 @@ export function primaryArtistNames(credits: Credit[]): string[] {
206
210
  function toTracks(
207
211
  release: Release,
208
212
  titles: Record<string, string>,
213
+ masterBlobIds: Partial<Record<string, string>>,
209
214
  ): TrackView[] {
210
- return release.tracks.map((track, index) => ({
211
- no: `${index + 1}`,
212
- title: titles[track.recordingId] ?? "Untitled",
213
- recordingId: track.recordingId,
214
- compositionId: track.compositionId,
215
- splitBps: int(track.splitBps.value),
216
- disc: 1,
217
- }));
215
+ return release.tracks.map((track, index) => {
216
+ const masterBlobId = masterBlobIds[track.recordingId];
217
+ return {
218
+ no: `${index + 1}`,
219
+ title: titles[track.recordingId] ?? "Untitled",
220
+ recordingId: track.recordingId,
221
+ compositionId: track.compositionId,
222
+ splitBps: int(track.splitBps.value),
223
+ disc: 1,
224
+ ...(masterBlobId ? { masterBlobId } : {}),
225
+ };
226
+ });
218
227
  }
219
228
 
220
229
  // ── Cover ────────────────────────────────────────────────────────────────────
@@ -360,17 +369,26 @@ export async function getReleaseDetail(
360
369
  );
361
370
 
362
371
  const recordingIds = release.tracks.map((track) => track.recordingId);
363
- const [titles, trackCredits] = await Promise.all([
372
+ const [titles, masterReferences, trackCredits] = await Promise.all([
364
373
  getRecordingTitles(
365
374
  client.protocol,
366
375
  client.graphql,
367
376
  recordingIds,
368
377
  client.config.deployment.miso,
369
378
  ),
379
+ getRecordingMasterReferencesByIds(
380
+ client.protocol,
381
+ recordingIds,
382
+ client.config.protocol.recordingMasterReference,
383
+ ).catch(() => ({})),
370
384
  options.include?.includes("trackCredits")
371
385
  ? getTrackCreditsForRecordingIds(client, recordingIds)
372
386
  : Promise.resolve(undefined),
373
387
  ]);
388
+ const masterBlobIds: Record<string, string> = {};
389
+ for (const [recordingId, blobId] of Object.entries(masterReferences)) {
390
+ if (blobId) masterBlobIds[recordingId] = u256ToB64Url(blobId);
391
+ }
374
392
 
375
393
  const creditViews = credits ?? [];
376
394
  return {
@@ -385,7 +403,7 @@ export async function getReleaseDetail(
385
403
  credits: creditViews,
386
404
  primaryArtists: primaryArtistNames(creditViews),
387
405
  discCount: release.tracks.length > 0 ? 1 : 0,
388
- tracks: toTracks(release, titles),
406
+ tracks: toTracks(release, titles, masterBlobIds),
389
407
  ...(trackCredits !== undefined ? { trackCredits } : {}),
390
408
  };
391
409
  }
@@ -35,6 +35,8 @@ export interface ProtocolIds {
35
35
  releaseCoverArt: string;
36
36
  /** `release_kind` — the Release's optional self-declared kind. */
37
37
  releaseKind: string;
38
+ /** `recording_master_reference` — optional Walrus master pointers. */
39
+ recordingMasterReference: string;
38
40
  /** `composition_credits` / `recording_credits` / `release_credits` extensions. */
39
41
  compositionCredits: string;
40
42
  recordingCredits: string;
@@ -99,6 +101,7 @@ export function misoConfig(network: Network, overrides: MisoConfigOverrides = {}
99
101
  vault: platform.packages.vault,
100
102
  releaseCoverArt: platform.packages.releaseCoverArt,
101
103
  releaseKind: platform.packages.releaseKind,
104
+ recordingMasterReference: platform.packages.recordingMasterReference,
102
105
  compositionCredits: platform.packages.compositionCredits,
103
106
  recordingCredits: platform.packages.recordingCredits,
104
107
  releaseCredits: platform.packages.releaseCredits,
@@ -14,6 +14,15 @@ export function u256ToB64Url(value: bigint | string): string {
14
14
  return toBase64Url(u256.serialize(BigInt(value)).toBytes());
15
15
  }
16
16
 
17
+ /** Build a blob URL with Walrus's non-strict default made explicit. */
18
+ export function walrusBlobReadUrl(
19
+ aggregator: string,
20
+ blobId: bigint | string,
21
+ ): string {
22
+ const base = aggregator.replace(/\/$/, "");
23
+ return `${base}/v1/blobs/${u256ToB64Url(blobId)}?strict_consistency_check=false`;
24
+ }
25
+
17
26
  /** Build Walrus's 37-byte quilt-patch id. All fields use BCS little-endian. */
18
27
  export function quiltPatchId(
19
28
  quiltId: bigint | string,
package/src/read/types.ts CHANGED
@@ -75,6 +75,8 @@ export interface TrackView {
75
75
  splitBps: number;
76
76
  /** 1-based disc this track sits on. */
77
77
  disc: number;
78
+ /** Base64url Walrus blob id for the master stream, when attached on-chain. */
79
+ masterBlobId?: string;
78
80
  }
79
81
 
80
82
  /** A release with everything a page renders: metadata, cover, credits, tracklist. */
@@ -406,7 +406,7 @@ async function resolveVaultedReleaseCaps(
406
406
  const vault = vaultContract.Vault(networkContracts.release.ReleaseAdminCap).parse(
407
407
  object.content,
408
408
  );
409
- const releaseId = vault.cap.value?.release_id;
409
+ const releaseId = vault.cap?.value?.release_id;
410
410
  if (releaseId) releasesByVault.set(object.objectId, releaseId);
411
411
  } catch {
412
412
  // Batch catalog discovery is best-effort per authority, matching the