Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions src/adaptors/aihedge-finance/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const sdk = require('@defillama/sdk');
const utils = require('../utils');

const VAULTS = [
{
address: '0x469201fA49DB171C0F95371533C2D3Ad5aE60400',
underlying: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
symbol: 'USDC',
},
];

const CHAIN = 'ethereum';

const convertToAssetsAbi =
'function convertToAssets(uint256 shares) external view returns (uint256)';

const SHARE_UNIT = (10n ** 6n).toString();
const DAY = 24 * 3600;

async function apy() {
const timestamp = Math.floor(Date.now() / 1000);

const [{ height: blockNow }, { height: blockPrev }] = await Promise.all([
utils.getPriceApiData(`/block/${CHAIN}/${timestamp}`),
utils.getPriceApiData(`/block/${CHAIN}/${timestamp - DAY}`),
Comment on lines +20 to +25

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline src/handlers/triggerAdaptor.js --items all
rg -n -C 3 -g '*.js' -g '*.ts' '\btimetravel\b|\bapy\s*\(' src

Repository: DefiLlama/yield-server

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== triggerAdaptor outline ==\n'
ast-grep outline src/handlers/triggerAdaptor.js --items all

printf '\n== aihedge-finance outline ==\n'
ast-grep outline src/adaptors/aihedge-finance/index.js --items all

printf '\n== aihedge-finance file size ==\n'
wc -l src/adaptors/aihedge-finance/index.js

printf '\n== relevant snippets ==\n'
sed -n '1,220p' src/adaptors/aihedge-finance/index.js

Repository: DefiLlama/yield-server

Length of output: 3606


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== search for adaptor invocation signatures ==\n'
rg -n -C 2 'triggerAdaptor|timetravel|module\.exports|exports\.main|adapter.*timestamp|timestamp.*adaptor|ctx\.timestamp|runAdaptor|apy\s*\(' src/handlers src/adaptors | head -n 200

Repository: DefiLlama/yield-server

Length of output: 10317


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== triggerAdaptor.js =='
wc -l src/handlers/triggerAdaptor.js
sed -n '1,220p' src/handlers/triggerAdaptor.js

echo
echo '== aihedge-finance index.js =='
wc -l src/adaptors/aihedge-finance/index.js
sed -n '1,220p' src/adaptors/aihedge-finance/index.js

echo
echo '== timestamp plumbing search =='
rg -n -C 3 'timetravel|timestamp|Date\.now\(|blockNow|blockPrev|getPriceApiData|requestTimestamp|historical' src/handlers src/adaptors/aihedge-finance src | head -n 200

Repository: DefiLlama/yield-server

Length of output: 22054


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== aihedge-finance relevant lines =='
nl -ba src/adaptors/aihedge-finance/index.js | sed -n '1,220p'

echo
echo '== exact module export usage =='
rg -n -C 2 'timetravel|module\.exports|apy' src/adaptors/aihedge-finance/index.js

Repository: DefiLlama/yield-server

Length of output: 237


🏁 Script executed:

#!/bin/bash
set -euo pipefail

log=/tmp/coderabbit-shell-logs/shell-output-QGQAs0

echo '== aihedge-finance hits in prior log =='
rg -n -C 2 'aihedge-finance|src/handlers/triggerAdaptor\.js|timetravel|Date\.now\(' "$log" | head -n 200

echo
echo '== focused slice around any aihedge-finance mentions =='
first=$(rg -n 'aihedge-finance' "$log" | head -n 1 | cut -d: -f1 || true)
if [ -n "${first:-}" ]; then
  start=$((first-20)); [ "$start" -lt 1 ] && start=1
  end=$((first+120))
  sed -n "${start},${end}p" "$log"
fi

Repository: DefiLlama/yield-server

Length of output: 10698


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== body timestamp fields in triggerAdaptor.js =='
rg -n -C 3 'body\.(timestamp|date|time|block|from|to)|requestTimestamp|targetDate|timetravel|project\.apy\(' src/handlers/triggerAdaptor.js

echo
echo '== other adaptor runners and timestamp plumbing =='
rg -n -C 2 'body\.(timestamp|date|time|block)|requestTimestamp|targetDate|timetravel' src/handlers src/adaptors | head -n 200

Repository: DefiLlama/yield-server

Length of output: 10268


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== all body field reads in triggerAdaptor.js =='
rg -n 'body\.' src/handlers/triggerAdaptor.js

echo
echo '== aihedge-finance and similar timetravel adaptors that do not accept params =='
rg -n -C 1 'module\.exports = \{|timetravel: true|async function apy\(' src/adaptors/aihedge-finance/index.js src/adaptors | head -n 120

Repository: DefiLlama/yield-server

Length of output: 5587


Honor the timetravel contract
apy() reads Date.now(), so historical backfills still use the live 24h window. Thread the requested timestamp through this adaptor (and align the price lookups to the same time), or set timetravel: false.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptors/aihedge-finance/index.js` around lines 20 - 25, Update apy() to
accept and use the requested timetravel timestamp instead of calling Date.now(),
and derive both block lookups from that same timestamp so historical backfills
calculate the correct 24-hour window. If this adaptor cannot support a supplied
timestamp, explicitly configure it with timetravel: false.

]);

const addresses = VAULTS.map((v) => v.address);
const calls = addresses.map((target) => ({ target }));
const shareCalls = addresses.map((target) => ({
target,
params: [SHARE_UNIT],
}));

const [decimals, totalAssets, rateNow, ratePrev] = await Promise.all([
sdk.api.abi.multiCall({ abi: 'erc20:decimals', calls, chain: CHAIN }),
sdk.api.abi.multiCall({
abi: 'uint:totalAssets',
calls,
chain: CHAIN,
block: blockNow,
}),
sdk.api.abi.multiCall({
abi: convertToAssetsAbi,
calls: shareCalls,
chain: CHAIN,
block: blockNow,
}),
sdk.api.abi.multiCall({
abi: convertToAssetsAbi,
calls: shareCalls,
chain: CHAIN,
block: blockPrev,
}),
]);

const underlyings = VAULTS.map((v) => v.underlying);
const { pricesByAddress } = await utils.getPrices(underlyings, CHAIN);

const pools = VAULTS.map((vault, i) => {
const dec = Number(decimals.output[i].output);
const total = Number(totalAssets.output[i].output);
const rNow = Number(rateNow.output[i].output);
const rPrev = Number(ratePrev.output[i].output);
const price = pricesByAddress[vault.underlying.toLowerCase()] || 0;

const tvlUsd = (total / 10 ** dec) * price;
Comment on lines +65 to +67

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not report a missing price as zero TVL.

A missing price becomes 0, which passes keepFinite; a price-service failure therefore emits a false zero-TVL pool. Skip the pool unless its price is finite and positive.

Suggested guard
-    const price = pricesByAddress[vault.underlying.toLowerCase()] || 0;
+    const price = Number(pricesByAddress[vault.underlying.toLowerCase()]);
+    if (!Number.isFinite(price) || price <= 0) return null;
...
-  return pools.filter(utils.keepFinite);
+  return pools.filter(Boolean).filter(utils.keepFinite);

Also applies to: 86-86

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptors/aihedge-finance/index.js` around lines 65 - 67, Update the price
handling in the vault TVL calculation to stop defaulting missing prices to zero.
Before calculating tvlUsd, validate the resolved price is finite and greater
than zero, and skip the current pool when it is not; apply the same guard to the
corresponding price lookup at the other reported occurrence.


let apyBase = 0;
if (rPrev > 0 && rNow > 0) {
apyBase = ((rNow / rPrev) ** 365 - 1) * 100;
}

return {
pool: `${vault.address}-${CHAIN}`.toLowerCase(),
chain: utils.formatChain(CHAIN),
project: 'aihedge-finance',
symbol: vault.symbol,
tvlUsd,
apyBase,
underlyingTokens: [vault.underlying],
url: `https://dapp.aihedge.finance/#/yield/1/${vault.address}`,
};
});

return pools.filter(utils.keepFinite);
}

module.exports = {
timetravel: true,
apy,
url: 'https://dapp.aihedge.finance',
};