1+ import { getLogs } from "@defillama/sdk/build/util" ;
2+ import { ethers } from "ethers" ;
3+ import BigNumber from "bignumber.js" ;
4+ import { getLlamaPrices } from "../../../utils/prices" ;
5+
6+ const FXRP = "0xAd552A648C74D49E10027AB8a618A3ad4901c5bE" ;
7+ const ZERO = "0x0000000000000000000000000000000000000000" ;
8+ const TRANSFER_TOPIC = ethers . utils . id ( "Transfer(address,address,uint256)" ) ;
9+
10+ async function main ( ) {
11+ // pick a recent range; widen if needed
12+ const fromBlock = 48104361 ;
13+ const toBlock = 48185336 ;
14+
15+ const logs = ( await getLogs ( {
16+ target : FXRP ,
17+ topic : "Transfer(address,address,uint256)" ,
18+ keys : [ ] ,
19+ fromBlock,
20+ toBlock,
21+ topics : [ TRANSFER_TOPIC ] ,
22+ chain : "flare" ,
23+ } ) ) . output ;
24+
25+ // Fetch price/decimals once for FXRP at a representative timestamp (end of window)
26+ const tokenKey = `flare:${ FXRP . toLowerCase ( ) } ` ;
27+ const approxTs = Math . floor ( Date . now ( ) / 1000 ) ; // Optionally replace with block->ts lookup for higher accuracy
28+ const prices = await getLlamaPrices ( [ tokenKey ] , approxTs ) ;
29+ const priceData = prices [ tokenKey ] ;
30+ if ( ! priceData ) {
31+ console . warn ( `No price data for ${ tokenKey } . USD values will be omitted.` ) ;
32+ }
33+ const tokenDecimals = priceData ?. decimals ?? 18 ; // fallback to 18 if missing
34+ const tokenPrice = priceData ?. price ?? 0 ;
35+
36+ const iface = new ethers . utils . Interface ( [
37+ "event Transfer(address indexed from, address indexed to, uint256 value)" ,
38+ ] ) ;
39+
40+ const specialHits : any [ ] = [ ] ;
41+ let mintCount = 0 , burnCount = 0 , xferCount = 0 ;
42+ let mintUsd = 0 , burnUsd = 0 , xferUsd = 0 ;
43+ for ( const log of logs ) {
44+ const parsed = iface . parseLog ( { topics : [ ...log . topics ] , data : log . data } ) ;
45+ const from = parsed . args . from . toLowerCase ( ) ;
46+ const to = parsed . args . to . toLowerCase ( ) ;
47+ const rawAmount = new BigNumber ( parsed . args . value . toString ( ) ) ;
48+ const amount = rawAmount . dividedBy ( new BigNumber ( 10 ) . pow ( tokenDecimals ) ) ;
49+ const usd = amount . multipliedBy ( tokenPrice ) . toNumber ( ) ;
50+ if ( from === ZERO || to === ZERO ) {
51+ specialHits . push ( {
52+ blockNumber : log . blockNumber ,
53+ txHash : log . transactionHash ,
54+ from,
55+ to,
56+ amount : amount . toString ( 10 ) ,
57+ usd,
58+ } ) ;
59+ }
60+
61+ if ( from === ZERO ) {
62+ mintCount += 1 ;
63+ mintUsd += usd || 0 ;
64+ } else if ( to === ZERO ) {
65+ burnCount += 1 ;
66+ burnUsd += usd || 0 ;
67+ } else {
68+ xferCount += 1 ;
69+ xferUsd += usd || 0 ;
70+ }
71+ }
72+
73+ console . log ( "Special mint/burn-like hits:" ) ;
74+ console . table ( specialHits ) ;
75+
76+ // USD summary
77+ const fmt = new Intl . NumberFormat ( "en-US" , { style : "currency" , currency : "USD" , maximumFractionDigits : 2 } ) ;
78+ const netMinted = mintUsd - burnUsd ;
79+ console . log ( `[flare | FXRP] Summary for blocks ${ fromBlock } -${ toBlock } ` ) ;
80+ console . log ( `Mints (from ZERO): ${ mintCount } , USD: ${ fmt . format ( mintUsd ) } ` ) ;
81+ console . log ( `Burns (to ZERO): ${ burnCount } , USD: ${ fmt . format ( burnUsd ) } ` ) ;
82+ console . log ( `Regular transfers: ${ xferCount } , USD: ${ fmt . format ( xferUsd ) } ` ) ;
83+ console . log ( `Net minted USD (Mints - Burns): ${ fmt . format ( netMinted ) } ` ) ;
84+
85+ // optional: surface any “suspicious” constant sink addresses you might treat as burns
86+ const counts : Record < string , number > = { } ;
87+ for ( const l of logs ) {
88+ const parsed = iface . parseLog ( { topics : [ ...l . topics ] , data : l . data } ) ;
89+ const to = parsed . args . to . toLowerCase ( ) ;
90+ counts [ to ] = ( counts [ to ] || 0 ) + 1 ;
91+ }
92+ console . log ( "Top 'to' addresses:" ) ;
93+ console . log ( Object . entries ( counts ) . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] ) . slice ( 0 , 20 ) ) ;
94+ }
95+
96+ main ( ) . catch ( console . error ) ;
0 commit comments