Skip to content

Commit fda018d

Browse files
committed
TW-2021 Add an endpoint for Youves stats
1 parent 059e91f commit fda018d

File tree

5 files changed

+469
-215
lines changed

5 files changed

+469
-215
lines changed

package.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
"@ethersproject/strings": "^5.7.0",
1212
"@ethersproject/transactions": "^5.7.0",
1313
"@stablelib/random": "^1.0.2",
14-
"@taquito/rpc": "14.0.0",
15-
"@taquito/taquito": "14.0.0",
16-
"@taquito/tzip12": "14.0.0",
17-
"@taquito/tzip16": "14.0.0",
18-
"@taquito/utils": "14.0.0",
19-
"axios": "^0.27.2",
14+
"@taquito/rpc": "^23.0.0",
15+
"@taquito/taquito": "^23.0.0",
16+
"@taquito/tzip12": "^23.0.0",
17+
"@taquito/tzip16": "^23.0.0",
18+
"@taquito/utils": "^23.0.0",
19+
"@temple-wallet/youves-sdk": "1.0.0-beta.3",
20+
"axios": "^0.30.0",
2021
"bignumber.js": "^9.1.0",
2122
"body-parser": "^1.20.2",
2223
"cors": "^2.8.5",
@@ -70,5 +71,8 @@
7071
"ts-prune": "^0.10.3",
7172
"typescript": "^5",
7273
"typescript-eslint": "^7"
74+
},
75+
"resolutions": {
76+
"bignumber.js": "9.1.0"
7377
}
7478
}

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { getSignedMoonPayUrl } from './utils/moonpay/get-signed-moonpay-url';
4242
import SingleQueryDataProvider from './utils/SingleQueryDataProvider';
4343
import { getExchangeRates } from './utils/tokens';
4444
import { getWertSessionId } from './utils/wert';
45+
import { youvesStatsProvider } from './utils/youves';
4546

