@misonetwork/sdk 0.4.0 → 0.6.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 (70) hide show
  1. package/README.md +101 -503
  2. package/dist/client.d.ts +21 -59
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +26 -58
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts/miso/release.d.ts +34 -31
  7. package/dist/contracts/miso/release.d.ts.map +1 -1
  8. package/dist/contracts/miso/release.js +32 -29
  9. package/dist/contracts/miso/release.js.map +1 -1
  10. package/dist/contracts/miso/track.d.ts +66 -22
  11. package/dist/contracts/miso/track.d.ts.map +1 -1
  12. package/dist/contracts/miso/track.js +65 -20
  13. package/dist/contracts/miso/track.js.map +1 -1
  14. package/dist/contracts/utils/index.d.ts +44 -0
  15. package/dist/contracts/utils/index.d.ts.map +1 -1
  16. package/dist/contracts/utils/index.js +104 -2
  17. package/dist/contracts/utils/index.js.map +1 -1
  18. package/dist/contracts.d.ts +0 -1
  19. package/dist/contracts.d.ts.map +1 -1
  20. package/dist/contracts.js +0 -1
  21. package/dist/contracts.js.map +1 -1
  22. package/dist/deployments.d.ts +21 -0
  23. package/dist/deployments.d.ts.map +1 -0
  24. package/dist/deployments.js +17 -0
  25. package/dist/deployments.js.map +1 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/internal.d.ts +0 -7
  31. package/dist/internal.d.ts.map +1 -1
  32. package/dist/internal.js +0 -22
  33. package/dist/internal.js.map +1 -1
  34. package/dist/parsers.d.ts +1 -4
  35. package/dist/parsers.d.ts.map +1 -1
  36. package/dist/parsers.js +0 -24
  37. package/dist/parsers.js.map +1 -1
  38. package/dist/queries.d.ts +2 -5
  39. package/dist/queries.d.ts.map +1 -1
  40. package/dist/queries.js +8 -45
  41. package/dist/queries.js.map +1 -1
  42. package/dist/transactions.d.ts +10 -71
  43. package/dist/transactions.d.ts.map +1 -1
  44. package/dist/transactions.js +15 -72
  45. package/dist/transactions.js.map +1 -1
  46. package/dist/types.d.ts +3 -40
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/view.d.ts +7 -7
  49. package/dist/view.d.ts.map +1 -1
  50. package/dist/view.js +9 -9
  51. package/dist/view.js.map +1 -1
  52. package/package.json +8 -4
  53. package/src/client.ts +47 -86
  54. package/src/contracts/miso/release.ts +39 -36
  55. package/src/contracts/miso/track.ts +81 -23
  56. package/src/contracts/utils/index.ts +156 -4
  57. package/src/contracts.ts +0 -1
  58. package/src/deployments.ts +42 -0
  59. package/src/index.ts +1 -0
  60. package/src/internal.ts +0 -24
  61. package/src/parsers.ts +0 -35
  62. package/src/queries.ts +11 -59
  63. package/src/transactions.ts +20 -112
  64. package/src/types.ts +3 -53
  65. package/src/view.ts +13 -13
  66. package/dist/contracts/miso/deal.d.ts +0 -184
  67. package/dist/contracts/miso/deal.d.ts.map +0 -1
  68. package/dist/contracts/miso/deal.js +0 -184
  69. package/dist/contracts/miso/deal.js.map +0 -1
  70. package/src/contracts/miso/deal.ts +0 -257
package/README.md CHANGED
@@ -1,17 +1,13 @@
1
1
  # @misonetwork/sdk
2
2
 
