1
1
import pino from "pino" ;
2
2
import { Bot } from 'grammy'
3
3
import cron from 'node-cron'
4
- import { LRUCache } from 'lru-cache'
5
4
import config from '../../config'
6
5
import { BotContext , OnMessageContext } from "../types" ;
7
- import { getFeeStats } from "./explorerApi" ;
6
+ import { getDailyMetrics , MetricsDailyType } from "./explorerApi" ;
8
7
import { getAddressBalance , getBotFee , getBotFeeStats } from "./harmonyApi" ;
9
- import { getBridgeStats } from "./bridgeAPI" ;
8
+ import { getTotalStakes , getTVL } from "./bridgeAPI" ;
10
9
import { statsService } from "../../database/services" ;
11
10
import { abbreviateNumber } from "./utils" ;
11
+ import { getOneRate } from "./exchangeApi" ;
12
+ import { getTradingVolume } from "./subgraphAPI" ;
12
13
13
14
enum SupportedCommands {
14
15
BOT_STATS = 'botstats' ,
@@ -29,9 +30,6 @@ export class BotSchedule {
29
30
}
30
31
} )
31
32
32
- private cache = new LRUCache ( { max : 100 , ttl : 1000 * 60 * 60 * 2 } )
33
- private reportMessage = ''
34
-
35
33
constructor ( bot : Bot < BotContext > ) {
36
34
this . bot = bot
37
35
@@ -47,70 +45,32 @@ export class BotSchedule {
47
45
48
46
}
49
47
50
- private async prepareMetricsUpdate ( refetchData = false ) {
51
- try {
52
- this . logger . info ( `Start preparing stats` )
53
-
54
- const networkFeeStats = await getFeeStats ( )
55
- const networkFeesReport = `*${ networkFeeStats . value } * ONE (${ networkFeeStats . change } %)`
56
-
57
- let bridgeStatsReport = this . cache . get ( 'bridge_report' ) || ''
58
- this . logger . info ( `Bridge stats report from cache: "${ bridgeStatsReport } "` )
59
- if ( refetchData || ! bridgeStatsReport ) {
60
- const bridgeStats = await getBridgeStats ( )
61
- bridgeStatsReport = `*${ bridgeStats . value } * USD (${ bridgeStats . change } %)`
62
- this . cache . set ( 'bridge_report' , bridgeStatsReport )
63
- }
64
-
65
- const botFeesReport = await this . getBotFeeReport ( this . holderAddress ) ;
66
-
67
- const reportMessage =
68
- `\nNetwork fees (7-day growth): ${ networkFeesReport } ` +
69
- `\nBridge flow: ${ bridgeStatsReport } ` +
70
- `\nBot fees: ${ botFeesReport } `
71
-
72
- this . logger . info ( `Prepared message: "${ reportMessage } "` )
73
- this . reportMessage = reportMessage
74
- return reportMessage
75
- } catch ( e ) {
76
- console . log ( '### e' , e ) ;
77
- this . logger . error ( `Cannot get stats: ${ ( e as Error ) . message } ` )
78
- }
79
- }
80
-
81
48
private async postMetricsUpdate ( ) {
82
49
const scheduleChatId = config . schedule . chatId
83
50
if ( ! scheduleChatId ) {
84
51
this . logger . error ( `Post updates: no chatId defined. Set [SCHEDULE_CHAT_ID] variable.` )
85
52
return
86
53
}
87
54
88
- if ( this . reportMessage ) {
89
- await this . bot . api . sendMessage ( scheduleChatId , this . reportMessage , {
55
+ const reportMessage = await this . generateReport ( )
56
+ if ( reportMessage ) {
57
+ await this . bot . api . sendMessage ( scheduleChatId , reportMessage , {
90
58
parse_mode : "Markdown" ,
91
59
} )
92
- this . logger . info ( `Daily metrics posted in chat ${ scheduleChatId } : ${ this . reportMessage } ` )
60
+ this . logger . info ( `Daily metrics posted in chat ${ scheduleChatId } : ${ reportMessage } ` )
61
+ } else {
62
+ this . logger . error ( `Cannot prepare daily /stats message` )
93
63
}
94
64
}
95
65
96
66
private async runCronJob ( ) {
97
- cron . schedule ( '30 17 * * *' , ( ) => {
98
- this . prepareMetricsUpdate ( true )
99
- } , {
100
- scheduled : true ,
101
- timezone : "Europe/Lisbon"
102
- } ) ;
103
-
104
67
cron . schedule ( '00 18 * * *' , ( ) => {
105
- this . logger . info ( 'Posting daily metrics' )
68
+ this . logger . info ( 'Posting daily metrics... ' )
106
69
this . postMetricsUpdate ( )
107
70
} , {
108
71
scheduled : true ,
109
72
timezone : "Europe/Lisbon"
110
73
} ) ;
111
-
112
- await this . prepareMetricsUpdate ( )
113
- // await this.postMetricsUpdate()
114
74
}
115
75
116
76
public isSupportedEvent ( ctx : OnMessageContext ) {
@@ -124,19 +84,53 @@ export class BotSchedule {
124
84
125
85
public async generateReport ( ) {
126
86
const [
87
+ networkFeesWeekly ,
88
+ walletsCountWeekly ,
89
+ oneRate ,
90
+
91
+ bridgeTVL ,
92
+ totalStakes ,
93
+ swapTradingVolume ,
94
+
127
95
balance ,
128
96
weeklyUsers ,
129
- totalSupportedMessages
97
+ dailyMessages
130
98
] = await Promise . all ( [
99
+ getDailyMetrics ( MetricsDailyType . totalFee , 7 ) ,
100
+ getDailyMetrics ( MetricsDailyType . walletsCount , 7 ) ,
101
+ getOneRate ( ) ,
102
+
103
+ getTVL ( ) ,
104
+ getTotalStakes ( ) ,
105
+ getTradingVolume ( ) ,
106
+
131
107
getAddressBalance ( this . holderAddress ) ,
132
108
statsService . getActiveUsers ( 7 ) ,
133
109
statsService . getTotalMessages ( 1 , true )
134
110
] )
135
111
136
- const report = `\nBot fees: *${ abbreviateNumber ( balance / Math . pow ( 10 , 18 ) ) } * ONE` +
137
- `\nWeekly active users: *${ abbreviateNumber ( weeklyUsers ) } *` +
138
- `\nDaily user engagement: *${ abbreviateNumber ( totalSupportedMessages ) } *`
139
- return report ;
112
+ const networkFeesSum = networkFeesWeekly . reduce ( ( sum , item ) => sum + + item . value , 0 )
113
+ const walletsCountSum = walletsCountWeekly . reduce ( ( sum , item ) => sum + + item . value , 0 )
114
+ const walletsCountAvg = Math . round ( walletsCountSum / walletsCountWeekly . length )
115
+
116
+ const networkUsage =
117
+ `- Network 7-day fees, wallets, price: ` +
118
+ `*${ abbreviateNumber ( networkFeesSum ) } * ONE, ${ abbreviateNumber ( walletsCountAvg ) } , $${ oneRate . toFixed ( 4 ) } `
119
+
120
+ const swapTradingVolumeSum = swapTradingVolume . reduce ( ( sum , item ) => sum + Math . round ( + item . volumeUSD ) , 0 )
121
+ const totalStakeUSD = Math . round ( oneRate * totalStakes )
122
+
123
+ const assetsUpdate =
124
+ `- Total assets, swaps, stakes: ` +
125
+ `$${ abbreviateNumber ( bridgeTVL ) } , $${ abbreviateNumber ( swapTradingVolumeSum ) } , $${ abbreviateNumber ( totalStakeUSD ) } `
126
+
127
+ const oneBotMetrics =
128
+ `- Bot total earns, weekly users, daily messages: ` +
129
+ `*${ abbreviateNumber ( balance / Math . pow ( 10 , 18 ) ) } * ONE` +
130
+ `, ${ abbreviateNumber ( weeklyUsers ) } ` +
131
+ `, ${ abbreviateNumber ( dailyMessages ) } `
132
+
133
+ return `${ networkUsage } \n${ assetsUpdate } \n${ oneBotMetrics } ` ;
140
134
}
141
135
142
136
public async generateReportEngagementByCommand ( days : number ) {
@@ -199,7 +193,7 @@ export class BotSchedule {
199
193
const { message_id } = ctx . update . message
200
194
201
195
if ( ctx . hasCommand ( SupportedCommands . BOT_STATS ) ) {
202
- const report = await this . prepareMetricsUpdate ( )
196
+ const report = await this . generateReport ( )
203
197
if ( report ) {
204
198
await ctx . reply ( report , {
205
199
parse_mode : "Markdown" ,
0 commit comments