Skip to content

Commit d289c0a

Browse files
committed
add Merkl rewards to existing pools
1 parent da2cdfa commit d289c0a

File tree

6 files changed

+99
-5
lines changed

6 files changed

+99
-5
lines changed

src/adaptors/euler-v2/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ const getApys = async () => {
131131
}
132132
}
133133
}
134-
return result;
134+
return utils.addMerklRewardApy(result, 'euler');
135135
};
136136

137137
module.exports = {

src/adaptors/gamma/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,11 +388,13 @@ const getApy = async () => {
388388
'0x431f6e577a431d9ee87a535fde2db830e352e33c',
389389
'0xed17209ab7f9224e29cc9894fa14a011f37b6115',
390390
];
391-
return pools.flat().map((i) => ({
391+
const data = pools.flat().map((i) => ({
392392
...i,
393393
apyReward: x.includes(i.pool) || i.chain === 'Manta' ? null : i.apyReward,
394394
rewardTokens: x.includes(i.pool) || i.chain === 'Manta' ? null : i.rewardTokens,
395395
})).filter(p => p.chain != 'Binance');
396+
397+
return utils.addMerklRewardApy(data, 'gamma', (p) => p.pool.split('-')[0]);
396398
};
397399

398400
module.exports = {

src/adaptors/merkl/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ const networks = {
99
1101: 'polygon_zkevm',
1010
8453: 'base',
1111
60808: 'bob',
12+
146: 'sonic',
13+
43114: 'avax',
14+
80094: 'berachain',
15+
56: 'bsc',
1216
};
1317

1418
// Protocols that should not be listed under Merkl
@@ -18,6 +22,7 @@ const protocolsBlacklist = [
1822
'crosscurve',
1923
'aerodrome',
2024
'gamma',
25+
'uniswap',
2126
];
2227

2328
// Allow specific pools from blacklisted protocols
@@ -50,6 +55,7 @@ const main = async () => {
5055
data = await utils.getData(`https://api.merkl.xyz/v4/opportunities?chainId=${chainId}&status=LIVE&items=100&page=${pageI}`);
5156
} catch (err) {
5257
console.log('failed to fetch Merkl data on chain ' + chain);
58+
break;
5359
}
5460

5561
if (data.length === 0) {

src/adaptors/uniswap-v2/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ const main = async (timestamp = null) => {
126126
}
127127
}
128128

129-
return data.filter((p) => utils.keepFinite(p));
129+
return utils.addMerklRewardApy(
130+
data.filter((p) => utils.keepFinite(p)),
131+
'uniswap'
132+
);
130133
};
131134

132135
module.exports = {

src/adaptors/uniswap-v3/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ const main = async (timestamp = null) => {
352352
);
353353
}
354354
data.push(...(await getOnchainPools()))
355-
return data
355+
return utils.addMerklRewardApy(
356+
data
356357
.flat()
357358
.filter(
358359
(p) =>
@@ -361,7 +362,9 @@ const main = async (timestamp = null) => {
361362
'0x0c6d9d0f82ed2e0b86c4d3e9a9febf95415d1b76',
362363
'0xc809d13e9ea08f296d3b32d4c69d46ff90f73fd8',
363364
].includes(p.pool)
364-
);
365+
),
366+
'uniswap'
367+
);
365368
};
366369

367370
module.exports = {

src/adaptors/utils.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,3 +513,83 @@ exports.getTotalSupply = async (tokenMintAddress) => {
513513

514514
return supplyInTokens;
515515
};
516+
517+
const merklNetworks = {
518+
1: 'ethereum',
519+
137: 'polygon',
520+
10: 'optimism',
521+
42161: 'arbitrum',
522+
1101: 'polygon_zkevm',
523+
8453: 'base',
524+
60808: 'bob',
525+
146: 'sonic',
526+
43114: 'avax',
527+
80094: 'berachain',
528+
56: 'bsc',
529+
}
530+
531+
exports.addMerklRewardApy = async (
532+
pools,
533+
protocolId,
534+
poolAddressGetter,
535+
) => {
536+
try {
537+
let merklPools = [];
538+
let pageI = 0;
539+
540+
while(true) {
541+
let data;
542+
try {
543+
data = await exports.getData(`https://api.merkl.xyz/v4/opportunities?mainProtocolId=${protocolId}&status=LIVE&items=100&page=${pageI}`);
544+
} catch (err) {
545+
console.log(`failed to fetch Merkl data for ${protocolId}: ${err}`);
546+
break;
547+
}
548+
549+
if (data.length === 0) {
550+
break;
551+
}
552+
553+
merklPools.push(...data);
554+
pageI++;
555+
}
556+
557+
558+
const merklPoolsMap = Object.fromEntries(Object.keys(merklNetworks).map(id => [merklNetworks[id], {}]));
559+
merklPools.forEach(pool => {
560+
if (!merklNetworks[pool.chainId]) {
561+
return;
562+
}
563+
564+
merklPoolsMap[merklNetworks[pool.chainId]][pool.identifier.toLowerCase()] = {
565+
apyReward: pool.apr,
566+
rewardTokens: [...new Set(pool.rewardsRecord?.breakdowns.map(x => x.token.address) || [])]
567+
}
568+
});
569+
570+
return pools.map(pool => {
571+
const poolAddress = poolAddressGetter ? poolAddressGetter(pool) : pool.pool;
572+
const merklRewards = merklPoolsMap[pool.chain.toLowerCase()][poolAddress.toLowerCase()];
573+
574+
if (!merklRewards) {
575+
return pool;
576+
}
577+
578+
// if the data is already present, don't overwrite it
579+
if (pool.apyReward || (pool.rewardTokens && pool.rewardTokens.length !== 0)) {
580+
console.log('pool already has apyReward or rewardTokens', pool.pool);
581+
return pool;
582+
}
583+
584+
return {
585+
...pool,
586+
...merklRewards,
587+
}
588+
});
589+
} catch (err) {
590+
console.log(`Failed to add Merkl reward apy to ${protocolId}: ${err}`);
591+
592+
// If we fail to fetch Merkl data, just return the original pools
593+
return pools;
594+
}
595+
};

0 commit comments

Comments
 (0)