Skip to content

Commit e170cff

Browse files
authored
Merge pull request #1803 from useLiquidOps/master
Add LiquidOps yield adapter
2 parents 9d74604 + 4e6e2c6 commit e170cff

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed

src/adaptors/liquidops/index.js

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
const utils = require('../utils');
2+
const axios = require('axios');
3+
4+
const endpoint = 'https://cu.ao-testnet.xyz'
5+
const controllerId = 'SmmMv0rJwfIDVM3RvY2-P729JFYwhdGSeGo2deynbfY'
6+
const redstoneOracleAddress = 'R5rRjBFS90qIGaohtzd1IoyPwZD0qJZ25QXkP7_p5a0'
7+
const chain = 'AO'
8+
9+
10+
const apy = async () => {
11+
12+
const supportedTokensRes = await DryRun(controllerId, "Get-Tokens")
13+
const supportedTokens = JSON.parse(supportedTokensRes.Messages[0].Data)
14+
const redstoneTickers = JSON.stringify(supportedTokens.map(token => convertTicker(token.ticker.toUpperCase())))
15+
16+
const redstonePriceFeedRes = await DryRun(redstoneOracleAddress, "v2.Request-Latest-Data", [["Tickers", redstoneTickers]]);
17+
const redstonePrices = JSON.parse(redstonePriceFeedRes.Messages[0].Data)
18+
19+
const poolPromises = supportedTokens.map(async poolObject => {
20+
21+
const getAPRRes = await DryRun(poolObject.oToken, "Get-APR");
22+
const APRTagsObject = Object.fromEntries(
23+
getAPRRes.Messages[0].Tags.map((tag) => [tag.name, tag.value])
24+
);
25+
const borrowAPR = formatBorrowAPR(APRTagsObject)
26+
27+
const infoRes = await DryRun(poolObject.oToken, "Info");
28+
const infoTagsObject = Object.fromEntries(
29+
infoRes.Messages[0].Tags.map((tag) => [tag.name, tag.value])
30+
);
31+
32+
const ticker = poolObject.ticker
33+
const redstoneTicker = convertTicker(ticker.toUpperCase())
34+
const tokenUSDPrice = (redstonePrices[redstoneTicker]).v
35+
36+
const totalLends = scaleBalance(infoTagsObject['Cash'], infoTagsObject['Denomination'])
37+
const totalBorrows = scaleBalance(infoTagsObject['Total-Borrows'], infoTagsObject['Denomination'])
38+
const totalSupply = scaleBalance(infoTagsObject['Total-Supply'], infoTagsObject['Denomination'])
39+
40+
const supplyAPY = formatSupplyAPR(borrowAPR, infoTagsObject, totalBorrows, totalSupply)
41+
42+
const ltv = Number(infoTagsObject['Collateral-Factor']) / 100
43+
44+
const tokenID = poolObject.id
45+
const oTokenID = poolObject.oToken
46+
47+
return {
48+
pool: `${oTokenID}-${chain}`.toLowerCase(),
49+
chain,
50+
project: 'liquidops',
51+
symbol: utils.formatSymbol(`o${ticker}`),
52+
tvlUsd: totalLends * tokenUSDPrice,
53+
apyBase: supplyAPY,
54+
underlyingTokens: [tokenID],
55+
url: `https://liquidops.io/${ticker}`,
56+
apyBaseBorrow: borrowAPR,
57+
totalSupplyUsd: totalSupply * tokenUSDPrice,
58+
totalBorrowUsd: totalBorrows * tokenUSDPrice,
59+
ltv
60+
};
61+
});
62+
63+
const poolsArray = await Promise.all(poolPromises);
64+
65+
return poolsArray
66+
67+
}
68+
69+
70+
// Access AO on chain data via the node endpoint
71+
async function DryRun(target, action, extraTags = []) {
72+
const response = await axios.post(`${endpoint}/dry-run?process-id=${target}`, {
73+
Id: "1234",
74+
Target: target,
75+
Owner: "1234",
76+
Anchor: "0",
77+
Data: "1234",
78+
Tags: [
79+
["Target", target],
80+
["Action", action],
81+
["Data-Protocol", "ao"],
82+
["Type", "Message"],
83+
["Variant", "ao.TN.1"],
84+
...extraTags
85+
].map(([name, value]) => ({ name, value }))
86+
}, {
87+
headers: {
88+
'Content-Type': 'application/json'
89+
}
90+
});
91+
await new Promise((resolve) => setTimeout(resolve, 1000));
92+
return response.data;
93+
}
94+
95+
96+
function scaleBalance(amount, denomination) {
97+
const scaledDivider = BigInt(10) ** BigInt(denomination)
98+
const balance = BigInt(amount) / scaledDivider
99+
return Number(balance)
100+
}
101+
102+
function formatBorrowAPR(aprResponse) {
103+
const apr = parseFloat(aprResponse["Annual-Percentage-Rate"]);
104+
const rateMultiplier = parseFloat(aprResponse["Rate-Multiplier"]);
105+
return apr / rateMultiplier
106+
}
107+
108+
function formatSupplyAPR(borrowAPR, infoTagsObject, totalBorrows, totalSupply) {
109+
const utilizationRate = totalBorrows / totalSupply
110+
const reserveFactorFract = Number(infoTagsObject['Reserve-Factor']) / 100;
111+
return borrowAPR * utilizationRate * (1 - reserveFactorFract);
112+
}
113+
114+
function convertTicker(ticker) {
115+
if (ticker === "QAR") return "AR";
116+
if (ticker === "WUSDC") return "USDC";
117+
return ticker;
118+
}
119+
120+
121+
module.exports = {
122+
apy,
123+
};
124+
// npm run test --adapter=liquidops
125+
126+
127+
128+
129+

0 commit comments

Comments
 (0)