Skip to content

Commit b235c0f

Browse files
bingyuyapevan-gray
authored andcommitted
dashboard: move CollapsibleSection into component
cloud_functions: use bignumber to handle bigint Signed-off-by: bingyuyap <bingyu.yap.21@gmail.com>
1 parent e373ce1 commit b235c0f

11 files changed

+170
-132
lines changed

cloud_functions/src/computeNTTRateLimits.ts

+16-9
Original file line numberDiff line numberDiff line change
@@ -65,35 +65,42 @@ async function computeNTTRateLimits_(
6565
tokenDecimals = await getEvmTokenDecimals(rpcEndpoint, managerContract);
6666
}
6767

68-
const outboundCapacity = await ntt.getCurrentOutboundCapacity();
69-
const normalizedOutboundCapacity = outboundCapacity / BigInt(10 ** tokenDecimals);
70-
7168
const inboundChains = NTT_SUPPORTED_CHAINS(network, token).filter(
7269
(inboundChain) => inboundChain !== chain
7370
);
7471

75-
let totalInboundCapacity = BigInt(0);
72+
let totalInboundCapacity = 0n;
7673
const inboundRateLimits = await Promise.all(
7774
inboundChains.map(async (inboundChain): Promise<NTTRateLimit> => {
7875
const inboundCapacity = await ntt.getCurrentInboundCapacity(inboundChain);
79-
const normalizedInboundCapacity = inboundCapacity / BigInt(10 ** tokenDecimals);
80-
totalInboundCapacity += normalizedInboundCapacity;
76+
totalInboundCapacity += inboundCapacity;
8177

8278
return {
8379
tokenName: token,
8480
srcChain: chainToChainId(inboundChain),
8581
destChain: chainToChainId(chain),
86-
amount: normalizedInboundCapacity.toString(),
82+
amount: {
83+
amount: inboundCapacity.toString(),
84+
decimals: tokenDecimals,
85+
},
8786
};
8887
})
8988
);
9089

90+
const outboundCapacity = await ntt.getCurrentOutboundCapacity();
91+
9192
return {
9293
tokenName: token,
9394
srcChain: chainToChainId(chain),
94-
amount: normalizedOutboundCapacity.toString(),
95+
amount: {
96+
amount: outboundCapacity.toString(),
97+
decimals: tokenDecimals,
98+
},
9599
inboundCapacity: inboundRateLimits,
96-
totalInboundCapacity: totalInboundCapacity.toString(),
100+
totalInboundCapacity: {
101+
amount: totalInboundCapacity.toString(),
102+
decimals: tokenDecimals,
103+
},
97104
};
98105
}
99106

cloud_functions/src/computeTotalSupplyAndLocked.ts

