@misofm/platform 0.25.0 → 0.26.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 (140) hide show
  1. package/README.md +144 -45
  2. package/dist/auth.d.ts +8 -13
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +78 -59
  5. package/dist/auth.js.map +1 -1
  6. package/dist/catalog.d.ts +5 -5
  7. package/dist/catalog.d.ts.map +1 -1
  8. package/dist/catalog.js +33 -21
  9. package/dist/catalog.js.map +1 -1
  10. package/dist/client.d.ts +17 -30
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +53 -75
  13. package/dist/client.js.map +1 -1
  14. package/dist/cover.d.ts +4 -3
  15. package/dist/cover.d.ts.map +1 -1
  16. package/dist/cover.js +28 -17
  17. package/dist/cover.js.map +1 -1
  18. package/dist/credits.d.ts +12 -10
  19. package/dist/credits.d.ts.map +1 -1
  20. package/dist/credits.js +60 -33
  21. package/dist/credits.js.map +1 -1
  22. package/dist/deployments.d.ts +21 -13
  23. package/dist/deployments.d.ts.map +1 -1
  24. package/dist/deployments.js +84 -37
  25. package/dist/deployments.js.map +1 -1
  26. package/dist/errors.d.ts +91 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +111 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/execute.d.ts +3 -1
  31. package/dist/execute.d.ts.map +1 -1
  32. package/dist/execute.js +9 -4
  33. package/dist/execute.js.map +1 -1
  34. package/dist/genre.d.ts +25 -41
  35. package/dist/genre.d.ts.map +1 -1
  36. package/dist/genre.js +71 -20
  37. package/dist/genre.js.map +1 -1
  38. package/dist/party/client.d.ts +16 -13
  39. package/dist/party/client.d.ts.map +1 -1
  40. package/dist/party/client.js +33 -22
  41. package/dist/party/client.js.map +1 -1
  42. package/dist/party/extensions/links.d.ts +2 -1
  43. package/dist/party/extensions/links.d.ts.map +1 -1
  44. package/dist/party/extensions/links.js +2 -1
  45. package/dist/party/extensions/links.js.map +1 -1
  46. package/dist/party/queries.d.ts +12 -11
  47. package/dist/party/queries.d.ts.map +1 -1
  48. package/dist/party/queries.js +63 -57
  49. package/dist/party/queries.js.map +1 -1
  50. package/dist/party/types.d.ts +31 -20
  51. package/dist/party/types.d.ts.map +1 -1
  52. package/dist/party/types.js +82 -1
  53. package/dist/party/types.js.map +1 -1
  54. package/dist/pressing.d.ts +55 -35
  55. package/dist/pressing.d.ts.map +1 -1
  56. package/dist/pressing.js +99 -76
  57. package/dist/pressing.js.map +1 -1
  58. package/dist/queries.d.ts +1 -1
  59. package/dist/queries.d.ts.map +1 -1
  60. package/dist/queries.js +5 -4
  61. package/dist/queries.js.map +1 -1
  62. package/dist/read/artist.d.ts +6 -4
  63. package/dist/read/artist.d.ts.map +1 -1
  64. package/dist/read/artist.js +29 -27
  65. package/dist/read/artist.js.map +1 -1
  66. package/dist/read/catalog.d.ts +20 -17
  67. package/dist/read/catalog.d.ts.map +1 -1
  68. package/dist/read/catalog.js +120 -141
  69. package/dist/read/catalog.js.map +1 -1
  70. package/dist/read/client.d.ts +10 -9
  71. package/dist/read/client.d.ts.map +1 -1
  72. package/dist/read/client.js.map +1 -1
  73. package/dist/read/genres.d.ts +5 -3
  74. package/dist/read/genres.d.ts.map +1 -1
  75. package/dist/read/genres.js +18 -15
  76. package/dist/read/genres.js.map +1 -1
  77. package/dist/read/index.d.ts.map +1 -1
  78. package/dist/read/index.js +7 -1
  79. package/dist/read/index.js.map +1 -1
  80. package/dist/read/receipts.d.ts +15 -6
  81. package/dist/read/receipts.d.ts.map +1 -1
  82. package/dist/read/receipts.js +73 -60
  83. package/dist/read/receipts.js.map +1 -1
  84. package/dist/read/wallet.d.ts +11 -9
  85. package/dist/read/wallet.d.ts.map +1 -1
  86. package/dist/read/wallet.js +117 -132
  87. package/dist/read/wallet.js.map +1 -1
  88. package/dist/read/works.d.ts +9 -16
  89. package/dist/read/works.d.ts.map +1 -1
  90. package/dist/read/works.js +48 -117
  91. package/dist/read/works.js.map +1 -1
  92. package/dist/recording-extensions.d.ts +8 -7
  93. package/dist/recording-extensions.d.ts.map +1 -1
  94. package/dist/recording-extensions.js +30 -63
  95. package/dist/recording-extensions.js.map +1 -1
  96. package/dist/release-extensions.d.ts +3 -2
  97. package/dist/release-extensions.d.ts.map +1 -1
  98. package/dist/release-extensions.js +9 -10
  99. package/dist/release-extensions.js.map +1 -1
  100. package/dist/royalty.d.ts +51 -51
  101. package/dist/royalty.d.ts.map +1 -1
  102. package/dist/royalty.js +93 -11
  103. package/dist/royalty.js.map +1 -1
  104. package/dist/share.d.ts +7 -6
  105. package/dist/share.d.ts.map +1 -1
  106. package/dist/share.js +37 -30
  107. package/dist/share.js.map +1 -1
  108. package/dist/vault.d.ts +20 -8
  109. package/dist/vault.d.ts.map +1 -1
  110. package/dist/vault.js +31 -15
  111. package/dist/vault.js.map +1 -1
  112. package/package.json +11 -4
  113. package/src/auth.ts +89 -70
  114. package/src/catalog.ts +33 -49
  115. package/src/client.ts +117 -97
  116. package/src/cover.ts +17 -26
  117. package/src/credits.ts +43 -75
  118. package/src/deployments.ts +103 -69
  119. package/src/errors.ts +156 -0
  120. package/src/execute.ts +10 -6
  121. package/src/genre.ts +38 -23
  122. package/src/party/client.ts +35 -23
  123. package/src/party/extensions/links.ts +3 -2
  124. package/src/party/queries.ts +77 -65
  125. package/src/party/types.ts +52 -48
  126. package/src/pressing.ts +158 -161
  127. package/src/queries.ts +5 -5
  128. package/src/read/artist.ts +47 -42
  129. package/src/read/catalog.ts +200 -223
  130. package/src/read/client.ts +12 -11
  131. package/src/read/genres.ts +24 -16
  132. package/src/read/index.ts +7 -1
  133. package/src/read/receipts.ts +128 -67
  134. package/src/read/wallet.ts +194 -162
  135. package/src/read/works.ts +75 -194
  136. package/src/recording-extensions.ts +38 -92
  137. package/src/release-extensions.ts +7 -12
  138. package/src/royalty.ts +117 -20
  139. package/src/share.ts +44 -29
  140. package/src/vault.ts +47 -24
