Skip to content
82 changes: 66 additions & 16 deletions fees/yieldfi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,43 @@ const CONTRACTS = {
V2_MANAGER: {
[CHAIN.ETHEREUM]: "0x03ACc35286bAAE6D73d99a9f14Ef13752208C8dC",
},
FROM_BLOCK: {
[CHAIN.ETHEREUM]: 24241384,
[CHAIN.BSC]: 76733207,
},
}

const YIELD_SEGMENTS = 10

const PROTOCOL_START_TS: Record<string, number> = {
[CHAIN.ETHEREUM]: Math.floor(new Date("2024-11-11T00:00:00Z").getTime() / 1000),
[CHAIN.BSC]: Math.floor(new Date("2025-07-27T00:00:00Z").getTime() / 1000),
}

async function fetchVaultDeployedLogs(options: FetchOptions, vaultDeployer: string) {
const startTs = PROTOCOL_START_TS[options.chain]
if (startTs === undefined) return []
const deployFromBlock = await options.getBlock(startTs, options.chain, {})
const toBlock = await options.getToBlock()
if (deployFromBlock > toBlock) return []
const span = toBlock - deployFromBlock
const seen = new Set<string>()
const merged: any[] = []
for (let i = 0; i < YIELD_SEGMENTS; i++) {
const chunkFrom = deployFromBlock + Math.floor((i * span) / YIELD_SEGMENTS)
const chunkTo = i === YIELD_SEGMENTS - 1 ? toBlock : deployFromBlock + Math.floor(((i + 1) * span) / YIELD_SEGMENTS) - 1
if (chunkFrom > chunkTo) continue
const chunkLogs = await options.getLogs({
target: vaultDeployer,
eventAbi: ABI.DEPLOY_VAULT,
cacheInCloud: true,
fromBlock: chunkFrom,
toBlock: chunkTo,
})
Comment on lines +39 to +55
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Handle failed block resolution and cap the discovery scan.

helpers/getBlock.ts can return null on Line 39. If that happens, the range math below degenerates into a genesis-sized scan, and even the non-null path still splits the full protocol lifetime into only 10 getLogs windows. CI is already failing on BSC with pruned-history / limit errors, so this needs a null guard plus block-span-based chunking.

Possible fix
     const startTs = PROTOCOL_START_TS[options.chain]
     if (startTs === undefined) return []
     const deployFromBlock = await options.getBlock(startTs, options.chain, {})
     const toBlock = await options.getToBlock()
-    if (deployFromBlock > toBlock) return []
-    const span = toBlock - deployFromBlock
+    if (deployFromBlock == null || deployFromBlock > toBlock) return []
+    const maxBlockSpan = 50_000
     const seen = new Set<string>()
     const merged: any[] = []
-    for (let i = 0; i < YIELD_SEGMENTS; i++) {
-        const chunkFrom = deployFromBlock + Math.floor((i * span) / YIELD_SEGMENTS)
-        const chunkTo = i === YIELD_SEGMENTS - 1 ? toBlock : deployFromBlock + Math.floor(((i + 1) * span) / YIELD_SEGMENTS) - 1
+    for (let chunkFrom = deployFromBlock; chunkFrom <= toBlock; chunkFrom += maxBlockSpan) {
+        const chunkTo = Math.min(chunkFrom + maxBlockSpan - 1, toBlock)
         if (chunkFrom > chunkTo) continue
         const chunkLogs = await options.getLogs({
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@fees/yieldfi/index.ts` around lines 39 - 55, The code assumes deployFromBlock
(from options.getBlock) is non-null and then computes a huge span; add a null
guard and a scan-cap before chunking: if deployFromBlock is null (or
options.getToBlock() is null) return [] or compute a safe fallback window
instead of using genesis (do not let deployFromBlock be treated as 0), and
introduce a MAX_SCAN_BLOCKS cap so span = Math.min(toBlock - deployFromBlock,
MAX_SCAN_BLOCKS) before calculating chunkFrom/chunkTo; keep using YIELD_SEGMENTS
to split that capped span and pass those chunkFrom/chunkTo into options.getLogs
(symbols: deployFromBlock, options.getBlock, options.getToBlock, YIELD_SEGMENTS,
chunkFrom, chunkTo, options.getLogs).

for (const log of chunkLogs) {
const key = String(log.vault).toLowerCase()
if (seen.has(key)) continue
seen.add(key)
merged.push(log)
}
}
return merged
}

async function fetch(options: FetchOptions): Promise<FetchResultV2> {
Expand All @@ -38,7 +71,6 @@ async function fetch(options: FetchOptions): Promise<FetchResultV2> {
const manager = CONTRACTS.V2_MANAGER[options.chain];
const navManager = CONTRACTS.NAV_MANAGER[options.chain];
const vaultDeployer = CONTRACTS.VAULT_DEPLOYER[options.chain];
const fromBlock = CONTRACTS.FROM_BLOCK[options.chain];

if (yieldProxy) {
const yieldDistributedLogs = await options.getLogs({ target: yieldProxy, eventAbi: ABI.YIELD_PROXY });
Expand All @@ -57,29 +89,47 @@ async function fetch(options: FetchOptions): Promise<FetchResultV2> {
target: navManager,
eventAbi: ABI.NAV,
});
const vaultDeployedLogs = await options.getLogs({
target: vaultDeployer,
eventAbi: ABI.DEPLOY_VAULT,
cacheInCloud: true,
fromBlock,
});
const vaultDeployedLogs = await fetchVaultDeployedLogs(options, vaultDeployer);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vauluDeployer was deployed 75 days ago, what do you intend to do by using fromBlock which is a year and half old


navManagerLogs.forEach((log: any) => {
dailyFees.add(log.vault, log.managementFee + log.performanceFee);
dailyRevenue.add(log.vault, log.managementFee + log.performanceFee);
});

const vaults = vaultDeployedLogs.map((log: any) => log.vault);
const totalSupplies = await options.api.multiCall({ abi: 'uint256:totalSupply', calls: vaults, permitFailure: true });
const assets = await options.api.multiCall({ abi: 'address:asset', calls: vaults, permitFailure: true });
const decimals = await options.api.multiCall({ abi: 'uint8:decimals', calls: vaults, permitFailure: true });
const assetDecimals = await options.api.multiCall({ abi: 'uint8:decimals', calls: assets, permitFailure: true });
const vaultRateBefore = await options.fromApi.multiCall({ abi: 'uint256:getRate', calls: vaults, permitFailure: true });
const vaultRateAfter = await options.toApi.multiCall({ abi: 'uint256:getRate', calls: vaults, permitFailure: true });

const fromFeeBlock = await options.getFromBlock();
const toFeeBlock = await options.getToBlock();
const feeSpan = toFeeBlock - fromFeeBlock;
const boundaryBlocks: number[] = [];
for (let j = 0; j <= YIELD_SEGMENTS; j++) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pull hourly fetches blocks every hour, so i dont think you need to split again to calculate every 6 minutes

boundaryBlocks.push(j === YIELD_SEGMENTS ? toFeeBlock : fromFeeBlock + Math.floor((j * feeSpan) / YIELD_SEGMENTS));
}

const suppliesAt: any[][] = [];
const ratesAt: any[][] = [];
for (const block of boundaryBlocks) {
suppliesAt.push(await options.api.multiCall({ abi: 'uint256:totalSupply', calls: vaults, permitFailure: true, block }));
ratesAt.push(await options.api.multiCall({ abi: 'uint256:getRate', calls: vaults, permitFailure: true, block }));
}

for (let i = 0; i < vaults.length; i++) {
if (assets[i] && totalSupplies[i] && decimals[i] && assetDecimals[i] && vaultRateAfter[i] && vaultRateBefore[i])
dailyFees.add(assets[i], (totalSupplies[i] / 10 ** decimals[i]) * (vaultRateAfter[i] - vaultRateBefore[i]) / 10 ** (decimals[i] - assetDecimals[i]));
if (!assets[i] || decimals[i] == null || assetDecimals[i] == null) continue;
let acc = 0;
for (let k = 0; k < YIELD_SEGMENTS; k++) {
const s0 = suppliesAt[k][i];
const s1 = suppliesAt[k + 1][i];
const r0 = ratesAt[k][i];
const r1 = ratesAt[k + 1][i];
if (s0 == null || s1 == null || r0 == null || r1 == null) continue;
const avgSupply = (Number(s0) + Number(s1)) / 2;
const rateDelta = Number(r1) - Number(r0);
acc += (avgSupply / 10 ** decimals[i]) * rateDelta / 10 ** (decimals[i] - assetDecimals[i]);
}
if (acc !== 0) dailyFees.add(assets[i], acc);
Comment on lines +121 to +132
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Python float uses the same IEEE-754 double-precision model as JS Number.
python - <<'PY'
max_safe = 2**53 - 1
print("max safe integer:", max_safe)
for raw in (10**18, 10**18 + 1, 10**23, 10**23 + 1):
    print(f"{raw}: float(raw) == float(raw + 1) -> {float(raw) == float(raw + 1)}")
PY

Repository: DefiLlama/dimension-adapters

Length of output: 349


🏁 Script executed:

# Find the yieldfi index file and examine the code around lines 121-132
find . -path "*fees/yieldfi/index.ts" -type f

Repository: DefiLlama/dimension-adapters

Length of output: 95


🏁 Script executed:

# Check the code at the specified lines
if [ -f "fees/yieldfi/index.ts" ]; then
  wc -l fees/yieldfi/index.ts
  echo "=== Lines 115-140 ===" 
  sed -n '115,140p' fees/yieldfi/index.ts
fi

Repository: DefiLlama/dimension-adapters

Length of output: 1405


🏁 Script executed:

# Also check what dailyFees is and what its add method expects
rg -A 5 "dailyFees\s*=" fees/yieldfi/index.ts | head -20

Repository: DefiLlama/dimension-adapters

Length of output: 350


🏁 Script executed:

# Check the file structure and imports to understand data types
head -50 fees/yieldfi/index.ts

Repository: DefiLlama/dimension-adapters

Length of output: 2564


🏁 Script executed:

# Find the Balances type definition
rg -r "class Balances" --type ts | head -5

Repository: DefiLlama/dimension-adapters

Length of output: 468


🏁 Script executed:

# Also check the adapters/types file
if [ -f "adapters/types.ts" ]; then
  rg "class Balances|interface.*Balances|add\(" adapters/types.ts | head -20
fi

Repository: DefiLlama/dimension-adapters

Length of output: 54


🏁 Script executed:

# Search more broadly for Balances definition
find . -name "*.ts" -type f -exec grep -l "class Balances" {} \; 2>/dev/null | head -5

Repository: DefiLlama/dimension-adapters

Length of output: 54


🏁 Script executed:

# Check helper files for Balances
ls -la helpers/

Repository: DefiLlama/dimension-adapters

Length of output: 3931


🏁 Script executed:

# Search for Balances class in adapters directory
find . -name "*.ts" -type f | xargs grep -l "class Balances" 2>/dev/null

Repository: DefiLlama/dimension-adapters

Length of output: 56


🏁 Script executed:

# Look in the main adapters directory
find adapters -name "*.ts" -type f | xargs grep -l "class Balances" 2>/dev/null

Repository: DefiLlama/dimension-adapters

Length of output: 56


🏁 Script executed:

# Try a different approach - search for the add method definition
rg "add\s*\(" adapters/types.ts

Repository: DefiLlama/dimension-adapters

Length of output: 54


🏁 Script executed:

# Check adapters/types.ts directly
if [ -f "adapters/types.ts" ]; then
  wc -l adapters/types.ts
fi

Repository: DefiLlama/dimension-adapters

Length of output: 93


🏁 Script executed:

# Read adapters/types.ts to find Balances
head -200 adapters/types.ts | tail -100

Repository: DefiLlama/dimension-adapters

Length of output: 3325


🏁 Script executed:

# Check the beginning of adapters/types.ts for imports
head -50 adapters/types.ts

Repository: DefiLlama/dimension-adapters

Length of output: 1666


🏁 Script executed:

# Search for where Balances is imported from in adapters/types.ts
grep "import.*Balances\|from.*Balances" adapters/types.ts

Repository: DefiLlama/dimension-adapters

Length of output: 130


🏁 Script executed:

# Try searching in the entire codebase for Balances class definition
find . -type f -name "*.ts" | head -50 | xargs grep -l "export.*class Balances" 2>/dev/null

Repository: DefiLlama/dimension-adapters

Length of output: 56


🏁 Script executed:

# Check if it's in a sdk or external package - search package.json
cat package.json | grep -A 50 '"dependencies"'

Repository: DefiLlama/dimension-adapters

Length of output: 772


🏁 Script executed:

# Search for usages of .add() on Balances-like objects in the codebase
rg "\.add\(" fees/ | head -30

Repository: DefiLlama/dimension-adapters

Length of output: 2716


🏁 Script executed:

# Look specifically at how dailyFees.add is used in yieldfi
grep -A 2 -B 2 "dailyFees.add" fees/yieldfi/index.ts

Repository: DefiLlama/dimension-adapters

Length of output: 866


🏁 Script executed:

# Check if there are any other files that use .add() with stringified values
rg "\.add\([^,]+,\s*['\"].*\.toString\(\)" fees/ | head -10

Repository: DefiLlama/dimension-adapters

Length of output: 54


🏁 Script executed:

# Look at other fee adapters to understand the pattern
rg "dailyFees\.add\(" fees/ | head -20

Repository: DefiLlama/dimension-adapters

Length of output: 1739


🏁 Script executed:

# Check if yieldfi adapter has allowNegativeValue
grep -n "allowNegativeValue" fees/yieldfi/index.ts

Repository: DefiLlama/dimension-adapters

Length of output: 123


🏁 Script executed:

# Check what types suppliesAt and ratesAt actually contain
grep -B 5 -A 5 "suppliesAt\|ratesAt" fees/yieldfi/index.ts | head -40

Repository: DefiLlama/dimension-adapters

Length of output: 1432


🏁 Script executed:

# Look for the export/return statement to see the adapter config
tail -20 fees/yieldfi/index.ts

Repository: DefiLlama/dimension-adapters

Length of output: 412


🏁 Script executed:

# Check if Balances.add accepts strings or numbers - search for documentation or method signature
rg "interface.*Balances|\.add.*:" adapters/ --type ts | head -20

Repository: DefiLlama/dimension-adapters

Length of output: 445


🏁 Script executed:

# Look at similar fee calculations to understand the pattern better
grep -B 5 -A 5 "avgSupply\|rateDelta" fees/ --include="*.ts" | head -50

Repository: DefiLlama/dimension-adapters

Length of output: 99


🏁 Script executed:

# Check what multiCall returns by looking at examples
grep -B 2 -A 5 "\.multiCall" fees/yieldfi/index.ts | head -30

Repository: DefiLlama/dimension-adapters

Length of output: 1227


🏁 Script executed:

# Look at the external SDK - check package and understand multiCall return type
rg "multiCall.*uint256" fees/ --type ts | head -5

Repository: DefiLlama/dimension-adapters

Length of output: 891


🏁 Script executed:

# Check actual usage in other files to see what type is returned
rg "multiCall.*uint256" . --type ts -B 2 -A 2 | head -50

Repository: DefiLlama/dimension-adapters

Length of output: 5018


🏁 Script executed:

# Search for how other adapters handle bigint/number conversions for fees
rg "BigInt.*add|acc.*=.*0n" fees/ --type ts | head -20

Repository: DefiLlama/dimension-adapters

Length of output: 644


🏁 Script executed:

# Look at how other adapters with large decimals handle precision
grep -r "toFixed\|toString\|BigInt" fees/ --include="*.ts" | grep -i "fees\|revenue" | head -20

Repository: DefiLlama/dimension-adapters

Length of output: 1615


🏁 Script executed:

# Let's understand what Balances.add() accepts by checking if there are any TypeScript definitions
rg "\.add\(" --type ts -A 2 | grep -E "string|number|bigint" | head -20

Repository: DefiLlama/dimension-adapters

Length of output: 747


🏁 Script executed:

# Check if the proposed fix's BigInt math is mathematically sound
python3 <<'EOF'
# Test the proposed fix logic for accuracy
# Original: (avgSupply / 10^decimals) * rateDelta / 10^(decimals - assetDecimals)
# Proposed: (supplySum * rateDelta) / (2 * 10^exponent) where exponent = 2*decimals - assetDecimals

# Example: decimals = 18, assetDecimals = 6
decimals = 18
assetDecimals = 6
exponent = 2 * decimals - assetDecimals  # 30

# Test with sample values
s0 = 10**18
s1 = 10**18
r0 = 10**9
r1 = 10**9 + 1

# Original calculation (in float)
avgSupply = (s0 + s1) / 2
rateDelta = r1 - r0
original_result = (avgSupply / 10 ** decimals) * rateDelta / 10 ** (decimals - assetDecimals)

# Proposed calculation (in bigint)
supplySum = s0 + s1
rateDelta_bi = r1 - r0
exponent = 2 * decimals - assetDecimals
if exponent >= 0:
    segmentAcc = (supplySum * rateDelta_bi) // (2 * 10 ** exponent)
else:
    segmentAcc = (supplySum * rateDelta_bi * 10 ** (-exponent)) // 2

print(f"Original (float): {original_result}")
print(f"Proposed (bigint, stringified): {str(segmentAcc)}")
print(f"Match: {original_result == float(segmentAcc)}")
print(f"\nPrecision difference: {abs(original_result - float(segmentAcc))}")
EOF

Repository: DefiLlama/dimension-adapters

Length of output: 171


🏁 Script executed:

# Check what Balances is and what methods it accepts
# Search for documentation or examples that pass strings to add()
rg "dailyFees\.add.*toString\|add.*\.toString" fees/ --type ts

Repository: DefiLlama/dimension-adapters

Length of output: 54


🏁 Script executed:

# Look more carefully at Balances usage - does it accept bigint or strings?
rg "\.add\(" fees/ --type ts -B 2 -A 1 | grep -E "\.add\(.*0n|\.add\(.*BigInt" | head -20

Repository: DefiLlama/dimension-adapters

Length of output: 2009


🏁 Script executed:

# Check if there are examples of passing bigint values to .add()
rg "\.add\([^,]+,\s*(0n|BigInt|[0-9]+n)" . --type ts | head -15

Repository: DefiLlama/dimension-adapters

Length of output: 1920


🏁 Script executed:

# Look at what types multiCall returns - check SDK usage more carefully
rg "multiCall.*uint256" fees/yieldfi/ --type ts -A 5 -B 2

Repository: DefiLlama/dimension-adapters

Length of output: 786


🏁 Script executed:

# Test the precision issue more comprehensively for various decimal combinations
python3 <<'EOF'
# Test precision for different decimal combinations that would occur in practice

test_cases = [
    # (decimals, assetDecimals, s0, s1, r0, r1, description)
    (18, 6, 10**18, 10**18 + 1000, 10**9, 10**9 + 1, "18-decimal vault"),
    (8, 6, 10**8, 10**8 + 100, 10**5, 10**5 + 1, "8-decimal vault"),
    (6, 6, 10**6, 10**6 + 10, 10**3, 10**3 + 1, "6-decimal vault"),
]

for decimals, assetDecimals, s0, s1, r0, r1, desc in test_cases:
    # Original (float)
    avgSupply = (s0 + s1) / 2
    rateDelta = r1 - r0
    original = (avgSupply / 10 ** decimals) * rateDelta / 10 ** (decimals - assetDecimals)
    
    # Proposed (bigint with integer division)
    supplySum = s0 + s1
    rateDelta_bi = r1 - r0
    exponent = 2 * decimals - assetDecimals
    if exponent >= 0:
        proposed = (supplySum * rateDelta_bi) // (2 * (10 ** exponent))
    else:
        proposed = ((supplySum * rateDelta_bi) * (10 ** (-exponent))) // 2
    
    print(f"\n{desc}:")
    print(f"  Original (float): {original}")
    print(f"  Proposed (bigint): {proposed}")
    print(f"  Precision loss: {original - proposed}")
    print(f"  Match: {original == proposed}")
EOF

Repository: DefiLlama/dimension-adapters

Length of output: 473


🏁 Script executed:

# Check if there's a type definition for Balances.add() signature in the SDK
# or if we can infer from documentation
rg "add.*\(.*\)" . --type ts -B 2 -A 2 | grep -E "add\s*\([^)]*:\s*(number|string|bigint)" | head -10

Repository: DefiLlama/dimension-adapters

Length of output: 54


🏁 Script executed:

# Check the fragment/index.ts mentioned in learnings to see if it uses a similar pattern
if [ -f "fees/fragment/index.ts" ]; then
  sed -n '95,110p' fees/fragment/index.ts
fi

Repository: DefiLlama/dimension-adapters

Length of output: 1176


🏁 Script executed:

# Verify whether stringification is actually needed - test if bigint is passed directly elsewhere
rg "\.add\([^,]+,\s*[a-zA-Z_][a-zA-Z0-9_]*n\s*\)" . --type ts | head -10

Repository: DefiLlama/dimension-adapters

Length of output: 426


🏁 Script executed:

# Look at the exact math one more time - check if there's a better approach
# Let's see if the calculation can be kept in bigint without stringification
python3 <<'EOF'
# Test if we can keep bigint arithmetic without stringification
# and what the actual impact is

# Case: 18-decimal vault with assetDecimals = 6
decimals = 18
assetDecimals = 6

s0_raw = 10**18
s1_raw = 10**18
r0_raw = 10**9
r1_raw = 10**9 + 1

# Original code path (problematic precision)
avgSupply_float = (float(s0_raw) + float(s1_raw)) / 2
rateDelta_float = float(r1_raw) - float(r0_raw)
original = (avgSupply_float / 10 ** decimals) * rateDelta_float / 10 ** (decimals - assetDecimals)

print(f"Original calculation (float): {original}")
print(f"Original (scientific): {original:.20e}")

# Better approach: keep in bigint but use different division strategy
# Instead of: (sum * delta) / (2 * 10^exponent)
# We could do: (sum * delta) / (2) / 10^exponent
# But this still loses precision with integer division

# Or even better: accumulate in base units and scale at the end
supplySum = s0_raw + s1_raw
rateDelta = r1_raw - r0_raw
# This is raw: (supply * rate_change) - but we need to divide by 2 and apply decimals
# If we keep as bigint: supplySum * rateDelta = 2e18 * 1 = 2e18
result_raw = (supplySum * rateDelta) // 2  # = 1e18

# Now we need to scale: divide by 10^decimals and by 10^(decimals - assetDecimals)
# Total scale: 10^(decimals + decimals - assetDecimals) = 10^(2*18 - 6) = 10^30
final_scaled = result_raw / (10 ** 30)
print(f"\nBetter bigint approach: {final_scaled}")
print(f"Better (scientific): {final_scaled:.20e}")

# The real question: is this precision loss acceptable?
# For yield farming, typically dealing with raw amounts anyway
EOF

Repository: DefiLlama/dimension-adapters

Length of output: 236


🏁 Script executed:

# Final check: verify the adapter's allowNegativeValue setting one more time
grep -B 5 -A 5 "allowNegativeValue" fees/yieldfi/index.ts

Repository: DefiLlama/dimension-adapters

Length of output: 328


🏁 Script executed:

# Check if there are any tests or comments about expected precision
grep -r "precision\|BigInt\|Number.*conversion" fees/yieldfi/ --include="*.ts"

Repository: DefiLlama/dimension-adapters

Length of output: 54


Keep raw token math in bigint.

Lines 128–130 convert raw supply/rate values to Number and then scale them with floating-point math. For 18-decimal vaults, 1e18 exceeds the safe-integer range (2^53 - 1), so this loses precision and can feed fractional raw amounts into dailyFees.add. Keep the accumulation in integer space.

Possible fix
-            let acc = 0;
+            let acc = 0n;
             for (let k = 0; k < YIELD_SEGMENTS; k++) {
                 const s0 = suppliesAt[k][i];
                 const s1 = suppliesAt[k + 1][i];
                 const r0 = ratesAt[k][i];
                 const r1 = ratesAt[k + 1][i];
                 if (s0 == null || s1 == null || r0 == null || r1 == null) continue;
-                const avgSupply = (Number(s0) + Number(s1)) / 2;
-                const rateDelta = Number(r1) - Number(r0);
-                acc += (avgSupply / 10 ** decimals[i]) * rateDelta / 10 ** (decimals[i] - assetDecimals[i]);
+                const supplySum = BigInt(s0) + BigInt(s1);
+                const rateDelta = BigInt(r1) - BigInt(r0);
+                const exponent = 2n * BigInt(decimals[i]) - BigInt(assetDecimals[i]);
+                acc += (supplySum * rateDelta) / (2n * 10n ** exponent);
             }
-            if (acc !== 0) dailyFees.add(assets[i], acc);
+            if (acc !== 0n) dailyFees.add(assets[i], acc);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let acc = 0;
for (let k = 0; k < YIELD_SEGMENTS; k++) {
const s0 = suppliesAt[k][i];
const s1 = suppliesAt[k + 1][i];
const r0 = ratesAt[k][i];
const r1 = ratesAt[k + 1][i];
if (s0 == null || s1 == null || r0 == null || r1 == null) continue;
const avgSupply = (Number(s0) + Number(s1)) / 2;
const rateDelta = Number(r1) - Number(r0);
acc += (avgSupply / 10 ** decimals[i]) * rateDelta / 10 ** (decimals[i] - assetDecimals[i]);
}
if (acc !== 0) dailyFees.add(assets[i], acc);
let acc = 0n;
for (let k = 0; k < YIELD_SEGMENTS; k++) {
const s0 = suppliesAt[k][i];
const s1 = suppliesAt[k + 1][i];
const r0 = ratesAt[k][i];
const r1 = ratesAt[k + 1][i];
if (s0 == null || s1 == null || r0 == null || r1 == null) continue;
const supplySum = BigInt(s0) + BigInt(s1);
const rateDelta = BigInt(r1) - BigInt(r0);
const exponent = 2n * BigInt(decimals[i]) - BigInt(assetDecimals[i]);
acc += (supplySum * rateDelta) / (2n * 10n ** exponent);
}
if (acc !== 0n) dailyFees.add(assets[i], acc);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@fees/yieldfi/index.ts` around lines 121 - 132, The loop currently converts
supplies/rates to Number and uses floating math (loss of precision for 1e18);
change the accumulation to use bigint math: convert s0,s1,r0,r1 from suppliesAt
and ratesAt into BigInt, compute avgSupply = (s0 + s1) / 2n and rateDelta = r1 -
r0 as BigInt, then perform all scaling with BigInt power expressions (e.g., 10n
** BigInt(decimals[i]) and 10n ** BigInt(decimals[i] - assetDecimals[i])) to
compute acc as a BigInt; only convert to the expected type when calling
dailyFees.add (or adjust dailyFees.add to accept BigInt) and use acc !== 0n for
the nonzero check. Ensure you reference YIELD_SEGMENTS, suppliesAt, ratesAt,
decimals, assetDecimals, acc, and dailyFees.add when applying the change.

}
}
const dailySupplySideRevenue = dailyFees.clone();
Expand Down
Loading