+28-28
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
derivePda,
66
getEvmTokenDecimals,
77
getEvmTotalSupply,
8+
normalizeToDecimals,
89
} from '@wormhole-foundation/wormhole-monitor-common';
910
import { PublicKey } from '@solana/web3.js';
1011
import {
@@ -25,23 +26,6 @@ const cacheBucket = storage.bucket(bucketName);
2526
const cacheFileName = 'ntt-total-supply-and-locked.json';
2627
const cloudStorageCache = cacheBucket.file(cacheFileName);
2728

28-
async function getEvmNormalizedTotalSupply(
29-
network: Network,
30-
token: string,
31-
chain: Chain
32-
): Promise<number> {
33-
const tokenDecimals = await getEvmTokenDecimals(
34-
rpc.rpcAddress(network, chain),
35-
NTT_MANAGER_CONTRACT[network][token][chain]!
36-
);
37-
const tokenSupply = await getEvmTotalSupply(
38-
rpc.rpcAddress(network, chain),
39-
NTT_TOKENS[network][token][chain]!
40-
);
41-
42-
return tokenSupply / 10 ** tokenDecimals;
43-
}
44-
4529
async function fetchTotalSupplyAndLocked(network: Network): Promise<NTTTotalSupplyAndLockedData[]> {
4630
const tokens = NTT_MANAGER_CONTRACT[network];
4731
const totalSupplyVsLocked: NTTTotalSupplyAndLockedData[] = [];
@@ -51,32 +35,49 @@ async function fetchTotalSupplyAndLocked(network: Network): Promise<NTTTotalSupp
5135
const programId = new PublicKey(NTT_MANAGER_CONTRACT[network][token].Solana!);
5236
const pda = derivePda('config', programId);
5337
const custody = await getCustody(rpc.rpcAddress(network, 'Solana'), pda.toBase58());
54-
const locked = await getCustodyAmount(rpc.rpcAddress(network, 'Solana'), custody);
38+
const custodyAmount = await getCustodyAmount(rpc.rpcAddress(network, 'Solana'), custody);
5539

5640
const evmTotalSupply: NTTTotalSupplyAndLockedData[] = [];
57-
let totalSupply = 0;
41+
let cumulativeEvmSupply = 0n;
5842
for (const [supportedChain] of Object.entries(NTT_TOKENS[network][token])) {
5943
if (supportedChain === 'Solana') continue;
60-
const tokenSupplyNormalized = await getEvmNormalizedTotalSupply(
61-
network,
62-
token,
63-
supportedChain as Chain
44+
const tokenSupply = await getEvmTotalSupply(
45+
rpc.rpcAddress(network, supportedChain as Chain),
46+
NTT_TOKENS[network][token][supportedChain as Chain]!
47+
);
48+
49+
const tokenDecimals = await getEvmTokenDecimals(
50+
rpc.rpcAddress(network, supportedChain as Chain),
51+
NTT_MANAGER_CONTRACT[network][token][supportedChain as Chain]!
6452
);
6553

6654
evmTotalSupply.push({
6755
tokenName: token,
6856
chain: chainToChainId(supportedChain as Chain),
69-
totalSupply: tokenSupplyNormalized,
57+
totalSupply: {
58+
amount: tokenSupply.toString(),
59+
decimals: tokenDecimals,
60+
},
7061
});
7162

72-
totalSupply += tokenSupplyNormalized;
63+
// Normalize to 18 decimals so prevent potential different decimals from affecting the total supply
64+
cumulativeEvmSupply += normalizeToDecimals(
65+
{
66+
amount: tokenSupply.toString(),
67+
decimals: tokenDecimals,
68+
},
69+
18
70+
);
7371
}
7472

7573
totalSupplyVsLocked.push({
7674
chain: chainToChainId('Solana'),
7775
tokenName: token,
78-
amountLocked: locked,
79-
totalSupply,
76+
amountLocked: custodyAmount,
77+
totalSupply: {
78+
amount: cumulativeEvmSupply.toString(),
79+
decimals: 18,
80+
},
8081
evmTotalSupply,
8182
});
8283
}
@@ -98,7 +99,6 @@ export async function computeTotalSupplyAndLocked(req: any, res: any) {
9899
const network = assertEnvironmentVariable('NETWORK') as Network;
99100
const totalSupplyAndLocked = await fetchTotalSupplyAndLocked(network);
100101
await cloudStorageCache.save(JSON.stringify(totalSupplyAndLocked));
101-
102102
res.status(200).send('Total supply and locked saved');
103103
} catch (e) {
104104
console.error(e);

cloud_functions/src/getNTTRateLimits.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { chainIdToChain } from '@wormhole-foundation/sdk-base';
33
import {
44
NTTRateLimit,
55
assertEnvironmentVariable,
6+
normalizeToDecimals,
67
} from '@wormhole-foundation/wormhole-monitor-common';
78
import { Gauge, register } from 'prom-client';
89

@@ -58,7 +59,9 @@ async function handlePrometheusMetrics(rateLimits: NTTRateLimit[]) {
5859
network,
5960
product: PRODUCT,
6061
},
61-
BigInt(rateLimit.amount)
62+
// Normalize the amount to 18 decimals, Grafana should hold high precision
63+
// It should also be able to handle the normalization to 0 decimals
64+
normalizeToDecimals(rateLimit.amount, 18)
6265
);
6366

6467
if (!rateLimit.inboundCapacity) return;
@@ -81,7 +84,7 @@ async function handlePrometheusMetrics(rateLimits: NTTRateLimit[]) {
8184
network,
8285
product: PRODUCT,
8386
},
84-
BigInt(inboundRateLimit.amount)
87+
normalizeToDecimals(inboundRateLimit.amount, 18)
8588
);
8689
});
8790
});

