diff --git a/src/components/DepositsTable/DepositsTable.tsx b/src/components/DepositsTable/DepositsTable.tsx
index 0caceea7a..596dea673 100644
--- a/src/components/DepositsTable/DepositsTable.tsx
+++ b/src/components/DepositsTable/DepositsTable.tsx
@@ -4,7 +4,7 @@ import { HeadRow, headerCells, ColumnKey } from "./HeadRow";
import { DataRow } from "./DataRow";
import { Deposit } from "hooks/useDeposits";
-type Props = {
+export type Props = {
disabledColumns?: ColumnKey[];
onClickSpeedUp?: () => void;
deposits: Deposit[];
diff --git a/src/components/DepositsTable/PaginatedDepositsTable.tsx b/src/components/DepositsTable/PaginatedDepositsTable.tsx
new file mode 100644
index 000000000..ea6c1ca18
--- /dev/null
+++ b/src/components/DepositsTable/PaginatedDepositsTable.tsx
@@ -0,0 +1,57 @@
+import styled from "@emotion/styled";
+
+import Pagination from "components/Pagination";
+import { usePagination } from "hooks/usePagination";
+import { DepositsTable, Props as DepositsTableProps } from "./DepositsTable";
+
+type Props = DepositsTableProps & {
+ onPageChange: (currentPage: number) => void;
+ onPageSizeChange: (currentPageSize: number) => void;
+ totalCount: number;
+ initialPageSize?: number;
+ pageSizes?: number[];
+};
+
+const DEFAULT_PAGE_SIZES = [10, 25, 50];
+
+export function PaginatedDepositsTable({
+ onPageChange,
+ onPageSizeChange,
+ totalCount,
+ initialPageSize = DEFAULT_PAGE_SIZES[0],
+ pageSizes = DEFAULT_PAGE_SIZES,
+ ...depositsTableProps
+}: Props) {
+ const { pageSize, currentPage, setCurrentPage, setPageSize, paginateValues } =
+ usePagination(totalCount, { initialPageSize });
+
+ return (
+ <>
+
+
+ {
+ setCurrentPage(newPage);
+ onPageChange(newPage);
+ }}
+ onPageSizeChange={(newPageSize) => {
+ setPageSize(newPageSize);
+ onPageSizeChange(newPageSize);
+ }}
+ pageList={paginateValues.pageList}
+ activeIndex={paginateValues.activeIndex}
+ disableBack={paginateValues.disableBack}
+ disableForward={paginateValues.disableForward}
+ hideStart={paginateValues.hideStart}
+ hideEnd={paginateValues.hideEnd}
+ lastPage={paginateValues.lastPage}
+ currentPage={currentPage}
+ pageSize={pageSize}
+ pageSizes={pageSizes}
+ />
+
+ >
+ );
+}
+
+const PaginationWrapper = styled.div``;
diff --git a/src/components/DepositsTable/index.tsx b/src/components/DepositsTable/index.tsx
index 06e80a0c1..259881db4 100644
--- a/src/components/DepositsTable/index.tsx
+++ b/src/components/DepositsTable/index.tsx
@@ -1,3 +1,4 @@
export * from "./DataRow";
export * from "./HeadRow";
export * from "./DepositsTable";
+export * from "./PaginatedDepositsTable";
diff --git a/src/hooks/usePagination.ts b/src/hooks/usePagination.ts
new file mode 100644
index 000000000..1565051f4
--- /dev/null
+++ b/src/hooks/usePagination.ts
@@ -0,0 +1,37 @@
+import { useState } from "react";
+
+import { paginate } from "components/Pagination";
+
+const DEFAULT_PAGE_SIZE = 10;
+const DEFAULT_MAX_NAVIGATION_COUNT = 5;
+
+export function usePagination(
+ totalCount: number,
+ options: Partial<{
+ maxNavigationCount: number;
+ initialPageSize: number;
+ }> = {}
+) {
+ const { maxNavigationCount = DEFAULT_MAX_NAVIGATION_COUNT, initialPageSize } =
+ options;
+
+ const [currentPage, setCurrentPage] = useState(0);
+ const [pageSize, setPageSize] = useState(
+ initialPageSize || DEFAULT_PAGE_SIZE
+ );
+
+ const paginateValues = paginate({
+ elementCount: totalCount,
+ currentPage,
+ maxNavigationCount,
+ elementsPerPage: pageSize,
+ });
+
+ return {
+ paginateValues,
+ currentPage,
+ setPageSize,
+ setCurrentPage,
+ pageSize,
+ };
+}
diff --git a/src/stories/PaginatedDepositsTable.stories.tsx b/src/stories/PaginatedDepositsTable.stories.tsx
new file mode 100644
index 000000000..7b371582a
--- /dev/null
+++ b/src/stories/PaginatedDepositsTable.stories.tsx
@@ -0,0 +1,190 @@
+import { useState } from "react";
+import type { Meta, StoryObj } from "@storybook/react";
+
+import { PaginatedDepositsTable } from "../components/DepositsTable";
+import { Deposit } from "../hooks/useDeposits";
+
+const mockedDeposits: Deposit[] = [
+ {
+ depositId: 1180880,
+ depositTime: 1698275877,
+ status: "pending",
+ filled: "0",
+ sourceChainId: 324,
+ destinationChainId: 42161,
+ assetAddr: "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
+ depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ recipientAddr: "0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A",
+ message: "0x",
+ amount: "50000000000000000",
+ depositTxHash:
+ "0x13a619b510e643d51f74f5a01f98c16161e1d93c2db6f689478472a3f42ec7e0",
+ fillTxs: [],
+ speedUps: [],
+ depositRelayerFeePct: "4952678372124980",
+ initialRelayerFeePct: "4952678372124980",
+ suggestedRelayerFeePct: "4952678372124980",
+ },
+ // Fee too low, i.e. unprofitable
+ {
+ depositId: 1144678,
+ depositTime: 1696447947,
+ status: "pending",
+ filled: "0",
+ sourceChainId: 42161,
+ destinationChainId: 324,
+ assetAddr: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
+ depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ message: "0x",
+ amount: "2000000000000000000000",
+ depositTxHash:
+ "0x66a7c4e34f91325d0c17bc7bb98350e15c61166d6138a0e89e002637b36fe3e5",
+ fillTxs: [],
+ speedUps: [],
+ depositRelayerFeePct: "0",
+ initialRelayerFeePct: "0",
+ suggestedRelayerFeePct: "156172500000000000",
+ },
+ // Finalized with fill time
+ {
+ depositId: 1205910,
+ depositTime: 1698998623,
+ fillTime: 1698998623 + 99,
+ status: "filled",
+ filled: "12000000",
+ sourceChainId: 324,
+ destinationChainId: 8453,
+ assetAddr: "0x3355df6D4c9C3035724Fd0e3914dE96A5a83aaf4",
+ depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ message: "0x",
+ amount: "12000000",
+ depositTxHash:
+ "0xe8a2d8ed449a6a2fe7fa3dc24e699a951f945280c27df259a910008683b1e296",
+ fillTxs: [
+ "0x8caf6a0e38a8788f47dfad89e709f1c0854783987558af9c34d0fadb61c20941",
+ ],
+ speedUps: [],
+ depositRelayerFeePct: "24394417866666666",
+ initialRelayerFeePct: "24394417866666666",
+ suggestedRelayerFeePct: "28289667866666666",
+ },
+ // Finalized without fill time
+ {
+ depositId: 1199308,
+ depositTime: 1698831959,
+ status: "filled",
+ filled: "12000000",
+ sourceChainId: 42161,
+ destinationChainId: 8453,
+ assetAddr: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
+ depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ message: "0x",
+ amount: "12000000",
+ depositTxHash:
+ "0x4eecaeee9b6d2df9d06d249b99ce042dd16dbf7bf2fd5d0cc6938e336fdaadd3",
+ fillTxs: [
+ "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806a",
+ "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806b",
+ "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806c",
+ ],
+ speedUps: [],
+ depositRelayerFeePct: "28434751200000000",
+ initialRelayerFeePct: "28434751200000000",
+ suggestedRelayerFeePct: "28443917866666666",
+ feeBreakdown: {
+ bridgeFee: {
+ pct: "28434751200000000",
+ usd: "341217014400000000",
+ },
+ destinationGasFee: {
+ pct: "28434751200000000",
+ usd: "341217014400000000",
+ },
+ },
+ rewards: {
+ type: "referrals",
+ rate: 0.4,
+ amount: "341217014400000000",
+ usd: "341217014400000000",
+ },
+ },
+ {
+ depositId: 1199309,
+ depositTime: 1698831959,
+ status: "filled",
+ filled: "12000000",
+ sourceChainId: 42161,
+ destinationChainId: 8453,
+ assetAddr: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
+ depositorAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ recipientAddr: "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D",
+ message: "0x",
+ amount: "12000000",
+ depositTxHash:
+ "0x4eecaeee9b6d2df9d06d249b99ce042dd16dbf7bf2fd5d0cc6938e336fdaadd3",
+ fillTxs: [
+ "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806a",
+ "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806b",
+ "0xb88ad8d998f0b453c351b0415475e197847e73911bcfb41cab2ee9b0ceb4806c",
+ ],
+ speedUps: [],
+ depositRelayerFeePct: "28434751200000000",
+ initialRelayerFeePct: "28434751200000000",
+ suggestedRelayerFeePct: "28443917866666666",
+ feeBreakdown: {
+ bridgeFee: {
+ pct: "28434751200000000",
+ usd: "341217014400000000",
+ },
+ destinationGasFee: {
+ pct: "28434751200000000",
+ usd: "341217014400000000",
+ },
+ },
+ rewards: {
+ type: "referrals",
+ rate: 0.4,
+ amount: "341217014400000000",
+ usd: "341217014400000000",
+ },
+ },
+];
+
+const meta: Meta = {
+ component: PaginatedDepositsTable,
+ argTypes: {},
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+const BasicPagination = () => {
+ const [pageSize, setPageSize] = useState(1);
+ const [deposits, setDeposits] = useState(
+ mockedDeposits.slice(0, 1)
+ );
+
+ return (
+ {
+ setDeposits(mockedDeposits.slice(page, page + pageSize));
+ }}
+ onPageSizeChange={(size) => {
+ setPageSize(size);
+ setDeposits(mockedDeposits.slice(0, size));
+ }}
+ totalCount={mockedDeposits.length}
+ pageSizes={[1, 2, 3]}
+ initialPageSize={pageSize}
+ />
+ );
+};
+
+export const Default: Story = {
+ render: () => ,
+};