Skip to content
Merged
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
179 changes: 175 additions & 4 deletions src/adaptors/termmax/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ const EVENTS = {
CreateVault:
'event CreateVault(address indexed vault, address indexed creator, (address admin,address curator,uint256 timelock,address asset,uint256 maxCapacity,string name,string symbol,uint64 performanceFeeRate) indexed initialParams)',
},
V1Plus: {
VaultCreated:
'event VaultCreated(address indexed vault, address indexed creator, tuple(address admin,address curator,address guardian,uint256 timelock,address asset,uint256 maxCapacity,string name,string symbol,uint64 performanceFeeRate,uint64 minApy,uint64 minIdleFundRate) initialParams)',
},
V2: {
VaultCreated:
'event VaultCreated(address indexed vault, address indexed creator, (address admin,address curator,address guardian,uint256 timelock,address asset,address pool,uint256 maxCapacity,string name,string symbol,uint64 performanceFeeRate,uint64 minApy) initialParams)',
},
};
const v1iface = new Interface([EVENTS.V1.CreateVault]);
const v1plusiface = new Interface([EVENTS.V1Plus.VaultCreated]);
const v2iface = new Interface([EVENTS.V2.VaultCreated]);

const VAULTS = {
Expand All @@ -33,14 +38,20 @@ const VAULTS = {
fromBlock: 22283092,
},
],
vaultFactoryV1Plus: [
{
address: '0x3a9ECfFDBDc595907f65640F810d3dDDDDe2FA61',
fromBlock: 23138659,
},
],
vaultFactoryV2: [
{
address: '0xF2BDa87CA467eB90A1b68f824cB136baA68a8177',
fromBlock: 23445703,
fromBlock: 23430000,
},
{
address: '0x5b8B26a6734B5eABDBe6C5A19580Ab2D0424f027',
fromBlock: 23488637,
fromBlock: 23430000,
},
],
},
Expand All @@ -59,6 +70,10 @@ const VAULTS = {
address: '0xa7c93162962D050098f4BB44E88661517484C5EB',
fromBlock: 385228046,
},
{
address: '0x18b8A9433dBefcd15370F10a75e28149bcc2e301',
fromBlock: 385228046,
},
],
},
bsc: {
Expand All @@ -68,13 +83,17 @@ const VAULTS = {
vaultFactory: [
{
address: '0x48bCd27e208dC973C3F56812F762077A90E88Cea',
fromBlock: 50519690,
fromBlock: 50519589,
},
],
vaultFactoryV2: [
{
address: '0x1401049368eD6AD8194f8bb7E41732c4620F170b',
fromBlock: 63192842,
fromBlock: 63100000,
},
{
address: '0xdffE6De6de1dB8e1B5Ce77D3222eba401C2573b5',
fromBlock: 63100000,
},
],
},
Expand Down Expand Up @@ -247,6 +266,145 @@ async function getVaultsV1({ alias, chain, chainId, number, opportunities }) {
return vaults;
}

async function getVaultV1PlusAddresses(chain, blockNumber) {
const { vaultFactoryV1Plus } = VAULTS[chain];
if (!vaultFactoryV1Plus) return [];

const addresses = [];

const tasks = [];
for (const factory of vaultFactoryV1Plus) {
const task = async () => {
const { output } = await sdk.api2.util.getLogs({
target: factory.address,
topic: '',
fromBlock: factory.fromBlock,
toBlock: blockNumber,
keys: [],
topics: [v1plusiface.getEventTopic('VaultCreated')],
chain,
});
const events = output
.filter((e) => !e.removed)
.map((e) => v1plusiface.parseLog(e));
for (const { args } of events) {
const [vault] = args;
addresses.push(vault);
}
};
tasks.push(task());
}
await Promise.all(tasks);

return addresses;
}

async function getVaultsV1Plus({
alias,
chain,
chainId,
number,
opportunities,
}) {
const vaults = [];

const addresses = await getVaultV1PlusAddresses(chain, number).then(
(addresses) => addresses.filter((a) => !VAULT_BLACKLIST[chain].includes(a))
);
if (addresses.length === 0) return vaults;

const calls = addresses.map((target) => ({ target }));
const [apys, assets, decimalses, names, totalAssetses] = await Promise.all([
sdk.api.abi.multiCall({
chain,
calls,
abi: 'uint256:apy',
}),
sdk.api.abi.multiCall({
chain,
calls,
abi: 'address:asset',
}),
sdk.api.abi.multiCall({
chain,
calls,
abi: 'uint8:decimals',
}),
sdk.api.abi.multiCall({
chain,
calls,
abi: 'string:name',
}),
sdk.api.abi.multiCall({
chain,
calls,
abi: 'uint256:totalAssets',
}),
]);

const [assetNames, priceMap] = await Promise.all([
sdk.api.abi.multiCall({
chain,
calls: assets.output.map((a) => ({ target: a.output })),
abi: 'string:symbol',
}),
getPrices(
chain,
assets.output.map((a) => a.output)
),
]);

for (let i = 0; i < addresses.length; i++) {
const address = addresses[i];
const assetAddress = assets.output[i].output;

const readableApy = new BigNumber(apys.output[i].output)
.div(new BigNumber(10).pow(6)) // actual decimals for APY is 8
.toNumber();
const tvlUsd = new BigNumber(totalAssetses.output[i].output)
.div(new BigNumber(10).pow(decimalses.output[i].output))
.times(priceMap.get(assetAddress) || 0)
.toNumber();

const url = new URL(
`https://app.termmax.ts.finance/earn/${alias}/${address.toLowerCase()}`
);
url.searchParams.set('chain', alias);

const vault = {
pool: `${address}-${chain.toLowerCase()}`,
chain,
project: 'termmax',
symbol: assetNames.output[i].output,
tvlUsd,
apyBase: readableApy,
url: String(url),
underlyingTokens: [assetAddress],
poolMeta: names.output[i].output,
};

const opportunity = opportunities.find(
(o) =>
o.chainId === chainId &&
o.identifier.toLowerCase() === address.toLowerCase()
);
if (opportunity) {
vault.apyReward = opportunity.apr;

const breakdowns =
(opportunity.rewardsRecord && opportunity.rewardsRecord.breakdowns) ||
[];
vault.rewardTokens = breakdowns
.map((b) => b.token.address)
.filter((a) => a);
}

vaults.push(vault);
}

return vaults;
}

async function getVaultV2Addresses(chain, blockNumber) {
const { vaultFactoryV2 } = VAULTS[chain];

Expand Down Expand Up @@ -539,6 +697,19 @@ async function getVaultsOnChain(chain, chainId, alias) {
};
tasks.push(taskV1());
}
{
const taskV1Plus = async () => {
const vaultsV1Plus = await getVaultsV1Plus({
alias,
chain,
chainId,
number,
opportunities,
});
for (const vault of vaultsV1Plus) vaultsOnChain.push(vault);
};
tasks.push(taskV1Plus());
}
{
const taskV2 = async () => {
const vaultsV2 = await getVaultsV2({
Expand Down
Loading