Skip to content

Commit d69fb48

Browse files
committed
Add persistence filtering, ARM/otoken/buyback custom renderers, and remove transactionLogs from config-alert
1 parent ba1ccea commit d69fb48

3 files changed

Lines changed: 148 additions & 4 deletions

File tree

src/notify/event/renderers/arm.ts

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const armFunctions = {
2222
traderate1: viewFun('0xcf1de5d8', 'traderate1()', {}, p.uint256),
2323
}
2424

25+
const erc4626Functions = {
26+
convertToAssets: viewFun('0x07a2d13a', 'convertToAssets(uint256)', { shares: p.uint256 }, p.uint256),
27+
}
28+
2529
class ArmContract extends ContractBase {
2630
traderate0() {
2731
return this.eth_call(armFunctions.traderate0, {})
@@ -31,12 +35,21 @@ class ArmContract extends ContractBase {
3135
}
3236
}
3337

38+
class ERC4626Contract extends ContractBase {
39+
convertToAssets(shares: bigint) {
40+
return this.eth_call(erc4626Functions.convertToAssets, { shares })
41+
}
42+
}
43+
3444
interface ArmConfig {
3545
address: string
3646
symbol0: string
3747
symbol1: string
3848
token0: string
3949
token1: string
50+
// ERC4626 vault token whose rate needs converting (e.g. sUSDe)
51+
// When set, rates are adjusted by the vault's convertToAssets rate
52+
vaultToken?: string
4053
}
4154

4255
// Build lookup from ARM contract address to config
@@ -68,6 +81,7 @@ registerArm({
6881
symbol1: 'sUSDe',
6982
token0: addresses.tokens.USDe,
7083
token1: addresses.tokens.sUSDe,
84+
vaultToken: addresses.tokens.sUSDe,
7185
})
7286

7387
registerArm({
@@ -81,6 +95,26 @@ registerArm({
8195
// Cache traderates per ARM address
8296
const traderateCache = new Map<string, { traderate0: bigint; traderate1: bigint }>()
8397

98+
// Cache vault exchange rate (e.g. sUSDe → USDe)
99+
const vaultRateCache = new Map<string, bigint>()
100+
const ONE = 10n ** 18n
101+
102+
type RendererCtx = Parameters<Parameters<typeof registerEventRenderer>[1]>[0]['ctx']
103+
type RendererBlock = Parameters<Parameters<typeof registerEventRenderer>[1]>[0]['log']['block']
104+
105+
async function getVaultRate(ctx: RendererCtx, block: RendererBlock, vaultToken: string): Promise<bigint> {
106+
const cached = vaultRateCache.get(vaultToken)
107+
if (cached) return cached
108+
try {
109+
const contract = new ERC4626Contract(ctx, block, vaultToken)
110+
const rate = await contract.convertToAssets(ONE)
111+
vaultRateCache.set(vaultToken, rate)
112+
return rate
113+
} catch {
114+
return ONE // Fallback: assume 1:1
115+
}
116+
}
117+
84118
async function getTraderates(
85119
ctx: Parameters<Parameters<typeof registerEventRenderer>[1]>[0]['ctx'],
86120
block: Parameters<Parameters<typeof registerEventRenderer>[1]>[0]['log']['block'],
@@ -112,16 +146,27 @@ registerEventRenderer(TraderateChanged.topic, async (params) => {
112146
traderate1: data.traderate1,
113147
})
114148

149+
// For vault tokens (e.g. sUSDe), adjust rates to show USDe-equivalent value
150+
let sellRate = 10n ** 72n / data.traderate0 // 1e36 precision
151+
let buyRate = data.traderate1 // 1e36 precision
152+
let rateLabel = `${arm.symbol1}/${arm.symbol0}`
153+
154+
if (arm.vaultToken) {
155+
const vaultRate = await getVaultRate(params.ctx, params.log.block, arm.vaultToken)
156+
// Multiply by vault rate to convert sUSDe amounts to USDe-equivalent
157+
sellRate = (sellRate * vaultRate) / ONE
158+
buyRate = (buyRate * vaultRate) / ONE
159+
rateLabel = `${arm.symbol0}/${arm.symbol0}` // e.g. USDe/USDe
160+
}
161+
115162
renderEventDiscordEmbed(params, {
116163
fields: [
117164
{
118-
name: `${formatAmount(10n ** 72n / data.traderate0, 36, { maximumFractionDigits: 8 })} ${arm.symbol1}/${
119-
arm.symbol0
120-
}`,
165+
name: `${formatAmount(sellRate, 36, { maximumFractionDigits: 8 })} ${rateLabel}`,
121166
value: 'Sell Price',
122167
},
123168
{
124-
name: `${formatAmount(data.traderate1, 36, { maximumFractionDigits: 8 })} ${arm.symbol1}/${arm.symbol0}`,
169+
name: `${formatAmount(buyRate, 36, { maximumFractionDigits: 8 })} ${rateLabel}`,
125170
value: 'Buy Price',
126171
},
127172
],
@@ -180,6 +225,18 @@ registerEventRenderer(erc20Abi.events.Transfer.topic, async (params) => {
180225
rate = Number(rates.traderate1) / 1e36
181226
}
182227

228+
// For vault tokens, convert output to underlying-equivalent for rate display
229+
if (arm.vaultToken) {
230+
const vaultRate = await getVaultRate(params.ctx, params.log.block, arm.vaultToken)
231+
if (isToken0In) {
232+
// Output is in vault token (sUSDe), convert to USDe-equivalent for rate
233+
rate = (rate * Number(vaultRate)) / 1e18
234+
} else {
235+
// Input is vault token (sUSDe), adjust rate
236+
rate = (rate * 1e18) / Number(vaultRate)
237+
}
238+
}
239+
183240
fields.push({
184241
name: formatAmount(outAmount, 18, { maximumFractionDigits: 6 }),
185242
value: `${outSymbol} out`,
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { event, indexed } from '@subsquid/evm-abi'
2+
import * as p from '@subsquid/evm-codec'
3+
4+
import { discordIconOrName } from '../../const'
5+
import { registerEventRenderer } from '../event'
6+
import { renderEventDiscordEmbed } from './utils'
7+
import { formatAmount } from '../../../utils/formatAmount'
8+
9+
const OTokenBuyback = event(
10+
'0x298e4dbf1f6f43b0e8cd13394bba43125c8c376005b44b664a9fd2eaaeb44743',
11+
'OTokenBuyback(address,address,uint256,uint256)',
12+
{ oToken: indexed(p.address), swappedFor: indexed(p.address), swapAmountIn: p.uint256, amountOut: p.uint256 },
13+
)
14+
15+
// OTokenBuyback — shows oToken sent and token received with icons
16+
registerEventRenderer(OTokenBuyback.topic, async (params) => {
17+
const data = OTokenBuyback.decode(params.log)
18+
renderEventDiscordEmbed(params, {
19+
fields: [
20+
{
21+
name: formatAmount(data.swapAmountIn),
22+
value: `${discordIconOrName(data.oToken) ?? data.oToken} Sent`,
23+
inline: true,
24+
},
25+
{
26+
name: formatAmount(data.amountOut),
27+
value: `${discordIconOrName(data.swappedFor) ?? data.swappedFor} Received`,
28+
inline: true,
29+
},
30+
],
31+
})
32+
})
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { ContractBase, event, viewFun } from '@subsquid/evm-abi'
2+
import * as p from '@subsquid/evm-codec'
3+
4+
import { formatAmount } from '../../../utils/formatAmount'
5+
import { transactionLink } from '../../../utils/links'
6+
import { registerEventRenderer } from '../event'
7+
import { renderDiscordEmbed } from './utils'
8+
9+
const TotalSupplyUpdatedHighres = event(
10+
'0x41645eb819d3011b13f97696a8109d14bfcddfaca7d063ec0564d62a3e257235',
11+
'TotalSupplyUpdatedHighres(uint256,uint256,uint256)',
12+
{ totalSupply: p.uint256, rebasingCredits: p.uint256, rebasingCreditsPerToken: p.uint256 },
13+
)
14+
15+
const totalSupplyFn = viewFun('0x18160ddd', 'totalSupply()', {}, p.uint256)
16+
17+
class OTokenContract extends ContractBase {
18+
totalSupply() {
19+
return this.eth_call(totalSupplyFn, {})
20+
}
21+
}
22+
23+
// TotalSupplyUpdatedHighres — shows previous, current, and diff
24+
registerEventRenderer(TotalSupplyUpdatedHighres.topic, async (params) => {
25+
const data = TotalSupplyUpdatedHighres.decode(params.log)
26+
27+
let previousSupply: bigint | undefined
28+
try {
29+
const contract = new OTokenContract(params.ctx, { height: params.log.block.height - 1 }, params.log.address)
30+
previousSupply = await contract.totalSupply()
31+
} catch {
32+
// RPC call failed — render without diff
33+
}
34+
35+
const fields: { name: string; value: string; inline: boolean }[] = []
36+
if (previousSupply !== undefined) {
37+
const diff = data.totalSupply - previousSupply
38+
fields.push(
39+
{ name: formatAmount(previousSupply), value: 'Previous', inline: true },
40+
{ name: formatAmount(data.totalSupply), value: 'Current', inline: true },
41+
{ name: formatAmount(diff), value: 'Diff', inline: true },
42+
)
43+
} else {
44+
fields.push({ name: formatAmount(data.totalSupply), value: 'Total Supply', inline: true })
45+
}
46+
47+
renderDiscordEmbed({
48+
sortId: `${params.log.block.height}:${params.log.transactionIndex}:${params.log.logIndex}`,
49+
topic: params.topic,
50+
severity: params.severity,
51+
title: `${params.name} - TotalSupplyUpdatedHighres`,
52+
titleUrl: transactionLink(params.log.transactionHash, params.ctx.chain),
53+
fields,
54+
})
55+
})

0 commit comments

Comments
 (0)