common/src/evm.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ export async function getEvmTokenDecimals(rpc: string, contractAddress: string):
4747
return Number(result);
4848
}
4949

50-
export async function getEvmTotalSupply(rpc: string, contractAddress: string): Promise<number> {
50+
export async function getEvmTotalSupply(rpc: string, contractAddress: string): Promise<bigint> {
5151
const methodId = getMethodId('totalSupply()');
5252
const result = await callContractMethod(rpc, contractAddress, methodId);
53-
return Number(result);
53+
return BigInt(result);
5454
}

common/src/solana.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import {
55
MessageV0,
66
PublicKeyInitData,
77
PublicKey,
8-
} from '@solana/web3.js'; // NOTE: types only for bundling size
9-
import { decode } from 'bs58';
8+
} from '@solana/web3.js';
109
import axios from 'axios';
10+
import { decode } from 'bs58';
1111
import { encoding } from '@wormhole-foundation/sdk-base';
12+
import { TokenAmount } from './types';
1213

1314
export const isLegacyMessage = (message: Message | MessageV0): message is Message => {
1415
return message.version === 'legacy';
@@ -72,12 +73,18 @@ export async function getCustody(rpcUrl: string, programAddress: string): Promis
7273
return pubkey.toString();
7374
}
7475

75-
export async function getCustodyAmount(rpcUrl: string, programAddress: string): Promise<number> {
76+
export async function getCustodyAmount(
77+
rpcUrl: string,
78+
programAddress: string
79+
): Promise<TokenAmount> {
7680
const accountInfo = await makeRpcCall(rpcUrl, 'getAccountInfo', [programAddress], 'jsonParsed');
7781
if (!accountInfo.value?.data?.parsed?.info?.tokenAmount?.uiAmount) {
7882
throw new Error('Custody amount not found or missing data');
7983
}
80-
return Number(accountInfo.value.data.parsed.info.tokenAmount.uiAmount);
84+
return {
85+
amount: accountInfo.value.data.parsed.info.tokenAmount.amount,
86+
decimals: accountInfo.value.data.parsed.info.tokenAmount.decimals,
87+
};
8188
}
8289

8390
// Helper function to make JSON-RPC requests

common/src/types.ts

+30-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,44 @@
11
import { ChainId } from '@wormhole-foundation/sdk-base';
22

3+
export type TokenAmount = {
4+
amount: string;
5+
decimals: number;
6+
};
7+
8+
export function normalizeToDecimals(tokenAmount: TokenAmount, targetDecimals: number): bigint {
9+
const { amount, decimals } = tokenAmount;
10+
const bigIntAmount = BigInt(amount);
11+
let normalizedAmount: bigint;
12+
13+
if (decimals < targetDecimals) {
14+
// If less decimals, multiply to shift the decimal point to the right
15+
const factor = BigInt(10 ** (targetDecimals - decimals));
16+
normalizedAmount = bigIntAmount * factor;
17+
} else if (decimals > targetDecimals) {
18+
// If more decimals, divide to shift the decimal point to the left
19+
const factor = BigInt(10 ** (decimals - targetDecimals));
20+
normalizedAmount = bigIntAmount / factor;
21+
} else {
22+
normalizedAmount = bigIntAmount;
23+
}
24+
25+
return normalizedAmount;
26+
}
27+
328
export type NTTTotalSupplyAndLockedData = {
429
tokenName: string;
530
chain: ChainId;
6-
amountLocked?: Number;
7-
totalSupply: Number;
31+
// this is bigint but for the sake of precision we are using string
32+
amountLocked?: TokenAmount;
33+
totalSupply?: TokenAmount;
834
evmTotalSupply?: NTTTotalSupplyAndLockedData[];
935
};
1036

1137
export type NTTRateLimit = {
1238
tokenName: string;
1339
srcChain?: ChainId;
1440
destChain?: ChainId;
15-
amount?: string;
16-
totalInboundCapacity?: string;
41+
amount?: TokenAmount;
42+
totalInboundCapacity?: TokenAmount;
1743
inboundCapacity?: NTTRateLimit[];
1844
};

dashboard/src/components/NTTMetrics.tsx

+5-66
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { Box, Divider } from '@mui/material';
1+
import { Divider } from '@mui/material';
22
import { useNetworkContext } from '../contexts/NetworkContext';
3-
import CollapsibleSection from './CollapsibleSection';
43
import { LookerDashboard } from './LookerDashboard';
54
import { NTTRateLimits } from './NTTRateLimits';
65
import { NTTTotalSupplyAndLocked } from './NTTTotalSupplyAndLocked';
@@ -16,39 +15,9 @@ function NTTMetrics() {
1615
hasTabs
1716
/>
1817
<Divider />
19-
<CollapsibleSection
20-
defaultExpanded={false}
21-
header={
22-
<Box
23-
sx={{
24-
display: 'flex',
25-
alignItems: 'center',
26-
paddingRight: 1,
27-
}}
28-
>
29-
<Box>Rate Limit Capacity</Box>
30-
</Box>
31-
}
32-
>
33-
<NTTRateLimits />
34-
</CollapsibleSection>
18+
<NTTRateLimits />
3519
<Divider />
36-
<CollapsibleSection
37-
defaultExpanded={false}
38-
header={
39-
<Box
40-
sx={{
41-
display: 'flex',
42-
alignItems: 'center',
43-
paddingRight: 1,
44-
}}
45-
>
46-
<Box>Total Supply and Locked</Box>
47-
</Box>
48-
}
49-
>
50-
<NTTTotalSupplyAndLocked />
51-
</CollapsibleSection>
20+
<NTTTotalSupplyAndLocked />
5221
</>
5322
);
5423
}
@@ -60,39 +29,9 @@ function NTTMetrics() {
6029
src="https://lookerstudio.google.com/embed/reporting/a47057a8-15a0-4cc7-8086-eb00f5d09d2a/page/SPpuD"
6130
/>
6231
<Divider />
63-
<CollapsibleSection
64-
defaultExpanded={false}
65-
header={
66-
<Box
67-
sx={{
68-
display: 'flex',
69-
alignItems: 'center',
70-
paddingRight: 1,
71-
}}
72-
>
73-
<Box>Rate Limit Capacity</Box>
74-
</Box>
75-
}
76-
>
77-
<NTTRateLimits />
78-
</CollapsibleSection>
32+
<NTTRateLimits />
7933
<Divider />
80-
<CollapsibleSection
81-
defaultExpanded={false}
82-
header={
83-
<Box
84-
sx={{
85-
display: 'flex',
86-
alignItems: 'center',
87-
paddingRight: 1,
88-
}}
89-
>
90-
<Box>Total Supply and Locked</Box>
91-
</Box>
92-
}
93-
>
94-
<NTTTotalSupplyAndLocked />
95-
</CollapsibleSection>
34+
<NTTTotalSupplyAndLocked />
9635
</>
9736
);
9837
}

0 commit comments

Comments
 (0)