package/src/royalty.ts CHANGED
@@ -7,10 +7,10 @@
7
7
  // royalty pool plugins, routed-stake Actions bound to a VaultAdminCap) live in
8
8
  // `./vault.ts` instead; this module does not duplicate those.
9
9
 
10
- import type { ClientWithCoreApi } from "@mysten/sui/client";
11
10
  import { Transaction, type TransactionArgument, type TransactionObjectArgument } from "@mysten/sui/transactions";
12
- import { deriveObjectID } from "@mysten/sui/utils";
13
- import { getObjectByBcs } from "@misofm/musicos/queries";
11
+ import { deriveObjectID, normalizeStructTag } from "@mysten/sui/utils";
12
+ import { Effect, Schema } from "effect";
13
+ import { decodeBcs, getOptionalObjectContent, type BcsDecodeError, type SuiClient, type SuiRpcError } from "@misofm/effect";
14
14
 
15
15
  import { RoyaltyPool as RoyaltyPoolBcs } from "./contracts/royalty_pool/pool.ts";
16
16
  import { Stake as RoyaltyStakeBcs } from "./contracts/royalty_pool/stake.ts";
@@ -22,34 +22,131 @@ import * as routedStake from "./contracts/routed_stake/routed_stake.ts";
22
22
  /** Key bytes for Move unit structs (single `0x00` for `dummy_field: bool = false`). */
