chain-insights 0.66.1 → 0.67.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/mcp-proxy.cjs +4 -4
- package/dist/mcp-proxy.mjs +4 -4
- package/dist/mcp-proxy.mjs.map +1 -1
- package/docs/graph-query-compatibility.md +5 -1
- package/docs/graph-tools.md +8 -3
- package/package.json +4 -1
- package/skills/chain-insights-cypher/SKILL.md +6 -2
- package/skills/chain-insights-dex/SKILL.md +178 -0
- package/skills/chain-insights-dex/agents/openai.yaml +4 -0
- package/skills/chain-insights-dex/reference.md +85 -0
- package/skills/chain-insights-dex-gauge/SKILL.md +136 -0
- package/skills/chain-insights-dex-gauge/agents/openai.yaml +4 -0
- package/skills/chain-insights-dex-launchpad/SKILL.md +94 -0
- package/skills/chain-insights-dex-launchpad/agents/openai.yaml +4 -0
- package/skills/chain-insights-dex-vault/SKILL.md +104 -0
- package/skills/chain-insights-dex-vault/agents/openai.yaml +4 -0
- package/skills/chain-insights-virtuals/SKILL.md +14 -2
- package/skills/chain-insights-virtuals/reference.md +4 -4
package/dist/mcp-proxy.cjs
CHANGED
|
@@ -777,12 +777,12 @@ const GRAPH_SCHEMA_HINTS = [
|
|
|
777
777
|
"- Facts graph labels include Address; the TRANSFER, SWAP, LIQUIDITY_ADD, LIQUIDITY_REMOVE and BRIDGE_CROSSING relationships each connect two Address nodes. Facts address keys match topology address values exactly.",
|
|
778
778
|
"- Topology relationships include FLOWS_TO, SWAPPED, OPERATED_BY, LINKED, and RISK_PROXIMITY between Address nodes, ADDED_LIQUIDITY and REMOVED_LIQUIDITY to and from Pool nodes, and BRIDGED to and from Chain nodes.",
|
|
779
779
|
"- (:Address)-[:OPERATED_BY]->(:Address) is the directed owner-to-operator edge: the transaction sender that moved the owner's tokens (ERC-20/721), or the event operator (ERC-1155); not the approved spender. Aggregate properties: tx_count, amount_usd_sum, first_seen_timestamp, last_seen_timestamp, and optional token_standard (ERC20/ERC721/ERC1155; absent when the pair is mixed-standard). Valuation fields: valuation_tracked_count, valued_count and the reason counters missing_valuation_price_count, unknown_quantity_count, unrepresentable_quantity_count and usd_range_count. valuation_complete is true when valued_count equals valuation_tracked_count, valuation_coverage_ratio is valued_count divided by valuation_tracked_count, and amount_usd_sum counts a transfer with no USD value as 0, so it is a floor unless valuation_complete is true. One edge per owner/operator pair; direct transfers with no operator create none; an owner never operates for itself. Topology-only, and a topology fact — not a risk label. Probe: MATCH (owner:Address)-[operation:OPERATED_BY]->(operator:Address {address: $addr}) RETURN owner.address AS owner, operation.tx_count AS tx_count ORDER BY operation.tx_count DESC LIMIT 10.",
|
|
780
|
-
"- FLOWS_TO properties are tx_count, amount_usd_sum, first_seen_timestamp, last_seen_timestamp. pair_key and synced_through_height are internal sync bookkeeping, not to be queried. synced_through_height is also on the other summed links (SWAPPED, OPERATED_BY, ADDED_LIQUIDITY, REMOVED_LIQUIDITY, BRIDGED, APPROVED, SPONSORED, BUNDLED, SIGNED_FOR) and pair_key on SWAPPED: bookkeeping there too. Tx ids of every transfer, internal ones included, come from USE facts TRANSFER. Averages come from inline arithmetic. FLOWS_TO into and out of pools is kept; the pool trace rule below governs a trace that reaches one.",
|
|
780
|
+
"- FLOWS_TO properties are tx_count, amount_usd_sum, first_seen_timestamp, last_seen_timestamp. pair_key and synced_through_height are internal sync bookkeeping, not to be queried. synced_through_height is also on the other summed links (SWAPPED, OPERATED_BY, ADDED_LIQUIDITY, REMOVED_LIQUIDITY, BRIDGED, APPROVED, SPONSORED, BUNDLED, SIGNED_FOR) and pair_key on SWAPPED, ADDED_LIQUIDITY, REMOVED_LIQUIDITY and BRIDGED: bookkeeping there too. Tx ids of every transfer, internal ones included, come from USE facts TRANSFER. Averages come from inline arithmetic. FLOWS_TO into and out of pools is kept; the pool trace rule below governs a trace that reaches one.",
|
|
781
781
|
"- Swaps, liquidity and bridges on USE topology are lifetime totals per pair; single events are USE facts rows. (:Address)-[:SWAPPED]->(:Address) joins a swap payer to a different recipient, one edge per payer, recipient, sold_asset and bought_asset, with swap_count, sold_amount_raw, bought_amount_raw, sold_usd, bought_usd, pools, families, strength, first_seen_height and last_seen_height. sold_usd and bought_usd sum the routes on the edge at the day price: a route side with no price adds 0, so 0 can mean no price. Do not read 0 as worth nothing. The USE facts SWAP row says which side had no price (sold_price_missing, bought_price_missing). strength is swap (the whole route is proven: payer, recipient, assets, exact raw amounts and conservation) or swap_like (the shape is a swap but the pool code is not proven). Today no route is swap: the swap reader reads transaction receipts only, with no execution trace, so every served route is swap_like, with reason unknown_pool_code and families unknown. A Uniswap V2 or V3 swap reads this way, and unknown does not mean the protocol is unsupported. A filter on strength = \"swap\" or on a known family matches nothing. A route that could not be paired (swap_unsplit) is never served: it has no payer, recipient or pool, makes no SWAPPED edge and no SWAP row, and exists in the warehouse only. Every Uniswap v4 swap is swap_unsplit today, by design, so v4 swaps are hidden. A self swap makes no edge, and a missing SWAPPED edge is not proof that no swap happened. Swap attribution is read from SWAPPED, the aggregate (strength, pools, families), or from the USE facts SWAP row, one route. FLOWS_TO carries value only.",
|
|
782
|
-
"- Pool is a second label on an Address: a pool contract the DEX indexer knows, traded or not (a bonding curve or an empty pair is a Pool too; a singleton pool manager never is). Once there is liquidity, it also carries liquidity_added_usd, liquidity_removed_usd, liquidity_net_usd, provider_count and receiver_count; a pool known only to the DEX indexer has none of them. (:Address)-[:ADDED_LIQUIDITY]->(:Pool) and (:Pool)-[:REMOVED_LIQUIDITY]->(:Address) join named providers and receivers to the pool, with event_count,
|
|
782
|
+
"- Pool is a second label on an Address: a pool contract the DEX indexer knows, traded or not (a bonding curve or an empty pair is a Pool too; a singleton pool manager never is). Once there is liquidity, it also carries liquidity_added_usd, liquidity_removed_usd, liquidity_net_usd, provider_count and receiver_count; a pool known only to the DEX indexer has none of them. (:Address)-[:ADDED_LIQUIDITY]->(:Pool) and (:Pool)-[:REMOVED_LIQUIDITY]->(:Address) join named providers and receivers to the pool, one link per party, pool and asset, with asset (the token contract in full, or NATIVE for the coin), event_count, amount_raw_sum (the exact total of that asset in base units, as text), usd, unpriced_count, first_seen_height and last_seen_height; REMOVED_LIQUIDITY adds fees_raw_sum (exact, that asset only), receiver_added_usd (USD the receiver itself added to the same pool, over every asset) and receiver_provided. asset_key is bookkeeping, never named in a query. A party with two assets in one pool has two links: sum usd over them for the pool total, and take receiver_added_usd once, as max(). A receiver's profit from a pool is that sum minus receiver_added_usd: receiver_provided false is a drain by a stranger, true with a large profit is the creator's rug pull.",
|
|
783
783
|
"- Token and NFT are second labels on an Address that mark a token contract: Token for every ERC20, ERC721, ERC1155 and ERC6909 contract the asset scan knows, NFT for the ERC721 and ERC1155 ones, and token_standard on the node says which. A token name from an explorer gives Token, not Protocol. They are marks, not stops: the pool trace rule and the guards below do not change.",
|
|
784
|
-
"- (:Address)-[:BRIDGED]->(:Chain) is outbound bridge use and (:Chain)-[:BRIDGED]->(:Address) inbound, with
|
|
785
|
-
"- Pool trace rule, for every trace: 1. Enter a `:Pool` on any edge. 2. Leave a `:Pool` only on `REMOVED_LIQUIDITY`, to the address the liquidity was paid to. 3. Never leave a `:Pool` on `FLOWS_TO`. 4. Across a swap, follow `SWAPPED` from payer to recipient, between two different addresses. Do not walk through the pool. Rug-pull probe: MATCH (victim:Address {address: $addr})-[paid:FLOWS_TO]->(pool:Pool)-[removal:REMOVED_LIQUIDITY]->(receiver:Address) WHERE NOT victim:Pool AND NOT victim:Protocol AND NOT victim:System AND NOT victim.address IN [\"0x0000000000000000000000000000000000000000\", \"0x000000000000000000000000000000000000dead\"] AND receiver.address <> victim.address RETURN pool.address AS pool_address, receiver.address AS receiver_address, removal.usd AS removed_usd, removal.receiver_added_usd AS receiver_added_usd, removal.receiver_provided AS receiver_provided LIMIT 25.",
|
|
784
|
+
"- (:Address)-[:BRIDGED]->(:Chain) is outbound bridge use and (:Chain)-[:BRIDGED]->(:Address) inbound, one link per address, Chain node, direction, event kind and asset, with kind, asset (the token contract in full, NATIVE for the coin, or UNKNOWN when the bridge named no local contract), events, amount_raw_sum (the exact total of that kind and asset in base units, as text), first_height, last_height and last_bridge_event_id. asset_key is bookkeeping, never named in a query. There is no kinds list and no totals_raw map: an address that used two kinds or two assets has one link for each. A Chain node (network, address) is the remote bridge endpoint, never an Address, so no FLOWS_TO walk passes through it.",
|
|
785
|
+
"- Pool trace rule, for every trace: 1. Enter a `:Pool` on any edge. 2. Leave a `:Pool` only on `REMOVED_LIQUIDITY`, to the address the liquidity was paid to. 3. Never leave a `:Pool` on `FLOWS_TO`. 4. Across a swap, follow `SWAPPED` from payer to recipient, between two different addresses. Do not walk through the pool. Rug-pull probe: MATCH (victim:Address {address: $addr})-[paid:FLOWS_TO]->(pool:Pool)-[removal:REMOVED_LIQUIDITY]->(receiver:Address) WHERE NOT victim:Pool AND NOT victim:Protocol AND NOT victim:System AND NOT victim.address IN [\"0x0000000000000000000000000000000000000000\", \"0x000000000000000000000000000000000000dead\"] AND receiver.address <> victim.address RETURN pool.address AS pool_address, receiver.address AS receiver_address, sum(removal.usd) AS removed_usd, max(removal.receiver_added_usd) AS receiver_added_usd, max(removal.receiver_provided) AS receiver_provided LIMIT 25.",
|
|
786
786
|
"- USE facts serves the single events. (payer:Address)-[s:SWAP]->(recipient:Address) is one row per swap route, self swaps included, with strength, reason, route_id and the sold_ and bought_ asset, amount and usd columns. (provider:Address)-[:LIQUIDITY_ADD]->(pool:Address) and (pool:Address)-[:LIQUIDITY_REMOVE]->(receiver:Address) are one row per liquidity event, with party_state and evidence_state. (sender:Address)-[c:BRIDGE_CROSSING]->(recipient:Address) is one row per bridge event. SWAP, LIQUIDITY_* and BRIDGE_CROSSING take the same rule as TRANSFER: an address pair with one day. USD comes from the daily price services, never from a swap: with no price, USD is empty and the matching price_missing column is true (price_missing on TRANSFER, sold_price_missing and bought_price_missing on SWAP, amount0_price_missing and amount1_price_missing on LIQUIDITY_*). block_timestamp on TRANSFER, SWAP and LIQUIDITY_* rows is epoch milliseconds, in filters and in results; BRIDGE_CROSSING has none.",
|
|
787
787
|
"- A USE facts SWAP row carries no route: it has no pools and no families column. A read that names one of them, to return it, to filter on it or to order by it, is refused. The route of a swap stays a topology question. For the pools of the swaps of an address, read SWAPPED.pools and SWAPPED.families on USE topology, anchored on the payer or the recipient. SWAPPED has one link per payer, recipient, sold asset and bought asset, so its pools cover every route on the link, not one route.",
|
|
788
788
|
"- Traversal rule: for BFS, fixed-hop fallback, shortest-path, or manual FLOWS_TO traversal, exchange hot wallets are terminal endpoints only. Do not expand from, through, or classify exchange nodes as deposit, suspect, or intermediate candidates; filter every non-terminal node with is_exchange IS NULL. is_exchange is absent unless true, so a labelled node with no is_exchange is walked through, and is_scam, is_victim and is_sanctioned do not end a walk. At a Pool, follow the pool trace rule above.",
|
package/dist/mcp-proxy.mjs
CHANGED
|
@@ -773,12 +773,12 @@ const GRAPH_SCHEMA_HINTS = [
|
|
|
773
773
|
"- Facts graph labels include Address; the TRANSFER, SWAP, LIQUIDITY_ADD, LIQUIDITY_REMOVE and BRIDGE_CROSSING relationships each connect two Address nodes. Facts address keys match topology address values exactly.",
|
|
774
774
|
"- Topology relationships include FLOWS_TO, SWAPPED, OPERATED_BY, LINKED, and RISK_PROXIMITY between Address nodes, ADDED_LIQUIDITY and REMOVED_LIQUIDITY to and from Pool nodes, and BRIDGED to and from Chain nodes.",
|
|
775
775
|
"- (:Address)-[:OPERATED_BY]->(:Address) is the directed owner-to-operator edge: the transaction sender that moved the owner's tokens (ERC-20/721), or the event operator (ERC-1155); not the approved spender. Aggregate properties: tx_count, amount_usd_sum, first_seen_timestamp, last_seen_timestamp, and optional token_standard (ERC20/ERC721/ERC1155; absent when the pair is mixed-standard). Valuation fields: valuation_tracked_count, valued_count and the reason counters missing_valuation_price_count, unknown_quantity_count, unrepresentable_quantity_count and usd_range_count. valuation_complete is true when valued_count equals valuation_tracked_count, valuation_coverage_ratio is valued_count divided by valuation_tracked_count, and amount_usd_sum counts a transfer with no USD value as 0, so it is a floor unless valuation_complete is true. One edge per owner/operator pair; direct transfers with no operator create none; an owner never operates for itself. Topology-only, and a topology fact — not a risk label. Probe: MATCH (owner:Address)-[operation:OPERATED_BY]->(operator:Address {address: $addr}) RETURN owner.address AS owner, operation.tx_count AS tx_count ORDER BY operation.tx_count DESC LIMIT 10.",
|
|
776
|
-
"- FLOWS_TO properties are tx_count, amount_usd_sum, first_seen_timestamp, last_seen_timestamp. pair_key and synced_through_height are internal sync bookkeeping, not to be queried. synced_through_height is also on the other summed links (SWAPPED, OPERATED_BY, ADDED_LIQUIDITY, REMOVED_LIQUIDITY, BRIDGED, APPROVED, SPONSORED, BUNDLED, SIGNED_FOR) and pair_key on SWAPPED: bookkeeping there too. Tx ids of every transfer, internal ones included, come from USE facts TRANSFER. Averages come from inline arithmetic. FLOWS_TO into and out of pools is kept; the pool trace rule below governs a trace that reaches one.",
|
|
776
|
+
"- FLOWS_TO properties are tx_count, amount_usd_sum, first_seen_timestamp, last_seen_timestamp. pair_key and synced_through_height are internal sync bookkeeping, not to be queried. synced_through_height is also on the other summed links (SWAPPED, OPERATED_BY, ADDED_LIQUIDITY, REMOVED_LIQUIDITY, BRIDGED, APPROVED, SPONSORED, BUNDLED, SIGNED_FOR) and pair_key on SWAPPED, ADDED_LIQUIDITY, REMOVED_LIQUIDITY and BRIDGED: bookkeeping there too. Tx ids of every transfer, internal ones included, come from USE facts TRANSFER. Averages come from inline arithmetic. FLOWS_TO into and out of pools is kept; the pool trace rule below governs a trace that reaches one.",
|
|
777
777
|
"- Swaps, liquidity and bridges on USE topology are lifetime totals per pair; single events are USE facts rows. (:Address)-[:SWAPPED]->(:Address) joins a swap payer to a different recipient, one edge per payer, recipient, sold_asset and bought_asset, with swap_count, sold_amount_raw, bought_amount_raw, sold_usd, bought_usd, pools, families, strength, first_seen_height and last_seen_height. sold_usd and bought_usd sum the routes on the edge at the day price: a route side with no price adds 0, so 0 can mean no price. Do not read 0 as worth nothing. The USE facts SWAP row says which side had no price (sold_price_missing, bought_price_missing). strength is swap (the whole route is proven: payer, recipient, assets, exact raw amounts and conservation) or swap_like (the shape is a swap but the pool code is not proven). Today no route is swap: the swap reader reads transaction receipts only, with no execution trace, so every served route is swap_like, with reason unknown_pool_code and families unknown. A Uniswap V2 or V3 swap reads this way, and unknown does not mean the protocol is unsupported. A filter on strength = \"swap\" or on a known family matches nothing. A route that could not be paired (swap_unsplit) is never served: it has no payer, recipient or pool, makes no SWAPPED edge and no SWAP row, and exists in the warehouse only. Every Uniswap v4 swap is swap_unsplit today, by design, so v4 swaps are hidden. A self swap makes no edge, and a missing SWAPPED edge is not proof that no swap happened. Swap attribution is read from SWAPPED, the aggregate (strength, pools, families), or from the USE facts SWAP row, one route. FLOWS_TO carries value only.",
|
|
778
|
-
"- Pool is a second label on an Address: a pool contract the DEX indexer knows, traded or not (a bonding curve or an empty pair is a Pool too; a singleton pool manager never is). Once there is liquidity, it also carries liquidity_added_usd, liquidity_removed_usd, liquidity_net_usd, provider_count and receiver_count; a pool known only to the DEX indexer has none of them. (:Address)-[:ADDED_LIQUIDITY]->(:Pool) and (:Pool)-[:REMOVED_LIQUIDITY]->(:Address) join named providers and receivers to the pool, with event_count,
|
|
778
|
+
"- Pool is a second label on an Address: a pool contract the DEX indexer knows, traded or not (a bonding curve or an empty pair is a Pool too; a singleton pool manager never is). Once there is liquidity, it also carries liquidity_added_usd, liquidity_removed_usd, liquidity_net_usd, provider_count and receiver_count; a pool known only to the DEX indexer has none of them. (:Address)-[:ADDED_LIQUIDITY]->(:Pool) and (:Pool)-[:REMOVED_LIQUIDITY]->(:Address) join named providers and receivers to the pool, one link per party, pool and asset, with asset (the token contract in full, or NATIVE for the coin), event_count, amount_raw_sum (the exact total of that asset in base units, as text), usd, unpriced_count, first_seen_height and last_seen_height; REMOVED_LIQUIDITY adds fees_raw_sum (exact, that asset only), receiver_added_usd (USD the receiver itself added to the same pool, over every asset) and receiver_provided. asset_key is bookkeeping, never named in a query. A party with two assets in one pool has two links: sum usd over them for the pool total, and take receiver_added_usd once, as max(). A receiver's profit from a pool is that sum minus receiver_added_usd: receiver_provided false is a drain by a stranger, true with a large profit is the creator's rug pull.",
|
|
779
779
|
"- Token and NFT are second labels on an Address that mark a token contract: Token for every ERC20, ERC721, ERC1155 and ERC6909 contract the asset scan knows, NFT for the ERC721 and ERC1155 ones, and token_standard on the node says which. A token name from an explorer gives Token, not Protocol. They are marks, not stops: the pool trace rule and the guards below do not change.",
|
|
780
|
-
"- (:Address)-[:BRIDGED]->(:Chain) is outbound bridge use and (:Chain)-[:BRIDGED]->(:Address) inbound, with
|
|
781
|
-
"- Pool trace rule, for every trace: 1. Enter a `:Pool` on any edge. 2. Leave a `:Pool` only on `REMOVED_LIQUIDITY`, to the address the liquidity was paid to. 3. Never leave a `:Pool` on `FLOWS_TO`. 4. Across a swap, follow `SWAPPED` from payer to recipient, between two different addresses. Do not walk through the pool. Rug-pull probe: MATCH (victim:Address {address: $addr})-[paid:FLOWS_TO]->(pool:Pool)-[removal:REMOVED_LIQUIDITY]->(receiver:Address) WHERE NOT victim:Pool AND NOT victim:Protocol AND NOT victim:System AND NOT victim.address IN [\"0x0000000000000000000000000000000000000000\", \"0x000000000000000000000000000000000000dead\"] AND receiver.address <> victim.address RETURN pool.address AS pool_address, receiver.address AS receiver_address, removal.usd AS removed_usd, removal.receiver_added_usd AS receiver_added_usd, removal.receiver_provided AS receiver_provided LIMIT 25.",
|
|
780
|
+
"- (:Address)-[:BRIDGED]->(:Chain) is outbound bridge use and (:Chain)-[:BRIDGED]->(:Address) inbound, one link per address, Chain node, direction, event kind and asset, with kind, asset (the token contract in full, NATIVE for the coin, or UNKNOWN when the bridge named no local contract), events, amount_raw_sum (the exact total of that kind and asset in base units, as text), first_height, last_height and last_bridge_event_id. asset_key is bookkeeping, never named in a query. There is no kinds list and no totals_raw map: an address that used two kinds or two assets has one link for each. A Chain node (network, address) is the remote bridge endpoint, never an Address, so no FLOWS_TO walk passes through it.",
|
|
781
|
+
"- Pool trace rule, for every trace: 1. Enter a `:Pool` on any edge. 2. Leave a `:Pool` only on `REMOVED_LIQUIDITY`, to the address the liquidity was paid to. 3. Never leave a `:Pool` on `FLOWS_TO`. 4. Across a swap, follow `SWAPPED` from payer to recipient, between two different addresses. Do not walk through the pool. Rug-pull probe: MATCH (victim:Address {address: $addr})-[paid:FLOWS_TO]->(pool:Pool)-[removal:REMOVED_LIQUIDITY]->(receiver:Address) WHERE NOT victim:Pool AND NOT victim:Protocol AND NOT victim:System AND NOT victim.address IN [\"0x0000000000000000000000000000000000000000\", \"0x000000000000000000000000000000000000dead\"] AND receiver.address <> victim.address RETURN pool.address AS pool_address, receiver.address AS receiver_address, sum(removal.usd) AS removed_usd, max(removal.receiver_added_usd) AS receiver_added_usd, max(removal.receiver_provided) AS receiver_provided LIMIT 25.",
|
|
782
782
|
"- USE facts serves the single events. (payer:Address)-[s:SWAP]->(recipient:Address) is one row per swap route, self swaps included, with strength, reason, route_id and the sold_ and bought_ asset, amount and usd columns. (provider:Address)-[:LIQUIDITY_ADD]->(pool:Address) and (pool:Address)-[:LIQUIDITY_REMOVE]->(receiver:Address) are one row per liquidity event, with party_state and evidence_state. (sender:Address)-[c:BRIDGE_CROSSING]->(recipient:Address) is one row per bridge event. SWAP, LIQUIDITY_* and BRIDGE_CROSSING take the same rule as TRANSFER: an address pair with one day. USD comes from the daily price services, never from a swap: with no price, USD is empty and the matching price_missing column is true (price_missing on TRANSFER, sold_price_missing and bought_price_missing on SWAP, amount0_price_missing and amount1_price_missing on LIQUIDITY_*). block_timestamp on TRANSFER, SWAP and LIQUIDITY_* rows is epoch milliseconds, in filters and in results; BRIDGE_CROSSING has none.",
|
|
783
783
|
"- A USE facts SWAP row carries no route: it has no pools and no families column. A read that names one of them, to return it, to filter on it or to order by it, is refused. The route of a swap stays a topology question. For the pools of the swaps of an address, read SWAPPED.pools and SWAPPED.families on USE topology, anchored on the payer or the recipient. SWAPPED has one link per payer, recipient, sold asset and bought asset, so its pools cover every route on the link, not one route.",
|
|
784
784
|
"- Traversal rule: for BFS, fixed-hop fallback, shortest-path, or manual FLOWS_TO traversal, exchange hot wallets are terminal endpoints only. Do not expand from, through, or classify exchange nodes as deposit, suspect, or intermediate candidates; filter every non-terminal node with is_exchange IS NULL. is_exchange is absent unless true, so a labelled node with no is_exchange is walked through, and is_scam, is_victim and is_sanctioned do not end a walk. At a Pool, follow the pool trace rule above.",
|