Skip to content

Commit

Permalink
feat: update proof of reserve hook to match api updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Polybius93 committed Mar 6, 2025
1 parent 482f217 commit 6b0cdc6
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { HStack, Image, Text } from '@chakra-ui/react';
import { useBitcoinPrice } from '@hooks/use-bitcoin-price';
import { unshiftValue } from 'dlc-btc-lib/utilities';

import { convertBitcoinToUSD } from '@shared/utils';

Expand All @@ -16,7 +15,7 @@ export function TokenStatsBoardChainValue({
const { data: bitcoinPrice } = useBitcoinPrice();

const chainValueInUSD =
chainValue && bitcoinPrice ? convertBitcoinToUSD(unshiftValue(bitcoinPrice), chainValue) : 0;
chainValue && bitcoinPrice ? convertBitcoinToUSD(bitcoinPrice, chainValue) : 0;

return (
<HStack w={'100%'} h={'100%'} alignItems={'start'}>
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/proof-of-reserve/proof-of-reserve.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,15 @@ export function ProofOfReserve(): React.JSX.Element {
'evm-hardhat-arb': '',
'evm-hardhat-eth': '',
'ripple-xrpl-mainnet': '/images/logos/xrpl-token.svg',
'ripple-xrpl-testnet': '/images/logos/xrpl-token.svg',
};
return chainImagePaths[chainName];
}

const chainData: ChainData[] = proofOfReserveByChain.map(chain => {
return {
chain: getChainImagePath(chain.chain),
value: chain.value,
value: chain.proofOfReserve,
};
});

Expand Down
113 changes: 36 additions & 77 deletions src/app/hooks/use-proof-of-reserve.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
import { useContext } from 'react';

import { Merchant, MerchantProofOfReserve } from '@models/merchant';
import { EthereumNetworkConfigurationContext } from '@providers/ethereum-network-configuration.provider';
import { RippleNetworkConfigurationContext } from '@providers/ripple-network-configuration.provider';
import { useQuery } from '@tanstack/react-query';
import { Decimal } from 'decimal.js';
import { AttestorChainID } from 'dlc-btc-lib/models';
import { unshiftValue } from 'dlc-btc-lib/utilities';

import { API_HELPERS } from '@shared/constants/api.constants';
import { EVMAttestorChainIDMap } from '@shared/constants/ethereum.constants';
import { XRPLAttestorChainIDMap } from '@shared/constants/ripple.constants';

export interface UseProofOfReserveReturnType {
proofOfReserveSum?: number;
merchantProofOfReserves: MerchantProofOfReserve[];
proofOfReserveByChain: ProofOfReserveByChainReturnType[];
proofOfReserveByChain: ProofOfReserveResult[];
}

interface ProofOfReserveResult {
chain: AttestorChainID;
proofOfReserve: number;
error?: string;
}

interface ProofOfReserveByChainReturnType {
chain: string;
value: number;
interface AggregatedProofOfReserveData {
proofOfReserve: number;
error?: string;
chains: ProofOfReserveResult[];
}

export function useProofOfReserve(): UseProofOfReserveReturnType {
async function fetchProofOfReserve(merchantAddress?: string): Promise<number> {
async function fetchProofOfReserve(
merchantAddress?: string
): Promise<AggregatedProofOfReserveData> {
try {
const apiURL = API_HELPERS.getProofOfReserveURL({ address: merchantAddress });

Expand All @@ -37,85 +40,41 @@ export function useProofOfReserve(): UseProofOfReserveReturnType {
} catch (error) {
// eslint-disable-next-line no-console
console.error('Error fetching Proof of Reserve', error);
return 0;
}
}

async function fetchProofOfReserveByChain(
chainName: AttestorChainID
): Promise<ProofOfReserveByChainReturnType> {
try {
const apiUrl = API_HELPERS.getProofOfReserveURL({ chain: chainName });

const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error('Error fetching Proof of Reserve by Chain');
}

const data = await response.json();
return {
chain: chainName,
value: data,
};
} catch (error) {
// eslint-disable-next-line no-console
console.error('Error fetching Proof of Reserve by Chain', error);
return {
chain: chainName,
value: 0,
proofOfReserve: 0,
error: 'Error fetching Proof of Reserve',
chains: [],
};
}
}

const {
ethereumNetworkConfiguration: { enabledEthereumNetworks },
} = useContext(EthereumNetworkConfigurationContext);
const { enabledRippleNetworks } = useContext(RippleNetworkConfigurationContext);

async function fetchAllProofOfReserve(): Promise<UseProofOfReserveReturnType> {
const proofOfReserve = await fetchProofOfReserve();

const evmAttestorChainIDs = enabledEthereumNetworks.map(
network => EVMAttestorChainIDMap[network.id]
);
const xrpAttestorChainIDs = enabledRippleNetworks.map(
network => XRPLAttestorChainIDMap[network.id]
);

const evmPorByChains = await Promise.allSettled(
evmAttestorChainIDs.map(async chain => fetchProofOfReserveByChain(chain))
);
const xrplPorByChains = await Promise.allSettled(
xrpAttestorChainIDs.map(async chain => fetchProofOfReserveByChain(chain))
);

const fulfilledPorByChains = [...evmPorByChains, ...xrplPorByChains]
.filter(por => por.status === 'fulfilled')
.map(por => por.value);

const promises = appConfiguration.merchants.map(async (merchant: Merchant) => {
const proofOfReserve = (
await Promise.all(
const merchantProofOfReserves = await Promise.all(
appConfiguration.merchants.map(async merchant => {
const proofOfReserves = await Promise.all(
merchant.addresses.map(async address => {
return await fetchProofOfReserve(address);
})
)
).reduce(
(totalProofOfReserve, addressProofOfReserve) => totalProofOfReserve + addressProofOfReserve,
0
);
return {
merchant,
iBTCAmount: unshiftValue(proofOfReserve),
};
});

const merchantProofOfReserves = await Promise.all(promises);
);

const iBTCAmount = proofOfReserves.reduce(
(sum, proof) => new Decimal(sum).add(proof.proofOfReserve).toNumber(),
0
);

return {
merchant,
iBTCAmount,
};
})
);

return {
proofOfReserveSum: unshiftValue(proofOfReserve),
proofOfReserveSum: proofOfReserve.proofOfReserve,
merchantProofOfReserves,
proofOfReserveByChain: fulfilledPorByChains,
proofOfReserveByChain: proofOfReserve.chains,
};
}

Expand Down
6 changes: 0 additions & 6 deletions src/shared/constants/ripple.constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { RippleNetwork, RippleNetworkID } from '@models/ripple.models';
import { XRPLAttestorChainID } from 'dlc-btc-lib/models';

const RippleMainnet: RippleNetwork = {
id: RippleNetworkID.Mainnet,
Expand All @@ -13,8 +12,3 @@ const RippleTestnet: RippleNetwork = {
};

export const supportedRippleNetworks: RippleNetwork[] = [RippleMainnet, RippleTestnet];

export const XRPLAttestorChainIDMap: Record<RippleNetworkID, XRPLAttestorChainID> = {
[RippleNetworkID.Mainnet]: XRPLAttestorChainID['ripple-xrpl-mainnet'],
[RippleNetworkID.Testnet]: XRPLAttestorChainID['ripple-xrpl-testnet'],
};
15 changes: 5 additions & 10 deletions src/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { DetailedEvent, FormattedEvent } from '@models/ethereum-models';
import Decimal from 'decimal.js';
import { EVMAttestorChainID, EthereumNetworkID } from 'dlc-btc-lib/models';
import { unshiftValue } from 'dlc-btc-lib/utilities';
import { pipe, when } from 'ramda';
import { Chain } from 'viem';

import { EVMAttestorChainIDMap, SUPPORTED_VIEM_CHAINS } from './constants/ethereum.constants';
Expand Down Expand Up @@ -68,15 +67,11 @@ export const convertBitcoinToUSD = (
bitcoinPrice: number,
bitcoinAmount: number,
shouldRound = true
): number =>
pipe(
(amount: number) => new Decimal(amount).mul(bitcoinPrice),
when(
() => shouldRound,
decimal => decimal.floor()
),
(decimal: Decimal) => decimal.toNumber()
)(bitcoinAmount);
): number => {
const amount = new Decimal(bitcoinAmount).mul(bitcoinPrice);

return shouldRound ? amount.floor().toNumber() : amount.toNumber();
};

export function getEthereumNetworkIDByAttestorChainID(attestorChainID: EVMAttestorChainID): Chain {
const networkID = Object.entries(EVMAttestorChainIDMap).find(
Expand Down

0 comments on commit 6b0cdc6

Please sign in to comment.