Skip to content

Commit

Permalink
Added end/withdraw all auctions button (#1630)
Browse files Browse the repository at this point in the history
  • Loading branch information
Valentine1898 authored Aug 7, 2024
1 parent afaaee9 commit 6094b6b
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-parents-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'minifront': minor
---

Add a "claim all" button to the auctions list
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { useAuctionInfos } from '../../../state/swap/dutch-auction';
import { AddressIndex } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb';
import { Button } from '@repo/ui/components/ui/button';
import { AllSlices } from '../../../state';
import { useStoreShallow } from '../../../utils/use-store-shallow.ts';
import { filterWithLimit } from './helpers.ts';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@repo/ui/components/ui/tooltip';
import { AuctionInfo } from '../../../fetchers/auction-infos.ts';

const endOrWithdrawAllButtonSelector = (state: AllSlices) => ({
endAllAuctions: state.swap.dutchAuction.endAllAuctions,
withdrawAllAuctions: state.swap.dutchAuction.withdrawAllAuctions,
});

export interface AuctionsBatch {
auctions: AuctionInfo[];
source: AddressIndex;
}

// Assemble batch auctions for end or withdrawal.
// All auctions in the batch will have the same 'AddressIndex'
export const assembleAuctionBatch = (
auctions: AuctionInfo[],
filteredSeqNumber: bigint,
batchLimit: number,
): AuctionsBatch => {
const filteredBySeqAuctions: AuctionInfo[] = auctions.filter(
a => a.localSeqNum === filteredSeqNumber,
);
// Get the address index of the first auction in the list and filter other auctions with this address index
const firstFoundAddressIndex = filteredBySeqAuctions[0]?.addressIndex;

const filteredBySeqAndAddressIndexAuctions = filterWithLimit(
filteredBySeqAuctions,
a => a.addressIndex.equals(firstFoundAddressIndex),
batchLimit,
);
return { auctions: filteredBySeqAndAddressIndexAuctions, source: firstFoundAddressIndex! };
};

export const EndOrWithdrawAllButton = () => {
const { endAllAuctions, withdrawAllAuctions } = useStoreShallow(endOrWithdrawAllButtonSelector);
const { data } = useAuctionInfos();

if (!data?.length) {
return null;
}
if (data.some(a => a.localSeqNum === 0n)) {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger
onClick={() => {
// Chain has a transaction size limit, so we can add at most a batch of 48 auctions in a single transaction
// see https://github.com/penumbra-zone/web/issues/1166#issuecomment-2263550249
const auctionBatch = assembleAuctionBatch(data, 0n, 48);

void endAllAuctions(
auctionBatch.auctions,
// TODO Should use the index of the selected account after the account selector for the auction is implemented
auctionBatch.source,
);
}}
aria-label='End all open auctions, with a limit of 48 auctions per transaction'
>
<div className='w-[85px] shrink-0'>
<Button size='sm' variant='secondary' className='w-full'>
End all
</Button>
</div>
</TooltipTrigger>
<TooltipContent>
End all open auctions, with a limit of 48 auctions per transaction
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

if (data.some(a => a.localSeqNum === 1n)) {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger
onClick={() => {
// Chain has a transaction size limit, so we can add at most a batch of 48 auctions in a single transaction
// see https://github.com/penumbra-zone/web/issues/1166#issuecomment-2263550249
const auctionBatch = assembleAuctionBatch(data, 1n, 48);
void withdrawAllAuctions(
auctionBatch.auctions,
// TODO Should use the index of the selected account after the account selector for the auction is implemented
auctionBatch.source,
);
}}
aria-label='Withdraw all ended auctions, with a limit of 48 auctions per transaction'
>
<div className='w-[95px] shrink-0'>
<Button size='sm' variant='secondary' className='w-full'>
Withdraw all
</Button>
</div>
</TooltipTrigger>
<TooltipContent>
Withdraw all ended auctions, with a limit of 48 auctions per transaction
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

return null;
};
20 changes: 20 additions & 0 deletions apps/minifront/src/components/swap/auction-list/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
import { AuctionInfo } from '../../../fetchers/auction-infos';

export const filterWithLimit = <T>(
array: T[],
predicate: (value: T) => boolean,
limit: number,
): T[] => {
const result: T[] = [];
let count = 0;

for (const item of array) {
if (predicate(item)) {
result.push(item);
count++;
if (count >= limit) {
break;
}
}
}
return result;
};

export const byStartHeightAscending = (a: AuctionInfo, b: AuctionInfo) => {
if (!a.auction.description?.startHeight || !b.auction.description?.startHeight) {
return 0;
Expand Down
2 changes: 2 additions & 0 deletions apps/minifront/src/components/swap/auction-list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useStatus } from '../../../state/status';
import { byStartHeightAscending } from './helpers';
import { Filters } from './filters';
import { AddressIndex } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb.js';
import { EndOrWithdrawAllButton } from './end-or-withdraw-all-button.tsx';

const auctionListSelector = (state: AllSlices) => ({
endAuction: state.swap.dutchAuction.endAuction,
Expand Down Expand Up @@ -66,6 +67,7 @@ export const AuctionList = () => {
{!!auctionInfos.data?.length && <QueryLatestStateButton />}

<Filters />
<EndOrWithdrawAllButton />
</motion.div>
</div>

Expand Down
33 changes: 31 additions & 2 deletions apps/minifront/src/state/swap/dutch-auction/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { TransactionPlannerRequest } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb.js';
import {
TransactionPlannerRequest,
TransactionPlannerRequest_ActionDutchAuctionWithdraw,
TransactionPlannerRequest_ActionDutchAuctionEnd,
} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb.js';
import { AllSlices, SliceCreator, useStore } from '../..';
import { planBuildBroadcast } from '../../helpers';
import { assembleScheduleRequest } from './assemble-schedule-request';
Expand Down Expand Up @@ -40,6 +44,8 @@ interface Actions {
currentSeqNum: bigint,
addressIndex: AddressIndex,
) => Promise<void>;
endAllAuctions: (auctions: AuctionInfo[], addressIndex: AddressIndex) => Promise<void>;
withdrawAllAuctions: (auctions: AuctionInfo[], addressIndex: AddressIndex) => Promise<void>;
reset: VoidFunction;
setFilter: (filter: Filter) => void;
estimate: () => Promise<void>;
Expand Down Expand Up @@ -199,7 +205,30 @@ export const createDutchAuctionSlice = (): SliceCreator<DutchAuctionSlice> => (s
get().swap.dutchAuction.auctionInfos.revalidate();
get().shared.balancesResponses.revalidate();
},

endAllAuctions: async (auctions: AuctionInfo[], addressIndex: AddressIndex) => {
const req = new TransactionPlannerRequest({
dutchAuctionEndActions: auctions.map(
au => new TransactionPlannerRequest_ActionDutchAuctionEnd({ auctionId: au.id }),
),
source: addressIndex,
});
await planBuildBroadcast('dutchAuctionEnd', req);
get().swap.dutchAuction.auctionInfos.revalidate();
},
withdrawAllAuctions: async (auctions: AuctionInfo[], addressIndex: AddressIndex) => {
const req = new TransactionPlannerRequest({
dutchAuctionWithdrawActions: auctions.map(
au =>
new TransactionPlannerRequest_ActionDutchAuctionWithdraw({
auctionId: au.id,
seq: au.localSeqNum + 1n,
}),
),
source: addressIndex,
});
await planBuildBroadcast('dutchAuctionWithdraw', req);
get().swap.dutchAuction.auctionInfos.revalidate();
},
reset: () =>
set(({ swap }) => {
swap.dutchAuction = {
Expand Down

0 comments on commit 6094b6b

Please sign in to comment.