diff --git a/apps/dapp/src/modules/auction/hooks/use-decrypt-auction.ts b/apps/dapp/src/modules/auction/hooks/use-decrypt-auction.ts index 12050150..2a573325 100644 --- a/apps/dapp/src/modules/auction/hooks/use-decrypt-auction.ts +++ b/apps/dapp/src/modules/auction/hooks/use-decrypt-auction.ts @@ -4,7 +4,7 @@ import { useQueryClient, } from "@tanstack/react-query"; import type { Auction, AuctionId, BatchAuction } from "@axis-finance/types"; -import { useEffect, useRef } from "react"; +import { useEffect } from "react"; import { useSimulateContract, useWaitForTransactionReceipt, @@ -19,6 +19,9 @@ import { optimisticUpdate, } from "modules/auction/utils/optimistic"; import { cloakClient } from "utils/cloak-client"; +import { useHasPrivateKey } from "./use-has-private-key"; + +const DECRYPT_NUM = 100; // TODO determine limit on amount per chain /** Used to manage decrypting the next set of bids */ export const useDecryptBids = (auction: BatchAuction) => { @@ -29,6 +32,15 @@ export const useDecryptBids = (auction: BatchAuction) => { const queryKey = getAuctionQueryKey(auction.id as AuctionId); const params = deriveParamsFromAuction(auction); + + const { data, ...hasPKQuery } = useHasPrivateKey({ + lotId: auction.lotId, + chainId: auction.chainId, + address: emp.address, + }); + + const isPKSubmitted = hasPKQuery.isSuccess && data; + const privateKeyQuery = useQuery({ queryKey: ["get_private_key", auction.id, auctionHouse.address, params], queryFn: () => @@ -38,13 +50,12 @@ export const useDecryptBids = (auction: BatchAuction) => { }), placeholderData: keepPreviousData, enabled: - auction.bids.length === 0 || - auction.bids.length - auction.bidsRefunded.length > - auction.bidsDecrypted.length, + (auction.bids.length === 0 || + auction.bids.length - auction.bidsRefunded.length > + auction.bidsDecrypted.length) && + !isPKSubmitted, }); - const DECRYPT_NUM = 100; // TODO determine limit on amount per chain - const hintsQuery = useQuery({ queryKey: ["hints", auction.id, auctionHouse.address, params, DECRYPT_NUM], queryFn: () => @@ -57,54 +68,87 @@ export const useDecryptBids = (auction: BatchAuction) => { const hints = hintsQuery.data as Hex[]; - //Send bids to the contract for decryption - const { data: decryptCall, ...decryptCallQuery } = useSimulateContract({ + //Submit private key and some bids to be decrypted + const { data: submitPKCall, ...submitPKCallQuery } = useSimulateContract({ address: emp.address, abi: emp.abi, functionName: "submitPrivateKey", chainId: auction.chainId, args: [ BigInt(auction.lotId), - BigInt(privateKeyQuery.data ?? 0), + BigInt(privateKeyQuery.data ?? 0n), BigInt(hints?.length ?? 0), hints, ], - query: { enabled: privateKeyQuery.isSuccess }, + query: { enabled: !isPKSubmitted && privateKeyQuery.isSuccess }, + }); + + const submitPk = useWriteContract(); + const submitPkReceipt = useWaitForTransactionReceipt({ hash: submitPk.data }); + + //Send bids to the contract for decryption + const { data: decryptCall, ...decryptCallQuery } = useSimulateContract({ + address: emp.address, + abi: emp.abi, + functionName: "decryptAndSortBids", + chainId: auction.chainId, + args: [BigInt(auction.lotId), BigInt(hints?.length ?? 0), hints], + query: { enabled: isPKSubmitted && privateKeyQuery.isSuccess }, }); const decrypt = useWriteContract(); const decryptReceipt = useWaitForTransactionReceipt({ hash: decrypt.data }); - const handleDecryption = () => decrypt.writeContract(decryptCall!.request); + const handleDecryption = () => { + const onSuccess = () => hintsQuery.refetch(); + isPKSubmitted + ? decrypt.writeContract(decryptCall!.request, { onSuccess }) + : submitPk.writeContract(submitPKCall!.request, { onSuccess }); + }; const queryClient = useQueryClient(); - const decryptTxnSucceeded = useRef(false); useEffect(() => { - if (decryptTxnSucceeded.current || !decryptReceipt.isSuccess) { - return; + if ( + !isPKSubmitted && + submitPkReceipt.isSuccess && + !hasPKQuery.isRefetching + ) { + hasPKQuery.refetch(); } + }, [isPKSubmitted, submitPkReceipt.isSuccess]); - decryptTxnSucceeded.current = true; - - if (!hintsQuery.isRefetching) { - hintsQuery.refetch(); + useEffect(() => { + const totalBidsRemaining = + (auction.formatted?.totalBids ?? 0) - + (auction.formatted?.totalBidsClaimed ?? 0); + + if (decryptReceipt.isSuccess || submitPkReceipt.isSuccess) { + /** Update bids to decrypted to show the correct progress*/ + if ((auction.formatted?.totalBidsDecrypted ?? 0) < totalBidsRemaining) { + optimisticUpdate( + queryClient, + queryKey, + (cachedAuction: GetBatchAuctionLotQuery) => + auctionCache.updateDecryptedBids(cachedAuction, DECRYPT_NUM), + ); + + return; + } + /** Optimistically update the auction status to "decrypted" */ + optimisticUpdate( + queryClient, + queryKey, + (cachedAuction: GetBatchAuctionLotQuery) => + auctionCache.updateStatus(cachedAuction, "decrypted"), + ); } - - /** Optimistically update the auction status to "decrypted" */ - optimisticUpdate( - queryClient, - queryKey, - (cachedAuction: GetBatchAuctionLotQuery) => - auctionCache.updateStatus(cachedAuction, "decrypted"), - ); // eslint-disable-next-line react-hooks/exhaustive-deps }, [ + submitPkReceipt.isSuccess, + submitPkReceipt.isRefetching, decryptReceipt.isSuccess, - hintsQuery.isRefetching, - hintsQuery.refetch, - queryClient, - queryKey, + decryptReceipt.isRefetching, ]); const error = [ @@ -112,15 +156,24 @@ export const useDecryptBids = (auction: BatchAuction) => { decrypt, decryptCallQuery, decryptReceipt, + submitPKCallQuery, + submitPk, + submitPkReceipt, ].find((tx) => tx.isError)?.error; + const isWaiting = + submitPk.isPending || + submitPkReceipt.isLoading || + decrypt.isPending || + decryptReceipt.isLoading; + return { nextBids: privateKeyQuery, - decryptTx: decrypt, - decryptReceipt, + decryptTx: isPKSubmitted ? decrypt : submitPk, + decryptReceipt: isPKSubmitted ? decryptReceipt : submitPkReceipt, handleDecryption, error, - isWaiting: decrypt.isPending || decryptReceipt.isLoading, + isWaiting, }; }; diff --git a/apps/dapp/src/modules/auction/hooks/use-has-private-key.ts b/apps/dapp/src/modules/auction/hooks/use-has-private-key.ts new file mode 100644 index 00000000..0ad55b36 --- /dev/null +++ b/apps/dapp/src/modules/auction/hooks/use-has-private-key.ts @@ -0,0 +1,33 @@ +import { abis } from "@axis-finance/abis"; +import { Address } from "viem"; +import { useReadContract } from "wagmi"; + +type UseHasPrivateKeyParameters = { + address: Address; + lotId: string; + chainId: number; + enabled?: boolean; +}; + +export function useHasPrivateKey({ + lotId, + address, + chainId, + enabled, +}: UseHasPrivateKeyParameters) { + const { data, ...query } = useReadContract({ + address, + chainId, + abi: abis.encryptedMarginalPrice, + functionName: "auctionData", + args: [BigInt(lotId)], + query: { enabled }, + }); + + const privateKey = data?.[9] !== 0n; + + return { + data: query.isSuccess && !!privateKey, + ...query, + }; +} diff --git a/apps/dapp/src/modules/auction/utils/optimistic/auction/index.ts b/apps/dapp/src/modules/auction/utils/optimistic/auction/index.ts index 56dd3af7..dd857e9b 100644 --- a/apps/dapp/src/modules/auction/utils/optimistic/auction/index.ts +++ b/apps/dapp/src/modules/auction/utils/optimistic/auction/index.ts @@ -1,3 +1,4 @@ export * from "./insert-bid"; export * from "./update-status"; +export * from "./update-bids-decrypted"; export * from "./create"; diff --git a/apps/dapp/src/modules/auction/utils/optimistic/auction/update-bids-decrypted.ts b/apps/dapp/src/modules/auction/utils/optimistic/auction/update-bids-decrypted.ts new file mode 100644 index 00000000..af4bc383 --- /dev/null +++ b/apps/dapp/src/modules/auction/utils/optimistic/auction/update-bids-decrypted.ts @@ -0,0 +1,27 @@ +import type { GetBatchAuctionLotQuery } from "@axis-finance/subgraph-client"; + +const updateDecryptedBids = ( + cachedAuction: GetBatchAuctionLotQuery, + numOfBids: number, +): GetBatchAuctionLotQuery => { + const bids = Array.from(cachedAuction.batchAuctionLot?.bids ?? []); + let updateCount = 0; + + for (let i = 0; i < bids.length && updateCount < numOfBids; i++) { + if (bids[i].status === "decrypted") { + continue; + } + bids[i].status = "decrypted"; + updateCount++; + } + + return { + ...cachedAuction, + batchAuctionLot: { + ...cachedAuction.batchAuctionLot!, + bids, + }, + } satisfies GetBatchAuctionLotQuery; +}; + +export { updateDecryptedBids };