@misofm/sdk 0.15.5 → 0.15.7

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 (41) hide show
  1. package/README.md +12 -2
  2. package/dist/client.d.ts +7 -7
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +15 -15
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.d.ts +29 -3
  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 +26 -2
  9. package/dist/contracts/composition_royalty_pool/composition_royalty_pool.js.map +1 -1
  10. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.d.ts +30 -3
  11. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.d.ts.map +1 -1
  12. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.js +26 -2
  13. package/dist/contracts/recording_royalty_pool/recording_royalty_pool.js.map +1 -1
  14. package/dist/deployments.d.ts +11 -11
  15. package/dist/deployments.d.ts.map +1 -1
  16. package/dist/deployments.js +5 -5
  17. package/dist/deployments.js.map +1 -1
  18. package/dist/publication.d.ts +4 -0
  19. package/dist/publication.d.ts.map +1 -1
  20. package/dist/publication.js +88 -19
  21. package/dist/publication.js.map +1 -1
  22. package/dist/read/wallet.d.ts.map +1 -1
  23. package/dist/read/wallet.js +40 -5
  24. package/dist/read/wallet.js.map +1 -1
  25. package/dist/transactions.d.ts +37 -0
  26. package/dist/transactions.d.ts.map +1 -1
  27. package/dist/transactions.js +65 -3
  28. package/dist/transactions.js.map +1 -1
  29. package/dist/vault.d.ts +6 -0
  30. package/dist/vault.d.ts.map +1 -1
  31. package/dist/vault.js +22 -0
  32. package/dist/vault.js.map +1 -1
  33. package/package.json +2 -2
  34. package/src/client.ts +26 -26
  35. package/src/contracts/composition_royalty_pool/composition_royalty_pool.ts +44 -3
  36. package/src/contracts/recording_royalty_pool/recording_royalty_pool.ts +45 -3
  37. package/src/deployments.ts +10 -10
  38. package/src/publication.ts +122 -18
  39. package/src/read/wallet.ts +52 -5
  40. package/src/transactions.ts +111 -3
  41. package/src/vault.ts +34 -0
