@clayno-club/asset-flow 0.2.2 → 0.4.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.
- package/dist/index.d.ts +55 -3
- package/dist/index.js +409 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ __export(solana_exports, {
|
|
|
32
32
|
extractValueMovements: () => extractValueMovements,
|
|
33
33
|
getMatchingAssetFlowMatchers: () => getMatchingAssetFlowMatchers,
|
|
34
34
|
getMintNftTransfers: () => getMintNftTransfers,
|
|
35
|
+
hasLoanProgramSettlement: () => hasLoanProgramSettlement,
|
|
35
36
|
hasMeaningfulNativeSettlement: () => hasMeaningfulNativeSettlement,
|
|
36
37
|
interpretMintFlowProtocolEvent: () => interpretMintFlowProtocolEvent,
|
|
37
38
|
isMintNftTransfer: () => isMintNftTransfer,
|
|
@@ -107,6 +108,15 @@ function hasMeaningfulNativeSettlement(tx, mint) {
|
|
|
107
108
|
}
|
|
108
109
|
return (tx.actions ?? []).some((action) => isMeaningfulPaidAction(action, primaryBuyer, primarySeller));
|
|
109
110
|
}
|
|
111
|
+
function hasLoanProgramSettlement(tx) {
|
|
112
|
+
for (const entry of tx.accountData ?? []) {
|
|
113
|
+
const delta = toNullableNumber(entry.nativeBalanceChange);
|
|
114
|
+
if (delta !== null && Math.abs(delta) >= MEANINGFUL_SETTLEMENT_LAMPORTS) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
110
120
|
|
|
111
121
|
// src/chains/solana/facts/build-facts.ts
|
|
112
122
|
var NOISY_OWNERSHIP_CHANGE_SOURCES = /* @__PURE__ */ new Set([
|
|
@@ -157,6 +167,7 @@ function buildTransactionFacts(tx, mint) {
|
|
|
157
167
|
const nftTouchKind = !hasTransferTouch ? "NONE" : hasOwnershipChange ? "OWNERSHIP_CHANGE" : primarySeller === primaryBuyer ? "SAME_OWNER" : "SAME_OWNER";
|
|
158
168
|
const ownershipKind = !hasTransferTouch ? "NONE" : isNoisyOwnershipChange ? "AMBIGUOUS" : hasOwnershipChange ? "DIRECT" : primarySeller && primaryBuyer && primarySeller === primaryBuyer ? "SAME_OWNER" : "AMBIGUOUS";
|
|
159
169
|
const settlementKind = hasMeaningfulSettlement ? primaryBuyer && primarySeller ? "NATIVE_SALE" : "POTENTIAL_SALE" : hasOwnershipChange && !hasProgramEvidence ? "AMBIGUOUS" : "NONE";
|
|
170
|
+
const mintInAccountData = (tx.accountData ?? []).some((entry) => entry.account === mint);
|
|
160
171
|
return {
|
|
161
172
|
mint,
|
|
162
173
|
tx,
|
|
@@ -173,6 +184,7 @@ function buildTransactionFacts(tx, mint) {
|
|
|
173
184
|
custodyEndpoint: hasTransferTouch ? primaryBuyer : null,
|
|
174
185
|
hasProgramEvidence,
|
|
175
186
|
isNoisyOwnershipChange,
|
|
187
|
+
mintInAccountData,
|
|
176
188
|
programIds: [...programIds],
|
|
177
189
|
instructionLabels: [...instructionLabels]
|
|
178
190
|
};
|
|
@@ -294,6 +306,7 @@ var HADESWAP_SOURCE = "HADESWAP";
|
|
|
294
306
|
var MAGIC_EDEN_M2_PROGRAM_ID = "M2mx93ekt1fmXSVkTrUL9xVFHkmME8HTUi5Cyc5aF7K";
|
|
295
307
|
var BUY_INTENT_INSTRUCTION_LABEL = "BuyV2";
|
|
296
308
|
var MEANINGFUL_SETTLEMENT_LAMPORTS2 = 1e7;
|
|
309
|
+
var RAW_MARKETPLACE_LISTING_LABELS = /* @__PURE__ */ new Set(["MIP1SELL", "LISTLEGACY"]);
|
|
297
310
|
function isPureNonSettlementObservation(observation) {
|
|
298
311
|
return observation.nftTransfers.length === 0 && !observation.hasOwnershipChange && !observation.hasMeaningfulSettlement;
|
|
299
312
|
}
|
|
@@ -301,7 +314,9 @@ function isUnknownSaleLikeMarketplaceObservation(observation, source) {
|
|
|
301
314
|
return observation.normalizedType === "UNKNOWN" && observation.normalizedSource === source && observation.hasOwnershipChange && observation.hasMeaningfulSettlement;
|
|
302
315
|
}
|
|
303
316
|
function isStandardMarketplaceListing(observation) {
|
|
304
|
-
return !observation.hasMeaningfulSettlement && (MARKETPLACE_SOURCES.has(observation.normalizedSource) && LISTING_TYPES.has(observation.normalizedType) || observation.
|
|
317
|
+
return !observation.hasMeaningfulSettlement && (MARKETPLACE_SOURCES.has(observation.normalizedSource) && LISTING_TYPES.has(observation.normalizedType) || observation.normalizedSource === "RAW_WEBHOOK" && observation.instructionLabels.some(
|
|
318
|
+
(label) => RAW_MARKETPLACE_LISTING_LABELS.has(label.replace(/[^a-z0-9]+/gi, "").toUpperCase())
|
|
319
|
+
) || observation.programIds.includes(TENSOR_LEGACY_MARKETPLACE_PROGRAM_ID) || observation.programIds.includes(MAGIC_EDEN_MMM_PROGRAM_ID));
|
|
305
320
|
}
|
|
306
321
|
function isFoxyRaffleListing(observation) {
|
|
307
322
|
return observation.normalizedSource === FOXY_RAFFLE_SOURCE && observation.hasOwnershipChange && (observation.normalizedType === FOXY_RAFFLE_CREATE_TYPE || observation.normalizedType === FOXY_RAFFLE_UNWIND_TYPE && !observation.hasMeaningfulSettlement && !observation.programIds.includes(ASSOCIATED_TOKEN_PROGRAM_ID));
|
|
@@ -325,6 +340,20 @@ function resolveMarketplaceListing(observation) {
|
|
|
325
340
|
hasTrackedMovement: true
|
|
326
341
|
};
|
|
327
342
|
}
|
|
343
|
+
function resolveMarketplacePassthroughTransfer(observation) {
|
|
344
|
+
if (!isStandardMarketplaceListing(observation) || isDelistLikeMarketplaceAction(observation)) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
if (observation.nftTransfers.length < 2 || !observation.hasOwnershipChange) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
const fromAddress = observation.primarySeller;
|
|
351
|
+
const toAddress = observation.primaryBuyer;
|
|
352
|
+
if (!fromAddress || !toAddress || fromAddress === toAddress) {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
return { matchedBy: "LISTING_SHAPED_NET_OWNER_CHANGE", fromAddress, toAddress };
|
|
356
|
+
}
|
|
328
357
|
function resolveMarketplaceBid(observation) {
|
|
329
358
|
if (!isPureNonSettlementObservation(observation)) {
|
|
330
359
|
return null;
|
|
@@ -394,6 +423,7 @@ function resolveRoutedSettlement(observation, intermediary, buyer) {
|
|
|
394
423
|
intermediary,
|
|
395
424
|
buyer,
|
|
396
425
|
counterparty: to,
|
|
426
|
+
amount,
|
|
397
427
|
matchedBy: "INTERMEDIARY_OUTBOUND_SETTLEMENT"
|
|
398
428
|
};
|
|
399
429
|
}
|
|
@@ -402,6 +432,7 @@ function resolveRoutedSettlement(observation, intermediary, buyer) {
|
|
|
402
432
|
intermediary,
|
|
403
433
|
buyer,
|
|
404
434
|
counterparty: from,
|
|
435
|
+
amount,
|
|
405
436
|
matchedBy: "INTERMEDIARY_INBOUND_SETTLEMENT"
|
|
406
437
|
};
|
|
407
438
|
}
|
|
@@ -526,6 +557,28 @@ var marketplaceListingMatcher = {
|
|
|
526
557
|
}
|
|
527
558
|
};
|
|
528
559
|
|
|
560
|
+
// src/chains/solana/matchers/marketplace/marketplace-passthrough-transfer.ts
|
|
561
|
+
var marketplacePassthroughTransferMatcher = {
|
|
562
|
+
id: "solana.marketplace-passthrough-transfer",
|
|
563
|
+
matches(observation) {
|
|
564
|
+
return resolveMarketplacePassthroughTransfer(observation) !== null;
|
|
565
|
+
},
|
|
566
|
+
classify(observation) {
|
|
567
|
+
if (!resolveMarketplacePassthroughTransfer(observation)) {
|
|
568
|
+
throw new Error(
|
|
569
|
+
`Marketplace passthrough transfer matcher classified a non-matching transaction: ${observation.tx.signature}`
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
return classification({
|
|
573
|
+
family: "GENERIC_TRANSFER",
|
|
574
|
+
derivedType: "TRANSFER",
|
|
575
|
+
matcherId: this.id,
|
|
576
|
+
reason: "matched_marketplace_passthrough_transfer_family",
|
|
577
|
+
observation
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
|
|
529
582
|
// src/chains/solana/matchers/marketplace/hyperspace-instant-sell.ts
|
|
530
583
|
var hyperspaceInstantSellMatcher = {
|
|
531
584
|
id: "solana.hyperspace-instant-sell",
|
|
@@ -728,10 +781,14 @@ var foxyCancelSwapMatcher = {
|
|
|
728
781
|
};
|
|
729
782
|
|
|
730
783
|
// src/chains/solana/matchers/protocol/foxy-init-swap.ts
|
|
784
|
+
function hasRawFoxyInitSwapDeposit(labels) {
|
|
785
|
+
const normalized = new Set(labels.map((label) => label.replace(/[^a-z0-9]+/gi, "").toUpperCase()));
|
|
786
|
+
return [...normalized].some((label) => label === "INITSWAP" || label === "INITSWAP2") && normalized.has("DEPOSITPNFT");
|
|
787
|
+
}
|
|
731
788
|
var foxyInitSwapMatcher = {
|
|
732
789
|
id: "solana.foxy-init-swap",
|
|
733
790
|
matches(observation) {
|
|
734
|
-
return observation.normalizedType === "INIT_SWAP" && observation.normalizedSource === "FOXY";
|
|
791
|
+
return observation.normalizedType === "INIT_SWAP" && observation.normalizedSource === "FOXY" || observation.normalizedSource === "RAW_WEBHOOK" && observation.normalizedType === "NFT_TRANSFER" && hasRawFoxyInitSwapDeposit(observation.instructionLabels);
|
|
735
792
|
},
|
|
736
793
|
classify(observation) {
|
|
737
794
|
const trackedMintMoves = observation.nftTransfers.length > 0 && observation.hasOwnershipChange;
|
|
@@ -846,8 +903,24 @@ var hadeswapActivityMatcher = {
|
|
|
846
903
|
};
|
|
847
904
|
|
|
848
905
|
// src/semantics/loan.ts
|
|
906
|
+
var BENEFICIAL_OWNERSHIP_DERIVED_TYPES = /* @__PURE__ */ new Set([
|
|
907
|
+
"MINT",
|
|
908
|
+
"SALE",
|
|
909
|
+
"TRANSFER",
|
|
910
|
+
"SWAP",
|
|
911
|
+
"FORECLOSURE"
|
|
912
|
+
]);
|
|
849
913
|
var LOAN_PROGRAM_SOURCES = /* @__PURE__ */ new Set(["SHARKY_FI", "CITRUS", "RAINFI", "CARDINAL_RENT", "FRAKT"]);
|
|
850
|
-
var LOAN_LOCK_TYPES = /* @__PURE__ */ new Set([
|
|
914
|
+
var LOAN_LOCK_TYPES = /* @__PURE__ */ new Set([
|
|
915
|
+
"TAKE_LOAN",
|
|
916
|
+
"BORROW_SOL_FOR_NFT",
|
|
917
|
+
"REBORROW_SOL_FOR_NFT",
|
|
918
|
+
"BORROW_PERPETUAL",
|
|
919
|
+
"FREEZE",
|
|
920
|
+
// RainFi: collateral deposit
|
|
921
|
+
"EXTEND_LOAN"
|
|
922
|
+
// RainFi: loan rollover (treated as a fresh lock for chain integrity)
|
|
923
|
+
]);
|
|
851
924
|
var LOAN_UNLOCK_TYPES = /* @__PURE__ */ new Set(["REPAY_LOAN", "REPAY_PERPETUAL_LOAN", "REPAY", "UNFREEZE"]);
|
|
852
925
|
var LOAN_UNLOCK_INSTRUCTION_LABELS = /* @__PURE__ */ new Set([
|
|
853
926
|
"DelistCollateral",
|
|
@@ -896,7 +969,10 @@ function resolveLoanProgramActivity(observation) {
|
|
|
896
969
|
if (!isLoanProgramSource(observation.normalizedSource) || !isLoanActivityType(observation.normalizedType) || observation.hasOwnershipChange && observation.hasMeaningfulSettlement) {
|
|
897
970
|
return null;
|
|
898
971
|
}
|
|
899
|
-
const
|
|
972
|
+
const hasExplicitLockType = isLoanLockType(observation.normalizedType) || isLoanUnlockType(observation.normalizedType);
|
|
973
|
+
const baseDelegationGate = observation.nftTransfers.length === 0 && observation.mintInAccountData;
|
|
974
|
+
const isDelegationLifecycle = baseDelegationGate && (hasExplicitLockType || observation.normalizedType === "UNKNOWN" && hasLoanProgramSettlement(observation.tx));
|
|
975
|
+
const hasTrackedMintTouch = observation.nftTransfers.length > 0 || isDelegationLifecycle;
|
|
900
976
|
const lifecycleDirection = inferLoanLifecycleDirection(observation);
|
|
901
977
|
return {
|
|
902
978
|
lifecycleDirection,
|
|
@@ -944,6 +1020,31 @@ function resolveLoanCollateralTransfer(observation) {
|
|
|
944
1020
|
}
|
|
945
1021
|
return { derivedType: "TRANSFER" };
|
|
946
1022
|
}
|
|
1023
|
+
function repairForeclosureFromAddresses(flows) {
|
|
1024
|
+
const result = [];
|
|
1025
|
+
let currentHolder = null;
|
|
1026
|
+
const activeEscrows = /* @__PURE__ */ new Set();
|
|
1027
|
+
for (const flow of flows) {
|
|
1028
|
+
const repaired = flow.derivedType === "FORECLOSURE" && currentHolder !== null && flow.fromAddress !== currentHolder ? { ...flow, fromAddress: currentHolder } : flow;
|
|
1029
|
+
result.push(repaired);
|
|
1030
|
+
if (repaired.derivedType === "LIST" || repaired.derivedType === "LOCK") {
|
|
1031
|
+
if (repaired.toAddress) activeEscrows.add(repaired.toAddress);
|
|
1032
|
+
continue;
|
|
1033
|
+
}
|
|
1034
|
+
if (repaired.derivedType === "DELIST" || repaired.derivedType === "UNLOCK") {
|
|
1035
|
+
if (repaired.fromAddress) activeEscrows.delete(repaired.fromAddress);
|
|
1036
|
+
if (repaired.toAddress && repaired.toAddress !== currentHolder && !activeEscrows.has(repaired.toAddress)) {
|
|
1037
|
+
currentHolder = repaired.toAddress;
|
|
1038
|
+
}
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
if (BENEFICIAL_OWNERSHIP_DERIVED_TYPES.has(repaired.derivedType)) {
|
|
1042
|
+
if (repaired.fromAddress) activeEscrows.delete(repaired.fromAddress);
|
|
1043
|
+
currentHolder = repaired.toAddress;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return result;
|
|
1047
|
+
}
|
|
947
1048
|
|
|
948
1049
|
// src/chains/solana/matchers/protocol/loan-collateral-transfer.ts
|
|
949
1050
|
var loanCollateralTransferMatcher = {
|
|
@@ -1054,12 +1155,15 @@ var metaplexMetadataUpdateMatcher = {
|
|
|
1054
1155
|
}
|
|
1055
1156
|
};
|
|
1056
1157
|
|
|
1057
|
-
// src/chains/solana/matchers/protocol/
|
|
1058
|
-
var
|
|
1059
|
-
|
|
1060
|
-
id: "solana.sharky-repay-loan-sale",
|
|
1158
|
+
// src/chains/solana/matchers/protocol/loan-repay-with-settlement.ts
|
|
1159
|
+
var loanRepayWithSettlementMatcher = {
|
|
1160
|
+
id: "solana.loan-repay-with-settlement",
|
|
1061
1161
|
matches(observation) {
|
|
1062
|
-
|
|
1162
|
+
if (!isLoanProgramSource(observation.normalizedSource)) return false;
|
|
1163
|
+
if (!observation.hasOwnershipChange || !observation.hasMeaningfulSettlement) return false;
|
|
1164
|
+
if (observation.nftTransfers.length === 0) return false;
|
|
1165
|
+
if (isLoanUnlockType(observation.normalizedType)) return true;
|
|
1166
|
+
return observation.normalizedSource === "SHARKY_FI" && observation.normalizedType === "UNKNOWN";
|
|
1063
1167
|
},
|
|
1064
1168
|
classify(observation) {
|
|
1065
1169
|
return classification({
|
|
@@ -1069,7 +1173,6 @@ var sharkyRepayLoanSaleMatcher = {
|
|
|
1069
1173
|
reason: "matched_loan_collateral_transfer_family",
|
|
1070
1174
|
observation,
|
|
1071
1175
|
overrides: {
|
|
1072
|
-
normalizedType: "REPAY_LOAN",
|
|
1073
1176
|
effect: "OWNERSHIP_CHANGE_AND_SETTLEMENT",
|
|
1074
1177
|
shouldExtractValueMovements: true
|
|
1075
1178
|
}
|
|
@@ -1079,19 +1182,19 @@ var sharkyRepayLoanSaleMatcher = {
|
|
|
1079
1182
|
|
|
1080
1183
|
// src/chains/solana/matchers/protocol/sharky-take-loan-transfer.ts
|
|
1081
1184
|
var sharkyTakeLoanTransferMatcher = {
|
|
1082
|
-
id: "solana.
|
|
1185
|
+
id: "solana.loan-take-with-transfer",
|
|
1083
1186
|
matches(observation) {
|
|
1084
|
-
return observation.normalizedSource
|
|
1187
|
+
return isLoanProgramSource(observation.normalizedSource) && isLoanLockType(observation.normalizedType) && observation.hasOwnershipChange && observation.hasMeaningfulSettlement && observation.nftTransfers.length > 0;
|
|
1085
1188
|
},
|
|
1086
1189
|
classify(observation) {
|
|
1087
1190
|
return classification({
|
|
1088
1191
|
family: "LOAN_PROGRAM_ACTIVITY",
|
|
1089
1192
|
derivedType: "TRANSFER",
|
|
1090
1193
|
matcherId: this.id,
|
|
1091
|
-
reason: "
|
|
1194
|
+
reason: "loan_take_with_settlement",
|
|
1092
1195
|
observation,
|
|
1093
1196
|
overrides: {
|
|
1094
|
-
normalizedType:
|
|
1197
|
+
normalizedType: observation.normalizedType,
|
|
1095
1198
|
effect: "OWNERSHIP_CHANGE_AND_SETTLEMENT",
|
|
1096
1199
|
shouldExtractValueMovements: false
|
|
1097
1200
|
}
|
|
@@ -1271,7 +1374,7 @@ var protocolMatchers = registerMatchers([
|
|
|
1271
1374
|
[loanProgramActivityMatcher, 870],
|
|
1272
1375
|
[migrateToPnftMatcher, 860],
|
|
1273
1376
|
[sharkyTakeLoanTransferMatcher, 855],
|
|
1274
|
-
[
|
|
1377
|
+
[loanRepayWithSettlementMatcher, 850],
|
|
1275
1378
|
[metaplexResizeActivityMatcher, 840],
|
|
1276
1379
|
[metaplexMetadataUpdateMatcher, 830]
|
|
1277
1380
|
]);
|
|
@@ -1282,6 +1385,7 @@ var coreAndMarketplaceMatchers = registerMatchers([
|
|
|
1282
1385
|
[magicEdenLuckyBuyMatcher, 670],
|
|
1283
1386
|
[hyperspaceInstantSellMatcher, 665],
|
|
1284
1387
|
[tensorUnknownSaleMatcher, 660],
|
|
1388
|
+
[marketplacePassthroughTransferMatcher, 655],
|
|
1285
1389
|
[marketplaceListingMatcher, 650],
|
|
1286
1390
|
[magicEdenBuyIntentMatcher, 640],
|
|
1287
1391
|
[marketplaceBidMatcher, 630]
|
|
@@ -1325,6 +1429,7 @@ function observationFromFacts(facts) {
|
|
|
1325
1429
|
hasMeaningfulSettlement: facts.hasMeaningfulSettlement,
|
|
1326
1430
|
primaryBuyer: facts.primaryBuyer,
|
|
1327
1431
|
primarySeller: facts.primarySeller,
|
|
1432
|
+
mintInAccountData: facts.mintInAccountData,
|
|
1328
1433
|
programIds: facts.programIds,
|
|
1329
1434
|
instructionLabels: facts.instructionLabels
|
|
1330
1435
|
};
|
|
@@ -1771,7 +1876,27 @@ function interpretMintFlowProtocolEvent(params) {
|
|
|
1771
1876
|
const derivedType = deriveMintFlowType(classification2, normalizedType);
|
|
1772
1877
|
if (normalizedType !== "NFT_MINT" && derivedType === "UNKNOWN") return null;
|
|
1773
1878
|
const mintTransfers = getMintTransfers(tx, mint);
|
|
1774
|
-
if (mintTransfers.length === 0)
|
|
1879
|
+
if (mintTransfers.length === 0) {
|
|
1880
|
+
if (classification2 && classification2.family === "LOAN_PROGRAM_ACTIVITY" && (derivedType === "LOCK" || derivedType === "UNLOCK") && tx.feePayer) {
|
|
1881
|
+
const borrower = tx.feePayer;
|
|
1882
|
+
return {
|
|
1883
|
+
kind: "DIRECT_FLOW",
|
|
1884
|
+
tx,
|
|
1885
|
+
timestamp,
|
|
1886
|
+
classification: classification2,
|
|
1887
|
+
flows: [
|
|
1888
|
+
{
|
|
1889
|
+
fromAddress: borrower,
|
|
1890
|
+
toAddress: borrower,
|
|
1891
|
+
transferIndex: 0,
|
|
1892
|
+
tokenStandard: null,
|
|
1893
|
+
derivedType
|
|
1894
|
+
}
|
|
1895
|
+
]
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1775
1900
|
const { firstTransfer, lastTransfer, fromAddress, toAddress, tokenStandard, intermediaries } = getTransferEndpoints(mintTransfers);
|
|
1776
1901
|
if (derivedType !== "MINT" && derivedType !== "LOCK" && derivedType !== "UNLOCK" && fromAddress === toAddress) {
|
|
1777
1902
|
return null;
|
|
@@ -1805,6 +1930,31 @@ function interpretMintFlowProtocolEvent(params) {
|
|
|
1805
1930
|
}
|
|
1806
1931
|
}
|
|
1807
1932
|
}
|
|
1933
|
+
const isCitrusComboBuy = (derivedType === "UNLOCK" || derivedType === "SALE") && normalizeEnhancedType(tx.source) === "CITRUS" && fromAddress !== null && toAddress !== null && fromAddress !== toAddress;
|
|
1934
|
+
if (isCitrusComboBuy && fromAddress && toAddress) {
|
|
1935
|
+
return {
|
|
1936
|
+
kind: "DIRECT_FLOW",
|
|
1937
|
+
tx,
|
|
1938
|
+
timestamp,
|
|
1939
|
+
classification: classification2,
|
|
1940
|
+
flows: [
|
|
1941
|
+
{
|
|
1942
|
+
fromAddress,
|
|
1943
|
+
toAddress,
|
|
1944
|
+
transferIndex: 0,
|
|
1945
|
+
tokenStandard,
|
|
1946
|
+
derivedType
|
|
1947
|
+
},
|
|
1948
|
+
{
|
|
1949
|
+
fromAddress: toAddress,
|
|
1950
|
+
toAddress,
|
|
1951
|
+
transferIndex: 1,
|
|
1952
|
+
tokenStandard,
|
|
1953
|
+
derivedType: "LOCK"
|
|
1954
|
+
}
|
|
1955
|
+
]
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1808
1958
|
if (derivedType === "SALE") {
|
|
1809
1959
|
const resolution = resolveSaleProtocolSemantics({
|
|
1810
1960
|
tx,
|
|
@@ -2193,6 +2343,13 @@ function extractCandidateMintsFromEnhancedTx(tx) {
|
|
|
2193
2343
|
mints.add(action.mint);
|
|
2194
2344
|
}
|
|
2195
2345
|
}
|
|
2346
|
+
for (const account of tx.accountData ?? []) {
|
|
2347
|
+
for (const change of account.tokenBalanceChanges ?? []) {
|
|
2348
|
+
if (change.mint) {
|
|
2349
|
+
mints.add(change.mint);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2196
2353
|
return [...mints];
|
|
2197
2354
|
}
|
|
2198
2355
|
function buildFlow(tx, timestamp, params) {
|
|
@@ -2258,7 +2415,9 @@ function extractValueMovements(transactions, mint, classificationCache = /* @__P
|
|
|
2258
2415
|
}
|
|
2259
2416
|
function normalizeMintHistory(transactions, mint) {
|
|
2260
2417
|
const classificationCache = /* @__PURE__ */ new Map();
|
|
2261
|
-
const flows =
|
|
2418
|
+
const flows = repairForeclosureFromAddresses(
|
|
2419
|
+
collapseRedundantCustodyFlows(extractMintFlows(transactions, mint, classificationCache))
|
|
2420
|
+
);
|
|
2262
2421
|
const valueMovements = extractValueMovements(transactions, mint, classificationCache);
|
|
2263
2422
|
const periods = reconstructOwnershipPeriods(flows);
|
|
2264
2423
|
return {
|
|
@@ -2648,6 +2807,8 @@ function shouldFetchRawForMintTx(tx, mint) {
|
|
|
2648
2807
|
var sui_exports = {};
|
|
2649
2808
|
__export(sui_exports, {
|
|
2650
2809
|
KIOSK_BIDDING_CLAIM_EVENT_SUFFIX: () => KIOSK_BIDDING_CLAIM_EVENT_SUFFIX,
|
|
2810
|
+
KIOSK_BIDDING_MATCH_BID_EVENT_SUFFIX: () => KIOSK_BIDDING_MATCH_BID_EVENT_SUFFIX,
|
|
2811
|
+
KIOSK_BIDDING_MATCH_COLLECTION_BID_EVENT_SUFFIX: () => KIOSK_BIDDING_MATCH_COLLECTION_BID_EVENT_SUFFIX,
|
|
2651
2812
|
KIOSK_CLAIM_EVENT_SUFFIX: () => KIOSK_CLAIM_EVENT_SUFFIX,
|
|
2652
2813
|
KIOSK_LIST_EVENT_SUFFIX: () => KIOSK_LIST_EVENT_SUFFIX,
|
|
2653
2814
|
KIOSK_TRANSFER_EVENT_SUFFIX: () => KIOSK_TRANSFER_EVENT_SUFFIX,
|
|
@@ -2660,6 +2821,7 @@ __export(sui_exports, {
|
|
|
2660
2821
|
TRADEPORT_ADD_LISTING_EVENT_SUFFIX: () => TRADEPORT_ADD_LISTING_EVENT_SUFFIX,
|
|
2661
2822
|
TRADEPORT_BUY_SIMPLE_EVENT_SUFFIX: () => TRADEPORT_BUY_SIMPLE_EVENT_SUFFIX,
|
|
2662
2823
|
TRADEPORT_CANCEL_SIMPLE_EVENT_SUFFIX: () => TRADEPORT_CANCEL_SIMPLE_EVENT_SUFFIX,
|
|
2824
|
+
TRADEPORT_CREATE_SIMPLE_LISTING_EVENT_SUFFIX: () => TRADEPORT_CREATE_SIMPLE_LISTING_EVENT_SUFFIX,
|
|
2663
2825
|
TRADEPORT_CREATE_SINGLE_BID_EVENT_SUFFIX: () => TRADEPORT_CREATE_SINGLE_BID_EVENT_SUFFIX,
|
|
2664
2826
|
TRADEPORT_KIOSK_BUY_EVENT_SUFFIX: () => TRADEPORT_KIOSK_BUY_EVENT_SUFFIX,
|
|
2665
2827
|
TRADEPORT_MATCH_SINGLE_BID_EVENT_SUFFIX: () => TRADEPORT_MATCH_SINGLE_BID_EVENT_SUFFIX,
|
|
@@ -2668,17 +2830,20 @@ __export(sui_exports, {
|
|
|
2668
2830
|
buildAssetHistory: () => normalizeAssetHistory,
|
|
2669
2831
|
buildFlows: () => extractAssetFlows,
|
|
2670
2832
|
buildOwnershipPeriods: () => reconstructOwnershipPeriods,
|
|
2833
|
+
buildValueMovements: () => extractSuiValueMovements,
|
|
2671
2834
|
classify: () => classifySuiTransactionForAsset,
|
|
2672
2835
|
classifySuiTransactionForAsset: () => classifySuiTransactionForAsset,
|
|
2673
2836
|
eventTouchesAsset: () => eventTouchesAsset,
|
|
2674
2837
|
eventTypeMatches: () => eventTypeMatches,
|
|
2675
2838
|
extractAssetFlows: () => extractAssetFlows,
|
|
2839
|
+
extractSuiValueMovements: () => extractSuiValueMovements,
|
|
2676
2840
|
findFirstEvent: () => findFirstEvent,
|
|
2677
2841
|
getAssetEvents: () => getAssetEvents,
|
|
2678
2842
|
getAssetObjectChange: () => getAssetObjectChange,
|
|
2679
2843
|
getAssetOwnerChange: () => getAssetOwnerChange,
|
|
2680
2844
|
getAssetOwnerChangeDetails: () => getAssetOwnerChangeDetails,
|
|
2681
2845
|
getEventTypes: () => getEventTypes,
|
|
2846
|
+
getKioskOwnerCapAddressOwnerChange: () => getKioskOwnerCapAddressOwnerChange,
|
|
2682
2847
|
getMarket: () => getMarket,
|
|
2683
2848
|
getPriceRaw: () => getPriceRaw,
|
|
2684
2849
|
getRecordString: () => getRecordString,
|
|
@@ -2700,10 +2865,13 @@ var TRADEPORT_BUY_SIMPLE_EVENT_SUFFIX = "::tradeport_listings::BuySimpleListingE
|
|
|
2700
2865
|
var TRADEPORT_MATCH_SINGLE_BID_EVENT_SUFFIX = "::tradeport_biddings::MatchSingleBidEvent";
|
|
2701
2866
|
var TRADEPORT_KIOSK_BUY_EVENT_SUFFIX = "::kiosk_listings::BuyEvent";
|
|
2702
2867
|
var TRADEPORT_ADD_LISTING_EVENT_SUFFIX = "::tradeport_orderbook::AddListingEvent";
|
|
2868
|
+
var TRADEPORT_CREATE_SIMPLE_LISTING_EVENT_SUFFIX = "::tradeport_listings::CreateSimpleListingEvent";
|
|
2703
2869
|
var TRADEPORT_RELIST_SIMPLE_EVENT_SUFFIX = "::tradeport_listings::RelistSimpleListingEvent";
|
|
2704
2870
|
var TRADEPORT_REMOVE_LISTING_EVENT_SUFFIX = "::tradeport_orderbook::RemoveListingEvent";
|
|
2705
2871
|
var TRADEPORT_CANCEL_SIMPLE_EVENT_SUFFIX = "::tradeport_listings::CancelSimpleListingEvent";
|
|
2706
2872
|
var TRADEPORT_CREATE_SINGLE_BID_EVENT_SUFFIX = "::tradeport_biddings::CreateSingleBidEvent";
|
|
2873
|
+
var KIOSK_BIDDING_MATCH_BID_EVENT_SUFFIX = "::kiosk_biddings::MatchBidWithPurchaseCapEvent";
|
|
2874
|
+
var KIOSK_BIDDING_MATCH_COLLECTION_BID_EVENT_SUFFIX = "::kiosk_biddings::MatchCollectionBidWithPurchaseCapEvent";
|
|
2707
2875
|
var KIOSK_LIST_EVENT_SUFFIX = "::kiosk_listings::ListEvent";
|
|
2708
2876
|
var KIOSK_UNLIST_EVENT_SUFFIX = "::kiosk_listings::UnlistEvent";
|
|
2709
2877
|
var KIOSK_TRANSFER_EVENT_SUFFIX = "::kiosk_transfers::TransferWithPurchaseCapEvent";
|
|
@@ -2778,6 +2946,31 @@ function getAssetOwnerChange(tx, assetId) {
|
|
|
2778
2946
|
objectType: ownerChange.objectType
|
|
2779
2947
|
};
|
|
2780
2948
|
}
|
|
2949
|
+
function getKioskOwnerCapAddressOwnerChange(tx) {
|
|
2950
|
+
const ownerCapChanges = (tx.objectChanges ?? []).filter(
|
|
2951
|
+
(change) => getString(change.objectType)?.endsWith("::kiosk::KioskOwnerCap") && getString(change.type) !== "created"
|
|
2952
|
+
);
|
|
2953
|
+
const addressOwners = [
|
|
2954
|
+
...new Set(
|
|
2955
|
+
ownerCapChanges.flatMap((change) => {
|
|
2956
|
+
const owner = normalizeOwnerRef(change.owner ?? change.recipient);
|
|
2957
|
+
return owner?.kind === "address" ? [owner.value] : [];
|
|
2958
|
+
})
|
|
2959
|
+
)
|
|
2960
|
+
];
|
|
2961
|
+
if (addressOwners.length !== 1) {
|
|
2962
|
+
return null;
|
|
2963
|
+
}
|
|
2964
|
+
const sender = getString(ownerCapChanges[0]?.sender) ?? getString(tx.transaction?.data?.sender);
|
|
2965
|
+
if (sender === addressOwners[0]) {
|
|
2966
|
+
return null;
|
|
2967
|
+
}
|
|
2968
|
+
return {
|
|
2969
|
+
sender,
|
|
2970
|
+
nextOwner: { value: addressOwners[0], kind: "address" },
|
|
2971
|
+
objectType: getString(ownerCapChanges[0]?.objectType)
|
|
2972
|
+
};
|
|
2973
|
+
}
|
|
2781
2974
|
function eventTouchesAsset(event, assetId) {
|
|
2782
2975
|
if (!isRecord(event.parsedJson)) {
|
|
2783
2976
|
return false;
|
|
@@ -2803,11 +2996,28 @@ function findFirstEvent(events, suffixes) {
|
|
|
2803
2996
|
}
|
|
2804
2997
|
return null;
|
|
2805
2998
|
}
|
|
2999
|
+
function parseNonNegativeBigInt(raw) {
|
|
3000
|
+
if (!raw) return null;
|
|
3001
|
+
try {
|
|
3002
|
+
const value = BigInt(raw);
|
|
3003
|
+
return value >= 0n ? value : null;
|
|
3004
|
+
} catch {
|
|
3005
|
+
return null;
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
2806
3008
|
function getPriceRaw(event) {
|
|
2807
3009
|
if (!event || !isRecord(event.parsedJson)) {
|
|
2808
3010
|
return null;
|
|
2809
3011
|
}
|
|
2810
|
-
|
|
3012
|
+
const rawPrice = getRecordString(event.parsedJson, "price") ?? getRecordString(event.parsedJson, "new_price");
|
|
3013
|
+
if (rawPrice && eventTypeMatches(event, [KIOSK_LIST_EVENT_SUFFIX])) {
|
|
3014
|
+
const price = parseNonNegativeBigInt(rawPrice);
|
|
3015
|
+
const commission = parseNonNegativeBigInt(getRecordString(event.parsedJson, "commission"));
|
|
3016
|
+
if (price !== null && commission !== null && commission <= price) {
|
|
3017
|
+
return (price - commission).toString();
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
return rawPrice;
|
|
2811
3021
|
}
|
|
2812
3022
|
function getMarket(event, fallback = null) {
|
|
2813
3023
|
if (!event || !isRecord(event.parsedJson)) {
|
|
@@ -2859,6 +3069,8 @@ function classifySuiTransactionForAsset(tx, assetId) {
|
|
|
2859
3069
|
const saleEvent = findFirstEvent(assetEvents, [
|
|
2860
3070
|
TRADEPORT_BUY_SIMPLE_EVENT_SUFFIX,
|
|
2861
3071
|
TRADEPORT_MATCH_SINGLE_BID_EVENT_SUFFIX,
|
|
3072
|
+
KIOSK_BIDDING_MATCH_BID_EVENT_SUFFIX,
|
|
3073
|
+
KIOSK_BIDDING_MATCH_COLLECTION_BID_EVENT_SUFFIX,
|
|
2862
3074
|
TRADEPORT_KIOSK_BUY_EVENT_SUFFIX
|
|
2863
3075
|
]);
|
|
2864
3076
|
if (saleEvent) {
|
|
@@ -2946,7 +3158,7 @@ function classifySuiTransactionForAsset(tx, assetId) {
|
|
|
2946
3158
|
assetId,
|
|
2947
3159
|
family: "TRADEPORT_LISTING",
|
|
2948
3160
|
effect: "NON_SETTLEMENT_MARKETPLACE_ACTION",
|
|
2949
|
-
materialization: "
|
|
3161
|
+
materialization: "PERSIST_FLOW",
|
|
2950
3162
|
confidence: "high",
|
|
2951
3163
|
derivedType: "LIST",
|
|
2952
3164
|
matcherId: "sui.tradeport-relist",
|
|
@@ -2960,7 +3172,10 @@ function classifySuiTransactionForAsset(tx, assetId) {
|
|
|
2960
3172
|
ownerChange
|
|
2961
3173
|
};
|
|
2962
3174
|
}
|
|
2963
|
-
const listingEvent = findFirstEvent(assetEvents, [
|
|
3175
|
+
const listingEvent = findFirstEvent(assetEvents, [
|
|
3176
|
+
TRADEPORT_ADD_LISTING_EVENT_SUFFIX,
|
|
3177
|
+
TRADEPORT_CREATE_SIMPLE_LISTING_EVENT_SUFFIX
|
|
3178
|
+
]);
|
|
2964
3179
|
if (listingEvent) {
|
|
2965
3180
|
return {
|
|
2966
3181
|
assetId,
|
|
@@ -3010,7 +3225,7 @@ function classifySuiTransactionForAsset(tx, assetId) {
|
|
|
3010
3225
|
assetId,
|
|
3011
3226
|
family: "KIOSK_LISTING",
|
|
3012
3227
|
effect: "NON_SETTLEMENT_MARKETPLACE_ACTION",
|
|
3013
|
-
materialization: "
|
|
3228
|
+
materialization: "PERSIST_FLOW",
|
|
3014
3229
|
confidence: "high",
|
|
3015
3230
|
derivedType: "LIST",
|
|
3016
3231
|
matcherId: "sui.kiosk-price-change",
|
|
@@ -3143,6 +3358,31 @@ function classifySuiTransactionForAsset(tx, assetId) {
|
|
|
3143
3358
|
ownerChange
|
|
3144
3359
|
};
|
|
3145
3360
|
}
|
|
3361
|
+
const kioskOwnerCapChange = getKioskOwnerCapAddressOwnerChange(tx);
|
|
3362
|
+
if ((tx.events?.length ?? 0) === 0 && kioskOwnerCapChange?.nextOwner?.kind === "address") {
|
|
3363
|
+
return {
|
|
3364
|
+
assetId,
|
|
3365
|
+
family: "GENERIC_OBJECT_TRANSFER",
|
|
3366
|
+
effect: "OWNERSHIP_CHANGE_ONLY",
|
|
3367
|
+
materialization: "PERSIST_FLOW",
|
|
3368
|
+
confidence: "medium",
|
|
3369
|
+
derivedType: "TRANSFER",
|
|
3370
|
+
matcherId: "sui.kiosk-owner-cap-transfer",
|
|
3371
|
+
reason: "matched_kiosk_owner_cap_address_transfer",
|
|
3372
|
+
hasOwnershipChange: true,
|
|
3373
|
+
shouldExtractValueMovements: false,
|
|
3374
|
+
eventTypes,
|
|
3375
|
+
market: null,
|
|
3376
|
+
priceRaw: null,
|
|
3377
|
+
currency: null,
|
|
3378
|
+
ownerChange: {
|
|
3379
|
+
sender: kioskOwnerCapChange.sender,
|
|
3380
|
+
nextOwner: kioskOwnerCapChange.nextOwner.value,
|
|
3381
|
+
nextOwnerKind: kioskOwnerCapChange.nextOwner.kind,
|
|
3382
|
+
objectType: kioskOwnerCapChange.objectType
|
|
3383
|
+
}
|
|
3384
|
+
};
|
|
3385
|
+
}
|
|
3146
3386
|
return buildClassification(tx, assetId, {
|
|
3147
3387
|
family: "UNKNOWN",
|
|
3148
3388
|
effect: "UNKNOWN",
|
|
@@ -3160,6 +3400,7 @@ function classifySuiTransactionForAsset(tx, assetId) {
|
|
|
3160
3400
|
}
|
|
3161
3401
|
|
|
3162
3402
|
// src/chains/sui/normalize.ts
|
|
3403
|
+
var MIST_PER_SUI = 1e9;
|
|
3163
3404
|
function parseSaleParticipants(saleEvent) {
|
|
3164
3405
|
if (!saleEvent || typeof saleEvent.parsedJson !== "object" || saleEvent.parsedJson === null) {
|
|
3165
3406
|
return {
|
|
@@ -3326,6 +3567,115 @@ function buildFlow2(tx, timestamp, params) {
|
|
|
3326
3567
|
derivedType: params.derivedType
|
|
3327
3568
|
};
|
|
3328
3569
|
}
|
|
3570
|
+
function parsePositiveRawAmount(value) {
|
|
3571
|
+
const raw = typeof value === "string" ? value : null;
|
|
3572
|
+
if (!raw) {
|
|
3573
|
+
return null;
|
|
3574
|
+
}
|
|
3575
|
+
try {
|
|
3576
|
+
return BigInt(raw) > 0n ? raw : null;
|
|
3577
|
+
} catch {
|
|
3578
|
+
return null;
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
function toSuiAmount(rawAmount) {
|
|
3582
|
+
try {
|
|
3583
|
+
const amount = Number(rawAmount);
|
|
3584
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
3585
|
+
return null;
|
|
3586
|
+
}
|
|
3587
|
+
return amount / MIST_PER_SUI;
|
|
3588
|
+
} catch {
|
|
3589
|
+
return null;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
function buildValueMovement(tx, timestamp, params) {
|
|
3593
|
+
const amount = toSuiAmount(params.rawAmount);
|
|
3594
|
+
if (!amount) {
|
|
3595
|
+
return null;
|
|
3596
|
+
}
|
|
3597
|
+
return {
|
|
3598
|
+
signature: tx.digest,
|
|
3599
|
+
slot: resolveSlot(tx),
|
|
3600
|
+
timestamp,
|
|
3601
|
+
heliusType: "SUI",
|
|
3602
|
+
source: "sui",
|
|
3603
|
+
movementKind: "NATIVE",
|
|
3604
|
+
currency: "SUI",
|
|
3605
|
+
amount,
|
|
3606
|
+
rawAmount: params.rawAmount,
|
|
3607
|
+
decimals: 9,
|
|
3608
|
+
fromAddress: params.fromAddress,
|
|
3609
|
+
toAddress: params.toAddress,
|
|
3610
|
+
movementIndex: params.movementIndex,
|
|
3611
|
+
tokenStandard: null,
|
|
3612
|
+
role: params.role,
|
|
3613
|
+
confidence: "HIGH",
|
|
3614
|
+
isSynthetic: true
|
|
3615
|
+
};
|
|
3616
|
+
}
|
|
3617
|
+
function buildSaleValueMovements(tx, assetId, timestamp) {
|
|
3618
|
+
const saleEvent = findFirstEvent(getAssetEvents(tx, assetId), [
|
|
3619
|
+
TRADEPORT_BUY_SIMPLE_EVENT_SUFFIX,
|
|
3620
|
+
TRADEPORT_MATCH_SINGLE_BID_EVENT_SUFFIX,
|
|
3621
|
+
KIOSK_BIDDING_MATCH_BID_EVENT_SUFFIX,
|
|
3622
|
+
KIOSK_BIDDING_MATCH_COLLECTION_BID_EVENT_SUFFIX,
|
|
3623
|
+
TRADEPORT_KIOSK_BUY_EVENT_SUFFIX
|
|
3624
|
+
]);
|
|
3625
|
+
if (!saleEvent || !isRecord(saleEvent.parsedJson)) {
|
|
3626
|
+
return [];
|
|
3627
|
+
}
|
|
3628
|
+
const parsedJson = saleEvent.parsedJson;
|
|
3629
|
+
const rawAmount = parsePositiveRawAmount(parsedJson.price);
|
|
3630
|
+
if (!rawAmount) {
|
|
3631
|
+
return [];
|
|
3632
|
+
}
|
|
3633
|
+
const movement = buildValueMovement(tx, timestamp, {
|
|
3634
|
+
movementIndex: 0,
|
|
3635
|
+
rawAmount,
|
|
3636
|
+
fromAddress: getString(parsedJson.buyer),
|
|
3637
|
+
toAddress: getString(parsedJson.seller),
|
|
3638
|
+
role: "SALE_GROSS"
|
|
3639
|
+
});
|
|
3640
|
+
return movement ? [movement] : [];
|
|
3641
|
+
}
|
|
3642
|
+
function buildSwapValueMovements(tx, assetId, timestamp) {
|
|
3643
|
+
const swapEvent = getAssetEvents(tx, assetId).find((event) => event.type.includes("SwapExecuted")) ?? null;
|
|
3644
|
+
if (!swapEvent || !isRecord(swapEvent.parsedJson)) {
|
|
3645
|
+
return [];
|
|
3646
|
+
}
|
|
3647
|
+
const parsedJson = swapEvent.parsedJson;
|
|
3648
|
+
const proposer = getString(parsedJson.proposer);
|
|
3649
|
+
const counterparty = getString(parsedJson.counterparty);
|
|
3650
|
+
const movements = [];
|
|
3651
|
+
const proposerRawAmount = parsePositiveRawAmount(parsedJson.proposer_sui_amount);
|
|
3652
|
+
const counterpartyRawAmount = parsePositiveRawAmount(parsedJson.counterparty_sui_amount);
|
|
3653
|
+
if (proposerRawAmount) {
|
|
3654
|
+
const movement = buildValueMovement(tx, timestamp, {
|
|
3655
|
+
movementIndex: movements.length,
|
|
3656
|
+
rawAmount: proposerRawAmount,
|
|
3657
|
+
fromAddress: proposer,
|
|
3658
|
+
toAddress: counterparty,
|
|
3659
|
+
role: "SWAP_CONSIDERATION"
|
|
3660
|
+
});
|
|
3661
|
+
if (movement) {
|
|
3662
|
+
movements.push(movement);
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
if (counterpartyRawAmount) {
|
|
3666
|
+
const movement = buildValueMovement(tx, timestamp, {
|
|
3667
|
+
movementIndex: movements.length,
|
|
3668
|
+
rawAmount: counterpartyRawAmount,
|
|
3669
|
+
fromAddress: counterparty,
|
|
3670
|
+
toAddress: proposer,
|
|
3671
|
+
role: "SWAP_CONSIDERATION"
|
|
3672
|
+
});
|
|
3673
|
+
if (movement) {
|
|
3674
|
+
movements.push(movement);
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
return movements;
|
|
3678
|
+
}
|
|
3329
3679
|
function buildSuiFlows(tx, assetId, classification2, currentBeneficialOwner) {
|
|
3330
3680
|
if (classification2.materialization !== "PERSIST_FLOW") {
|
|
3331
3681
|
return [];
|
|
@@ -3333,8 +3683,10 @@ function buildSuiFlows(tx, assetId, classification2, currentBeneficialOwner) {
|
|
|
3333
3683
|
const timestamp = resolveTimestamp(tx);
|
|
3334
3684
|
const assetEvents = getAssetEvents(tx, assetId);
|
|
3335
3685
|
const ownerChange = getAssetOwnerChangeDetails(tx, assetId);
|
|
3686
|
+
const kioskOwnerCapChange = getKioskOwnerCapAddressOwnerChange(tx);
|
|
3336
3687
|
const sender = getString(tx.transaction?.data?.sender) ?? ownerChange?.sender ?? null;
|
|
3337
3688
|
const addressOwner = (ownerChange?.nextOwner?.kind === "address" ? ownerChange.nextOwner.value : null) ?? resolveNextBeneficialOwner(tx, ownerChange);
|
|
3689
|
+
const kioskOwnerCapAddressOwner = kioskOwnerCapChange?.nextOwner?.kind === "address" ? kioskOwnerCapChange.nextOwner.value : null;
|
|
3338
3690
|
let fromAddress = null;
|
|
3339
3691
|
let toAddress = null;
|
|
3340
3692
|
switch (classification2.derivedType) {
|
|
@@ -3345,6 +3697,8 @@ function buildSuiFlows(tx, assetId, classification2, currentBeneficialOwner) {
|
|
|
3345
3697
|
const saleEvent = findFirstEvent(assetEvents, [
|
|
3346
3698
|
TRADEPORT_BUY_SIMPLE_EVENT_SUFFIX,
|
|
3347
3699
|
TRADEPORT_MATCH_SINGLE_BID_EVENT_SUFFIX,
|
|
3700
|
+
KIOSK_BIDDING_MATCH_BID_EVENT_SUFFIX,
|
|
3701
|
+
KIOSK_BIDDING_MATCH_COLLECTION_BID_EVENT_SUFFIX,
|
|
3348
3702
|
TRADEPORT_KIOSK_BUY_EVENT_SUFFIX
|
|
3349
3703
|
]);
|
|
3350
3704
|
const sale = parseSaleParticipants(saleEvent);
|
|
@@ -3361,10 +3715,15 @@ function buildSuiFlows(tx, assetId, classification2, currentBeneficialOwner) {
|
|
|
3361
3715
|
}
|
|
3362
3716
|
case "TRANSFER":
|
|
3363
3717
|
fromAddress = currentBeneficialOwner ?? sender ?? null;
|
|
3364
|
-
toAddress = addressOwner ?? (ownerChange?.nextOwner?.kind === "object" ? sender ?? currentBeneficialOwner ?? null : sender ?? null);
|
|
3718
|
+
toAddress = (classification2.matcherId === "sui.kiosk-owner-cap-transfer" ? kioskOwnerCapAddressOwner : null) ?? addressOwner ?? (ownerChange?.nextOwner?.kind === "object" ? sender ?? currentBeneficialOwner ?? null : sender ?? null);
|
|
3365
3719
|
break;
|
|
3366
3720
|
case "LIST": {
|
|
3367
|
-
const listingEvent = findFirstEvent(assetEvents, [
|
|
3721
|
+
const listingEvent = findFirstEvent(assetEvents, [
|
|
3722
|
+
TRADEPORT_ADD_LISTING_EVENT_SUFFIX,
|
|
3723
|
+
TRADEPORT_CREATE_SIMPLE_LISTING_EVENT_SUFFIX,
|
|
3724
|
+
TRADEPORT_RELIST_SIMPLE_EVENT_SUFFIX,
|
|
3725
|
+
KIOSK_LIST_EVENT_SUFFIX
|
|
3726
|
+
]);
|
|
3368
3727
|
const owner = parseListingSeller(listingEvent) ?? currentBeneficialOwner ?? sender ?? addressOwner;
|
|
3369
3728
|
fromAddress = owner;
|
|
3370
3729
|
toAddress = owner;
|
|
@@ -3420,17 +3779,40 @@ function extractAssetFlows(transactions, assetId, classificationCache = /* @__PU
|
|
|
3420
3779
|
}
|
|
3421
3780
|
return collapseRedundantCustodyFlows(canonicalizeMintFlows(flows));
|
|
3422
3781
|
}
|
|
3782
|
+
function extractSuiValueMovements(transactions, assetId, classificationCache = /* @__PURE__ */ new Map()) {
|
|
3783
|
+
const movements = [];
|
|
3784
|
+
for (const tx of sortTransactions(transactions)) {
|
|
3785
|
+
const classification2 = classificationCache.get(tx.digest) ?? classifySuiTransactionForAsset(tx, assetId);
|
|
3786
|
+
classificationCache.set(tx.digest, classification2);
|
|
3787
|
+
if (classification2.materialization !== "PERSIST_FLOW" || !classification2.shouldExtractValueMovements) {
|
|
3788
|
+
continue;
|
|
3789
|
+
}
|
|
3790
|
+
const timestamp = resolveTimestamp(tx);
|
|
3791
|
+
if (classification2.derivedType === "SALE") {
|
|
3792
|
+
movements.push(...buildSaleValueMovements(tx, assetId, timestamp));
|
|
3793
|
+
continue;
|
|
3794
|
+
}
|
|
3795
|
+
if (classification2.derivedType === "SWAP") {
|
|
3796
|
+
movements.push(...buildSwapValueMovements(tx, assetId, timestamp));
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
return canonicalizeValueMovements(movements);
|
|
3800
|
+
}
|
|
3423
3801
|
function normalizeAssetHistory(transactions, assetId) {
|
|
3424
3802
|
const classificationCache = /* @__PURE__ */ new Map();
|
|
3425
3803
|
const flows = extractAssetFlows(transactions, assetId, classificationCache);
|
|
3804
|
+
const valueMovements = extractSuiValueMovements(transactions, assetId, classificationCache);
|
|
3426
3805
|
const periods = reconstructOwnershipPeriods(flows);
|
|
3427
3806
|
return {
|
|
3428
3807
|
flows,
|
|
3808
|
+
valueMovements,
|
|
3429
3809
|
periods
|
|
3430
3810
|
};
|
|
3431
3811
|
}
|
|
3432
3812
|
export {
|
|
3433
3813
|
KIOSK_BIDDING_CLAIM_EVENT_SUFFIX,
|
|
3814
|
+
KIOSK_BIDDING_MATCH_BID_EVENT_SUFFIX,
|
|
3815
|
+
KIOSK_BIDDING_MATCH_COLLECTION_BID_EVENT_SUFFIX,
|
|
3434
3816
|
KIOSK_CLAIM_EVENT_SUFFIX,
|
|
3435
3817
|
KIOSK_LIST_EVENT_SUFFIX,
|
|
3436
3818
|
KIOSK_TRANSFER_EVENT_SUFFIX,
|
|
@@ -3444,6 +3826,7 @@ export {
|
|
|
3444
3826
|
TRADEPORT_ADD_LISTING_EVENT_SUFFIX,
|
|
3445
3827
|
TRADEPORT_BUY_SIMPLE_EVENT_SUFFIX,
|
|
3446
3828
|
TRADEPORT_CANCEL_SIMPLE_EVENT_SUFFIX,
|
|
3829
|
+
TRADEPORT_CREATE_SIMPLE_LISTING_EVENT_SUFFIX,
|
|
3447
3830
|
TRADEPORT_CREATE_SINGLE_BID_EVENT_SUFFIX,
|
|
3448
3831
|
TRADEPORT_KIOSK_BUY_EVENT_SUFFIX,
|
|
3449
3832
|
TRADEPORT_MATCH_SINGLE_BID_EVENT_SUFFIX,
|
|
@@ -3474,6 +3857,7 @@ export {
|
|
|
3474
3857
|
extractCandidateMintsFromRawTransaction,
|
|
3475
3858
|
extractMintFlows,
|
|
3476
3859
|
extractCandidateMintsFromEnhancedTx as extractMints,
|
|
3860
|
+
extractSuiValueMovements,
|
|
3477
3861
|
extractValueMovements,
|
|
3478
3862
|
findFirstEvent,
|
|
3479
3863
|
getAssetEvents,
|
|
@@ -3481,6 +3865,7 @@ export {
|
|
|
3481
3865
|
getAssetOwnerChange,
|
|
3482
3866
|
getAssetOwnerChangeDetails,
|
|
3483
3867
|
getEventTypes,
|
|
3868
|
+
getKioskOwnerCapAddressOwnerChange,
|
|
3484
3869
|
getMarket,
|
|
3485
3870
|
getMatchingAssetFlowMatchers,
|
|
3486
3871
|
getMintNftTransfers,
|
|
@@ -3488,6 +3873,7 @@ export {
|
|
|
3488
3873
|
getRecordString,
|
|
3489
3874
|
getRecordStringArray,
|
|
3490
3875
|
getString,
|
|
3876
|
+
hasLoanProgramSettlement,
|
|
3491
3877
|
hasMeaningfulNativeSettlement,
|
|
3492
3878
|
hasMeaningfulSuiSettlement,
|
|
3493
3879
|
interpretMintFlowProtocolEvent,
|