@clayno-club/asset-flow 0.2.0 → 0.2.2

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.
package/dist/index.js CHANGED
@@ -3202,6 +3202,90 @@ function parseSwapParticipants(swapEvent, assetId) {
3202
3202
  toAddress: counterparty
3203
3203
  };
3204
3204
  }
3205
+ function parseListingSeller(event) {
3206
+ if (!event || typeof event.parsedJson !== "object" || event.parsedJson === null) {
3207
+ return null;
3208
+ }
3209
+ return getString(event.parsedJson.seller);
3210
+ }
3211
+ function getObjectChangeById(tx, objectId) {
3212
+ const matches = (tx.objectChanges ?? []).filter((change) => change.objectId === objectId);
3213
+ return matches[matches.length - 1] ?? null;
3214
+ }
3215
+ function resolveKioskOwnerAddress(tx, options = {}) {
3216
+ const ownerCapChanges = (tx.objectChanges ?? []).filter(
3217
+ (change) => getString(change.objectType)?.endsWith("::kiosk::KioskOwnerCap")
3218
+ );
3219
+ if (options.preferCreated) {
3220
+ const createdOwners = [
3221
+ ...new Set(
3222
+ ownerCapChanges.filter((change) => change.type === "created").flatMap((change) => {
3223
+ const owner = normalizeOwnerRef(change.owner ?? change.recipient);
3224
+ return owner?.kind === "address" ? [owner.value] : [];
3225
+ })
3226
+ )
3227
+ ];
3228
+ if (createdOwners.length === 1) {
3229
+ return createdOwners[0];
3230
+ }
3231
+ }
3232
+ const addressOwners = [
3233
+ ...new Set(
3234
+ ownerCapChanges.flatMap((change) => {
3235
+ const owner = normalizeOwnerRef(change.owner ?? change.recipient);
3236
+ return owner?.kind === "address" ? [owner.value] : [];
3237
+ })
3238
+ )
3239
+ ];
3240
+ return addressOwners.length === 1 ? addressOwners[0] : null;
3241
+ }
3242
+ function resolveAddressOwnerFromObjectChain(tx, rootObjectId) {
3243
+ const visited = /* @__PURE__ */ new Set();
3244
+ let currentObjectId = rootObjectId;
3245
+ while (currentObjectId && !visited.has(currentObjectId)) {
3246
+ visited.add(currentObjectId);
3247
+ const change = getObjectChangeById(tx, currentObjectId);
3248
+ if (!change) {
3249
+ return null;
3250
+ }
3251
+ if (getString(change.objectType)?.endsWith("::kiosk::Kiosk")) {
3252
+ return resolveKioskOwnerAddress(tx, {
3253
+ preferCreated: change.type === "created"
3254
+ });
3255
+ }
3256
+ const owner = normalizeOwnerRef(change.owner ?? change.recipient);
3257
+ if (!owner) {
3258
+ return null;
3259
+ }
3260
+ if (owner.kind === "address") {
3261
+ return owner.value;
3262
+ }
3263
+ if (owner.kind === "object") {
3264
+ currentObjectId = owner.value;
3265
+ continue;
3266
+ }
3267
+ if (owner.kind === "shared") {
3268
+ return resolveKioskOwnerAddress(tx);
3269
+ }
3270
+ return null;
3271
+ }
3272
+ return null;
3273
+ }
3274
+ function resolveNextBeneficialOwner(tx, ownerChange) {
3275
+ if (!ownerChange?.nextOwner) {
3276
+ return null;
3277
+ }
3278
+ if (ownerChange.nextOwner.kind === "address") {
3279
+ return ownerChange.nextOwner.value;
3280
+ }
3281
+ if (ownerChange.nextOwner.kind === "object") {
3282
+ return resolveAddressOwnerFromObjectChain(tx, ownerChange.nextOwner.value);
3283
+ }
3284
+ if (ownerChange.nextOwner.kind === "shared") {
3285
+ return resolveKioskOwnerAddress(tx);
3286
+ }
3287
+ return null;
3288
+ }
3205
3289
  function sortTransactions(transactions) {
3206
3290
  return [...transactions].sort((left, right) => {
3207
3291
  const leftTime = Number(left.timestampMs ?? 0) || 0;
@@ -3237,20 +3321,20 @@ function buildFlow2(tx, timestamp, params) {
3237
3321
  source: "sui",
3238
3322
  fromAddress: params.fromAddress,
3239
3323
  toAddress: params.toAddress,
3240
- transferIndex: 0,
3324
+ transferIndex: params.transferIndex ?? 0,
3241
3325
  tokenStandard: null,
3242
3326
  derivedType: params.derivedType
3243
3327
  };
3244
3328
  }
3245
- function buildSuiFlow(tx, assetId, classification2, currentBeneficialOwner) {
3329
+ function buildSuiFlows(tx, assetId, classification2, currentBeneficialOwner) {
3246
3330
  if (classification2.materialization !== "PERSIST_FLOW") {
3247
- return null;
3331
+ return [];
3248
3332
  }
3249
3333
  const timestamp = resolveTimestamp(tx);
3250
3334
  const assetEvents = getAssetEvents(tx, assetId);
3251
3335
  const ownerChange = getAssetOwnerChangeDetails(tx, assetId);
3252
3336
  const sender = getString(tx.transaction?.data?.sender) ?? ownerChange?.sender ?? null;
3253
- const addressOwner = ownerChange?.nextOwner?.kind === "address" ? ownerChange.nextOwner.value : null;
3337
+ const addressOwner = (ownerChange?.nextOwner?.kind === "address" ? ownerChange.nextOwner.value : null) ?? resolveNextBeneficialOwner(tx, ownerChange);
3254
3338
  let fromAddress = null;
3255
3339
  let toAddress = null;
3256
3340
  switch (classification2.derivedType) {
@@ -3264,23 +3348,24 @@ function buildSuiFlow(tx, assetId, classification2, currentBeneficialOwner) {
3264
3348
  TRADEPORT_KIOSK_BUY_EVENT_SUFFIX
3265
3349
  ]);
3266
3350
  const sale = parseSaleParticipants(saleEvent);
3267
- fromAddress = sale.seller ?? currentBeneficialOwner ?? sender ?? null;
3351
+ fromAddress = currentBeneficialOwner ?? sale.seller ?? sender ?? null;
3268
3352
  toAddress = sale.buyer ?? addressOwner ?? sender ?? null;
3269
3353
  break;
3270
3354
  }
3271
3355
  case "SWAP": {
3272
3356
  const swapEvent = assetEvents.find((event) => event.type.includes("SwapExecuted")) ?? null;
3273
3357
  const swap = parseSwapParticipants(swapEvent, assetId);
3274
- fromAddress = swap.fromAddress ?? currentBeneficialOwner ?? sender ?? null;
3358
+ fromAddress = currentBeneficialOwner ?? swap.fromAddress ?? sender ?? null;
3275
3359
  toAddress = swap.toAddress ?? addressOwner ?? sender ?? null;
3276
3360
  break;
3277
3361
  }
3278
3362
  case "TRANSFER":
3279
3363
  fromAddress = currentBeneficialOwner ?? sender ?? null;
3280
- toAddress = addressOwner ?? (ownerChange?.nextOwner?.kind === "object" ? currentBeneficialOwner ?? sender ?? null : sender ?? null);
3364
+ toAddress = addressOwner ?? (ownerChange?.nextOwner?.kind === "object" ? sender ?? currentBeneficialOwner ?? null : sender ?? null);
3281
3365
  break;
3282
3366
  case "LIST": {
3283
- const owner = currentBeneficialOwner ?? sender ?? addressOwner;
3367
+ const listingEvent = findFirstEvent(assetEvents, [TRADEPORT_ADD_LISTING_EVENT_SUFFIX, KIOSK_LIST_EVENT_SUFFIX]);
3368
+ const owner = parseListingSeller(listingEvent) ?? currentBeneficialOwner ?? sender ?? addressOwner;
3284
3369
  fromAddress = owner;
3285
3370
  toAddress = owner;
3286
3371
  break;
@@ -3288,7 +3373,12 @@ function buildSuiFlow(tx, assetId, classification2, currentBeneficialOwner) {
3288
3373
  case "DELIST":
3289
3374
  case "LOCK":
3290
3375
  case "UNLOCK": {
3291
- const owner = addressOwner ?? sender ?? currentBeneficialOwner;
3376
+ const delistEvent = classification2.derivedType === "DELIST" ? findFirstEvent(assetEvents, [
3377
+ TRADEPORT_CANCEL_SIMPLE_EVENT_SUFFIX,
3378
+ TRADEPORT_REMOVE_LISTING_EVENT_SUFFIX,
3379
+ KIOSK_UNLIST_EVENT_SUFFIX
3380
+ ]) : null;
3381
+ const owner = parseListingSeller(delistEvent) ?? addressOwner ?? sender ?? currentBeneficialOwner;
3292
3382
  if (owner && currentBeneficialOwner && owner !== currentBeneficialOwner) {
3293
3383
  fromAddress = currentBeneficialOwner;
3294
3384
  toAddress = owner;
@@ -3300,13 +3390,15 @@ function buildSuiFlow(tx, assetId, classification2, currentBeneficialOwner) {
3300
3390
  break;
3301
3391
  }
3302
3392
  default:
3303
- return null;
3393
+ return [];
3304
3394
  }
3305
- return buildFlow2(tx, timestamp, {
3306
- fromAddress,
3307
- toAddress,
3308
- derivedType: classification2.derivedType
3309
- });
3395
+ return [
3396
+ buildFlow2(tx, timestamp, {
3397
+ fromAddress,
3398
+ toAddress,
3399
+ derivedType: classification2.derivedType
3400
+ })
3401
+ ];
3310
3402
  }
3311
3403
  function extractAssetFlows(transactions, assetId, classificationCache = /* @__PURE__ */ new Map()) {
3312
3404
  const flows = [];
@@ -3314,14 +3406,17 @@ function extractAssetFlows(transactions, assetId, classificationCache = /* @__PU
3314
3406
  for (const tx of sortTransactions(transactions)) {
3315
3407
  const classification2 = classificationCache.get(tx.digest) ?? classifySuiTransactionForAsset(tx, assetId);
3316
3408
  classificationCache.set(tx.digest, classification2);
3317
- const flow = buildSuiFlow(tx, assetId, classification2, currentBeneficialOwner);
3318
- if (!flow) {
3409
+ const txFlows = buildSuiFlows(tx, assetId, classification2, currentBeneficialOwner);
3410
+ if (txFlows.length === 0) {
3319
3411
  continue;
3320
3412
  }
3321
- flows.push(flow);
3322
- if (flow.toAddress && (flow.derivedType === "MINT" || flow.derivedType === "TRANSFER" || flow.derivedType === "SALE" || flow.derivedType === "SWAP" || flow.derivedType === "FORECLOSURE") && flow.toAddress !== currentBeneficialOwner) {
3323
- currentBeneficialOwner = flow.toAddress;
3324
- }
3413
+ txFlows.forEach((flow, index) => {
3414
+ flow.transferIndex = index;
3415
+ flows.push(flow);
3416
+ if (flow.toAddress && (flow.derivedType === "MINT" || flow.derivedType === "TRANSFER" || flow.derivedType === "SALE" || flow.derivedType === "SWAP" || flow.derivedType === "FORECLOSURE") && flow.toAddress !== currentBeneficialOwner) {
3417
+ currentBeneficialOwner = flow.toAddress;
3418
+ }
3419
+ });
3325
3420
  }
3326
3421
  return collapseRedundantCustodyFlows(canonicalizeMintFlows(flows));
3327
3422
  }