@@ -28,15 +28,15 @@ export interface MisoPlatformDeployment {
28
28
  /** Shared custody package for protocol admin capabilities. */
29
29
  readonly vault: string;
30
30
  /** Vault plugin that creates and cranks Composition royalty pools. */
31
- readonly compositionRoyaltyPoolPlugin: string;
31
+ readonly vaultCompositionRoyaltyPoolPlugin: string;
32
32
  /** Vault plugin that creates and cranks Recording royalty pools. */
33
- readonly recordingRoyaltyPoolPlugin: string;
33
+ readonly vaultRecordingRoyaltyPoolPlugin: string;
34
34
  /** Vault plugin that manages a Party's royalty-bearing wallet. */
35
- readonly partyWalletPlugin: string;
35
+ readonly vaultPartyWalletPlugin: string;
36
36
  /** Generic stake wrapper used by the composition routed-stake plugin. */
37
37
  readonly routedStake: string;
38
38
  /** Vault plugin for Composition-owned Recording-share staking. */
39
- readonly compositionRoutedStakePlugin: string;
39
+ readonly vaultCompositionRoutedStakePlugin: string;
40
40
  /** Cover-art value type used by the release cover extension. */
41
41
  readonly coverArt: string;
42
42
  readonly releaseCoverArt: string;
@@ -47,7 +47,7 @@ export interface MisoPlatformDeployment {
47
47
  readonly releaseGenre: string;
48
48
  readonly releaseKind: string;
49
49
  /** Vault plugin that routes Release revenue into Recording addresses. */
50
- readonly releaseRevenueDistributorPlugin: string;
50
+ readonly vaultReleaseRevenueDistributorPlugin: string;
51
51
  readonly recordingAdvisory: string;
52
52
  readonly recordingLanguage: string;
53
53
  readonly recordingMasterReference: string;
@@ -86,11 +86,11 @@ export const MISO_PLATFORM_DEPLOYMENTS = {
86
86
  releaseCredits: "0xbe293700ef758c95b69838df6cfa8377b9cad1dd59cbf933974f68b1766d87b5",
87
87
  royaltyPool: "0x8021942b5e91c5ef5e383ad481102ee96f52dd77b9b3dbcdf06bb133cd7c91ed",
88
88
  vault: "0x7075ce4bfc2c738e774c94f1eeb7dc532a5f11ead9b4e3815d90dc16053eae9c",
89
- compositionRoyaltyPoolPlugin: "0x38e6cb0318e692d1c6e31e7eaf24e3771ae045c0ab10b41c21c5c35ef562cd7e",
90
- recordingRoyaltyPoolPlugin: "0x0feab2ec88e814c8cfbdfe61ececb2cfb8400c60db04344f0d514fd5ab30ed4b",
91
- partyWalletPlugin: "0xfb600cc71773f4b9a22921ba16906b4ccfef791540402dbd556b555ca7a305f7",
89
+ vaultCompositionRoyaltyPoolPlugin: "0xdd259821c97e887ec7ca20459ef98e3afbb36d2d613b537fbc0027e02c0eb378",
90
+ vaultRecordingRoyaltyPoolPlugin: "0xbb873a4e285a8e987d8b5e53919f35172071493872a342ca4c02a941c2af44e3",
91
+ vaultPartyWalletPlugin: "0xfb600cc71773f4b9a22921ba16906b4ccfef791540402dbd556b555ca7a305f7",
92
92
  routedStake: "0x7a55b1841043efea865d65a6601e057400a79a0aa7bb11e781a25dbe622cbe5f",
93
- compositionRoutedStakePlugin: "0x59a5aa190ed14c754ef292a23320bd5749bbb781c4990dcd4a8ad1dff60797d4",
93
+ vaultCompositionRoutedStakePlugin: "0x59a5aa190ed14c754ef292a23320bd5749bbb781c4990dcd4a8ad1dff60797d4",
94
94
  coverArt: "0x2dae28058b89df93224bacfb9af42fd3ab41f001c2c815fd57fd575024d9a50b",
95
95
  releaseCoverArt: "0x649b18f2bb3d94f6a611a8e4ad3a29dcf8b7bba3f684056d60897a8a5e835106",
96
96
  genre: "0x5091d30e893105abe24adf75223f587361034e90516c6e509897bb86d18d2387",
@@ -98,7 +98,7 @@ export const MISO_PLATFORM_DEPLOYMENTS = {
98
98
  releaseDspLink: "0x2b8e1d7be7a3cbc07e6167c5b5c6511059791b4a2116c1fa97d65cfd871d0bda",
99
99
  releaseGenre: "0x7882367d45efff41ef0cb9e937029a3f8a3cdf5908d83beeb5cbc0cff178d290",
100
100
  releaseKind: "0x3e74c960d9446ae2ebf228456ddc1b099d2090501c9cbcd284a999aa2e774e12",
101
- releaseRevenueDistributorPlugin: "0x23b214507e4b4c344916d10367eaceea1f0dd233b609d99329bb98d55d3c1363",
101
+ vaultReleaseRevenueDistributorPlugin: "0x23b214507e4b4c344916d10367eaceea1f0dd233b609d99329bb98d55d3c1363",
102
102
  recordingAdvisory: "0x28e0e72c5b892fc888a9007afa59ebe04ed8e47f12632ddb42cd685d09c4af2e",
103
103
  recordingLanguage: "0x4b284a9435cf4f48e3785e4485d16be2fcbcef5beaa2b44b6556d9c1028e2c0d",
104
104
  recordingMasterReference: "0x2b06ab58f2d5a915b42fc5879d52241fc72e804b3da782fa752b2d2f242170c0",
@@ -6,10 +6,13 @@
6
6
  *
7
7
  * Share packages and their registered Currency objects must already exist. This
8
8
  * builder then creates every declared Party, Composition, Recording, Track,
9
- * Release, extension, Vault plugin, Pressing, and Listing in one PTB. Fresh raw
10
- * protocol capabilities never leave the transaction: data extensions use them
11
- * directly, Vault-only plugins are configured while each new Vault is still
12
- * owned, and only the selected direct cap or VaultAdminCap is delivered.
9
+ * Release, extension, Vault plugin, Pressing, and Listing in one PTB. Share
10
+ * allocation is explicit: callers may preserve raw address balances or create
11
+ * holder Stakes, register them before a fresh pool is shared, and transfer the
12
+ * registered objects. Fresh raw protocol capabilities never leave the
13
+ * transaction: data extensions use them directly, Vault-only plugins are
14
+ * configured while each new Vault is still owned, and only the selected direct
15
+ * cap or VaultAdminCap is delivered.
13
16
  */
14
17
 
15
18
  import { Transaction, type TransactionObjectArgument } from "@mysten/sui/transactions";
@@ -22,7 +25,14 @@ import {
22
25
  import { derivePartyAdminCapId } from "@misonetwork/sdk/party";
23
26
  import type { MisoPlatformDeployment } from "./deployments.ts";
24
27
  import type { TxThunk } from "./transactions.ts";
25
- import { disperseShares, requiredCommandResult, type ShareRecipient } from "./transactions.ts";
28
+ import {
29
+ createShareStakes,
30
+ disperseShares,
31
+ registerShareStake,
32
+ requiredCommandResult,
33
+ shareRoyaltyPool,
34
+ type ShareRecipient,
35
+ } from "./transactions.ts";
26
36
  import {
27
37
  addRecordingPrimaryArtist,
28
38
  addReleaseCredit,
@@ -59,6 +69,8 @@ import {
59
69
  installRecordingRoyaltyPoolPlugin,
60
70
  installReleaseRevenueDistributorPlugin,
61
71
  invokeWithAdminCap,
72
+ newCompositionRoyaltyPool,
73
+ newRecordingRoyaltyPool,
62
74
  parseVaultCreatedEvent,
63
75
  type AdminCapAuthority,
64
76
  type AdminCapCustody,
@@ -121,6 +133,8 @@ export interface PublicationComposition {
121
133
  readonly title: string;
122
134
  readonly royaltyRateBps: number;
123
135
  readonly shareRecipients: ShareRecipient[];
136
+ /** Defaults to raw address balances for SDK compatibility; the CLI selects `stake`. */
137
+ readonly shareDistribution?: "balance" | "stake";
124
138
  readonly custody: PublicationCustody;
125
139
  readonly credits?: PublicationCompositionCredit[];
126
140
  readonly royaltyPool?: { readonly currencyType: string };
@@ -142,6 +156,8 @@ export type PublicationRecording = PublicationRecordingParent & {
142
156
  readonly shareTreasuryCapId: string;
143
157
  readonly compositionShareType: string;
144
158
  readonly shareRecipients: ShareRecipient[];
159
+ /** Defaults to raw address balances for SDK compatibility; the CLI selects `stake`. */
160
+ readonly shareDistribution?: "balance" | "stake";
145
161
  readonly custody: PublicationCustody;
146
162
  readonly credits?: PublicationRecordingCredit[];
147
163
  readonly royaltyPool?: { readonly currencyType: string };
@@ -314,13 +330,73 @@ function listingPrice(tx: Transaction, p: AtomicPublicationParams, price: Listin
314
330
  : listingContract.newFloorPrice(args));
315
331
  }
316
332
 
333
+ interface PublicationShareAllocation {
334
+ readonly shareType: string;
335
+ readonly shareRecipients: ShareRecipient[];
336
+ readonly shareDistribution?: "balance" | "stake";
337
+ }
338
+
339
+ function allocatePublicationShares(
340
+ tx: Transaction,
341
+ p: AtomicPublicationParams,
342
+ node: PublicationShareAllocation,
343
+ balance: TransactionObjectArgument,
344
+ ): TransactionObjectArgument[] {
345
+ if (node.shareDistribution !== "stake") {
346
+ disperseShares(tx, p.deployment.packages.minato, node.shareType, balance, node.shareRecipients);
347
+ return [];
348
+ }
349
+ return createShareStakes(tx, {
350
+ balance,
351
+ shareType: node.shareType,
352
+ recipients: node.shareRecipients,
353
+ royaltyPoolPackageId: p.deployment.packages.royaltyPool,
354
+ });
355
+ }
356
+
357
+ function registerPublicationStakes(
358
+ tx: Transaction,
359
+ p: AtomicPublicationParams,
360
+ node: PublicationShareAllocation,
361
+ stakes: readonly TransactionObjectArgument[],
362
+ pool: TransactionObjectArgument,
363
+ currencyType: string,
364
+ ): void {
365
+ for (const stake of stakes) {
366
+ registerShareStake(tx, {
367
+ stake,
368
+ pool,
369
+ shareType: node.shareType,
370
+ currencyType,
371
+ royaltyPoolPackageId: p.deployment.packages.royaltyPool,
372
+ });
373
+ }
374
+ }
375
+
376
+ function transferPublicationStakes(
377
+ tx: Transaction,
378
+ node: PublicationShareAllocation,
379
+ stakes: readonly TransactionObjectArgument[],
380
+ ): void {
381
+ if (node.shareDistribution !== "stake") {
382
+ if (stakes.length !== 0) throw new Error("balance distribution unexpectedly created stakes");
383
+ return;
384
+ }
385
+ if (stakes.length !== node.shareRecipients.length) {
386
+ throw new Error("publication stake count does not match share recipient count");
387
+ }
388
+ stakes.forEach((stake, index) => {
389
+ tx.transferObjects([stake], tx.pure.address(node.shareRecipients[index]!.address));
390
+ });
391
+ }
392
+
317
393
  function publishComposition(
318
394
  tx: Transaction,
319
395
  p: AtomicPublicationParams,
320
396
  node: PublicationComposition,
321
397
  parts: WorkParts,
322
398
  ): void {
323
- disperseShares(tx, p.deployment.packages.minato, node.shareType, parts.balance, node.shareRecipients);
399
+ const stakes = allocatePublicationShares(tx, p, node, parts.balance);
324
400
  const typeArguments: [string] = [node.shareType];
325
401
  if (node.custody.kind === "direct") {
326
402
  tx.add(composition.publish({
@@ -329,6 +405,7 @@ function publishComposition(
329
405
  arguments: [parts.work, parts.adminCap],
330
406
  }));
331
407
  disposeNewAdminCap(tx, parts.adminCap, custody(p, node.custody, compositionCapType(p, node.shareType)));
408
+ transferPublicationStakes(tx, node, stakes);
332
409
  return;
333
410
  }
334
411
  custodyNewAdminCap(tx, {
@@ -340,19 +417,31 @@ function publishComposition(
340
417
  if (node.royaltyPool) {
341
418
  installCompositionRoyaltyPoolPlugin(tx, {
342
419
  vault, vaultAdminCap, compositionShareType: node.shareType,
343
- pluginPackageId: p.deployment.packages.compositionRoyaltyPoolPlugin,
420
+ pluginPackageId: p.deployment.packages.vaultCompositionRoyaltyPoolPlugin,
344
421
  });
345
- initializeCompositionRoyaltyPool(tx, {
422
+ const poolParams = {
346
423
  vault, vaultAdminCap, composition: parts.work,
347
424
  compositionShareType: node.shareType,
348
425
  currencyType: node.royaltyPool.currencyType,
349
- pluginPackageId: p.deployment.packages.compositionRoyaltyPoolPlugin,
350
- });
426
+ pluginPackageId: p.deployment.packages.vaultCompositionRoyaltyPoolPlugin,
427
+ };
428
+ if (stakes.length > 0) {
429
+ const pool = newCompositionRoyaltyPool(tx, poolParams);
430
+ registerPublicationStakes(tx, p, node, stakes, pool, node.royaltyPool.currencyType);
431
+ shareRoyaltyPool(tx, {
432
+ pool,
433
+ shareType: node.shareType,
434
+ currencyType: node.royaltyPool.currencyType,
435
+ royaltyPoolPackageId: p.deployment.packages.royaltyPool,
436
+ });
437
+ } else {
438
+ initializeCompositionRoyaltyPool(tx, poolParams);
439
+ }
351
440
  }
352
441
  if (node.routedStake) {
353
442
  installCompositionRoutedStakePlugin(tx, {
354
443
  vault, vaultAdminCap, compositionShareType: node.shareType,
355
- pluginPackageId: p.deployment.packages.compositionRoutedStakePlugin,
444
+ pluginPackageId: p.deployment.packages.vaultCompositionRoutedStakePlugin,
356
445
  });
357
446
  }
358
447
  invokeWithAdminCap(tx, {
@@ -367,6 +456,7 @@ function publishComposition(
367
456
  });
368
457
  },
369
458
  });
459
+ transferPublicationStakes(tx, node, stakes);
370
460
  }
371
461
 
372
462
  function publishRecording(
@@ -376,7 +466,7 @@ function publishRecording(
376
466
  parts: WorkParts,
377
467
  ): void {
378
468
  const typeArguments: [string, string] = [node.shareType, node.compositionShareType];
379
- disperseShares(tx, p.deployment.packages.minato, node.shareType, parts.balance, node.shareRecipients);
469
+ const stakes = allocatePublicationShares(tx, p, node, parts.balance);
380
470
  if (node.custody.kind === "direct") {
381
471
  tx.add(recording.publish({
382
472
  package: p.deployment.protocol.miso,
@@ -384,6 +474,7 @@ function publishRecording(
384
474
  arguments: [parts.work, parts.adminCap],
385
475
  }));
386
476
  disposeNewAdminCap(tx, parts.adminCap, custody(p, node.custody, recordingCapType(p, node.shareType)));
477
+ transferPublicationStakes(tx, node, stakes);
387
478
  return;
388
479
  }
389
480
  custodyNewAdminCap(tx, {
@@ -397,15 +488,27 @@ function publishRecording(
397
488
  vault, vaultAdminCap,
398
489
  recordingShareType: node.shareType,
399
490
  compositionShareType: node.compositionShareType,
400
- pluginPackageId: p.deployment.packages.recordingRoyaltyPoolPlugin,
491
+ pluginPackageId: p.deployment.packages.vaultRecordingRoyaltyPoolPlugin,
401
492
  });
402
- initializeRecordingRoyaltyPool(tx, {
493
+ const poolParams = {
403
494
  vault, vaultAdminCap, recording: parts.work,
404
495
  recordingShareType: node.shareType,
405
496
  compositionShareType: node.compositionShareType,
406
497
  currencyType: node.royaltyPool.currencyType,
407
- pluginPackageId: p.deployment.packages.recordingRoyaltyPoolPlugin,
408
- });
498
+ pluginPackageId: p.deployment.packages.vaultRecordingRoyaltyPoolPlugin,
499
+ };
500
+ if (stakes.length > 0) {
501
+ const pool = newRecordingRoyaltyPool(tx, poolParams);
502
+ registerPublicationStakes(tx, p, node, stakes, pool, node.royaltyPool.currencyType);
503
+ shareRoyaltyPool(tx, {
504
+ pool,
505
+ shareType: node.shareType,
506
+ currencyType: node.royaltyPool.currencyType,
507
+ royaltyPoolPackageId: p.deployment.packages.royaltyPool,
508
+ });
509
+ } else {
510
+ initializeRecordingRoyaltyPool(tx, poolParams);
511
+ }
409
512
  }
410
513
  invokeWithAdminCap(tx, {
411
514
  kind: "vault", vault, vaultAdminCap,
@@ -419,6 +522,7 @@ function publishRecording(
419
522
  });
420
523
  },
421
524
  });
525
+ transferPublicationStakes(tx, node, stakes);
422
526
  }
423
527
 
424
528
  function publishReleaseObject(
@@ -445,7 +549,7 @@ function publishReleaseObject(
445
549
  if (node.revenueDistribution) {
446
550
  installReleaseRevenueDistributorPlugin(tx, {
447
551
  vault, vaultAdminCap,
448
- pluginPackageId: p.deployment.packages.releaseRevenueDistributorPlugin,
552
+ pluginPackageId: p.deployment.packages.vaultReleaseRevenueDistributorPlugin,
449
553
  });
450
554
  }
451
555
  invokeWithAdminCap(tx, {
@@ -747,7 +851,7 @@ export function publishAtomicCatalog(p: AtomicPublicationParams): TxThunk {
747
851
  node.custody.kind === "vault" && node.installWallet !== false
748
852
  ? (vault, vaultAdminCap) => installPartyWalletPlugin(tx, {
749
853
  vault, vaultAdminCap,
750
- pluginPackageId: p.deployment.packages.partyWalletPlugin,
854
+ pluginPackageId: p.deployment.packages.vaultPartyWalletPlugin,
751
855
  })
752
856
  : undefined,
753
857
  ));
@@ -132,13 +132,57 @@ function coerceNumber(v: unknown): number | null {
132
132
  return null;
133
133
  }
134
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
+ /**
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`.
146
+ */
147
+ function isCanonicalRecordType(
148
+ type: string,
149
+ recordPackageId: string,
150
+ pressingPackageId: string,
151
+ ): boolean {
152
+ let tag: ReturnType<typeof parseStructTag>;
153
+ try {
154
+ tag = parseStructTag(type);
155
+ } catch {
156
+ return false;
157
+ }
158
+
159
+ if (
160
+ tag.address !== normalizeSuiAddress(recordPackageId) ||
161
+ tag.module !== "record" ||
162
+ tag.name !== "Record" ||
163
+ tag.typeParams.length !== 1
164
+ ) {
165
+ return false;
166
+ }
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
+
135
179
  /**
136
- * This copy's number in its run. Fresh records expose the canonical
137
- * `{ release_id, number }` shape; pre-publish layouts are intentionally not
138
- * accepted by the pre-launch SDK.
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 } }`.
139
183
  */
140
184
  function readRecordNumber(json: Record<string, unknown>): number | null {
141
- return coerceNumber(json.number);
185
+ return coerceNumber(record(json.certificate)?.number);
142
186
  }
143
187
 
144
188
  function readReleaseId(json: Record<string, unknown>): string | null {
@@ -156,6 +200,7 @@ export async function getOwnedRecords(client: MisoClient, owner: string): Promis
156
200
  const out: OwnedRecord[] = [];
157
201
  let cursor: string | null = null;
158
202
  const recordType = `${client.config.protocol.record}::record::Record`;
203
+ const pressingPackageId = client.config.protocol.pressing;
159
204
 
160
205
  for (let page = 0; page < MAX_PAGES; page++) {
161
206
  // Annotated: `cursor` is both an input and assigned from the result, which
@@ -169,7 +214,9 @@ export async function getOwnedRecords(client: MisoClient, owner: string): Promis
169
214
  include: { json: true },
170
215
  });
171
216
  for (const obj of res.objects) {
172
- if (obj.type !== recordType) continue;
217
+ if (!isCanonicalRecordType(obj.type, client.config.protocol.record, pressingPackageId)) {
218
+ continue;
219
+ }
173
220
  const json = (obj.json ?? {}) as Record<string, unknown>;
174
221
  out.push({
175
222
  id: obj.objectId,
@@ -12,9 +12,9 @@
12
12
  // platform-layer call that lives here:
13
13
  //
14
14
  // - minting a work's share supply is a protocol primitive
15
- // (`createComposition`/`createRecording`) — dispersing it to recipients via
16
- // minato, publishing (sharing) the work, and transferring its admin cap is
17
- // an opinion about economics;
15
+ // (`createComposition`/`createRecording`) — allocating it to raw address
16
+ // balances or composable Stake objects, publishing (sharing) the work, and
17
+ // transferring its admin cap is an opinion about economics;
18
18
  // - minting a release is a platform primitive: core's `release::new` takes an
19
19
  // unconstructible PTB `&mut UID`, so core `release::new(registry, …)` is the
20
20
  // canonical client path. Choosing a track-assembly strategy, publishing
@@ -43,6 +43,8 @@ import {
43
43
  type TxThunk,
44
44
  } from "@misonetwork/sdk";
45
45
  import { asU64, directAdminCap, disposeNewAdminCap, invokeWithAdminCap, type AdminCapAuthority, type AdminCapCustody, type U64Input } from "./vault.ts";
46
+ import * as royaltyPool from "./contracts/royalty_pool/pool.ts";
47
+ import * as royaltyPoolStake from "./contracts/royalty_pool/stake.ts";
46
48
 
47
49
  const { track, release } = contracts;
48
50
 
@@ -96,6 +98,112 @@ export interface ShareRecipient {
96
98
  value: U64Input;
97
99
  }
98
100
 
101
+ export interface CreateShareStakeParams {
102
+ readonly balance: TransactionObjectArgument;
103
+ readonly shareType: string;
104
+ readonly value: U64Input;
105
+ readonly royaltyPoolPackageId: string;
106
+ }
107
+
108
+ /** Split shares from a Balance and return a fresh, unregistered Stake object. */
109
+ export function createShareStake(
110
+ tx: Transaction,
111
+ params: CreateShareStakeParams,
112
+ ): TransactionObjectArgument {
113
+ const value = asU64("share stake value", params.value);
114
+ if (value === 0n) throw new Error("share stake value must be greater than zero");
115
+ const stakeBalance = tx.moveCall({
116
+ target: "0x2::balance::split",
117
+ typeArguments: [params.shareType],
118
+ arguments: [params.balance, tx.pure.u64(value)],
119
+ });
120
+ return tx.add(
121
+ royaltyPoolStake._new({
122
+ package: params.royaltyPoolPackageId,
123
+ typeArguments: [params.shareType],
124
+ arguments: [stakeBalance],
125
+ }),
126
+ );
127
+ }
128
+
129
+ export interface RegisterShareStakeParams {
130
+ readonly stake: TransactionObjectArgument;
131
+ readonly pool: TransactionObjectArgument;
132
+ readonly shareType: string;
133
+ readonly currencyType: string;
134
+ readonly royaltyPoolPackageId: string;
135
+ }
136
+
137
+ /** Register an existing Stake with one RoyaltyPool. */
138
+ export function registerShareStake(
139
+ tx: Transaction,
140
+ params: RegisterShareStakeParams,
141
+ ): void {
142
+ tx.add(
143
+ royaltyPool.registerStake({
144
+ package: params.royaltyPoolPackageId,
145
+ typeArguments: [params.shareType, params.currencyType],
146
+ arguments: [params.pool, params.stake],
147
+ }),
148
+ );
149
+ }
150
+
151
+ export interface CreateShareStakesParams {
152
+ readonly balance: TransactionObjectArgument;
153
+ readonly shareType: string;
154
+ readonly recipients: readonly ShareRecipient[];
155
+ readonly royaltyPoolPackageId: string;
156
+ }
157
+
158
+ /**
159
+ * Convert an entire share Balance into one unregistered Stake per recipient.
160
+ * The emptied Balance is destroyed, so recipient values must consume it exactly.
161
+ * Returned stakes remain caller-controlled for optional registration and transfer.
162
+ */
163
+ export function createShareStakes(
164
+ tx: Transaction,
165
+ params: CreateShareStakesParams,
166
+ ): TransactionObjectArgument[] {
167
+ if (params.recipients.length === 0) {
168
+ throw new Error("share stake recipients must not be empty");
169
+ }
170
+ const values = params.recipients.map((recipient) => {
171
+ const value = asU64("share stake value", recipient.value);
172
+ if (value === 0n) throw new Error("share stake value must be greater than zero");
173
+ return value;
174
+ });
175
+ const stakes = params.recipients.map((recipient, index) => createShareStake(tx, {
176
+ balance: params.balance,
177
+ shareType: params.shareType,
178
+ value: values[index]!,
179
+ royaltyPoolPackageId: params.royaltyPoolPackageId,
180
+ }));
181
+ tx.moveCall({
182
+ target: "0x2::balance::destroy_zero",
183
+ typeArguments: [params.shareType],
184
+ arguments: [params.balance],
185
+ });
186
+ return stakes;
187
+ }
188
+
189
+ export interface ShareRoyaltyPoolParams {
190
+ readonly pool: TransactionObjectArgument;
191
+ readonly shareType: string;
192
+ readonly currencyType: string;
193
+ readonly royaltyPoolPackageId: string;
194
+ }
195
+
196
+ /** Consume an unshared RoyaltyPool and make it globally accessible. */
197
+ export function shareRoyaltyPool(tx: Transaction, params: ShareRoyaltyPoolParams): void {
198
+ tx.add(
199
+ royaltyPool.share({
200
+ package: params.royaltyPoolPackageId,
201
+ typeArguments: [params.shareType, params.currencyType],
202
+ arguments: [params.pool],
203
+ }),
204
+ );
205
+ }
206
+
99
207
  /**
100
208
  * Splits a share `Balance` across `recipients` via `minato::disperse_balance`, then
101
209
  * destroys the emptied balance. Exposed for consumers assembling custom share
package/src/vault.ts CHANGED
@@ -267,6 +267,21 @@ export interface InitializeCompositionRoyaltyPoolParams
267
267
  readonly currencyType: string;
268
268
  }
269
269
 
270
+ /** Create the canonical pool without sharing it so callers can configure fresh stakes first. */
271
+ export function newCompositionRoyaltyPool(
272
+ tx: Transaction,
273
+ params: InitializeCompositionRoyaltyPoolParams,
274
+ ): TransactionObjectArgument {
275
+ return tx.add(
276
+ compositionRoyaltyPool.newPool({
277
+ package: params.pluginPackageId,
278
+ typeArguments: [params.compositionShareType, params.currencyType],
279
+ arguments: [params.vault, params.composition, params.vaultAdminCap],
280
+ }),
281
+ );
282
+ }
283
+
284
+ /** Create and immediately share the canonical Composition royalty pool. */
270
285
  export function initializeCompositionRoyaltyPool(
271
286
  tx: Transaction,
272
287
  params: InitializeCompositionRoyaltyPoolParams,
@@ -470,6 +485,25 @@ export interface InitializeRecordingRoyaltyPoolParams
470
485
  readonly currencyType: string;
471
486
  }
472
487
 
488
+ /** Create the canonical pool without sharing it so callers can configure fresh stakes first. */
489
+ export function newRecordingRoyaltyPool(
490
+ tx: Transaction,
491
+ params: InitializeRecordingRoyaltyPoolParams,
492
+ ): TransactionObjectArgument {
493
+ return tx.add(
494
+ recordingRoyaltyPool.newPool({
495
+ package: params.pluginPackageId,
496
+ typeArguments: [
497
+ params.recordingShareType,
498
+ params.compositionShareType,
499
+ params.currencyType,
500
+ ],
501
+ arguments: [params.vault, params.recording, params.vaultAdminCap],
502
+ }),
503
+ );
504
+ }
505
+
506
+ /** Create and immediately share the canonical Recording royalty pool. */
473
507
  export function initializeRecordingRoyaltyPool(
474
508
  tx: Transaction,
475
509
  params: InitializeRecordingRoyaltyPoolParams,