23
23
  const UNIT_STRUCT_KEY_BYTES = new Uint8Array([0x00]);
24
24
 
25
+ // ============================================================================
26
+ // Domain types
27
+ // ============================================================================
28
+
29
+ /** A stake's active registration against one royalty pool, keyed by currency type. */
30
+ export class RoyaltyStakeRegistration extends Schema.Class<RoyaltyStakeRegistration>(
31
+ "@misofm/platform/RoyaltyStakeRegistration",
32
+ )({
33
+ currencyType: Schema.String,
34
+ poolId: Schema.String,
35
+ /** Reward debt in `shares · index` units (u256, decimal string). */
36
+ debt: Schema.String,
37
+ }) {}
38
+
39
+ /** A bare `royalty_pool::pool::RoyaltyPool<Share, Currency>` object. Phantom type arguments do not affect BCS. */
40
+ export class RoyaltyPool extends Schema.Class<RoyaltyPool>("@misofm/platform/RoyaltyPool")({
41
+ id: Schema.String,
42
+ /** Currency balance held by the pool (u64, decimal string). */
43
+ balance: Schema.String,
44
+ /** Sum of every registered stake's shares (u64, decimal string). */
45
+ stakedShares: Schema.String,
46
+ /** Cumulative reward-per-share index (u256, decimal string). */
47
+ cumulativeRewardPerShare: Schema.String,
48
+ /** Deposit remainder not yet folded into the index (u128, decimal string). */
49
+ carry: Schema.String,
50
+ /** Lifetime sum of every deposited value; analytics only (u128, decimal string). */
51
+ cumulativeDeposits: Schema.String,
52
+ }) {}
53
+
54
+ /** A bare `royalty_pool::stake::Stake<Share>` object. */
55
+ export class RoyaltyStake extends Schema.Class<RoyaltyStake>("@misofm/platform/RoyaltyStake")({
56
+ id: Schema.String,
57
+ /** The staked balance (u64, decimal string). Immutable after creation. */
58
+ balance: Schema.String,
59
+ registrations: Schema.Array(RoyaltyStakeRegistration),
60
+ }) {}
61
+
62
+ /** A bare `routed_stake::routed_stake::RoutedStake<StakeShare, PoolShare>` object. */
63
+ export class RoutedStake extends Schema.Class<RoutedStake>("@misofm/platform/RoutedStake")({
64
+ id: Schema.String,
65
+ /** The wrapped position; `null` between `unstake` and `restake`. */
66
+ stake: Schema.NullOr(RoyaltyStake),
67
+ }) {}
68
+
25
69
  // ============================================================================
26
70
  // Reads
27
71
  // ============================================================================
28
72
 
