Skip to content

Commit b705ae8

Browse files
authored
Merge pull request #205 from madfish-solutions/TW-2021-on-send-operation-time-to-time-appears-error-no-suitable-nodes-available-for-request
TW-2021 Add an endpoint for Youves stats
2 parents 059e91f + 70a45d8 commit b705ae8

File tree

5 files changed

+453
-209
lines changed

5 files changed

+453
-209
lines changed

package.json

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

0 commit comments

Comments
 (0)