tx-indexer 0.2.0 → 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/{classification.types-w82k4B1F.d.ts → classification.types-DlJe6bDZ.d.ts} +2 -6
- package/dist/{client-BS9KUBU7.d.ts → client-yGDWPKKf.d.ts} +6 -81
- package/dist/client.d.ts +2 -2
- package/dist/client.js +396 -256
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +396 -256
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -137,6 +137,7 @@ function extractProgramIds(transaction) {
|
|
|
137
137
|
var SYSTEM_PROGRAM_ID = "11111111111111111111111111111111";
|
|
138
138
|
var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
|
|
139
139
|
var STAKE_PROGRAM_ID = "Stake11111111111111111111111111111111111111";
|
|
140
|
+
var STAKE_POOL_PROGRAM_ID = "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy";
|
|
140
141
|
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
141
142
|
var ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
|
142
143
|
var SPL_MEMO_PROGRAM_ID = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
|
|
@@ -146,6 +147,15 @@ var JUPITER_V4_PROGRAM_ID = "JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB";
|
|
|
146
147
|
var RAYDIUM_PROGRAM_ID = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
|
|
147
148
|
var ORCA_WHIRLPOOL_PROGRAM_ID = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
|
|
148
149
|
var METAPLEX_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
150
|
+
var CANDY_MACHINE_V3_PROGRAM_ID = "CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR";
|
|
151
|
+
var CANDY_GUARD_PROGRAM_ID = "Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g";
|
|
152
|
+
var BUBBLEGUM_PROGRAM_ID = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY";
|
|
153
|
+
var MAGIC_EDEN_CANDY_MACHINE_ID = "CMZYPASGWeTz7RNGHaRJfCq2XQ5pYK6nDvVQxzkH51zb";
|
|
154
|
+
var WORMHOLE_PROGRAM_ID = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth";
|
|
155
|
+
var WORMHOLE_TOKEN_BRIDGE_ID = "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb";
|
|
156
|
+
var DEGODS_BRIDGE_PROGRAM_ID = "35iLrpYNNR9ygHLcvE1xKFHbHq6paHthrF6wSovdWgGu";
|
|
157
|
+
var DEBRIDGE_PROGRAM_ID = "DEbrdGj3HsRsAzx6uH4MKyREKxVAfBydijLUF3ygsFfh";
|
|
158
|
+
var ALLBRIDGE_PROGRAM_ID = "BrdgN2RPzEMWF96ZbnnJaUtQDQx7VRXYaHHbYCBvceWB";
|
|
149
159
|
var PAYAI_FACILITATOR = "2wKupLR9q6wXYppw8Gr2NvWxKBUqm4PPJKkQfoxHDBg4";
|
|
150
160
|
var KNOWN_FACILITATORS = [
|
|
151
161
|
PAYAI_FACILITATOR
|
|
@@ -372,7 +382,7 @@ function isSolanaPayTransaction(programIds, memo) {
|
|
|
372
382
|
|
|
373
383
|
// ../solana/src/fetcher/transactions.ts
|
|
374
384
|
async function fetchWalletSignatures(rpc, walletAddress, config = {}) {
|
|
375
|
-
const { limit =
|
|
385
|
+
const { limit = 100, before, until } = config;
|
|
376
386
|
const response = await rpc.getSignaturesForAddress(walletAddress, {
|
|
377
387
|
limit,
|
|
378
388
|
before,
|
|
@@ -558,7 +568,7 @@ var DEX_PROTOCOL_IDS = /* @__PURE__ */ new Set([
|
|
|
558
568
|
function isDexProtocol(protocol) {
|
|
559
569
|
return protocol !== null && protocol !== void 0 && DEX_PROTOCOL_IDS.has(protocol.id);
|
|
560
570
|
}
|
|
561
|
-
function transactionToLegs(tx
|
|
571
|
+
function transactionToLegs(tx) {
|
|
562
572
|
const legs = [];
|
|
563
573
|
const feePayer = tx.accountKeys?.[0]?.toLowerCase();
|
|
564
574
|
const solChanges = extractSolBalanceChanges(tx);
|
|
@@ -566,9 +576,8 @@ function transactionToLegs(tx, walletAddress) {
|
|
|
566
576
|
let totalSolCredits = 0n;
|
|
567
577
|
for (const change of solChanges) {
|
|
568
578
|
if (change.change === 0n) continue;
|
|
569
|
-
const isWallet = walletAddress ? change.address.toLowerCase() === walletAddress.toLowerCase() : false;
|
|
570
579
|
const accountId = buildAccountId({
|
|
571
|
-
type:
|
|
580
|
+
type: "external",
|
|
572
581
|
address: change.address
|
|
573
582
|
});
|
|
574
583
|
const solInfo = TOKEN_INFO[KNOWN_TOKENS.SOL];
|
|
@@ -588,7 +597,7 @@ function transactionToLegs(tx, walletAddress) {
|
|
|
588
597
|
amountRaw: change.change.toString().replace("-", ""),
|
|
589
598
|
amountUi: Math.abs(change.changeUi)
|
|
590
599
|
},
|
|
591
|
-
role: determineSolRole(change,
|
|
600
|
+
role: determineSolRole(change, tx, feePayer)
|
|
592
601
|
});
|
|
593
602
|
}
|
|
594
603
|
const networkFee = totalSolDebits - totalSolCredits;
|
|
@@ -610,26 +619,22 @@ function transactionToLegs(tx, walletAddress) {
|
|
|
610
619
|
const tokenChanges = extractTokenBalanceChanges(tx);
|
|
611
620
|
for (const change of tokenChanges) {
|
|
612
621
|
if (change.change.raw === "0") continue;
|
|
613
|
-
const isWallet = walletAddress ? change.owner?.toLowerCase() === walletAddress.toLowerCase() : false;
|
|
614
|
-
const isFeePayer = !walletAddress && feePayer ? change.owner?.toLowerCase() === feePayer : false;
|
|
615
622
|
let accountId;
|
|
616
|
-
if (
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
token: change.tokenInfo.symbol
|
|
632
|
-
});
|
|
623
|
+
if (isDexProtocol(tx.protocol)) {
|
|
624
|
+
const isFeePayer = feePayer && change.owner?.toLowerCase() === feePayer;
|
|
625
|
+
if (isFeePayer) {
|
|
626
|
+
accountId = buildAccountId({
|
|
627
|
+
type: "external",
|
|
628
|
+
address: change.owner || feePayer
|
|
629
|
+
});
|
|
630
|
+
} else {
|
|
631
|
+
accountId = buildAccountId({
|
|
632
|
+
type: "protocol",
|
|
633
|
+
address: change.owner || change.tokenInfo.mint,
|
|
634
|
+
protocol: tx.protocol.id,
|
|
635
|
+
token: change.tokenInfo.symbol
|
|
636
|
+
});
|
|
637
|
+
}
|
|
633
638
|
} else {
|
|
634
639
|
accountId = buildAccountId({
|
|
635
640
|
type: "external",
|
|
@@ -644,41 +649,30 @@ function transactionToLegs(tx, walletAddress) {
|
|
|
644
649
|
amountRaw: change.change.raw.replace("-", ""),
|
|
645
650
|
amountUi: Math.abs(change.change.ui)
|
|
646
651
|
},
|
|
647
|
-
role: determineTokenRole(change,
|
|
652
|
+
role: determineTokenRole(change, tx, feePayer)
|
|
648
653
|
});
|
|
649
654
|
}
|
|
650
655
|
return legs;
|
|
651
656
|
}
|
|
652
|
-
function determineSolRole(change,
|
|
653
|
-
const
|
|
654
|
-
const isFeePayer = !walletAddress && feePayer ? change.address.toLowerCase() === feePayer : false;
|
|
657
|
+
function determineSolRole(change, tx, feePayer) {
|
|
658
|
+
const isFeePayer = feePayer ? change.address.toLowerCase() === feePayer : false;
|
|
655
659
|
const isPositive = change.change > 0n;
|
|
656
660
|
const amountSol = Math.abs(change.changeUi);
|
|
657
|
-
if (isWallet) {
|
|
658
|
-
if (!isPositive && amountSol < 0.01) {
|
|
659
|
-
return "fee";
|
|
660
|
-
}
|
|
661
|
-
if (isPositive) {
|
|
662
|
-
if (tx.protocol?.id === "stake") {
|
|
663
|
-
return "reward";
|
|
664
|
-
}
|
|
665
|
-
return "received";
|
|
666
|
-
}
|
|
667
|
-
return "sent";
|
|
668
|
-
}
|
|
669
661
|
if (isFeePayer && !isPositive && amountSol < 0.01) {
|
|
670
662
|
return "fee";
|
|
671
663
|
}
|
|
672
664
|
if (isPositive) {
|
|
665
|
+
if (tx.protocol?.id === "stake") {
|
|
666
|
+
return "reward";
|
|
667
|
+
}
|
|
673
668
|
return "received";
|
|
674
669
|
}
|
|
675
670
|
return "sent";
|
|
676
671
|
}
|
|
677
|
-
function determineTokenRole(change,
|
|
678
|
-
const
|
|
679
|
-
const isFeePayer = !walletAddress && feePayer ? change.owner?.toLowerCase() === feePayer : false;
|
|
672
|
+
function determineTokenRole(change, tx, feePayer) {
|
|
673
|
+
const isFeePayer = feePayer ? change.owner?.toLowerCase() === feePayer : false;
|
|
680
674
|
const isPositive = change.change.ui > 0;
|
|
681
|
-
if (
|
|
675
|
+
if (isFeePayer) {
|
|
682
676
|
return isPositive ? "received" : "sent";
|
|
683
677
|
}
|
|
684
678
|
if (isDexProtocol(tx.protocol)) {
|
|
@@ -692,85 +686,35 @@ var TransferClassifier = class {
|
|
|
692
686
|
name = "transfer";
|
|
693
687
|
priority = 20;
|
|
694
688
|
classify(context) {
|
|
695
|
-
const { legs,
|
|
689
|
+
const { legs, tx } = context;
|
|
696
690
|
const facilitator = tx.accountKeys ? detectFacilitator(tx.accountKeys) : null;
|
|
697
|
-
const
|
|
698
|
-
|
|
699
|
-
let participantPrefix;
|
|
700
|
-
if (walletAddress) {
|
|
701
|
-
participantAddress = walletAddress.toLowerCase();
|
|
702
|
-
participantPrefix = `wallet:${participantAddress}`;
|
|
703
|
-
} else {
|
|
704
|
-
const feeLeg = legs.find(
|
|
705
|
-
(leg) => leg.role === "fee" && leg.accountId.startsWith("external:")
|
|
706
|
-
);
|
|
707
|
-
if (!feeLeg) return null;
|
|
708
|
-
participantAddress = feeLeg.accountId.replace("external:", "").toLowerCase();
|
|
709
|
-
participantPrefix = `external:${participantAddress}`;
|
|
710
|
-
}
|
|
711
|
-
const participantSent = legs.filter(
|
|
712
|
-
(l) => l.accountId.toLowerCase().startsWith(participantPrefix.toLowerCase()) && l.side === "debit" && l.role === "sent"
|
|
691
|
+
const senderLeg = legs.find(
|
|
692
|
+
(l) => l.accountId.startsWith("external:") && l.side === "debit" && l.role === "sent"
|
|
713
693
|
);
|
|
714
|
-
|
|
715
|
-
|
|
694
|
+
if (!senderLeg) return null;
|
|
695
|
+
const sender = senderLeg.accountId.replace("external:", "");
|
|
696
|
+
const receiverLeg = legs.find(
|
|
697
|
+
(l) => l.accountId.startsWith("external:") && l.side === "credit" && l.role === "received" && l.amount.token.mint === senderLeg.amount.token.mint
|
|
716
698
|
);
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
counterparty: {
|
|
735
|
-
type: "unknown",
|
|
736
|
-
address: receiverAddress,
|
|
737
|
-
name: `${receiverAddress.slice(0, 8)}...`
|
|
738
|
-
},
|
|
739
|
-
confidence: isObserverMode ? 0.9 : 0.95,
|
|
740
|
-
isRelevant: true,
|
|
741
|
-
metadata: {
|
|
742
|
-
...isObserverMode && { observer_mode: true, sender: participantAddress },
|
|
743
|
-
...facilitator && { facilitator, payment_type: "facilitated" }
|
|
744
|
-
}
|
|
745
|
-
};
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
for (const received of participantReceived) {
|
|
749
|
-
const matchingSent = otherSent.find(
|
|
750
|
-
(s) => s.amount.token.mint === received.amount.token.mint
|
|
751
|
-
);
|
|
752
|
-
if (matchingSent) {
|
|
753
|
-
const senderAddress = matchingSent.accountId.replace("external:", "");
|
|
754
|
-
return {
|
|
755
|
-
primaryType: "transfer",
|
|
756
|
-
direction: isObserverMode ? "neutral" : "incoming",
|
|
757
|
-
primaryAmount: received.amount,
|
|
758
|
-
secondaryAmount: null,
|
|
759
|
-
counterparty: {
|
|
760
|
-
type: "unknown",
|
|
761
|
-
address: senderAddress,
|
|
762
|
-
name: `${senderAddress.slice(0, 8)}...`
|
|
763
|
-
},
|
|
764
|
-
confidence: isObserverMode ? 0.9 : 0.95,
|
|
765
|
-
isRelevant: true,
|
|
766
|
-
metadata: {
|
|
767
|
-
...isObserverMode && { observer_mode: true, receiver: participantAddress },
|
|
768
|
-
...facilitator && { facilitator, payment_type: "facilitated" }
|
|
769
|
-
}
|
|
770
|
-
};
|
|
699
|
+
if (!receiverLeg) return null;
|
|
700
|
+
const receiver = receiverLeg.accountId.replace("external:", "");
|
|
701
|
+
return {
|
|
702
|
+
primaryType: "transfer",
|
|
703
|
+
primaryAmount: senderLeg.amount,
|
|
704
|
+
secondaryAmount: null,
|
|
705
|
+
sender,
|
|
706
|
+
receiver,
|
|
707
|
+
counterparty: {
|
|
708
|
+
type: "wallet",
|
|
709
|
+
address: receiver,
|
|
710
|
+
name: `${receiver.slice(0, 8)}...`
|
|
711
|
+
},
|
|
712
|
+
confidence: 0.95,
|
|
713
|
+
isRelevant: true,
|
|
714
|
+
metadata: {
|
|
715
|
+
...facilitator && { facilitator, payment_type: "facilitated" }
|
|
771
716
|
}
|
|
772
|
-
}
|
|
773
|
-
return null;
|
|
717
|
+
};
|
|
774
718
|
}
|
|
775
719
|
};
|
|
776
720
|
|
|
@@ -815,9 +759,54 @@ var KNOWN_PROGRAMS = {
|
|
|
815
759
|
[STAKE_PROGRAM_ID]: {
|
|
816
760
|
id: "stake",
|
|
817
761
|
name: "Stake Program"
|
|
762
|
+
},
|
|
763
|
+
[STAKE_POOL_PROGRAM_ID]: {
|
|
764
|
+
id: "stake-pool",
|
|
765
|
+
name: "Stake Pool Program"
|
|
766
|
+
},
|
|
767
|
+
[CANDY_GUARD_PROGRAM_ID]: {
|
|
768
|
+
id: "candy-guard",
|
|
769
|
+
name: "Metaplex Candy Guard Program"
|
|
770
|
+
},
|
|
771
|
+
[CANDY_MACHINE_V3_PROGRAM_ID]: {
|
|
772
|
+
id: "candy-machine-v3",
|
|
773
|
+
name: "Metaplex Candy Machine Core Program"
|
|
774
|
+
},
|
|
775
|
+
[BUBBLEGUM_PROGRAM_ID]: {
|
|
776
|
+
id: "bubblegum",
|
|
777
|
+
name: "Bubblegum Program"
|
|
778
|
+
},
|
|
779
|
+
[MAGIC_EDEN_CANDY_MACHINE_ID]: {
|
|
780
|
+
id: "magic-eden-candy-machine",
|
|
781
|
+
name: "Nft Candy Machine Program (Magic Eden)"
|
|
782
|
+
},
|
|
783
|
+
[WORMHOLE_PROGRAM_ID]: {
|
|
784
|
+
id: "wormhole",
|
|
785
|
+
name: "Wormhole"
|
|
786
|
+
},
|
|
787
|
+
[WORMHOLE_TOKEN_BRIDGE_ID]: {
|
|
788
|
+
id: "wormhole-token-bridge",
|
|
789
|
+
name: "Wormhole Token Bridge"
|
|
790
|
+
},
|
|
791
|
+
[DEGODS_BRIDGE_PROGRAM_ID]: {
|
|
792
|
+
id: "degods-bridge",
|
|
793
|
+
name: "DeGods Bridge"
|
|
794
|
+
},
|
|
795
|
+
[DEBRIDGE_PROGRAM_ID]: {
|
|
796
|
+
id: "debridge",
|
|
797
|
+
name: "deBridge"
|
|
798
|
+
},
|
|
799
|
+
[ALLBRIDGE_PROGRAM_ID]: {
|
|
800
|
+
id: "allbridge",
|
|
801
|
+
name: "Allbridge"
|
|
818
802
|
}
|
|
819
803
|
};
|
|
820
804
|
var PRIORITY_ORDER = [
|
|
805
|
+
"wormhole",
|
|
806
|
+
"wormhole-token-bridge",
|
|
807
|
+
"degods-bridge",
|
|
808
|
+
"debridge",
|
|
809
|
+
"allbridge",
|
|
821
810
|
"jupiter",
|
|
822
811
|
"jupiter-v4",
|
|
823
812
|
"raydium",
|
|
@@ -835,9 +824,33 @@ var DEX_PROTOCOL_IDS2 = /* @__PURE__ */ new Set([
|
|
|
835
824
|
"raydium",
|
|
836
825
|
"orca-whirlpool"
|
|
837
826
|
]);
|
|
827
|
+
var NFT_MINT_PROTOCOL_IDS = /* @__PURE__ */ new Set([
|
|
828
|
+
"metaplex",
|
|
829
|
+
"candy-machine-v3",
|
|
830
|
+
"candy-guard",
|
|
831
|
+
"bubblegum",
|
|
832
|
+
"magic-eden-candy-machine"
|
|
833
|
+
]);
|
|
834
|
+
var STAKE_PROTOCOL_IDS = /* @__PURE__ */ new Set(["stake", "stake-pool"]);
|
|
835
|
+
var BRIDGE_PROTOCOL_IDS = /* @__PURE__ */ new Set([
|
|
836
|
+
"wormhole",
|
|
837
|
+
"wormhole-token-bridge",
|
|
838
|
+
"degods-bridge",
|
|
839
|
+
"debridge",
|
|
840
|
+
"allbridge"
|
|
841
|
+
]);
|
|
838
842
|
function isDexProtocolById(protocolId) {
|
|
839
843
|
return protocolId !== void 0 && DEX_PROTOCOL_IDS2.has(protocolId);
|
|
840
844
|
}
|
|
845
|
+
function isNftMintProtocolById(protocolId) {
|
|
846
|
+
return protocolId !== void 0 && NFT_MINT_PROTOCOL_IDS.has(protocolId);
|
|
847
|
+
}
|
|
848
|
+
function isStakeProtocolById(protocolId) {
|
|
849
|
+
return protocolId !== void 0 && STAKE_PROTOCOL_IDS.has(protocolId);
|
|
850
|
+
}
|
|
851
|
+
function isBridgeProtocolById(protocolId) {
|
|
852
|
+
return protocolId !== void 0 && BRIDGE_PROTOCOL_IDS.has(protocolId);
|
|
853
|
+
}
|
|
841
854
|
function detectProtocol(programIds) {
|
|
842
855
|
const detectedProtocols = [];
|
|
843
856
|
for (const programId of programIds) {
|
|
@@ -862,65 +875,46 @@ var SwapClassifier = class {
|
|
|
862
875
|
name = "swap";
|
|
863
876
|
priority = 80;
|
|
864
877
|
classify(context) {
|
|
865
|
-
const { legs,
|
|
866
|
-
const protocolLegs = legs.filter(
|
|
867
|
-
(leg) => leg.accountId.startsWith("protocol:")
|
|
868
|
-
);
|
|
878
|
+
const { legs, tx } = context;
|
|
869
879
|
const hasDexProtocol = isDexProtocolById(tx.protocol?.id);
|
|
870
|
-
if (
|
|
880
|
+
if (!hasDexProtocol) {
|
|
871
881
|
return null;
|
|
872
882
|
}
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
if (walletAddress) {
|
|
876
|
-
participantPrefix = `wallet:${walletAddress}`;
|
|
877
|
-
} else {
|
|
878
|
-
const feeLeg = legs.find(
|
|
879
|
-
(leg) => leg.role === "fee" && leg.accountId.startsWith("external:")
|
|
880
|
-
);
|
|
881
|
-
if (!feeLeg) return null;
|
|
882
|
-
const feePayerAddress = feeLeg.accountId.replace("external:", "");
|
|
883
|
-
participantPrefix = `external:${feePayerAddress}`;
|
|
884
|
-
}
|
|
885
|
-
const participantDebits = legs.filter(
|
|
886
|
-
(leg) => leg.accountId.startsWith(participantPrefix) && leg.side === "debit"
|
|
887
|
-
);
|
|
888
|
-
const participantCredits = legs.filter(
|
|
889
|
-
(leg) => leg.accountId.startsWith(participantPrefix) && leg.side === "credit"
|
|
883
|
+
const feeLeg = legs.find(
|
|
884
|
+
(leg) => leg.role === "fee" && leg.side === "debit"
|
|
890
885
|
);
|
|
891
|
-
const
|
|
892
|
-
|
|
886
|
+
const initiator = feeLeg?.accountId.replace("external:", "") ?? null;
|
|
887
|
+
const tokensOut = legs.filter(
|
|
888
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "debit" && (leg.role === "sent" || leg.role === "protocol_deposit")
|
|
893
889
|
);
|
|
894
|
-
const tokensIn =
|
|
895
|
-
(leg) => leg.role === "received" || leg.role === "protocol_withdraw"
|
|
890
|
+
const tokensIn = legs.filter(
|
|
891
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "credit" && (leg.role === "received" || leg.role === "protocol_withdraw")
|
|
896
892
|
);
|
|
897
893
|
if (tokensOut.length === 0 || tokensIn.length === 0) {
|
|
898
894
|
return null;
|
|
899
895
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
return {
|
|
905
|
-
primaryType: "swap",
|
|
906
|
-
direction: "neutral",
|
|
907
|
-
primaryAmount: tokenOut.amount,
|
|
908
|
-
secondaryAmount: tokenIn.amount,
|
|
909
|
-
counterparty: null,
|
|
910
|
-
confidence: isObserverMode ? 0.85 : 0.9,
|
|
911
|
-
isRelevant: true,
|
|
912
|
-
metadata: {
|
|
913
|
-
swap_type: "token_to_token",
|
|
914
|
-
from_token: tokenOut.amount.token.symbol,
|
|
915
|
-
to_token: tokenIn.amount.token.symbol,
|
|
916
|
-
from_amount: tokenOut.amount.amountUi,
|
|
917
|
-
to_amount: tokenIn.amount.amountUi,
|
|
918
|
-
...isObserverMode && { observer_mode: true }
|
|
919
|
-
}
|
|
920
|
-
};
|
|
921
|
-
}
|
|
896
|
+
const tokenOut = tokensOut[0];
|
|
897
|
+
const tokenIn = tokensIn[0];
|
|
898
|
+
if (tokenOut.amount.token.symbol === tokenIn.amount.token.symbol) {
|
|
899
|
+
return null;
|
|
922
900
|
}
|
|
923
|
-
return
|
|
901
|
+
return {
|
|
902
|
+
primaryType: "swap",
|
|
903
|
+
primaryAmount: tokenOut.amount,
|
|
904
|
+
secondaryAmount: tokenIn.amount,
|
|
905
|
+
sender: initiator,
|
|
906
|
+
receiver: initiator,
|
|
907
|
+
counterparty: null,
|
|
908
|
+
confidence: 0.9,
|
|
909
|
+
isRelevant: true,
|
|
910
|
+
metadata: {
|
|
911
|
+
swap_type: "token_to_token",
|
|
912
|
+
from_token: tokenOut.amount.token.symbol,
|
|
913
|
+
to_token: tokenIn.amount.token.symbol,
|
|
914
|
+
from_amount: tokenOut.amount.amountUi,
|
|
915
|
+
to_amount: tokenIn.amount.amountUi
|
|
916
|
+
}
|
|
917
|
+
};
|
|
924
918
|
}
|
|
925
919
|
};
|
|
926
920
|
|
|
@@ -929,7 +923,7 @@ var AirdropClassifier = class {
|
|
|
929
923
|
name = "airdrop";
|
|
930
924
|
priority = 70;
|
|
931
925
|
classify(context) {
|
|
932
|
-
const { legs,
|
|
926
|
+
const { legs, tx } = context;
|
|
933
927
|
const facilitator = tx.accountKeys ? detectFacilitator(tx.accountKeys) : null;
|
|
934
928
|
const protocolLegs = legs.filter(
|
|
935
929
|
(leg) => leg.accountId.startsWith("protocol:")
|
|
@@ -937,49 +931,41 @@ var AirdropClassifier = class {
|
|
|
937
931
|
if (protocolLegs.length === 0) {
|
|
938
932
|
return null;
|
|
939
933
|
}
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
const participantCredits = legs.filter(
|
|
943
|
-
(leg) => leg.accountId.startsWith(accountPrefix) && leg.side === "credit"
|
|
944
|
-
);
|
|
945
|
-
const participantDebits = legs.filter(
|
|
946
|
-
(leg) => leg.accountId.startsWith(accountPrefix) && leg.side === "debit"
|
|
947
|
-
);
|
|
948
|
-
const tokenReceived = participantCredits.filter(
|
|
949
|
-
(leg) => leg.role === "received" && leg.amount.token.symbol !== "SOL"
|
|
934
|
+
const tokenReceived = legs.filter(
|
|
935
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "credit" && leg.role === "received" && leg.amount.token.symbol !== "SOL"
|
|
950
936
|
);
|
|
951
937
|
if (tokenReceived.length === 0) {
|
|
952
938
|
return null;
|
|
953
939
|
}
|
|
954
|
-
const tokenSent =
|
|
955
|
-
(leg) => leg.role === "sent" && leg.amount.token.symbol !== "SOL"
|
|
940
|
+
const tokenSent = legs.filter(
|
|
941
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "debit" && leg.role === "sent" && leg.amount.token.symbol !== "SOL"
|
|
956
942
|
);
|
|
957
943
|
if (tokenSent.length > 0) {
|
|
958
944
|
return null;
|
|
959
945
|
}
|
|
960
946
|
const mainToken = tokenReceived[0];
|
|
961
|
-
const
|
|
962
|
-
|
|
947
|
+
const receiver = mainToken.accountId.replace("external:", "");
|
|
948
|
+
const senderLeg = legs.find(
|
|
949
|
+
(leg) => leg.side === "debit" && leg.amount.token.mint === mainToken.amount.token.mint
|
|
963
950
|
);
|
|
964
|
-
const sender =
|
|
965
|
-
const receiverAddress = mainToken.accountId.replace(/^(external:|wallet:)/, "");
|
|
951
|
+
const sender = senderLeg ? senderLeg.accountId.replace(/^(external:|protocol:)/, "") : null;
|
|
966
952
|
return {
|
|
967
953
|
primaryType: "airdrop",
|
|
968
|
-
direction: isObserverMode ? "neutral" : "incoming",
|
|
969
954
|
primaryAmount: mainToken.amount,
|
|
970
955
|
secondaryAmount: null,
|
|
956
|
+
sender,
|
|
957
|
+
receiver,
|
|
971
958
|
counterparty: sender ? {
|
|
972
|
-
type: "
|
|
973
|
-
address: sender
|
|
959
|
+
type: "protocol",
|
|
960
|
+
address: sender
|
|
974
961
|
} : null,
|
|
975
|
-
confidence:
|
|
962
|
+
confidence: 0.85,
|
|
976
963
|
isRelevant: true,
|
|
977
964
|
metadata: {
|
|
978
965
|
airdrop_type: "token",
|
|
979
966
|
token: mainToken.amount.token.symbol,
|
|
980
967
|
amount: mainToken.amount.amountUi,
|
|
981
|
-
...
|
|
982
|
-
...facilitator && { facilitator, payment_type: "facilitated" }
|
|
968
|
+
...facilitator && { facilitator }
|
|
983
969
|
}
|
|
984
970
|
};
|
|
985
971
|
}
|
|
@@ -990,30 +976,34 @@ var FeeOnlyClassifier = class {
|
|
|
990
976
|
name = "fee-only";
|
|
991
977
|
priority = 60;
|
|
992
978
|
classify(context) {
|
|
993
|
-
const { legs
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
const
|
|
998
|
-
if (
|
|
979
|
+
const { legs } = context;
|
|
980
|
+
const externalLegs = legs.filter(
|
|
981
|
+
(leg) => leg.accountId.startsWith("external:")
|
|
982
|
+
);
|
|
983
|
+
const nonFeeLegs = externalLegs.filter((leg) => leg.role !== "fee");
|
|
984
|
+
if (nonFeeLegs.length > 0) {
|
|
999
985
|
return null;
|
|
1000
986
|
}
|
|
1001
987
|
const feeLegs = legs.filter((leg) => leg.role === "fee");
|
|
1002
988
|
if (feeLegs.length === 0) {
|
|
1003
989
|
return null;
|
|
1004
990
|
}
|
|
991
|
+
const feePayerLeg = feeLegs.find(
|
|
992
|
+
(leg) => leg.side === "debit" && leg.amount.token.symbol === "SOL"
|
|
993
|
+
);
|
|
994
|
+
const feePayer = feePayerLeg?.accountId.replace("external:", "") ?? null;
|
|
1005
995
|
const totalFee = feeLegs.find((leg) => leg.amount.token.symbol === "SOL");
|
|
1006
996
|
return {
|
|
1007
997
|
primaryType: "fee_only",
|
|
1008
|
-
direction: "outgoing",
|
|
1009
998
|
primaryAmount: totalFee?.amount ?? null,
|
|
1010
999
|
secondaryAmount: null,
|
|
1000
|
+
sender: feePayer,
|
|
1001
|
+
receiver: null,
|
|
1011
1002
|
counterparty: null,
|
|
1012
|
-
confidence:
|
|
1003
|
+
confidence: 0.95,
|
|
1013
1004
|
isRelevant: false,
|
|
1014
1005
|
metadata: {
|
|
1015
|
-
fee_type: "network"
|
|
1016
|
-
...isObserverMode && { observer_mode: true }
|
|
1006
|
+
fee_type: "network"
|
|
1017
1007
|
}
|
|
1018
1008
|
};
|
|
1019
1009
|
}
|
|
@@ -1024,59 +1014,31 @@ var SolanaPayClassifier = class {
|
|
|
1024
1014
|
name = "solana-pay";
|
|
1025
1015
|
priority = 95;
|
|
1026
1016
|
classify(context) {
|
|
1027
|
-
const { tx,
|
|
1017
|
+
const { tx, legs } = context;
|
|
1028
1018
|
if (!isSolanaPayTransaction(tx.programIds, tx.memo)) {
|
|
1029
1019
|
return null;
|
|
1030
1020
|
}
|
|
1031
1021
|
const memo = parseSolanaPayMemo(tx.memo);
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
const senderLeg = legs.find(
|
|
1035
|
-
(leg) => leg.accountId.startsWith("external:") && leg.side === "debit" && leg.role === "sent"
|
|
1036
|
-
);
|
|
1037
|
-
const receiverLeg = legs.find(
|
|
1038
|
-
(leg) => leg.accountId.startsWith("external:") && leg.side === "credit" && leg.role === "received"
|
|
1039
|
-
);
|
|
1040
|
-
const primaryAmount2 = senderLeg?.amount ?? receiverLeg?.amount ?? null;
|
|
1041
|
-
const senderAddress = senderLeg?.accountId.replace("external:", "");
|
|
1042
|
-
const receiverAddress = receiverLeg?.accountId.replace("external:", "");
|
|
1043
|
-
return {
|
|
1044
|
-
primaryType: "transfer",
|
|
1045
|
-
direction: "neutral",
|
|
1046
|
-
primaryAmount: primaryAmount2,
|
|
1047
|
-
secondaryAmount: null,
|
|
1048
|
-
counterparty: memo.merchant ? { address: receiverAddress ?? "", name: memo.merchant, type: "merchant" } : null,
|
|
1049
|
-
confidence: 0.95,
|
|
1050
|
-
isRelevant: true,
|
|
1051
|
-
metadata: {
|
|
1052
|
-
payment_type: "solana_pay",
|
|
1053
|
-
observer_mode: true,
|
|
1054
|
-
sender: senderAddress,
|
|
1055
|
-
receiver: receiverAddress,
|
|
1056
|
-
memo: memo.raw,
|
|
1057
|
-
merchant: memo.merchant,
|
|
1058
|
-
item: memo.item,
|
|
1059
|
-
reference: memo.reference,
|
|
1060
|
-
label: memo.label,
|
|
1061
|
-
message: memo.message
|
|
1062
|
-
}
|
|
1063
|
-
};
|
|
1064
|
-
}
|
|
1065
|
-
const walletPrefix = `wallet:${walletAddress}`;
|
|
1066
|
-
const userSent = legs.find(
|
|
1067
|
-
(leg) => leg.accountId.includes(walletPrefix) && leg.side === "debit" && leg.role === "sent"
|
|
1022
|
+
const senderLeg = legs.find(
|
|
1023
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "debit" && leg.role === "sent"
|
|
1068
1024
|
);
|
|
1069
|
-
const
|
|
1070
|
-
(leg) => leg.accountId.
|
|
1025
|
+
const receiverLeg = legs.find(
|
|
1026
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "credit" && leg.role === "received"
|
|
1071
1027
|
);
|
|
1072
|
-
const
|
|
1073
|
-
const
|
|
1028
|
+
const sender = senderLeg?.accountId.replace("external:", "") ?? null;
|
|
1029
|
+
const receiver = receiverLeg?.accountId.replace("external:", "") ?? null;
|
|
1030
|
+
const primaryAmount = senderLeg?.amount ?? receiverLeg?.amount ?? null;
|
|
1074
1031
|
return {
|
|
1075
1032
|
primaryType: "transfer",
|
|
1076
|
-
direction,
|
|
1077
1033
|
primaryAmount,
|
|
1078
1034
|
secondaryAmount: null,
|
|
1079
|
-
|
|
1035
|
+
sender,
|
|
1036
|
+
receiver,
|
|
1037
|
+
counterparty: receiver ? {
|
|
1038
|
+
address: receiver,
|
|
1039
|
+
name: memo.merchant ?? void 0,
|
|
1040
|
+
type: memo.merchant ? "merchant" : "wallet"
|
|
1041
|
+
} : null,
|
|
1080
1042
|
confidence: 0.98,
|
|
1081
1043
|
isRelevant: true,
|
|
1082
1044
|
metadata: {
|
|
@@ -1092,11 +1054,188 @@ var SolanaPayClassifier = class {
|
|
|
1092
1054
|
}
|
|
1093
1055
|
};
|
|
1094
1056
|
|
|
1057
|
+
// ../classification/src/classifiers/nft-mint-classifier.ts
|
|
1058
|
+
var NftMintClassifier = class {
|
|
1059
|
+
name = "nft-mint";
|
|
1060
|
+
priority = 85;
|
|
1061
|
+
classify(context) {
|
|
1062
|
+
const { legs, tx } = context;
|
|
1063
|
+
const hasNftMintProtocol = isNftMintProtocolById(tx.protocol?.id);
|
|
1064
|
+
if (!hasNftMintProtocol) {
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
1067
|
+
const nftCredits = legs.filter(
|
|
1068
|
+
(leg) => leg.side === "credit" && leg.amount.token.decimals === 0 && leg.amount.amountUi >= 1 && (leg.role === "received" || leg.role === "protocol_withdraw")
|
|
1069
|
+
);
|
|
1070
|
+
if (nftCredits.length === 0) {
|
|
1071
|
+
return null;
|
|
1072
|
+
}
|
|
1073
|
+
const primaryNft = nftCredits[0];
|
|
1074
|
+
const minter = primaryNft.accountId.replace("external:", "");
|
|
1075
|
+
const paymentLeg = legs.find(
|
|
1076
|
+
(leg) => leg.side === "debit" && leg.role === "sent" && leg.amount.token.symbol === "SOL"
|
|
1077
|
+
);
|
|
1078
|
+
const totalMinted = nftCredits.reduce(
|
|
1079
|
+
(sum, leg) => sum + leg.amount.amountUi,
|
|
1080
|
+
0
|
|
1081
|
+
);
|
|
1082
|
+
return {
|
|
1083
|
+
primaryType: "nft_mint",
|
|
1084
|
+
primaryAmount: primaryNft.amount,
|
|
1085
|
+
secondaryAmount: paymentLeg?.amount ?? null,
|
|
1086
|
+
sender: null,
|
|
1087
|
+
receiver: minter,
|
|
1088
|
+
counterparty: null,
|
|
1089
|
+
confidence: 0.9,
|
|
1090
|
+
isRelevant: true,
|
|
1091
|
+
metadata: {
|
|
1092
|
+
nft_mint: primaryNft.amount.token.mint,
|
|
1093
|
+
nft_name: primaryNft.amount.token.name,
|
|
1094
|
+
quantity: totalMinted,
|
|
1095
|
+
mint_price: paymentLeg?.amount.amountUi,
|
|
1096
|
+
protocol: tx.protocol?.id
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
// ../classification/src/classifiers/stake-deposit-classifier.ts
|
|
1103
|
+
var StakeDepositClassifier = class {
|
|
1104
|
+
name = "stake-deposit";
|
|
1105
|
+
priority = 82;
|
|
1106
|
+
classify(context) {
|
|
1107
|
+
const { legs, tx } = context;
|
|
1108
|
+
const hasStakeProtocol = isStakeProtocolById(tx.protocol?.id);
|
|
1109
|
+
if (!hasStakeProtocol) {
|
|
1110
|
+
return null;
|
|
1111
|
+
}
|
|
1112
|
+
const solDebit = legs.find(
|
|
1113
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "debit" && leg.amount.token.symbol === "SOL" && (leg.role === "sent" || leg.role === "protocol_deposit")
|
|
1114
|
+
);
|
|
1115
|
+
if (!solDebit) {
|
|
1116
|
+
return null;
|
|
1117
|
+
}
|
|
1118
|
+
const staker = solDebit.accountId.replace("external:", "");
|
|
1119
|
+
return {
|
|
1120
|
+
primaryType: "stake_deposit",
|
|
1121
|
+
primaryAmount: solDebit.amount,
|
|
1122
|
+
secondaryAmount: null,
|
|
1123
|
+
sender: staker,
|
|
1124
|
+
receiver: null,
|
|
1125
|
+
counterparty: null,
|
|
1126
|
+
confidence: 0.9,
|
|
1127
|
+
isRelevant: true,
|
|
1128
|
+
metadata: {
|
|
1129
|
+
stake_amount: solDebit.amount.amountUi,
|
|
1130
|
+
protocol: tx.protocol?.id
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
|
|
1136
|
+
// ../classification/src/classifiers/stake-withdraw-classifier.ts
|
|
1137
|
+
var StakeWithdrawClassifier = class {
|
|
1138
|
+
name = "stake-withdraw";
|
|
1139
|
+
priority = 81;
|
|
1140
|
+
classify(context) {
|
|
1141
|
+
const { legs, tx } = context;
|
|
1142
|
+
const hasStakeProtocol = isStakeProtocolById(tx.protocol?.id);
|
|
1143
|
+
if (!hasStakeProtocol) {
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
const solCredit = legs.find(
|
|
1147
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "credit" && leg.amount.token.symbol === "SOL" && (leg.role === "received" || leg.role === "protocol_withdraw")
|
|
1148
|
+
);
|
|
1149
|
+
if (!solCredit) {
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
const solDebit = legs.find(
|
|
1153
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "debit" && leg.amount.token.symbol === "SOL" && (leg.role === "sent" || leg.role === "protocol_deposit")
|
|
1154
|
+
);
|
|
1155
|
+
if (solDebit) {
|
|
1156
|
+
return null;
|
|
1157
|
+
}
|
|
1158
|
+
const withdrawer = solCredit.accountId.replace("external:", "");
|
|
1159
|
+
return {
|
|
1160
|
+
primaryType: "stake_withdraw",
|
|
1161
|
+
primaryAmount: solCredit.amount,
|
|
1162
|
+
secondaryAmount: null,
|
|
1163
|
+
sender: null,
|
|
1164
|
+
receiver: withdrawer,
|
|
1165
|
+
counterparty: null,
|
|
1166
|
+
confidence: 0.9,
|
|
1167
|
+
isRelevant: true,
|
|
1168
|
+
metadata: {
|
|
1169
|
+
withdraw_amount: solCredit.amount.amountUi,
|
|
1170
|
+
protocol: tx.protocol?.id
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
|
|
1176
|
+
// ../classification/src/classifiers/bridge-classifier.ts
|
|
1177
|
+
var BridgeClassifier = class {
|
|
1178
|
+
name = "bridge";
|
|
1179
|
+
priority = 88;
|
|
1180
|
+
classify(context) {
|
|
1181
|
+
const { legs, tx } = context;
|
|
1182
|
+
const hasBridgeProtocol = isBridgeProtocolById(tx.protocol?.id);
|
|
1183
|
+
if (!hasBridgeProtocol) {
|
|
1184
|
+
return null;
|
|
1185
|
+
}
|
|
1186
|
+
const tokensOut = legs.filter(
|
|
1187
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "debit" && leg.role !== "fee" && (leg.role === "sent" || leg.role === "protocol_deposit")
|
|
1188
|
+
);
|
|
1189
|
+
const tokensIn = legs.filter(
|
|
1190
|
+
(leg) => leg.accountId.startsWith("external:") && leg.side === "credit" && (leg.role === "received" || leg.role === "protocol_withdraw")
|
|
1191
|
+
);
|
|
1192
|
+
let primaryType;
|
|
1193
|
+
let primaryAmount = null;
|
|
1194
|
+
let participant = null;
|
|
1195
|
+
if (tokensIn.length > 0 && tokensOut.length === 0) {
|
|
1196
|
+
primaryType = "bridge_in";
|
|
1197
|
+
const creditLeg = tokensIn[0];
|
|
1198
|
+
primaryAmount = creditLeg.amount;
|
|
1199
|
+
participant = creditLeg.accountId.replace("external:", "");
|
|
1200
|
+
} else if (tokensOut.length > 0 && tokensIn.length === 0) {
|
|
1201
|
+
primaryType = "bridge_out";
|
|
1202
|
+
const debitLeg = tokensOut[0];
|
|
1203
|
+
primaryAmount = debitLeg.amount;
|
|
1204
|
+
participant = debitLeg.accountId.replace("external:", "");
|
|
1205
|
+
} else if (tokensIn.length > 0 && tokensOut.length > 0) {
|
|
1206
|
+
primaryType = "bridge_in";
|
|
1207
|
+
const creditLeg = tokensIn[0];
|
|
1208
|
+
primaryAmount = creditLeg.amount;
|
|
1209
|
+
participant = creditLeg.accountId.replace("external:", "");
|
|
1210
|
+
} else {
|
|
1211
|
+
return null;
|
|
1212
|
+
}
|
|
1213
|
+
return {
|
|
1214
|
+
primaryType,
|
|
1215
|
+
primaryAmount,
|
|
1216
|
+
secondaryAmount: null,
|
|
1217
|
+
sender: primaryType === "bridge_out" ? participant : null,
|
|
1218
|
+
receiver: primaryType === "bridge_in" ? participant : null,
|
|
1219
|
+
counterparty: null,
|
|
1220
|
+
confidence: 0.9,
|
|
1221
|
+
isRelevant: true,
|
|
1222
|
+
metadata: {
|
|
1223
|
+
bridge_protocol: tx.protocol?.id,
|
|
1224
|
+
bridge_name: tx.protocol?.name
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
|
|
1095
1230
|
// ../classification/src/engine/classification-service.ts
|
|
1096
1231
|
var ClassificationService = class {
|
|
1097
1232
|
classifiers = [];
|
|
1098
1233
|
constructor() {
|
|
1099
1234
|
this.registerClassifier(new SolanaPayClassifier());
|
|
1235
|
+
this.registerClassifier(new BridgeClassifier());
|
|
1236
|
+
this.registerClassifier(new NftMintClassifier());
|
|
1237
|
+
this.registerClassifier(new StakeDepositClassifier());
|
|
1238
|
+
this.registerClassifier(new StakeWithdrawClassifier());
|
|
1100
1239
|
this.registerClassifier(new SwapClassifier());
|
|
1101
1240
|
this.registerClassifier(new AirdropClassifier());
|
|
1102
1241
|
this.registerClassifier(new TransferClassifier());
|
|
@@ -1106,8 +1245,8 @@ var ClassificationService = class {
|
|
|
1106
1245
|
this.classifiers.push(classifier);
|
|
1107
1246
|
this.classifiers.sort((a, b) => b.priority - a.priority);
|
|
1108
1247
|
}
|
|
1109
|
-
classify(legs,
|
|
1110
|
-
const context = { legs,
|
|
1248
|
+
classify(legs, tx) {
|
|
1249
|
+
const context = { legs, tx };
|
|
1111
1250
|
for (const classifier of this.classifiers) {
|
|
1112
1251
|
const result = classifier.classify(context);
|
|
1113
1252
|
if (result && result.isRelevant) {
|
|
@@ -1116,9 +1255,10 @@ var ClassificationService = class {
|
|
|
1116
1255
|
}
|
|
1117
1256
|
return {
|
|
1118
1257
|
primaryType: "other",
|
|
1119
|
-
direction: "neutral",
|
|
1120
1258
|
primaryAmount: null,
|
|
1121
1259
|
secondaryAmount: null,
|
|
1260
|
+
sender: null,
|
|
1261
|
+
receiver: null,
|
|
1122
1262
|
counterparty: null,
|
|
1123
1263
|
confidence: 0,
|
|
1124
1264
|
isRelevant: false,
|
|
@@ -1127,8 +1267,8 @@ var ClassificationService = class {
|
|
|
1127
1267
|
}
|
|
1128
1268
|
};
|
|
1129
1269
|
var classificationService = new ClassificationService();
|
|
1130
|
-
function classifyTransaction(legs,
|
|
1131
|
-
return classificationService.classify(legs,
|
|
1270
|
+
function classifyTransaction(legs, tx) {
|
|
1271
|
+
return classificationService.classify(legs, tx);
|
|
1132
1272
|
}
|
|
1133
1273
|
|
|
1134
1274
|
// ../domain/src/tx/spam-filter.ts
|
|
@@ -1202,8 +1342,8 @@ function createIndexer(options) {
|
|
|
1202
1342
|
);
|
|
1203
1343
|
const classified = transactions.map((tx) => {
|
|
1204
1344
|
tx.protocol = detectProtocol(tx.programIds);
|
|
1205
|
-
const legs = transactionToLegs(tx
|
|
1206
|
-
const classification = classifyTransaction(legs,
|
|
1345
|
+
const legs = transactionToLegs(tx);
|
|
1346
|
+
const classification = classifyTransaction(legs, tx);
|
|
1207
1347
|
return { tx, classification, legs };
|
|
1208
1348
|
});
|
|
1209
1349
|
return classified;
|
|
@@ -1232,8 +1372,8 @@ function createIndexer(options) {
|
|
|
1232
1372
|
);
|
|
1233
1373
|
const classified = transactions.map((tx) => {
|
|
1234
1374
|
tx.protocol = detectProtocol(tx.programIds);
|
|
1235
|
-
const legs = transactionToLegs(tx
|
|
1236
|
-
const classification = classifyTransaction(legs,
|
|
1375
|
+
const legs = transactionToLegs(tx);
|
|
1376
|
+
const classification = classifyTransaction(legs, tx);
|
|
1237
1377
|
return { tx, classification, legs };
|
|
1238
1378
|
});
|
|
1239
1379
|
const nonSpam = filterSpamTransactions(classified, spamConfig);
|
|
@@ -1247,14 +1387,14 @@ function createIndexer(options) {
|
|
|
1247
1387
|
}
|
|
1248
1388
|
return accumulated.slice(0, limit);
|
|
1249
1389
|
},
|
|
1250
|
-
async getTransaction(signature2
|
|
1390
|
+
async getTransaction(signature2) {
|
|
1251
1391
|
const tx = await fetchTransaction(client.rpc, signature2);
|
|
1252
1392
|
if (!tx) {
|
|
1253
1393
|
return null;
|
|
1254
1394
|
}
|
|
1255
1395
|
tx.protocol = detectProtocol(tx.programIds);
|
|
1256
|
-
const legs = transactionToLegs(tx
|
|
1257
|
-
const classification = classifyTransaction(legs,
|
|
1396
|
+
const legs = transactionToLegs(tx);
|
|
1397
|
+
const classification = classifyTransaction(legs, tx);
|
|
1258
1398
|
return { tx, classification, legs };
|
|
1259
1399
|
},
|
|
1260
1400
|
async getRawTransaction(signature2) {
|