29
- /** Parse a royalty pool by object ID. Phantom type arguments do not affect BCS. */
30
- export async function getRoyaltyPoolById(
31
- client: ClientWithCoreApi,
32
- poolId: string,
33
- ) {
34
- return getObjectByBcs(client, poolId, RoyaltyPoolBcs);
73
+ function mapRegistration(currencyType: string, poolId: string, debt: string): typeof RoyaltyStakeRegistration.Encoded {
74
+ return { currencyType: normalizeStructTag(currencyType), poolId, debt };
35
75
  }
36
76
 
37
- /** Parse an owned `Stake<Share>` by object ID. */
38
- export async function getRoyaltyStakeById(
39
- client: ClientWithCoreApi,
40
- stakeId: string,
41
- ) {
42
- return getObjectByBcs(client, stakeId, RoyaltyStakeBcs);
77
+ function mapRoyaltyPool(poolId: string, parsed: ReturnType<typeof RoyaltyPoolBcs.parse>): typeof RoyaltyPool.Encoded {
78
+ return {
79
+ id: poolId,
80
+ balance: String(parsed.balance.value),
81
+ stakedShares: String(parsed.staked_shares),
82
+ cumulativeRewardPerShare: String(parsed.cumulative_reward_per_share),
83
+ carry: String(parsed.carry),
84
+ cumulativeDeposits: String(parsed.cumulative_deposits),
85
+ };
86
+ }
87
+
88
+ function mapRoyaltyStake(stakeId: string, parsed: ReturnType<typeof RoyaltyStakeBcs.parse>): typeof RoyaltyStake.Encoded {
89
+ return {
90
+ id: stakeId,
91
+ balance: String(parsed.balance.value),
92
+ registrations: parsed.registrations.contents.map((entry) =>
93
+ mapRegistration(entry.key.name, entry.value.pool_id, String(entry.value.debt)),
94
+ ),
95
+ };
43
96
  }
44
97
 
45
- /** Parse a shared routed stake by object ID. */
46
- export async function getRoutedStakeById(
47
- client: ClientWithCoreApi,
98
+ function mapRoutedStake(
48
99
  routedStakeId: string,
49
- ) {
50
- return getObjectByBcs(client, routedStakeId, RoutedStakeBcs);
100
+ parsed: ReturnType<typeof RoutedStakeBcs.parse>,
101
+ ): typeof RoutedStake.Encoded {
102
+ return {
103
+ id: routedStakeId,
104
+ stake: parsed.stake ? mapRoyaltyStake(routedStakeId, parsed.stake) : null,
105
+ };
51
106
  }
52
107
 
108
+ /** One royalty pool by object ID, or `null` when no such object exists. */
109
+ export const getRoyaltyPoolById = Effect.fn("getRoyaltyPoolById")(function* (
110
+ poolId: string,
111
+ ): Effect.fn.Return<RoyaltyPool | null, BcsDecodeError | SuiRpcError, SuiClient> {
112
+ const found = yield* getOptionalObjectContent(poolId);
113
+ if (found._tag === "None") return null;
114
+ return yield* decodeBcs(
115
+ { parse: (bytes) => mapRoyaltyPool(poolId, RoyaltyPoolBcs.parse(bytes)) },
116
+ RoyaltyPool,
117
+ found.value.content,
118
+ { type: "RoyaltyPool", objectId: poolId },
119
+ );
120
+ });
121
+
122
+ /** One owned `Stake<Share>` by object ID, or `null` when no such object exists. */
123
+ export const getRoyaltyStakeById = Effect.fn("getRoyaltyStakeById")(function* (
124
+ stakeId: string,
125
+ ): Effect.fn.Return<RoyaltyStake | null, BcsDecodeError | SuiRpcError, SuiClient> {
126
+ const found = yield* getOptionalObjectContent(stakeId);
127
+ if (found._tag === "None") return null;
128
+ return yield* decodeBcs(
129
+ { parse: (bytes) => mapRoyaltyStake(stakeId, RoyaltyStakeBcs.parse(bytes)) },
130
+ RoyaltyStake,
131
+ found.value.content,
132
+ { type: "RoyaltyStake", objectId: stakeId },
133
+ );
134
+ });
135
+
136
+ /** One shared routed stake by object ID, or `null` when no such object exists. */
137
+ export const getRoutedStakeById = Effect.fn("getRoutedStakeById")(function* (
138
+ routedStakeId: string,
139
+ ): Effect.fn.Return<RoutedStake | null, BcsDecodeError | SuiRpcError, SuiClient> {
140
+ const found = yield* getOptionalObjectContent(routedStakeId);
141
+ if (found._tag === "None") return null;
142
+ return yield* decodeBcs(
143
+ { parse: (bytes) => mapRoutedStake(routedStakeId, RoutedStakeBcs.parse(bytes)) },
144
+ RoutedStake,
145
+ found.value.content,
146
+ { type: "RoutedStake", objectId: routedStakeId },
147
+ );
148
+ });
149
+
53
150
  /** Deterministically derive the royalty-pool ID for a parent and type pair. */
54
151
  export function deriveRoyaltyPoolId(
55
152
  parentId: string,
package/src/share.ts CHANGED
@@ -21,10 +21,10 @@
21
21
  // currency still gets a descriptive, work-specific name.
22
22
 
23
23
  import type { ParallelTransactionExecutor } from "@mysten/sui/transactions";
24
- import type { ClientWithCoreApi } from "@mysten/sui/client";
25
24
  import type { Signer } from "@mysten/sui/cryptography";
26
25
  import { fromBase64, fromHex, toBase64 } from "@mysten/sui/utils";
27
26
  import { update_constants } from "@mysten/move-bytecode-template";
27
+ import { Effect } from "effect";
28
28
  import {
29
29
  execThunks,
30
30
  publishedPackageId,
@@ -33,6 +33,7 @@ import {
33
33
  allCreatedByType,
34
34
  type ExecResult,
35
35
  } from "@misofm/musicos";
36
+ import { SuiClient, SuiRpcError, type TransactionFailedError } from "@misofm/effect";
36
37
 
37
38
  import { publishShareCurrency, initializeShareCurrency, type PackageBytecode } from "./transactions.ts";
38
39
  import { SHARE_TEMPLATE } from "./share-template.ts";
@@ -107,23 +108,21 @@ export interface CreateShareCurrencyParams {
107
108
  }
108
109
 
109
110
  /** Publishes an immutable package, then initializes a fresh share currency in a second tx. */
110
- export async function createShareCurrency(
111
- client: ClientWithCoreApi,
111
+ export const createShareCurrency = Effect.fn("createShareCurrency")(function* (
112
112
  signer: Signer,
113
113
  params: CreateShareCurrencyParams,
114
- ): Promise<ShareCurrency> {
114
+ ): Effect.fn.Return<ShareCurrency, TransactionFailedError | SuiRpcError, SuiClient> {
115
115
  const signerAddress = signer.toSuiAddress();
116
116
  const initializer = params.initializerAddress ?? signerAddress;
117
117
  const recipient = params.treasuryCapRecipient ?? signerAddress;
118
118
 
119
119
  // Tx 1: publish the share package with the initializer baked in.
120
120
  const patched = patchInitializer(params.template ?? SHARE_TEMPLATE, initializer);
121
- const publishRes = await execThunks(client, signer, publishShareCurrency(patched));
121
+ const publishRes = yield* execThunks(signer, publishShareCurrency(patched));
122
122
  const packageId = publishedPackageId(publishRes);
123
123
 
124
124
  // Tx 2: initialize → creates the Currency object + transfers the TreasuryCap.
125
- const initRes = await execThunks(
126
- client,
125
+ const initRes = yield* execThunks(
127
126
  signer,
128
127
  initializeShareCurrency({
129
128
  shareCurrencyPackageId: packageId,
@@ -141,7 +140,7 @@ export async function createShareCurrency(
141
140
  treasuryCapId: createdByType(initRes, TREASURY_CAP_TYPE),
142
141
  gasUsed: publishRes.gasUsed + initRes.gasUsed,
143
142
  };
144
- }
143
+ });
145
144
 
146
145
  // ── Batched (parallel) ─────────────────────────────────────────────────────
147
146
 
@@ -158,12 +157,12 @@ function chunk<T>(items: T[], size: number): T[][] {
158
157
  * consumes its UpgradeCap in the same PTB. Returns the published package ids
159
158
  * (fungible — order is not meaningful; the caller assigns them to work slots).
160
159
  */
161
- export async function publishShareCurrencies(
160
+ export const publishShareCurrencies = Effect.fn("publishShareCurrencies")(function* (
162
161
  executor: ParallelTransactionExecutor,
163
162
  initializerAddress: string,
164
163
  count: number,
165
164
  template: PackageBytecode = SHARE_TEMPLATE,
166
- ): Promise<{ packageIds: string[]; gasUsed: number }> {
165
+ ): Effect.fn.Return<{ packageIds: string[]; gasUsed: number }, SuiRpcError> {
167
166
  if (count <= 0) return { packageIds: [], gasUsed: 0 };
168
167
 
169
168
  // One patched template, reused for every publish (identical bytecode → distinct packages).
@@ -174,8 +173,10 @@ export async function publishShareCurrencies(
174
173
  batchSizes.push(Math.min(PUBLISHES_PER_PTB, remaining));
175
174
  }
176
175
 
177
- const results = await Promise.all(
178
- batchSizes.map((n) => executeViaExecutor(executor, ...Array.from({ length: n }, () => publishShareCurrency(patched)))),
176
+ const results = yield* Effect.forEach(
177
+ batchSizes,
178
+ (n) => executeViaExecutor(executor, ...Array.from({ length: n }, () => publishShareCurrency(patched))),
179
+ { concurrency: "unbounded" },
179
180
  );
180
181
 
181
182
  const packageIds = results.flatMap(allPublishedPackageIds);
@@ -184,7 +185,7 @@ export async function publishShareCurrencies(
184
185
  throw new Error(`Expected ${count} published share packages, got ${packageIds.length}.`);
185
186
  }
186
187
  return { packageIds, gasUsed };
187
- }
188
+ });
188
189
 
189
190
  /** Re-associates one init PTB's created objects back to their packages by share type. */
190
191
  function currenciesFromResult(res: ExecResult, batchPkgs: string[]): ShareCurrency[] {
@@ -211,19 +212,22 @@ function currenciesFromResult(res: ExecResult, batchPkgs: string[]): ShareCurren
211
212
  * persist that batch immediately. If any batch fails, the succeeded ones are already
212
213
  * reported and this throws, so a resume re-initializes only the still-missing packages.
213
214
  */
214
- export async function initializeShareCurrencies(
215
+ export const initializeShareCurrencies = Effect.fn("initializeShareCurrencies")(function* (
215
216
  executor: ParallelTransactionExecutor,
216
217
  signerAddress: string,
217
218
  packageIds: string[],
218
219
  metaOf: (packageId: string) => ShareCurrencyMeta,
219
220
  onBatch?: (currencies: ShareCurrency[], gasUsed: number) => void | Promise<void>,
220
- ): Promise<{ currencies: ShareCurrency[]; gasUsed: number }> {
221
+ ): Effect.fn.Return<{ currencies: ShareCurrency[]; gasUsed: number }, never> {
221
222
  if (packageIds.length === 0) return { currencies: [], gasUsed: 0 };
222
223
 
223
224
  const batches = chunk(packageIds, INITS_PER_PTB);
224
- const settled = await Promise.allSettled(
225
- batches.map(async (batchPkgs) => {
226
- const res = await executeViaExecutor(
225
+ // `Effect.either` per batch preserves `Promise.allSettled`'s partial-failure
226
+ // tolerance: one batch's `SuiRpcError` does not cancel the others in flight.
227
+ const outcomes = yield* Effect.forEach(
228
+ batches,
229
+ (batchPkgs) =>
230
+ executeViaExecutor(
227
231
  executor,
228
232
  ...batchPkgs.map((pkg) => {
229
233
  const meta = metaOf(pkg);
@@ -235,22 +239,33 @@ export async function initializeShareCurrencies(
235
239
  treasuryCapRecipient: signerAddress,
236
240
  });
237
241
  }),
238
- );
239
- const batchCurrencies = currenciesFromResult(res, batchPkgs);
240
- if (onBatch) await onBatch(batchCurrencies, res.gasUsed);
241
- return { batchCurrencies, gasUsed: res.gasUsed };
242
- }),
242
+ ).pipe(
243
+ Effect.map((res) => ({ batchCurrencies: currenciesFromResult(res, batchPkgs), gasUsed: res.gasUsed })),
244
+ // A rejecting callback is this batch's failure, not a defect: a defect
245
+ // would fail the whole forEach and interrupt sibling batches whose
246
+ // transactions are already submitted.
247
+ Effect.tap(({ batchCurrencies, gasUsed }) =>
248
+ onBatch
249
+ ? Effect.tryPromise({
250
+ try: () => Promise.resolve(onBatch(batchCurrencies, gasUsed)),
251
+ catch: (cause) => new SuiRpcError({ operation: "onBatch", cause }),
252
+ })
253
+ : Effect.void,
254
+ ),
255
+ Effect.result,
256
+ ),
257
+ { concurrency: "unbounded" },
243
258
  );
244
259
 
245
260
  const currencies: ShareCurrency[] = [];
246
261
  const errors: unknown[] = [];
247
262
  let gasUsed = 0;
248
- for (const s of settled) {
249
- if (s.status === "fulfilled") {
250
- currencies.push(...s.value.batchCurrencies);
251
- gasUsed += s.value.gasUsed;
263
+ for (const outcome of outcomes) {
264
+ if (outcome._tag === "Success") {
265
+ currencies.push(...outcome.success.batchCurrencies);
266
+ gasUsed += outcome.success.gasUsed;
252
267
  } else {
253
- errors.push(s.reason);
268
+ errors.push(outcome.failure);
254
269
  }
255
270
  }
256
271
  if (errors.length > 0) {
@@ -258,4 +273,4 @@ export async function initializeShareCurrencies(
258
273
  throw new Error(`${errors.length}/${batches.length} initialize batch(es) failed: ${msg}`);
259
274
  }
260
275
  return { currencies, gasUsed };
261
- }
276
+ });
package/src/vault.ts CHANGED
@@ -13,13 +13,22 @@
13
13
  */
14
14
 
15
15
  import type { BcsType } from "@mysten/sui/bcs";
16
- import type { ClientWithCoreApi } from "@mysten/sui/client";
17
16
  import type {
18
17
  Transaction,
19
18
  TransactionArgument,
20
19
  TransactionObjectArgument,
21
20
  } from "@mysten/sui/transactions";
22
21
  import { deriveObjectID, normalizeStructTag } from "@mysten/sui/utils";
22
+ import { Effect, Schema } from "effect";
23
+ import {
24
+ assertObjectType,
25
+ decodeBcs,
26
+ getOptionalObjectContent,
27
+ SuiClient,
28
+ SuiRpcError,
29
+ type BcsDecodeError,
30
+ type ObjectTypeMismatchError,
31
+ } from "@misofm/effect";
23
32
  import * as vault from "./contracts/vault/vault.ts";
24
33
  import * as releaseRevenueDistributor from "./contracts/release_revenue_distributor/release_revenue_distributor.ts";
25
34
  import * as compositionRoyaltyPoolPlugin from "./contracts/composition_royalty_pool_plugin/composition_royalty_pool_plugin.ts";
@@ -948,27 +957,38 @@ export function parseReleaseTrackRevenueDistributedEvent(content: Uint8Array) {
948
957
  };
949
958
  }
950
959
 
951
- /** Read and BCS-parse an owner-held VaultAdminCap. */
952
- export async function getVaultAdminCap(
953
- client: ClientWithCoreApi,
960
+ /**
961
+ * A caller-held handle to a shared `Vault<Cap>`: the vault's id and this cap's
962
+ * own id. There is no separate `Vault` BCS struct to decode — the vault
963
+ * itself is a UID-only shared object whose state lives entirely in dynamic
964
+ * fields, so `VaultAdminCap` is the addressable domain value for vault
965
+ * custody.
966
+ */
967
+ export class VaultAdminCap extends Schema.Class<VaultAdminCap>("@misofm/platform/VaultAdminCap")({
968
+ id: Schema.String,
969
+ vaultId: Schema.String,
970
+ }) {}
971
+
972
+ function mapVaultAdminCap(id: string, parsed: ReturnType<typeof vault.VaultAdminCap.parse>): typeof VaultAdminCap.Encoded {
973
+ return { id, vaultId: parsed.vault_id };
974
+ }
975
+
976
+ /** Read and BCS-parse an owner-held VaultAdminCap, or `null` when no such object exists. */
977
+ export const getVaultAdminCap = Effect.fn("getVaultAdminCap")(function* (
954
978
  vaultAdminCapId: string,
955
979
  expected: { readonly vaultPackageId: string; readonly capType: string },
956
- ) {
957
- const { object } = await client.core.getObject({
958
- objectId: vaultAdminCapId,
959
- include: { content: true },
960
- });
961
- if (!object || object instanceof Error || !object.content) return null;
962
- const expectedType = normalizeStructTag(
963
- `${expected.vaultPackageId}::vault::VaultAdminCap<${expected.capType}>`,
980
+ ): Effect.fn.Return<VaultAdminCap | null, ObjectTypeMismatchError | BcsDecodeError | SuiRpcError, SuiClient> {
981
+ const found = yield* getOptionalObjectContent(vaultAdminCapId);
982
+ if (found._tag === "None") return null;
983
+ const expectedType = normalizeStructTag(`${expected.vaultPackageId}::vault::VaultAdminCap<${expected.capType}>`);
984
+ yield* assertObjectType(vaultAdminCapId, normalizeStructTag(found.value.type), expectedType);
985
+ return yield* decodeBcs(
986
+ { parse: (bytes) => mapVaultAdminCap(vaultAdminCapId, vault.VaultAdminCap.parse(bytes)) },
987
+ VaultAdminCap,
988
+ found.value.content,
989
+ { type: "VaultAdminCap", objectId: vaultAdminCapId },
964
990
  );
965
- if (!object.type || normalizeStructTag(object.type) !== expectedType) {
966
- throw new Error(
967
- `getVaultAdminCap: expected ${expectedType}, received ${object.type ?? "unknown"}`,
968
- );
969
- }
970
- return parseVaultAdminCap(object.content);
971
- }
991
+ });
972
992
 
973
993
  /**
974
994
  * Build a `vector<Receiving<Coin<Currency>>>` for receive-and-* plugin calls.
@@ -982,18 +1002,21 @@ export interface ReceivingObjectRef {
982
1002
  }
983
1003
 
984
1004
  /** Resolve owned coins to the exact references required by a Receiving input. */
985
- export async function resolveReceivingCoins(
986
- client: ClientWithCoreApi,
1005
+ export const resolveReceivingCoins = Effect.fn("resolveReceivingCoins")(function* (
987
1006
  coinIds: readonly string[],
988
- ): Promise<ReceivingObjectRef[]> {
989
- const { objects } = await client.core.getObjects({ objectIds: [...coinIds] });
1007
+ ): Effect.fn.Return<ReceivingObjectRef[], SuiRpcError, SuiClient> {
1008
+ const client = yield* SuiClient;
1009
+ const { objects } = yield* Effect.tryPromise({
1010
+ try: (signal) => client.core.getObjects({ objectIds: [...coinIds], signal }),
1011
+ catch: (cause) => new SuiRpcError({ operation: "getObjects", cause }),
1012
+ });
990
1013
  return objects.map((coin, index) => {
991
1014
  if (coin instanceof Error || !coin) {
992
1015
  throw new Error(`resolveReceivingCoins: could not resolve ${coinIds[index]}`);
993
1016
  }
994
1017
  return { objectId: coin.objectId, version: coin.version, digest: coin.digest };
995
1018
  });
996
- }
1019
+ });
997
1020
 
998
1021
  export function receivingCoins(
999
1022
  tx: Transaction,