Skip to content

Commit 20031ee

Browse files
authored
✨ add Arcadia V2 accounts (DefiLlama#13448)
1 parent 405a3f1 commit 20031ee

File tree

1 file changed

+72
-7
lines changed

1 file changed

+72
-7
lines changed

projects/arcadia-finance-v2/index.js

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const { sumTokens2, unwrapSlipstreamNFT } = require("../helper/unwrapLPs");
2+
const utils = require('../helper/utils')
23

34
const config = {
45
factory: "0xDa14Fdd72345c4d2511357214c5B89A919768e59",
@@ -8,6 +9,7 @@ const config = {
89
wAeroNFT: "0x17B5826382e3a5257b829cF0546A08Bd77409270".toLowerCase(),
910
sAeroNFT: "0x9f42361B7602Df1A8Ae28Bf63E6cb1883CD44C27".toLowerCase(),
1011
sSlipNFT: "0x1Dc7A0f5336F52724B650E39174cfcbbEdD67bF1".toLowerCase(),
12+
wsSlipNFT: "0xD74339e0F10fcE96894916B93E5Cc7dE89C98272".toLowerCase(),
1113
pools: [
1214
"0x803ea69c7e87D1d6C86adeB40CB636cC0E6B98E2", // wethPool
1315
"0x3ec4a293Fb906DD2Cd440c20dECB250DeF141dF1", // usdcPool
@@ -16,7 +18,7 @@ const config = {
1618
};
1719

1820
async function unwrapArcadiaAeroLP({ api, ownerIds }) {
19-
const { wAeroNFT, sAeroNFT, sSlipNFT } = config
21+
const { wAeroNFT, sAeroNFT, sSlipNFT, wsSlipNFT } = config
2022
const wAERONFTIds = []
2123
const sAERONFTIds = []
2224
const sSlipNftIds = []
@@ -39,6 +41,9 @@ async function unwrapArcadiaAeroLP({ api, ownerIds }) {
3941
case sSlipNFT:
4042
sSlipNftIds.push(ids[i]);
4143
break;
44+
case wsSlipNFT:
45+
sSlipNftIds.push(ids[i]);
46+
break;
4247
}
4348
}
4449
}
@@ -60,19 +65,79 @@ async function uwrapStakedSlipstreamLP({ api, sSlipNftIds, }) {
6065
}
6166

6267
async function tvl (api) {
63-
const { factory, pools, uniNFT, slipNFT, wAeroNFT, sAeroNFT, sSlipNFT, alienBaseNFT } = config;
68+
const { factory, pools, uniNFT, slipNFT, wAeroNFT, sAeroNFT, sSlipNFT, alienBaseNFT, wsSlipNFT } = config;
6469
const ownerTokens = []
6570
const ownerIds = []
6671
const accs = []
6772

6873
const uTokens = await api.multiCall({ abi: "address:asset", calls: pools });
69-
await api.sumTokens({ blacklistedTokens: [uniNFT, slipNFT, wAeroNFT, sAeroNFT, sSlipNFT, alienBaseNFT], tokensAndOwners2: [uTokens, pools] });
74+
await api.sumTokens({ blacklistedTokens: [uniNFT, slipNFT, wAeroNFT, sAeroNFT, sSlipNFT, alienBaseNFT, wsSlipNFT], tokensAndOwners2: [uTokens, pools] });
7075

7176
const accounts = await api.fetchList({ lengthAbi: 'allAccountsLength', itemAbi: 'allAccounts', target: factory, })
72-
const assetDatas = await api.multiCall({ abi: abi.generateAssetData, calls: accounts, permitFailure: true })
7377

74-
accounts.forEach((account, i) => {
75-
const assetData = assetDatas[i];
78+
// Account version 1 has a stored state of all assets, and can be fetched using generateAssetData()
79+
// Account version 2 has no such stored state, and must be fetched with external api calls.
80+
const versions = await api.multiCall({abi: 'function ACCOUNT_VERSION() view returns (uint256)', calls: accounts,});
81+
const v1Accounts = accounts.filter((_, i) => versions[i] === '1');
82+
const v2Accounts = accounts.filter((_, i) => versions[i] === '2');
83+
84+
// This endpoint uses the following logic:
85+
// 1. Uses batches of all v2Accounts (to prevent rate limiting)
86+
// 2. calls Arcadia's endpoint to fetch the asset data of a V2 account
87+
// 3. verifies onchain that the ownership of the NFTs is indeed correct
88+
// 4. Return format is then transformed to be identical to the format of the V1 assetData
89+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
90+
91+
const batchSize = 10;
92+
for (let i = 0; i < v2Accounts.length; i += batchSize) {
93+
const batch = v2Accounts.slice(i, i + batchSize);
94+
await Promise.all(batch.map(async (account) => {
95+
try {
96+
const assetDataCall = await utils.fetchURL(`https://api.arcadia.finance/v1/api/accounts/spot_asset_data?chain_id=8453&account_addresses=${account}`);
97+
const assetData = assetDataCall.data[0] // call is made for multiple addresses, but may time out if all accounts are requested at once
98+
if (!assetData || !assetData[0][0] || assetData[0][0].length < 1) return;
99+
100+
// Since the return of the ownership data comes from a "blackbox" backend,
101+
// we verify onchain that the ownership of the NFTs is indeed correct
102+
// We check this for each asset where ID != 0
103+
const verificationCalls = assetData[0][1].map((tokenId, index) => {
104+
if (tokenId === "0") return null; // Skip if tokenId is 0, just an erc20, balance will be fetched through sdk
105+
return {
106+
target: assetData[0][0][index],
107+
params: [tokenId]
108+
}
109+
}).filter(call => call !== null); // Remove null entries
110+
111+
if (verificationCalls.length > 0) {
112+
const owners = await api.multiCall({
113+
abi: 'function ownerOf(uint256) view returns (address)',
114+
calls: verificationCalls
115+
});
116+
117+
// Verify all owners match the account
118+
const allOwnersMatch = owners.every(owner => owner.toLowerCase() === account.toLowerCase());
119+
if (!allOwnersMatch) return; // Skip this account if any ownership verification fails
120+
}
121+
122+
ownerTokens.push([assetData[0][0], account])
123+
if (!assetData[0][0].length || !assetData[0][1].length || assetData[0][1] == "0") return;
124+
ownerIds.push([assetData[0][0], assetData[0][1], account])
125+
accs.push(account)
126+
} catch (error) {
127+
console.log(`Failed to fetch/process data for account ${account}:`, error);
128+
return;
129+
}
130+
}));
131+
132+
// Add small delay between batches to prevent rate limiting
133+
if (i + batchSize < v2Accounts.length) { // Only sleep if there are more batches to process
134+
await sleep(1000);
135+
}
136+
}
137+
138+
const assetDatasV1 = await api.multiCall({ abi: abi.generateAssetData, calls: v1Accounts, permitFailure: true })
139+
v1Accounts.forEach((account, i) => {
140+
const assetData = assetDatasV1[i];
76141
if (!assetData || !assetData.assets || !assetData.assets.length ) return;
77142
ownerTokens.push([assetData.assets, account])
78143
if (!assetData[0].length || !assetData[1].length) return;
@@ -84,7 +149,7 @@ async function tvl (api) {
84149
await sumTokens2({ api, owners: accs, uniV3ExtraConfig: { nftAddress: alienBaseNFT } })
85150

86151
// add all simple ERC20s
87-
await api.sumTokens({ ownerTokens, blacklistedTokens: [uniNFT, slipNFT, wAeroNFT, sAeroNFT, sSlipNFT, alienBaseNFT],});
152+
await api.sumTokens({ ownerTokens, blacklistedTokens: [uniNFT, slipNFT, wAeroNFT, sAeroNFT, sSlipNFT, alienBaseNFT, wsSlipNFT],});
88153

89154
// add all Arcadia-wrapped LP positions
90155
await unwrapArcadiaAeroLP({ api, ownerIds });

0 commit comments

Comments
 (0)