4647
const PINO_LOGGER = {
4748
logger: logger.child({ name: 'web' }),
@@ -411,6 +412,8 @@ app.post('/api/temple-tap/check-airdrop-confirmation', tezosSigAuthMiddleware, (
411412
handleTempleTapApiProxyRequest(req, res, 'v1/check-airdrop-address-confirmation')
412413
);
413414

415+
app.get('/api/youves/stats', makeProviderDataRequestHandler(youvesStatsProvider));
416+
414417
// start the server listening for requests
415418
const port = Boolean(process.env.PORT) ? process.env.PORT : 3000;
416419
app.listen(port, () => console.info(`Server is running on port ${port}...`));

src/utils/tezos.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class LambdaViewSigner implements Signer {
2828

2929
const lambdaSigner = new LambdaViewSigner();
3030
const michelEncoder = new MichelCodecPacker();
31-
const tezosToolkit = new TezosToolkit(RPC_URL);
31+
32+
export const tezosToolkit = new TezosToolkit(RPC_URL);
3233
tezosToolkit.setSignerProvider(lambdaSigner);
3334
tezosToolkit.setPackerProvider(michelEncoder);

src/utils/youves.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import {
2+
BailoutPool,
3+
contracts,
4+
AssetDefinition,
5+
createEngine,
6+
Storage,
7+
StorageKey,
8+
StorageKeyReturnType,
9+
UnifiedStaking,
10+
mainnetTokens,
11+
mainnetNetworkConstants
12+
} from '@temple-wallet/youves-sdk';
13+
import BigNumber from 'bignumber.js';
14+
import memoizee from 'memoizee';
15+
16+
import SingleQueryDataProvider from './SingleQueryDataProvider';
17+
import { tezosToolkit as tezos } from './tezos';
18+
import { getExchangeRates } from './tokens';
19+
20+
const YOUVES_INDEXER_URL = 'https://indexer.youves.com/v1/graphql';
21+
const INDEXER_CONFIG = { url: YOUVES_INDEXER_URL, headCheckUrl: '' };
22+
const MULTIPLIER = 100;
23+
const ubtcToken = contracts.mainnet.find(token => token.id === 'uBTC')!;
24+
const uusdToken = contracts.mainnet.find(token => token.id === 'uUSD')!;
25+
const youToken = mainnetTokens.youToken;
26+
27+
class MemoryStorage implements Storage {
28+
public storage: Map<string, any>;
29+
30+
constructor() {
31+
this.storage = new Map();
32+
}
33+
public async set<K extends StorageKey>(key: K, value: StorageKeyReturnType[K]): Promise<void> {
34+
this.storage.set(key, value);
35+
}
36+
public async get<K extends StorageKey>(key: K): Promise<StorageKeyReturnType[K]> {
37+
return this.storage.get(key);
38+
}
39+
public async delete<K extends StorageKey>(key: K): Promise<void> {
40+
this.storage.delete(key);
41+
}
42+
public async clear() {
43+
this.storage.clear();
44+
}
45+
}
46+
47+
const unifiedStaking = new UnifiedStaking(tezos, INDEXER_CONFIG, mainnetNetworkConstants);
48+
const bailoutPool = new BailoutPool(tezos, INDEXER_CONFIG, mainnetNetworkConstants);
49+
50+
const createEngineMemoized = memoizee(
51+
(token: AssetDefinition) =>
52+
createEngine({
53+
tezos,
54+
contracts: token,
55+
storage: new MemoryStorage(),
56+
indexerConfig: INDEXER_CONFIG,
57+
tokens: mainnetTokens,
58+
activeCollateral: token.collateralOptions[0],
59+
networkConstants: mainnetNetworkConstants
60+
}),
61+
{ normalizer: ([token]) => token.id }
62+
);
63+
64+
const withToPercentage =
65+
<A extends unknown[]>(fn: (...args: A) => Promise<BigNumber>) =>
66+
async (...args: A) => {
67+
const rawApr = await fn(...args);
68+
69+
return Number(rawApr.multipliedBy(MULTIPLIER));
70+
};
71+
72+
const getV2YOUTokenApr = withToPercentage((assetToUsdExchangeRate: BigNumber, governanceToUsdExchangeRate: BigNumber) =>
73+
unifiedStaking.getAPR(assetToUsdExchangeRate, governanceToUsdExchangeRate)
74+
);
75+
76+
const getV3YOUTokenApr = withToPercentage(() => bailoutPool.getAPR());
77+
78+
const getYouvesTokenApr = withToPercentage((token: AssetDefinition) =>
79+
createEngineMemoized(token).getSavingsPoolV3YearlyInterestRate()
80+
);
81+
82+
export const youvesStatsProvider = new SingleQueryDataProvider(60000, async () => {
83+
const exchangeRates = await getExchangeRates();
84+
const youToUsdExchangeRate = exchangeRates.find(
85+
rate => rate.tokenAddress === youToken.contractAddress && rate.tokenId === youToken.tokenId
86+
)!.exchangeRate;
87+
88+
const aprResults = await Promise.all([
89+
Promise.all([
90+
getV2YOUTokenApr(youToUsdExchangeRate, youToUsdExchangeRate).then(value => ({ v2: value })),
91+
getV3YOUTokenApr().then(value => ({ v3: value }))
92+
]),
93+
getYouvesTokenApr(ubtcToken),
94+
getYouvesTokenApr(uusdToken)
95+
]);
96+
97+
return {
98+
apr: Object.fromEntries(
99+
[youToken, ubtcToken, uusdToken].map((asset, index) => {
100+
const rawResult = aprResults[index];
101+
const { contractAddress, tokenId } = 'token' in asset ? asset.token : asset;
102+
103+
return [
104+
`${contractAddress}_${tokenId}`,
105+
typeof rawResult === 'number' ? rawResult : Object.assign(...rawResult)
106+
];
107+
})
108+
)
109+
};
110+
});

0 commit comments

Comments
 (0)