3
- TypeScript SDK for the [Miso](https://github.com/misonetwork/miso-protocol) protocol on [Sui](https://sui.io).
3
+ TypeScript SDK for the [Miso](https://github.com/misonetwork/protocol) protocol
4
+ core on [Sui](https://sui.io). Bindings are regenerated from the local
5
+ `misonetwork/protocol` Move source with `bun run codegen`.
4
6
 
5
- This package mirrors the on-chain ABI of the [`misonetwork/miso-protocol`](https://github.com/misonetwork/miso-protocol) Move package — the protocol core, and nothing else — regenerated from the live Move source via `bun run codegen`.
6
-
7
- Miso is a permissionless on-chain music protocol that models compositions, recordings, and releases — and their associated rights and royalties — as Sui objects. This SDK provides typed queries, composable transaction builders, BCS event parsers, and a client extension.
8
-
9
- Helpers for the first-party **extensions** — credits, cover art, royalty pools —
10
- live in [`@misofm/sdk`](https://github.com/misofm/sdk), not here. An extension is
11
- opinionated business logic hung off the protocol's `&mut UID` hook (which roles
12
- exist and what they are called, what a cover is, how royalties accumulate), so it
13
- ships with the platform layer. The protocol package stays the open thing anyone
14
- can build on without adopting Miso's opinions.
7
+ Miso models compositions, recordings, releases, their rights, and royalties as
8
+ Sui objects. This package provides core queries, PTB primitives, generated BCS
9
+ bindings, event parsers, and a client extension. First-party policy and
10
+ extension helpers live in [`@misofm/sdk`](https://github.com/misofm/sdk).
15
11
 
16
12
  ## Installation
17
13
 
@@ -19,555 +15,157 @@ can build on without adopting Miso's opinions.
19
15
  bun add @misonetwork/sdk @mysten/sui
20
16
  ```
21
17
 
22
- ## Quick Start
18
+ ## Client extension
23
19
 
24
20
  ```ts
25
21
  import { SuiGrpcClient } from "@mysten/sui/grpc";
26
22
  import { miso } from "@misonetwork/sdk";
27
23
 
28
- const client = new SuiGrpcClient({ network: "testnet" })
29
- .$extend(miso({ misoPackageId: "0x..." }));
24
+ const client = new SuiGrpcClient({
25
+ network: "testnet",
26
+ baseUrl: "https://fullnode.testnet.sui.io:443",
27
+ })
28
+ .$extend(miso());
30
29
 
31
- // Fetch a recording
32
30
  const recording = await client.miso.getRecordingById("0x...");
33
- console.log(recording.state); // display title comes from the parent composition
34
-
35
- // Derive an admin cap ID (pure, no network call)
36
31
  const adminCapId = client.miso.deriveRecordingAdminCapId("0x...");
37
32
  ```
38
33
 
39
- ## Client Extension
40
-
41
- The SDK provides a `miso()` client extension that works with any Sui client implementing the Core API:
42
-
43
- ```ts
44
- import { SuiGrpcClient } from "@mysten/sui/grpc";
45
- import { SuiGraphQLClient } from "@mysten/sui/graphql";
46
- import { miso } from "@misonetwork/sdk";
47
-
48
- const graphqlClient = new SuiGraphQLClient({
49
- url: "https://sui-testnet.mystenlabs.com/graphql",
50
- network: "testnet",
51
- });
52
-
53
- const client = new SuiGrpcClient({ network: "testnet" })
54
- .$extend(miso({
55
- misoPackageId: "0x...",
56
- graphqlClient, // Required for generic type-based queries (getByShareType, getOwnedCompositionAdminCaps, getOwnedRecordingAdminCaps, getReleaseRegistry, getAdministeredRecordings)
57
- }));
58
- ```
59
-
60
- ### API Priority
61
-
62
- Methods use the most efficient transport available:
34
+ Pass a `SuiGraphQLClient` as `graphqlClient` only for generic type discovery,
35
+ such as `getCompositionByShareType` and `getRecordingByShareType`. ID reads and
36
+ owned-cap queries use the Core API.
63
37
 
64
- | Transport | When Used | Examples |
65
- |-----------|-----------|----------|
66
- | **Core API** | Single-object fetch by ID, derivation | `getRecordingById`, `deriveCompositionAdminCapId` |
67
- | **Core API** | Non-generic type queries | `getOwnedReleaseAdminCaps` |
68
- | **GraphQL** | Generic type queries (partial type matching) | `getOwnedCompositionAdminCaps`, `getRecordingByShareType` |
38
+ The current Testnet package is bundled with the SDK and selected from the Sui
39
+ client's network. Mainnet fails closed until this protocol ABI is deployed there;
40
+ custom deployments can be supplied explicitly with `miso({ deployment })`.
69
41
 
70
- ## Data Model
42
+ ## Data model
71
43
 
72
- Miso stores only protocol-verifiable state. Each entity follows a build-then-freeze
73
- lifecycle (`Initialized Published`) and is immutable once published.
44
+ - `Composition`: the written work, with a share currency and royalty rate.
45
+ - `Recording`: an audio performance of a composition, with its own share currency.
46
+ - `Track`: a recording admin's consent to an exact target release ID and split.
47
+ - `Release`: a flat ordered sequence of tracks. Disc/side grouping is extension
48
+ presentation data, not core state.
74
49
 
75
- - **Composition** the underlying written work. Earns an immutable-floored `royaltyRate` from each recording. Backed by its own share currency.
76
- - **Recording** an audio performance of a composition. Backed by its own share currency. Carries no name of its own — its display title is its composition's title; richer naming lives in the metadata extension.
77
- - **Release** — a flat, ordered tracklist of `Track`s (album, EP, or single), assembled from `Deal`s. Display grouping (discs/sides) lives in extensions.
78
- - **Deal** — a recording admin's transferable authorization to include the recording on one exact release id.
79
-
80
- Everything else — credits, cover art, royalty pools, masters, descriptive
81
- metadata — attaches to the frozen core objects as dynamic fields through
82
- extension packages (see [Extensions](#extensions)).
83
-
84
- On publish, each entity emits a single lean pointer event carrying just its identity;
85
- indexers subscribe to that pointer and fetch the immutable object by ID.
50
+ Core objects are built then published. Credits, cover art, royalty pools, and
51
+ release coordination are extension-layer concerns in `@misofm/sdk`.
86
52
 
87
53
  ## Queries
88
54
 
89
- All client methods are also available as standalone functions (taking the client
90
- explicitly) from the package root.
91
-
92
- ### Compositions
93
-
94
- ```ts
95
- // Core API (by ID)
96
- const comp = await client.miso.getCompositionById("0x...");
97
- const comps = await client.miso.getCompositionsByIds(["0x...", "0x..."]);
98
- const capId = client.miso.deriveCompositionAdminCapId("0x...");
99
- const cap = await client.miso.getCompositionAdminCapById(capId);
100
- const shareType = await client.miso.getCompositionShareType("0x...");
101
-
102
- // GraphQL (by type or owner)
103
- const comp2 = await client.miso.getCompositionByShareType("0x...::share::Share");
104
- const caps = await client.miso.getOwnedCompositionAdminCaps(ownerAddress);
105
- ```
106
-
107
- ### Recordings
55
+ All client methods are also exported as standalone functions.
108
56
 
109
57
  ```ts
110
- // Core API (by ID)
111
- const rec = await client.miso.getRecordingById("0x...");
112
- const recs = await client.miso.getRecordingsByIds(["0x...", "0x..."]);
113
- const recCapId = client.miso.deriveRecordingAdminCapId("0x...");
114
- const recCap = await client.miso.getRecordingAdminCapById(recCapId);
115
-
116
- // A Recording is generic over two phantoms — Recording<RecordingShare, CompositionShare>.
117
- const recShareType = await client.miso.getRecordingShareType("0x..."); // the recording's OWN share type
118
- const [recShare, compShare] = await getRecordingShareTypes(client, "0x..."); // both, in that order
119
-
120
- // GraphQL (by type or owner)
121
- const rec2 = await client.miso.getRecordingByShareType("0x...::share::Share");
122
- const recCaps = await client.miso.getOwnedRecordingAdminCaps(ownerAddress);
123
- const administered = await client.miso.getAdministeredRecordings(ownerAddress);
124
- ```
125
-
126
- `getRecordingShareType` returns the recording's own share type
127
- (`RecordingShare`) and is bound on the client. `getRecordingShareTypes` is the
128
- standalone query that returns both as `[RecordingShare, CompositionShare]` —
129
- reach for it when building anything generic over the pair, which is most of the
130
- protocol: `deal::new`, `track::new`, `recording::publish`, and the recording
131
- credit/royalty-pool extensions all take the two phantoms in exactly that order.
132
-
133
- ### Deals
134
-
135
- ```ts
136
- // Share types are read from the object's `Deal<RecordingShare, CompositionShare>` type parameters.
137
- const deal = await client.miso.getDealById("0x...");
138
- // { id, releaseId, trackSplitBps, recordingShareType, compositionShareType }
139
- ```
140
-
141
- ### Releases
142
-
143
- ```ts
144
- // Core API (by ID)
145
58
  const release = await client.miso.getReleaseById("0x...");
146
- const releases = await client.miso.getReleasesByIds(["0x...", "0x..."]);
147
- const relCapId = client.miso.deriveReleaseAdminCapId("0x...");
148
- const relCap = await client.miso.getReleaseAdminCapById(relCapId);
149
- const relCaps = await client.miso.getOwnedReleaseAdminCaps(ownerAddress);
150
-
151
- // GraphQL
152
- const registryId = await client.miso.getReleaseRegistry();
153
- ```
154
-
155
- ### Share currencies
156
-
157
- ```ts
158
- const shareType = await client.miso.getShareCurrencyType("0x..."); // Currency<T> object id → T
159
- // Takes the share TYPE (which builders already thread around), not the Currency
160
- // object id — so this is one call, not two.
161
- const treasuryCapId = await client.miso.getShareCurrencyTreasuryCap(shareType, ownerAddress);
59
+ const caps = await client.miso.getOwnedReleaseAdminCaps(ownerAddress);
60
+ const [recordingShare, compositionShare] = await getRecordingShareTypes(
61
+ client,
62
+ "0x...",
63
+ );
162
64
  ```
163
65
 
164
- ### Missing objects: null vs throw
66
+ Core object getters throw for a missing object. The exported `isNotFound(error)`
67
+ helper distinguishes that condition from transport failures.
165
68
 
166
- Core-object getters (`getCompositionById`, `getDealById`, …) **throw** when the
167
- object is missing — a miss means a broken reference. Extension readers
168
- (`getCompositionCredits`, `getReleaseCover`, … — now in `@misofm/sdk`) return
169
- **`null`** instead, because extension data is optional by design. The exported
170
- `isNotFound(e)` helper distinguishes a missing-object error from a transport
171
- failure across all Sui client transports, and `@misofm/sdk` re-exports it so
172
- both packages share one not-found taxonomy:
173
-
174
- ```ts
175
- import { isNotFound } from "@misonetwork/sdk";
176
-
177
- try {
178
- await client.miso.getReleaseById(id);
179
- } catch (e) {
180
- if (isNotFound(e)) { /* no such object */ } else throw e;
181
- }
182
- ```
183
-
184
- Also exported: `extractTypeParam("p::m::T<A>")` → `"A"` and
185
- `extractTypeParams2("p::m::T<A, B>")` → `["A", "B"]` for reading share types
186
- out of object type tags.
187
-
188
- ## Transaction Builders
189
-
190
- This module exports five builders, in two shapes:
191
-
192
- | Builder | Shape |
193
- |---------|-------|
194
- | `createComposition(tx, params)` | takes the `Transaction` first, returns `CompositionParts` |
195
- | `createRecording(tx, params)` | takes the `Transaction` first, returns `RecordingParts` |
196
- | `createDeal(tx, params)` | takes the `Transaction` first, returns a `TransactionObjectArgument` |
197
- | `createRelease(tx, params, trackVec)` | takes the `Transaction` first, returns `ReleaseParts` |
198
- | `rejectDeal(params)` | returns a `TxThunk` |
199
-
200
- Only `rejectDeal` follows the thunk pattern — it returns a `TxThunk`
201
- (`(tx: Transaction) => void | Promise<void>`) that appends commands to a
202
- caller-owned `Transaction`. The four `create*` primitives take the
203
- `Transaction` as their **first argument** and return their by-value results, so
204
- those results can be threaded into later commands. Either way, everything
205
- composes inside a single caller-owned PTB.
206
-
207
- The client binds exactly one builder — `client.miso.tx.rejectDeal` — which
208
- injects the client's `misoPackageId`. The `create*` primitives have no thunk to
209
- bind, so they stay free functions: import them from the package root and pass
210
- `misoPackageId` explicitly.
211
-
212
- This SDK keeps the bare protocol primitives only. The four `create*` functions
213
- each append a single `::new` and hand back its by-value results — never
214
- dispersing a share supply, publishing (sharing) the object, or routing an admin
215
- cap. The opinionated layers — the finish (disperse via minato, publish,
216
- transfer), track assembly, cap disposition, and the share-currency lifecycle —
217
- live in [`@misofm/sdk`](https://github.com/misofm/sdk) as **free functions that
218
- take `misoPackageId` explicitly** (they are not bound onto any client's `tx`
219
- namespace): `finalizeComposition`/`finalizeRecording`/`finalizeRelease`,
220
- `publishComposition`/`publishRecording`/`publishCompositionAndRecording`,
221
- `publishRelease`/`publishReleaseFromDeals`/`publishReleaseGraph`,
222
- `disperseShares`, share-currency provisioning, and `executeViaExecutor`. Those
223
- import the primitives from here and build on top.
224
-
225
- Execute any thunk (from this SDK or composed with another) with `buildTx` +
226
- `signAndExecute` — see [Execution](#execution-executets):
227
-
228
- ```ts
229
- import { buildTx, signAndExecute } from "@misonetwork/sdk";
230
-
231
- const tx = await buildTx(client.miso.tx.rejectDeal({ /* … */ }));
232
- await signAndExecute(client, signer, tx);
233
- ```
69
+ ## Transaction primitives
234
70
 
235
- ### Deals
71
+ The core exports these synchronous builders, each operating on the caller's
72
+ `Transaction`:
236
73
 
237
- `createDeal` is a primitive: it appends `deal::new` and returns the `Deal` for
238
- you to route. It is a free function (not on `client.tx`) because it takes the
239
- `Transaction` directly, so pass `misoPackageId` explicitly.
74
+ | Builder | Result |
75
+ | --- | --- |
76
+ | `createComposition(tx, params)` | `CompositionParts` |
77
+ | `createRecording(tx, params)` | `RecordingParts` |
78
+ | `createTrack(tx, params)` | `TransactionObjectArgument` |
240
79
 
241
- The returned `Deal` MUST be consumed in the same transaction — it is
242
- `key, store` with no `drop` but it can go to either of two places, which is
243
- why the SDK does not choose for you:
80
+ `createTrack` adds cap-gated `track::new`; it accepts either an on-chain
81
+ `recordingAdminCapId` or a PTB-local `recordingAdminCap` result. A `Track` has
82
+ `drop, store`, so leaving it unconsumed is valid. To create a release, collect
83
+ tracks with `tx.makeMoveVec({ type: `${misoPackageId}::track::Track`, elements })`
84
+ and call the extension's `release_registry::new_release` via `@misofm/sdk`.
244
85
 
245
86
  ```ts
246
- import { createDeal } from "@misonetwork/sdk";
87
+ import { createTrack } from "@misonetwork/sdk";
247
88
 
248
- const deal = createDeal(tx, {
89
+ const track = createTrack(tx, {
249
90
  recordingId: "0x...",
250
- recordingAdminCapId: "0x...", // or `recordingAdminCap` as an in-PTB argument
91
+ recordingAdminCapId: "0x...",
251
92
  recordingShareType: "0x...::share::Share",
252
93
  compositionShareType: "0x...::share::Share",
253
- releaseId: "0x...", // pre-derived to match release::new — see view.deriveReleaseId
94
+ targetReleaseId: "0x...",
254
95
  trackSplitBps: 5000,
255
96
  misoPackageId,
256
97
  });
257
-
258
- // (1) cross-party: send it to whoever assembles the release, to redeem later
259
- tx.transferObjects([deal], releaseCreator);
260
-
261
- // (2) same-party: spend it immediately as authorization for a track
262
- // tx.add(contracts.track._new({ package: misoPackageId, typeArguments, arguments: [deal, recording] }));
263
98
  ```
264
99
 
265
- `rejectDeal` is the one builder bound on the client. It destroys a deal without
266
- including it in a release, and emits `DealRejectedEvent`:
267
-
268
- ```ts
269
- client.miso.tx.rejectDeal({
270
- dealId: "0x...",
271
- recordingShareType: "0x...::share::Share",
272
- compositionShareType: "0x...::share::Share",
273
- });
274
- ```
100
+ `createComposition` and `createRecording` return their by-value components so
101
+ they can be composed in the same PTB. `recording::new` borrows its composition,
102
+ so a fresh composition can be passed directly into `createRecording` before it
103
+ is published.
275
104
 
276
- ### Releases
105
+ ### Release IDs
277
106
 
278
- The end-to-end release publishers are **not** on `client.miso.tx` they are free
279
- functions in [`@misofm/sdk`](https://github.com/misofm/sdk) that take
280
- `misoPackageId` explicitly:
107
+ Release IDs are derived on chain by simulation. `parentId` is a pure object ID,
108
+ not an object input—for example, the shared `ReleaseRegistry` owned by the
109
+ extension package.
281
110
 
282
111
  ```ts
283
- import { publishRelease, publishReleaseFromDeals } from "@misofm/sdk";
284
-
285
- // Sender holds every recording's admin cap (a deal is created inline per track).
286
- await buildTx(publishRelease({ title, tracks, releaseRegistryId, releaseId, releaseNonce, adminAddress, misoPackageId }));
287
-
288
- // Or assemble from pre-made Deals the sender already holds.
289
- await buildTx(publishReleaseFromDeals({ title, deals, releaseRegistryId, releaseNonce, adminAddress, misoPackageId }));
290
- ```
291
-
292
- `releaseId` is a field on `PublishReleaseParams` only — pre-derive it (see
293
- [Deriving the release id](#deriving-the-release-id-view)) so the inline deals
294
- pin the right release. `PublishReleaseFromDealsParams` has no `releaseId`: each
295
- pre-made deal already embeds it, so the from-deals variant derives it from them.
296
-
297
- This package supplies the primitive underneath both: `createRelease(tx, params,
298
- trackVec)`, which appends `release::new` over a caller-built `vector<Track>` and
299
- returns the release plus its admin cap.
300
-
301
- ### Deriving the release id (`view`)
302
-
303
- Deals embed the exact release id, which the chain derives from the full
304
- tracklist + nonce. Compute it up front via `simulateTransaction`:
305
-
306
- ```ts
307
- const releaseId = await client.miso.view.deriveReleaseId({
308
- sender: ownerAddress, // any address; not charged
309
- recordingIds: ["0x...", "0x..."], // in track order
310
- splitBps: [5000, 5000], // aligned to recordingIds
112
+ const targetReleaseId = await client.miso.view.deriveTargetReleaseId({
113
+ sender: ownerAddress,
114
+ recordingIds: ["0x...", "0x..."],
115
+ splitBps: [5000, 5000],
311
116
  nonce: "42",
312
- releaseRegistryId: "0x...",
117
+ parentId: releaseRegistryId,
313
118
  });
314
119
  ```
315
120
 
316
- ### Creating works (`createComposition` / `createRecording` / `createRelease`)
317
-
318
- Each `create*` appends a single `::new` and returns its by-value parts — the
319
- object, its admin cap, and for a work its freshly-minted share `Balance`. The
320
- caller decides what happens next.
321
-
322
- The key move is **borrow-before-share**: `recording::new` takes the parent
323
- composition by immutable reference, so you can pass a `createComposition(...)`
324
- result straight into `createRecording`'s `composition` param while it is still an
325
- unshared, transaction-local value. That is what lets a composition and its first
326
- recording be minted in one PTB.
327
-
328
- ```ts
329
- import { Transaction } from "@mysten/sui/transactions";
330
- import { createComposition, createRecording } from "@misonetwork/sdk";
331
-
332
- const tx = new Transaction();
333
-
334
- // 1. Composition — returns { composition, adminCap, balance }.
335
- const comp = createComposition(tx, {
336
- title: "Song Title",
337
- royaltyRateBps: 1000,
338
- shareType: compositionShareType, // `${sharePkg}::share::Share`
339
- shareCurrencyId: "0x...", // Currency<Share>
340
- shareTreasuryCapId: "0x...", // TreasuryCap<Share>, consumed by `new`
341
- misoPackageId,
342
- });
343
-
344
- // 2. Recording — borrow-before-share: hand the still-unshared composition
345
- // straight in. No on-chain object id is needed for it.
346
- const rec = createRecording(tx, {
347
- composition: comp.composition, // or `tx.object(compositionId)` if already on chain
348
- compositionShareType,
349
- shareType: recordingShareType,
350
- shareCurrencyId: "0x...",
351
- shareTreasuryCapId: "0x...",
352
- maxRoyaltyRateBps: 1000, // slippage guard — see below
353
- misoPackageId,
354
- });
355
-
356
- // 3. Both objects MUST still be consumed by their `publish` in THIS transaction
357
- // — e.g. `finalizeComposition(tx, { ...comp, ... })` / `finalizeRecording(tx,
358
- // { ...rec, ... })` from `@misofm/sdk`, which disperse the balances, publish
359
- // the works, and route the admin caps.
360
- ```
361
-
362
- `createRelease` takes the `vector<Track>` as an argument, because track assembly
363
- is the part that genuinely varies between flows — from recording admin caps,
364
- from pre-made deals, or from a mix of fresh and existing recordings:
365
-
366
- ```ts
367
- import { createRelease } from "@misonetwork/sdk";
368
-
369
- const trackVec = tx.makeMoveVec({ type: `${misoPackageId}::track::Track`, elements: trackArgs });
370
- const rel = createRelease(tx, { title: "Album Title", nonce: "42", releaseRegistryId, misoPackageId }, trackVec);
371
- // rel.release must be consumed by `release::publish` in this same tx.
372
- ```
373
-
374
- #### Royalty-rate slippage (`maxRoyaltyRateBps`)
375
-
376
- A composition's royalty rate is floored but can be **raised** by its admin. If it
377
- goes up between the moment you read it and the moment your transaction lands, a
378
- recording you thought owed 10% could land owing more. `CreateRecordingParams.maxRoyaltyRateBps`
379
- is the guard: it is the maximum composition royalty rate (in bps) the recorder is
380
- willing to grant, and `recording::new` aborts with `ERoyaltyRateAboveMax` if the
381
- composition's live rate exceeds it. Pass the rate you actually observed.
382
-
383
- It is optional, and defaults to the exported `PROTOCOL_MAX_ROYALTY_RATE_BPS`
384
- (`2000`, the protocol's `MAX_ROYALTY_RATE_BPS`) — which accepts any legal rate,
385
- i.e. no slippage protection. Set it explicitly whenever you are recording someone
386
- else's composition.
387
-
388
- ```ts
389
- import { PROTOCOL_MAX_ROYALTY_RATE_BPS } from "@misonetwork/sdk";
390
-
391
- const comp = await client.miso.getCompositionById(compositionId);
392
- createRecording(tx, { /* … */ maxRoyaltyRateBps: comp.royaltyRate.value });
393
- ```
394
-
395
- #### Result shapes
396
-
397
- ```ts
398
- import type {
399
- CompositionParts, RecordingParts, ReleaseParts, ShareCurrencyBinding,
400
- } from "@misonetwork/sdk";
401
-
402
- // CompositionParts { composition, adminCap, balance } — balance is the creator's
403
- // freshly-minted share supply
404
- // RecordingParts { recording, adminCap, balance } — balance is what remains
405
- // after the composition's cut
406
- // ReleaseParts { release, adminCap }
407
- // All fields are `TransactionObjectArgument`s, for threading onward in the PTB.
408
- ```
409
-
410
- `ShareCurrencyBinding` is the trio every work-creating builder needs, extended by
411
- both `CreateCompositionParams` and `CreateRecordingParams`: `shareType` (the
412
- `${packageId}::share::Share` type), `shareCurrencyId` (the `Currency<Share>`
413
- object), and `shareTreasuryCapId` (the `TreasuryCap<Share>`, consumed by `new`).
414
- All three are passed explicitly rather than read from chain, which keeps the
415
- builders synchronous — no RPC inside the transaction build.
416
-
417
- **Lifecycle requirement.** `Composition`, `Recording`, and `Release` are all
418
- `key`-only with no `drop`, so each created object MUST be consumed by its
419
- `publish` in the same transaction — none can be transferred, wrapped, shared, or
420
- discarded, and none can outlive its creating PTB. That is a same-**transaction**
421
- requirement, not a same-**function** one: pairing a `create*` here with a
422
- `finalize*` from `@misofm/sdk` on the same `tx` satisfies it. Keeping them apart
423
- is what makes the intermediate value useful at all — borrowing a still-unshared
424
- composition into `recording::new`, attaching a royalty pool via `uid_mut`, or
425
- routing an admin cap somewhere other than a plain address (every admin cap is
426
- `key, store`, hence freely routable).
427
-
428
- Whole-graph orchestration lives in `@misofm/sdk` too: `publishReleaseGraph`
429
- mints every composition and recording, attaches optional royalty pools, builds
430
- the deals/tracks, and publishes the release — with the release id derived
431
- on-chain — all in one PTB, importing the primitives from here.
121
+ Generated `contracts.release._new` is intentionally exposed because codegen
122
+ mirrors the ABI, but it is not PTB-callable: its final parameter is `&mut UID`.
123
+ Release construction therefore belongs in `@misofm/sdk`, whose
124
+ `release_registry::new_release` already owns that UID.
432
125
 
433
- ```ts
434
- import { publishReleaseGraph } from "@misofm/sdk";
435
- ```
436
-
437
- ## Extensions (moved to `@misofm/sdk`)
438
-
439
- Extension helpers are no longer part of this package. As of **0.3.0**, credits,
440
- cover art, and royalty pools ship from [`@misofm/sdk`](https://github.com/misofm/sdk):
441
-
442
- | Was `@misonetwork/sdk` | Now `@misofm/sdk` |
443
- |---|---|
444
- | `attachCompositionCredit`, `attachRecordingCredit`, `addReleaseCredit`, `addRecordingPrimaryArtist`, `addRecordingFeaturedArtist`, `getCompositionCredits`, `getRecordingCredits`, `getReleaseCredits` | same names |
445
- | `setReleaseCover`, `getReleaseCover` | same names |
446
- | `attachCompositionRoyaltyPool`, `attachRecordingRoyaltyPool` | same names |
447
- | `contracts.compositionCredits`, `.recordingCredits`, `.releaseCredits`, `.compositionPartyRole`, `.recordingPartyRole`, `.releasePartyRole`, `.royaltyPool`, `.royaltyPoolStake`, `.compositionRoyaltyPool`, `.recordingRoyaltyPool`, `.coverArt`, `.releaseCoverArt` | `contracts.*`, same names |
448
- | types `CreditView`, `RecordingCreditsView`, `CompositionRole`, `RecordingRole`, `RecordingRoleLevel`, `RecordingLeveledRoleType`, `ReleaseRole`, `ReleaseCoverView`, `CoverImageRef` | same names |
449
-
450
- Signatures are unchanged — only the import specifier moves:
451
-
452
- ```diff
453
- -import { attachRecordingCredit, setReleaseCover } from "@misonetwork/sdk";
454
- +import { attachRecordingCredit, setReleaseCover } from "@misofm/sdk";
455
- ```
456
-
457
- The reasoning is the split this package exists to hold. An extension is not part
458
- of what a Composition or Recording *is*; it is a choice about how to describe one
459
- — which roles exist and what they are called, what counts as a cover, whether
460
- royalties accumulate in a pool. The protocol offers a cap-gated `&mut UID` hook
461
- and takes no position on what hangs off it. Everything that *does* take a
462
- position is business logic, and business logic ships from the platform package.
463
-
464
- Share-currency provisioning (`createShareCurrency`, `publishShareCurrencies`,
465
- `initializeShareCurrencies`) moved to `@misofm/sdk` earlier for the same reason —
466
- every composition and recording is backed by its own fixed-supply share currency,
467
- and provisioning one is part of the opinionated publish flow, not a protocol
468
- primitive.
469
-
470
- ## Execution (`execute.ts`)
471
-
472
- Builders only append to a `Transaction`; this module submits:
473
-
474
- ```ts
475
- import { buildTx, signAndExecute, execThunks, publishedPackageId, createdByType, balanceDelta } from "@misonetwork/sdk";
476
-
477
- const result = await execThunks(client, signer, thunkA, thunkB); // build + sign + execute + wait
478
- // ExecResult: { digest, changedObjects, objectTypes, balanceChanges, gasUsed }
126
+ ### Generated bindings
479
127
 
480
- // Object-change extractors:
481
- const pkgId = publishedPackageId(result);
482
- const currencyId = createdByType(result, "::coin_registry::Currency<");
483
- const delta = balanceDelta(result, address, "0x2::sui::SUI");
484
- ```
485
-
486
- `@misofm/sdk` builds `executeViaExecutor(executor, ...thunks)` on top of this
487
- module's `buildTx`/`toExecResult` — it submits a non-idempotent PTB through a
488
- `ParallelTransactionExecutor` exactly once (no auto-retry), for its batched
489
- share-currency provisioning.
490
-
491
- ## Event Parsers
492
-
493
- Miso uses a lean publish-only event model: published objects emit a single pointer event,
494
- and indexers fetch the immutable object by ID. Parse the BCS-encoded events from transaction
495
- results:
128
+ `contracts` and `client.miso.call` expose generated `composition`, `recording`,
129
+ `release`, and `track` modules. Do not edit `src/contracts/`; run `bun run
130
+ codegen` after updating protocol source.
496
131
 
497
132
  ```ts
498
- // Pointer events (carry only identities)
499
- const comp = client.miso.parse.compositionPublishedEvent(bcsBytes); // { compositionId }
500
- const rec = client.miso.parse.recordingPublishedEvent(bcsBytes); // { recordingId }
501
- const rel = client.miso.parse.releasePublishedEvent(bcsBytes); // { releaseId }
502
-
503
- // Non-pointer events
504
- const royalty = client.miso.parse.compositionRoyaltySetEvent(bcsBytes); // { royaltyRateBps }
505
- const created = client.miso.parse.dealCreatedEvent(bcsBytes); // { dealId, releaseId, trackSplitBps }
506
- const accepted = client.miso.parse.dealAcceptedEvent(bcsBytes); // { dealId, releaseId }
507
- const rejected = client.miso.parse.dealRejectedEvent(bcsBytes); // { dealId, releaseId }
133
+ tx.add(client.miso.call.track._new({
134
+ typeArguments: [recordingShareType, compositionShareType],
135
+ arguments: [adminCap, tx.object(recordingId), tx.pure.id(targetReleaseId), tx.pure.u16(5000)],
136
+ }));
508
137
  ```
509
138
 
510
- The same functions are exported standalone as `parseCompositionPublishedEvent`, etc.
139
+ ## Event parsers
511
140
 
512
- ## Types
513
-
514
- All Miso domain types are exported:
515
-
516
- ```ts
517
- import type {
518
- // Core entities
519
- Composition, Recording, Release, Deal, Track, BPS,
520
- // Admin caps
521
- CompositionAdminCap, RecordingAdminCap, ReleaseAdminCap,
522
- // State machines
523
- CompositionState, RecordingState, ReleaseState, TrackState,
524
- // Events
525
- CompositionPublishedEvent, CompositionRoyaltySetEvent,
526
- RecordingPublishedEvent, ReleasePublishedEvent,
527
- DealCreatedEvent, DealAcceptedEvent, DealRejectedEvent,
528
- // Transaction builder inputs & results (from ./transactions)
529
- TxThunk, ShareCurrencyBinding,
530
- CompositionParts, RecordingParts, ReleaseParts,
531
- CreateCompositionParams, CreateRecordingParams, CreateDealParams,
532
- CreateReleaseParams, RejectDealParams,
533
- } from "@misonetwork/sdk";
534
- ```
141
+ Core emits only publish/royalty events. Parse them with
142
+ `client.miso.parse.compositionPublishedEvent`,
143
+ `compositionRoyaltySetEvent`, `recordingPublishedEvent`, and
144
+ `releasePublishedEvent`. Track creation has no core event; pre-publish
145
+ observability is an extension concern.
535
146
 
536
- The credit and cover types (`CreditView`, `RecordingCreditsView`,
537
- `CompositionRole`, `RecordingRole`, `RecordingRoleLevel`,
538
- `RecordingLeveledRoleType`, `ReleaseRole`, `ReleaseCoverView`, `CoverImageRef`)
539
- moved to `@misofm/sdk` in 0.3.0 — see [Extensions](#extensions-moved-to-misofmsdk).
540
-
541
- The non-type value export `PROTOCOL_MAX_ROYALTY_RATE_BPS` (`2000`) is documented
542
- under [royalty-rate slippage](#royalty-rate-slippage-maxroyaltyratebps).
543
-
544
- ## Generated Bindings (`contracts`)
545
-
546
- The codegen-generated, ABI-bound bindings (BCS structs + type-safe Move calls)
547
- are exported under the `contracts` namespace — the core protocol modules
548
- `composition`, `recording`, `release`, `deal`, and `track`. Bindings for the
549
- extension packages are in `@misofm/sdk`'s own `contracts` namespace:
550
-
551
- ```ts
552
- import { contracts } from "@misonetwork/sdk";
553
-
554
- const parsed = contracts.composition.Composition.parse(bcsBytes);
555
- tx.add(contracts.deal.reject({ package: misoPackageId, typeArguments, arguments: [dealId] }));
556
- ```
147
+ ## 0.4.0 0.5.0 migration
557
148
 
558
- On the client, `client.miso.call.*` exposes the core modules with the package
559
- id pre-bound, and `client.miso.bcs.*` the core BCS structs.
149
+ | Previous API | 0.5.0 |
150
+ | --- | --- |
151
+ | `createDeal` | `createTrack`; use `targetReleaseId` rather than `releaseId` |
152
+ | `rejectDeal`, `getDealById`, Deal event parsers/types, `contracts.deal` | removed; offer/withdrawal policy is extension-layer |
153
+ | `createRelease` | removed; use `@misofm/sdk` `release_registry::new_release` |
154
+ | `deriveReleaseId({ releaseRegistryId })` | `deriveTargetReleaseId({ parentId })`; the parent is pure |
155
+ | `getReleaseRegistry`, `MisoOptions.releaseRegistryId` | removed; extension registry is a different package type |
156
+ | `client.miso.tx` | removed; no core thunk builders remain |
157
+ | deployed disc-shaped release fallback | removed; reads parse only canonical flat `Release.tracks` |
560
158
 
561
- ## Derived Objects
159
+ Update `@misofm/sdk` in the same release window: it owns release-registry
160
+ bindings and the callable release-construction flow.
562
161
 
563
- Miso uses Sui's derived object pattern for admin caps. The SDK provides pure derivation
564
- functions that compute object IDs without network calls:
162
+ ## Derived admin caps
565
163
 
566
- | Function | Derivation Key | Parent Object |
567
- |----------|---------------|---------------|
568
- | `deriveCompositionAdminCapId` | `CompositionAdminCapKey()` | Composition |
569
- | `deriveRecordingAdminCapId` | `RecordingAdminCapKey()` | Recording |
570
- | `deriveReleaseAdminCapId` | `ReleaseAdminCapKey()` | Release |
164
+ | Function | Parent |
165
+ | --- | --- |
166
+ | `deriveCompositionAdminCapId` | Composition |
167
+ | `deriveRecordingAdminCapId` | Recording |
168
+ | `deriveReleaseAdminCapId` | Release |
571
169
 
572
170
  ## License
573
171