From 7c0a28d994523a199182f4d160015f2789f974a8 Mon Sep 17 00:00:00 2001
From: Polybius93 <99192647+Polybius93@users.noreply.github.com>
Date: Tue, 10 Sep 2024 16:09:04 +0200
Subject: [PATCH] =?UTF-8?q?feat:=20remove=20mint=20burn=20events=20related?=
=?UTF-8?q?=20functions,=20replace=20them=20with=20ap=E2=80=A6=20(#170)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: remove mint burn events related functions, replace them with api calls
---
.../components/generic-table-header-text.tsx | 4 +-
.../components/generic-table-header.tsx | 6 +-
.../components/points-table-item.tsx | 8 +-
src/app/components/points/points.tsx | 2 +-
.../merchant-details/merchant-details.tsx | 59 +-----------
.../merchant-details-table-item.tsx | 92 +++++++++----------
.../merchant-table/merchant-details-table.tsx | 9 +-
.../proof-of-reserve/proof-of-reserve.tsx | 34 +------
.../protocol-history-table-item.tsx | 59 ++++++++----
.../protocol-history-table.tsx | 4 +-
src/app/functions/ethereum.functions.ts | 24 -----
src/app/hooks/use-mint-burn-events.ts | 77 ++++++++++++++++
.../proof-of-reserve-context-provider.tsx | 9 ++
src/shared/constants/api.constants.ts | 1 +
src/shared/constants/ethereum.constants.ts | 1 -
src/shared/models/ethereum-models.ts | 12 +++
src/shared/models/points.models.ts | 1 +
src/shared/utils.ts | 34 +++++++
18 files changed, 241 insertions(+), 195 deletions(-)
delete mode 100644 src/app/functions/ethereum.functions.ts
create mode 100644 src/app/hooks/use-mint-burn-events.ts
diff --git a/src/app/components/generic-table/components/generic-table-header-text.tsx b/src/app/components/generic-table/components/generic-table-header-text.tsx
index d9348426..ec87b8d4 100644
--- a/src/app/components/generic-table/components/generic-table-header-text.tsx
+++ b/src/app/components/generic-table/components/generic-table-header-text.tsx
@@ -8,7 +8,6 @@ interface GenericTableHeaderTextProps {
fontSize?: string;
fontWeight?: string;
children: React.ReactNode;
- pl?: string;
}
export function GenericTableHeaderText({
@@ -17,10 +16,9 @@ export function GenericTableHeaderText({
fontSize = 'small',
children,
fontWeight = '600',
- pl = '10px',
}: GenericTableHeaderTextProps): React.JSX.Element {
return (
-
+
{children}
);
diff --git a/src/app/components/generic-table/components/generic-table-header.tsx b/src/app/components/generic-table/components/generic-table-header.tsx
index e2cf3122..1ec144e7 100644
--- a/src/app/components/generic-table/components/generic-table-header.tsx
+++ b/src/app/components/generic-table/components/generic-table-header.tsx
@@ -5,5 +5,9 @@ interface GenericTableHeaderProps {
}
export function GenericTableHeader({ children }: GenericTableHeaderProps): React.JSX.Element {
- return {children};
+ return (
+
+ {children}
+
+ );
}
diff --git a/src/app/components/points/components/points-table/components/points-table-item.tsx b/src/app/components/points/components/points-table/components/points-table-item.tsx
index 2c6996ee..e544e380 100644
--- a/src/app/components/points/components/points-table/components/points-table-item.tsx
+++ b/src/app/components/points/components/points-table/components/points-table-item.tsx
@@ -41,9 +41,11 @@ export function PointsTableItem(pointsTableItem: ProtocolRewards): React.JSX.Ele
{`(${multiplier}x)`}
-
- {name}
-
+
+
+ {name}
+
+
);
}
diff --git a/src/app/components/points/points.tsx b/src/app/components/points/points.tsx
index 39016a59..c56e37db 100644
--- a/src/app/components/points/points.tsx
+++ b/src/app/components/points/points.tsx
@@ -55,7 +55,7 @@ export function Points(): React.JSX.Element {
p.name == 'Curve')?.points}
+ totalSupply={userPoints?.useTotal}
tokenSuffix={'Use'}
/>
{
- return {
- merchant,
- dlcBTCAmount: undefined,
- };
- }),
- ];
- const selectedMerchant = merchantProofOfReserves.find(item => item.merchant.name === name);
-
- const { ethereumNetworkConfiguration } = useContext(EthereumNetworkConfigurationContext);
-
- const { data: mintBurnEvents } = useQuery({
- queryKey: [`mintBurnEvents${name}`, ethereumNetworkConfiguration.dlcBTCContract.address],
- queryFn: fetchMintBurnEventsHandler,
- });
+ const selectedMerchant = proofOfReserve?.[1].find(item => item.merchant.name === name);
+ const mintBurnEvents = merchantMintBurnEvents?.find(item => item.name === name)?.mintBurnEvents;
if (!name) return Error: No merchant name provided;
- async function fetchMintBurnEventsHandler(): Promise {
- if (!selectedMerchant || isEmpty(selectedMerchant?.merchant.addresses)) return [];
- const detailedEvents: DetailedEvent[] = (
- await Promise.all(
- selectedMerchant.merchant.addresses.map(async address => {
- return await fetchMintBurnEvents(
- ethereumNetworkConfiguration.dlcBTCContract,
- ethereumNetworkConfiguration.httpURL,
- address
- );
- })
- )
- ).flat();
-
- return detailedEvents.map((event, index) => {
- return {
- id: index,
- orderBook: selectedMerchant.merchant.addresses
- .map(address => address.toLowerCase())
- .includes(event.from.toLowerCase())
- ? 'REDEEM'
- : 'MINT',
- amount: event.value,
- inUSD: 'TODO', //TODO: calculate usd value at the time of mint
- txHash: event.txHash,
- date: new Date(event.timestamp * 1000).toDateString(),
- };
- });
- }
-
return (
;
- const { orderBook, amount, txHash, date } = merchantFocusTableItem;
-
- const { ethereumNetworkConfiguration } = useContext(EthereumNetworkConfigurationContext);
+ const {
+ dlcBTCAmount,
+ txHash,
+ date,
+ isMint,
+ chain: eventChain,
+ } = formatEvent(merchantFocusTableItem);
- const renderAmount = () => {
- const unshiftedValue = unshiftValue(amount);
- return orderBook === 'REDEEM' ? -unshiftedValue : unshiftedValue;
- };
+ const ethereumNetwork = findEthereumNetworkByName(eventChain);
return (
-
- {orderBook}
-
-
+
+
+ {isMint ? 'MINT' : 'REDEEM'}
+
+
+
- {renderAmount()}
+ {unshiftValue(dlcBTCAmount)}
{/* add back the USD calculation later and adjus the width accordingly */}
{/*
{inUSD}
*/}
-
- window.open(
- `${ethereumNetworkConfiguration.ethereumExplorerAPIURL}/tx/${txHash}`,
- '_blank'
- )
- }
- cursor={'pointer'}
- textDecoration={'underline'}
- >
- {truncateAddress(txHash)}
-
-
- {date}
-
+
+
+ window.open(`${ethereumNetwork.blockExplorers?.default.url}/tx/${txHash}`, '_blank')
+ }
+ cursor={'pointer'}
+ textDecoration={'underline'}
+ >
+ {truncateAddress(txHash)}
+
+
+
+
+ {ethereumNetwork.name}
+
+
+
+
+ {date}
+
+
);
}
diff --git a/src/app/components/proof-of-reserve/components/merchant-table/merchant-details-table.tsx b/src/app/components/proof-of-reserve/components/merchant-table/merchant-details-table.tsx
index 1ab78b69..0609d692 100644
--- a/src/app/components/proof-of-reserve/components/merchant-table/merchant-details-table.tsx
+++ b/src/app/components/proof-of-reserve/components/merchant-table/merchant-details-table.tsx
@@ -16,11 +16,12 @@ export function MerchantDetailsTable({ items }: MerchantDetailsTableProps): Reac
return (
- Order Book
- Amount
+ Order Book
+ Amount
{/* in USD */}
- Transaction
- Date
+ Transaction
+ Chain
+ Date
{items?.length === 0 && (
diff --git a/src/app/components/proof-of-reserve/proof-of-reserve.tsx b/src/app/components/proof-of-reserve/proof-of-reserve.tsx
index 5ef1f002..2abe1358 100644
--- a/src/app/components/proof-of-reserve/proof-of-reserve.tsx
+++ b/src/app/components/proof-of-reserve/proof-of-reserve.tsx
@@ -1,16 +1,10 @@
import { useContext } from 'react';
import { Divider, HStack, Text } from '@chakra-ui/react';
-import { ProtocolHistoryTableItemProps } from '@components/protocol-history-table/components/protocol-history-table-item';
import { ProtocolHistoryTable } from '@components/protocol-history-table/protocol-history-table';
-import { fetchMintBurnEvents } from '@functions/ethereum.functions';
import { Merchant } from '@models/merchant';
import { bitcoin, dlcBTC } from '@models/token';
-import { EthereumNetworkConfigurationContext } from '@providers/ethereum-network-configuration.provider';
import { ProofOfReserveContext } from '@providers/proof-of-reserve-context-provider';
-import { useQuery } from '@tanstack/react-query';
-
-import { BURN_ADDRESS } from '@shared/constants/ethereum.constants';
import { MerchantTableHeader } from './components/merchant-table/components/merchant-table-header';
import { MerchantTableItem } from './components/merchant-table/components/merchant-table-item';
@@ -21,7 +15,8 @@ import { TokenStatsBoardTVL } from './components/token-stats-board/components/to
import { TokenStatsBoardLayout } from './components/token-stats-board/token-stats-board.layout';
export function ProofOfReserve(): React.JSX.Element {
- const { proofOfReserve, totalSupply, bitcoinPrice } = useContext(ProofOfReserveContext);
+ const { proofOfReserve, totalSupply, bitcoinPrice, allMintBurnEvents } =
+ useContext(ProofOfReserveContext);
const [proofOfReserveSum, merchantProofOfReserves] = proofOfReserve || [
undefined,
@@ -32,31 +27,6 @@ export function ProofOfReserve(): React.JSX.Element {
};
}),
];
- const { ethereumNetworkConfiguration } = useContext(EthereumNetworkConfigurationContext);
-
- const { data: allMintBurnEvents } = useQuery({
- queryKey: ['allMintBurnEvents', ethereumNetworkConfiguration.dlcBTCContract.address],
- queryFn: fetchMintBurnEventsHandler,
- });
-
- async function fetchMintBurnEventsHandler(): Promise {
- const detailedEvents = await fetchMintBurnEvents(
- ethereumNetworkConfiguration.dlcBTCContract,
- ethereumNetworkConfiguration.httpURL,
- undefined,
- 10
- );
- return detailedEvents.map((event, index) => {
- const isMint = event.from.toLowerCase() === BURN_ADDRESS.toLowerCase();
- return {
- id: index,
- dlcBTCAmount: isMint ? event.value : event.value * -1,
- merchant: isMint ? event.to : event.from,
- txHash: event.txHash,
- date: new Date(event.timestamp * 1000).toDateString(),
- };
- });
- }
return (
diff --git a/src/app/components/protocol-history-table/components/protocol-history-table-item.tsx b/src/app/components/protocol-history-table/components/protocol-history-table-item.tsx
index 4516272f..7a81fde4 100644
--- a/src/app/components/protocol-history-table/components/protocol-history-table-item.tsx
+++ b/src/app/components/protocol-history-table/components/protocol-history-table-item.tsx
@@ -1,33 +1,40 @@
/* eslint-disable */
import { HStack, Image, Text } from '@chakra-ui/react';
import { CustomSkeleton } from '@components/custom-skeleton/custom-skeleton';
+import { DetailedEvent } from '@models/ethereum-models';
import { truncateAddress, unshiftValue } from 'dlc-btc-lib/utilities';
-export interface ProtocolHistoryTableItemProps {
- id: number;
- merchant: string;
- dlcBTCAmount: number;
- txHash: string;
- date: string;
-}
+import { findEthereumNetworkByName, formatEvent } from '@shared/utils';
export function ProtocolHistoryTableItem(
- protocolHistoryTableItem: ProtocolHistoryTableItemProps
+ protocolHistoryTableItem: DetailedEvent
): React.JSX.Element {
if (!protocolHistoryTableItem) return ;
- const { merchant, dlcBTCAmount, txHash, date } = protocolHistoryTableItem;
+ const {
+ merchant,
+ dlcBTCAmount,
+ txHash,
+ date,
+ isMint,
+ chain: eventChain,
+ } = formatEvent(protocolHistoryTableItem);
+
+ const ethereumNetwork = findEthereumNetworkByName(eventChain);
+
+ console.log('dlcBTCAmount', dlcBTCAmount);
return (
= 0 ? 'table.background.green' : 'table.background.red'}
+ bg={isMint ? 'table.background.green' : 'table.background.red'}
blendMode={'screen'}
border={'1px solid'}
borderRadius={'md'}
borderColor={'border.white.01'}
+ justifyContent={'space-between'}
>
@@ -35,15 +42,29 @@ export function ProtocolHistoryTableItem(
{unshiftValue(dlcBTCAmount)}
-
- {truncateAddress(merchant)}
-
-
- {truncateAddress(txHash)}
-
-
- {date}
-
+
+
+ {truncateAddress(merchant)}
+
+
+
+
+ window.open(`${ethereumNetwork.blockExplorers?.default.url}/tx/${txHash}`, '_blank')
+ }
+ cursor={'pointer'}
+ textDecoration={'underline'}
+ >
+ {truncateAddress(txHash)}
+
+
+
+
+ {date}
+
+
);
}
diff --git a/src/app/components/protocol-history-table/protocol-history-table.tsx b/src/app/components/protocol-history-table/protocol-history-table.tsx
index 5af63923..dbbbb505 100644
--- a/src/app/components/protocol-history-table/protocol-history-table.tsx
+++ b/src/app/components/protocol-history-table/protocol-history-table.tsx
@@ -16,9 +16,9 @@ export function ProtocolHistoryTable({ items }: ProtocolHistoryTableProps): Reac
Order Book
- Merchant
+ Merchant
Transaction
- Date
+ Date
diff --git a/src/app/functions/ethereum.functions.ts b/src/app/functions/ethereum.functions.ts
deleted file mode 100644
index e9d17f0a..00000000
--- a/src/app/functions/ethereum.functions.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { DetailedEvent } from '@models/ethereum-models';
-import { Contract } from 'ethers';
-
-export async function fetchMintBurnEvents(
- dlcBTCContract: Contract,
- rpcEndpoint: string,
- ethreumAddress?: string,
- lastN?: number
-): Promise {
- const contractAddress = dlcBTCContract.address;
-
- const req = await fetch(
- `/.netlify/functions/fetch-mint-burn-events?providerURL=${rpcEndpoint}&contractAddress=${contractAddress}${ethreumAddress ? `&userAddress=${ethreumAddress}` : ''}&lastN=${lastN}`
- );
-
- if (!req.ok) {
- throw new Error(`HTTP error! status: ${req.status}`);
- }
-
- const events = await req.json();
- const detailedEvents: DetailedEvent[] = events.detailedEvents;
-
- return detailedEvents;
-}
diff --git a/src/app/hooks/use-mint-burn-events.ts b/src/app/hooks/use-mint-burn-events.ts
new file mode 100644
index 00000000..b9cfdbdb
--- /dev/null
+++ b/src/app/hooks/use-mint-burn-events.ts
@@ -0,0 +1,77 @@
+import { DetailedEvent } from '@models/ethereum-models';
+import { Merchant } from '@models/merchant';
+import { useQuery } from '@tanstack/react-query';
+
+import { MINT_BURN_EVENTS_API_URL } from '@shared/constants/api.constants';
+
+interface UseMintBurnEventsReturnType {
+ allMintBurnEvents: DetailedEvent[] | undefined;
+ merchantMintBurnEvents: { name: string; mintBurnEvents: DetailedEvent[] }[] | undefined;
+}
+
+export function useMintBurnEvents(): UseMintBurnEventsReturnType {
+ async function fetchMintBurnEvents(ethereumAddress: string): Promise {
+ try {
+ const response = await fetch(
+ `${MINT_BURN_EVENTS_API_URL}/${appConfiguration.appEnvironment}/${ethereumAddress}`
+ );
+
+ if (!response.ok) {
+ throw new Error(`Error fetching mint burn events`);
+ }
+
+ return await response.json();
+ } catch (error) {
+ console.error(`Error fetching mint burn events`, error);
+ return [];
+ }
+ }
+
+ async function fetchAllMintBurnEvents(): Promise {
+ try {
+ const mintBurnEvents = await Promise.all(
+ appConfiguration.merchants.map(async (merchant: Merchant) => {
+ const allMerchantMinBurnEvents = await Promise.all(
+ merchant.addresses.map(async address => {
+ return await fetchMintBurnEvents(address);
+ })
+ );
+
+ const sortedAllMerchantMinBurnEvents = allMerchantMinBurnEvents
+ .flat()
+ .sort((a: DetailedEvent, b: DetailedEvent) => {
+ return b.timestamp - a.timestamp;
+ });
+
+ return {
+ name: merchant.name,
+ mintBurnEvents: sortedAllMerchantMinBurnEvents,
+ };
+ })
+ );
+
+ const allMintBurnEvents = mintBurnEvents
+ .map(merchant => merchant.mintBurnEvents)
+ .flat()
+ .sort((a, b) => b.timestamp - a.timestamp);
+
+ return {
+ allMintBurnEvents,
+ merchantMintBurnEvents: mintBurnEvents,
+ };
+ } catch (error) {
+ console.error(`Error fetching mint burn events`, error);
+ return undefined;
+ }
+ }
+
+ const { data: mintBurnEvents } = useQuery({
+ queryKey: ['mintBurnEvents'],
+ queryFn: fetchAllMintBurnEvents,
+ });
+
+ return {
+ allMintBurnEvents: mintBurnEvents?.allMintBurnEvents,
+ merchantMintBurnEvents: mintBurnEvents?.merchantMintBurnEvents,
+ };
+}
diff --git a/src/app/providers/proof-of-reserve-context-provider.tsx b/src/app/providers/proof-of-reserve-context-provider.tsx
index cb4e0c1c..f1a7e6a4 100644
--- a/src/app/providers/proof-of-reserve-context-provider.tsx
+++ b/src/app/providers/proof-of-reserve-context-provider.tsx
@@ -1,27 +1,34 @@
import { createContext } from 'react';
import { useBitcoinPrice } from '@hooks/use-bitcoin-price';
+import { useMintBurnEvents } from '@hooks/use-mint-burn-events';
import { useProofOfReserve } from '@hooks/use-proof-of-reserve';
import { useTotalSupply } from '@hooks/use-total-supply';
import { HasChildren } from '@models/has-children';
import { MerchantProofOfReserve } from '@models/merchant';
+import { DetailedEvent } from 'dlc-btc-lib/models';
interface ProofOfReserveContextProviderType {
proofOfReserve: [number | undefined, MerchantProofOfReserve[]] | undefined;
totalSupply: number | undefined;
bitcoinPrice: number | undefined;
+ allMintBurnEvents: DetailedEvent[] | undefined;
+ merchantMintBurnEvents: { name: string; mintBurnEvents: DetailedEvent[] }[] | undefined;
}
export const ProofOfReserveContext = createContext({
proofOfReserve: undefined,
totalSupply: undefined,
bitcoinPrice: undefined,
+ allMintBurnEvents: undefined,
+ merchantMintBurnEvents: undefined,
});
export function ProofOfReserveContextProvider({ children }: HasChildren): React.JSX.Element {
const { proofOfReserve } = useProofOfReserve();
const { totalSupply } = useTotalSupply();
const { bitcoinPrice } = useBitcoinPrice();
+ const { allMintBurnEvents, merchantMintBurnEvents } = useMintBurnEvents();
return (
{children}
diff --git a/src/shared/constants/api.constants.ts b/src/shared/constants/api.constants.ts
index cda15b30..d07361c8 100644
--- a/src/shared/constants/api.constants.ts
+++ b/src/shared/constants/api.constants.ts
@@ -1,4 +1,5 @@
const API_URL = 'https://api.dlc.link';
export const POINTS_API_URL = `${API_URL}/points`;
export const PROOF_OF_RESERVE_API_URL = `${API_URL}/proof-of-reserve`;
+export const MINT_BURN_EVENTS_API_URL = `${API_URL}/mint-burn-events`;
export const TOTAL_SUPPLY_API_URL = `${API_URL}/dlcbtc/total-supply`;
diff --git a/src/shared/constants/ethereum.constants.ts b/src/shared/constants/ethereum.constants.ts
index 2c2e49bf..0ce0779d 100644
--- a/src/shared/constants/ethereum.constants.ts
+++ b/src/shared/constants/ethereum.constants.ts
@@ -9,7 +9,6 @@ import {
sepolia,
} from 'viem/chains';
-export const BURN_ADDRESS = '0x0000000000000000000000000000000000000000';
export const SUPPORTED_VIEM_CHAINS: Chain[] = [
mainnet,
sepolia,
diff --git a/src/shared/models/ethereum-models.ts b/src/shared/models/ethereum-models.ts
index 3c0fc565..4c72a60f 100644
--- a/src/shared/models/ethereum-models.ts
+++ b/src/shared/models/ethereum-models.ts
@@ -27,4 +27,16 @@ export interface DetailedEvent {
value: number;
timestamp: number;
txHash: string;
+ isCCIP: boolean;
+ chain: string;
+ eventType: 'mint' | 'burn' | 'transfer';
+}
+export interface FormattedEvent {
+ merchant: string;
+ dlcBTCAmount: number;
+ txHash: string;
+ date: string;
+ chain: string;
+ isMint: boolean;
+ isCCIP: boolean;
}
diff --git a/src/shared/models/points.models.ts b/src/shared/models/points.models.ts
index ca8811be..083e99d5 100644
--- a/src/shared/models/points.models.ts
+++ b/src/shared/models/points.models.ts
@@ -7,5 +7,6 @@ export interface ProtocolRewards {
export interface PointsData {
total: number;
+ useTotal: number;
protocols: ProtocolRewards[];
}
diff --git a/src/shared/utils.ts b/src/shared/utils.ts
index 44e04a7b..08595695 100644
--- a/src/shared/utils.ts
+++ b/src/shared/utils.ts
@@ -1,4 +1,9 @@
+import { DetailedEvent, FormattedEvent } from '@models/ethereum-models';
import Decimal from 'decimal.js';
+import { supportedEthereumNetworks } from 'dlc-btc-lib/constants';
+import { Chain } from 'viem';
+
+import { SUPPORTED_VIEM_CHAINS } from './constants/ethereum.constants';
export function formatNumber(value: number): string {
if (value < 10000) {
@@ -13,3 +18,32 @@ export function formatNumber(value: number): string {
return new Decimal(value).dividedBy(1000000000000).toFixed(1).replace(/\.0$/, '') + 'T';
}
}
+
+export function findEthereumNetworkByName(ethereumNetworkName: string): Chain {
+ const ethereumNetworkID = supportedEthereumNetworks.find(
+ network => network.name.toLowerCase() === ethereumNetworkName
+ )?.id;
+ if (!ethereumNetworkID) {
+ throw new Error(`Could not find Ethereum network with name ${ethereumNetworkName}`);
+ }
+ const chain = SUPPORTED_VIEM_CHAINS.find(chain => chain.id === parseInt(ethereumNetworkID));
+
+ if (!chain) {
+ throw new Error(`Could not find chain with id ${ethereumNetworkID}`);
+ }
+
+ return chain;
+}
+
+export function formatEvent(event: DetailedEvent): FormattedEvent {
+ const isMint = event.eventType === 'mint';
+ return {
+ dlcBTCAmount: isMint ? event.value : -event.value,
+ merchant: isMint ? event.to : event.from,
+ txHash: event.txHash,
+ date: new Date(event.timestamp * 1000).toDateString(),
+ isMint,
+ chain: event.chain,
+ isCCIP: event.isCCIP,
+ };
+}