diff --git a/.env.example b/.env.example
index c5cde61..d50a27a 100644
--- a/.env.example
+++ b/.env.example
@@ -3,7 +3,7 @@ NEXT_PUBLIC_RPC_HOST=http://127.0.0.1:8545
COSMOS_RPC_HOST=http://127.0.0.1:1317
# Proxy
-GITHUB_API_PROXY=
+GH_API_PROXY=
# Chain info
NEXT_PUBLIC_CHAIN_ID=9000
diff --git a/.github/workflows/types-lint-license-tests.yml b/.github/workflows/types-lint-license-tests.yml
new file mode 100644
index 0000000..3d908cf
--- /dev/null
+++ b/.github/workflows/types-lint-license-tests.yml
@@ -0,0 +1,112 @@
+name: Check types, lint, license and run tests
+
+on:
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ setup:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.16.0'
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v2
+ with:
+ version: 8
+
+ - name: Install dependencies
+ run: pnpm install
+
+ - name: Cache dependencies
+ uses: actions/cache@v3
+ id: cache
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-pnpm-
+
+ test:
+ needs: setup
+ runs-on: ubuntu-latest
+ env:
+ NEXT_PUBLIC_RPC_HOST: 'http://127.0.0.1:8545'
+ NEXT_PUBLIC_ENABLED_LOGS: true
+ GH_API_PROXY: ${{ secrets.GH_API_PROXY }}
+ MOCK_COINGECKO_API: true
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20.16.0'
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 8
+ - uses: actions/cache@v3
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
+ - run: pnpm install
+ - run: pnpm test
+
+ typecheck:
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20.16.0'
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 8
+ - uses: actions/cache@v3
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
+ - run: pnpm install
+ - run: pnpm typecheck
+
+ lint:
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20.16.0'
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 8
+ - uses: actions/cache@v3
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
+ - run: pnpm install
+ - run: pnpm lint
+
+ license:
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20.16.0'
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 8
+ - uses: actions/cache@v3
+ with:
+ path: ~/.pnpm-store
+ key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
+ - run: pnpm install
+ - run: pnpm license
diff --git a/README.md b/README.md
index d1ffb15..ea34288 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
-🚧 Work in progress, not ready for production 🚧
-
Evmos Burn Auction Instant dApp
@@ -32,6 +30,8 @@ Pre-requisites:
```bash
pnpm install
+pnpm prisma:db:push
+
cp .env.example .env
# edit the .env file with your own values
```
@@ -55,7 +55,7 @@ pnpm build
### Test with a local node
-Follow the instructions described in this issue in order to run a local node with the Burn Auction module enabled: https://github.com/evmos/burn-auction-dapp/issues/5
+Follow the instructions described in this issue in order to run a local node with the Burn Auction module enabled check this [file](./docs/DEVELOP_WITH_LOCAL_NODE.md).
### Indexing Endpoints
diff --git a/package.json b/package.json
index 2ac901b..3bbe9d0 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"prepare": "husky",
"test": "vitest",
"gen:types": "cross-env NODE_OPTIONS='--experimental-import-meta-resolve' tsx ./src/utilities/registry/scripts/gen-schema-types.mts",
- "postinstall": "npm run gen:types",
+ "postinstall": "npm run gen:types && npm run prisma:generate",
"license": "node ./check-license.mjs",
"license:fix": "node ./check-license.mjs --fix",
"typecheck": "tsc --noEmit",
@@ -73,4 +73,3 @@
"vitest": "^2.0.5"
}
}
-
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2357417..4cdd49c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1538,6 +1538,10 @@ packages:
resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==}
dev: true
+ /@types/luxon@3.4.2:
+ resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
+ dev: false
+
/@types/mime@1.3.5:
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
dev: false
diff --git a/src/app/_components/AuctionDetails.tsx b/src/app/_components/AuctionDetails.tsx
index 25e559a..c1f5d44 100644
--- a/src/app/_components/AuctionDetails.tsx
+++ b/src/app/_components/AuctionDetails.tsx
@@ -9,7 +9,7 @@ import type { AuctionDetailed } from '@/types/AuctionDetailed';
import { formatUnits } from '@/utilities/formatUnits';
import { EVMOS_DECIMALS } from '@/constants';
import { ButtonLink } from '@/components/ui/ButtonLink';
-import { fetchCurrentCryptoPrice } from '@/queries/fetchCurrentCryptoPrice';
+import { Tooltip } from '@/components/ui/Tooltip';
import { AssetsTable } from './AssetsTable';
import { BiddingHistory } from './BiddingHistory';
@@ -18,12 +18,6 @@ import { Countdown } from './Countdown';
import { BiddingProgress } from './BiddingProgress';
import { DiscountChip } from './DiscountChip';
-import { EVMOS_DECIMALS } from '@/constants';
-import { ButtonLink } from '@/components/ui/ButtonLink';
-import Image from 'next/image';
-import { Tooltip } from '@/components/ui/Tooltip';
-import { fetchCurrentCryptoPrice } from '@/queries/fetchCurrentCryptoPrice';
-
export const AuctionDetails = async ({ auctionDetails }: { auctionDetails: AuctionDetailed }) => {
const { round, auction, highestBid }: AuctionDetailed = auctionDetails;
@@ -49,8 +43,6 @@ export const AuctionDetails = async ({ auctionDetails }: { auctionDetails: Aucti
timeZoneName: 'short',
});
- const evmosToUsdRate = await fetchCurrentCryptoPrice(['evmos']).then((res) => res.evmos.usd);
-
return (
@@ -63,7 +55,7 @@ export const AuctionDetails = async ({ auctionDetails }: { auctionDetails: Aucti
)}
- Auction #{Number(round.round)}
+ Auction #{Number(round.round)}
{round.isLast && (
@@ -119,12 +111,12 @@ export const AuctionDetails = async ({ auctionDetails }: { auctionDetails: Aucti
{highestBid.bidderAddress !== '0x0000000000000000000000000000000000000000' && (
-
- {highestBid.bidderAddress}
+
+ {highestBid.bidderAddress}
)}
- {round.isLast && }
+ {round.isLast && }
diff --git a/src/app/_components/BiddingForm.tsx b/src/app/_components/BiddingForm.tsx
index 55394f2..adb53e6 100644
--- a/src/app/_components/BiddingForm.tsx
+++ b/src/app/_components/BiddingForm.tsx
@@ -13,8 +13,9 @@ import { viemPublicClient } from '@/utilities/viem';
import { formatUnits } from '@/utilities/formatUnits';
import { EVMOS_DECIMALS } from '@/constants';
import { LoadingSpinner } from '@/components/ui/LoadingSpinner';
+import { Tooltip } from '@/components/ui/Tooltip';
-export const BiddingForm = ({ evmosToUsdRate }: { evmosToUsdRate: number }) => {
+export const BiddingForm = ({ evmosToUsdRate, priceError }: { evmosToUsdRate: number; priceError: boolean }) => {
const [state, send] = useMachine(biddingStateMachine);
dappstore.onAccountsChange((accounts) => send({ type: 'SET_WALLET', wallet: accounts[0] }));
@@ -39,7 +40,7 @@ export const BiddingForm = ({ evmosToUsdRate }: { evmosToUsdRate: number }) => {
send({ type: 'SUBMIT' });
};
- const isSubmitDisabled = (state.context.bidAmount !== '' && !state.can({ type: 'SUBMIT' })) || state.matches('submitting');
+ const isSubmitDisabled = (state.context.bidAmount !== '' && !state.can({ type: 'SUBMIT' })) || state.matches('submitting') || state.matches('success');
const errorMessage =
Number(state.context.bidAmount) < 0
? 'Bid amount must be greater than 0'
@@ -66,7 +67,7 @@ export const BiddingForm = ({ evmosToUsdRate }: { evmosToUsdRate: number }) => {
placeholder="Amount"
value={state.context.bidAmount}
onChange={(e) => send({ type: 'SET_BID_AMOUNT', value: e.target.value })}
- disabled={state.matches('submitting')}
+ disabled={isSubmitDisabled}
/>
@@ -74,16 +75,21 @@ export const BiddingForm = ({ evmosToUsdRate }: { evmosToUsdRate: number }) => {
className="disabled:text-evmos-gray-light disabled:bg-evmos-gray disabled:border-evmos-gray items-center justify-center rounded-full transition-[background-color,outline-color,filter] transition-200 flex gap-x-1 outline outline-offset-2 outline-1 outline-transparent bg-evmos-orange-500 hover:bg-evmos-orange-400 py-[9px] px-5 active:outline-evmos-secondary-dark"
disabled={isSubmitDisabled}
>
- {state.matches('submitting') ? : 'Bid'}
+ {state.matches('submitting') || state.matches('success') ? : 'Bid'}
-
- {Number(state.context.bidAmount) > 0 &&
≈ ${(Number(state.context.bidAmount) * evmosToUsdRate).toFixed(2)}}
+
+ {Number(state.context.bidAmount) > 0 && ≈ ${(Number(state.context.bidAmount) * evmosToUsdRate).toFixed(2)}}
+ {Number(state.context.bidAmount) > 0 && priceError && (
+
+
+
+ )}
{errorMessage &&
{errorMessage}
}
{state.matches('error') &&
{state.context.error}
}
- {state.matches('success') &&
Bid placed successfully!
}
+ {state.matches('success') &&
Bid placed successfully! It will appear in a few seconds.
}
);
};
diff --git a/src/app/_components/BiddingHistory.tsx b/src/app/_components/BiddingHistory.tsx
index cc82ad4..a8f4888 100644
--- a/src/app/_components/BiddingHistory.tsx
+++ b/src/app/_components/BiddingHistory.tsx
@@ -40,20 +40,22 @@ export const BiddingHistory = async ({ round }: { round: bigint }) => {
-
-
- |
-
-
- |
-
-
- |
-
-
- |
-
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
}
>
diff --git a/src/app/_components/BiddingHistoryData.tsx b/src/app/_components/BiddingHistoryData.tsx
index efe9b34..a874635 100644
--- a/src/app/_components/BiddingHistoryData.tsx
+++ b/src/app/_components/BiddingHistoryData.tsx
@@ -30,8 +30,8 @@ export const BiddingHistoryData = async ({ round }: { round: bigint }) => {
{bids.map((bid) => (
-
- {shortenAddress(bid.bidder)}
+
+ {shortenAddress(bid.bidder)}
|
@@ -40,8 +40,8 @@ export const BiddingHistoryData = async ({ round }: { round: bigint }) => {
|
{bid.time ? dayjs(bid.time).fromNow() : ''} |
-
- {shortenAddress(bid.transactionHash)}
+
+ {shortenAddress(bid.transactionHash)}
|
diff --git a/src/app/_components/Countdown.tsx b/src/app/_components/Countdown.tsx
index 79adacc..510f4ae 100644
--- a/src/app/_components/Countdown.tsx
+++ b/src/app/_components/Countdown.tsx
@@ -3,9 +3,11 @@
'use client';
import { useState, useEffect } from 'react';
-import reloadData from '../_actions/reloadData';
+
import { Log } from '@/utilities/logger';
+import reloadData from '../_actions/reloadData';
+
type TimeLeft = {
days: number;
hours: number;
@@ -14,6 +16,7 @@ type TimeLeft = {
};
const REFRESH_INTERVAL = 1000;
+const DELAY_BEFORE_RELOAD_AFTER_COUNTDOWN_GOES_TO_ZERO = 5000;
const calculateTimeLeft = (date: Date): TimeLeft => {
const difference = +date - +new Date();
@@ -57,10 +60,10 @@ export const Countdown = ({ date }: { date: Date }) => {
setTimeout(() => {
Log().info('Reloading data after countdown to 0');
reloadData();
- }, 5000);
+ }, DELAY_BEFORE_RELOAD_AFTER_COUNTDOWN_GOES_TO_ZERO);
}
- }, 1000);
-
+ }, REFRESH_INTERVAL);
+
return () => {
clearInterval(interval);
};
diff --git a/src/app/_state-machines/biddingStateMachine.ts b/src/app/_state-machines/biddingStateMachine.ts
index 476a989..d2f2a34 100644
--- a/src/app/_state-machines/biddingStateMachine.ts
+++ b/src/app/_state-machines/biddingStateMachine.ts
@@ -42,6 +42,10 @@ export const biddingStateMachine = setup({
bidAmount: ({ context }) => Math.max(Number(formatUnits(context.balance, EVMOS_DECIMALS, 2)) - DECIMAL_DISPLAY_FIX, 0),
error: () => null,
}),
+ resetBidAmount: assign({
+ bidAmount: () => '',
+ error: () => null,
+ }),
refreshPage: () => {
reloadData();
},
@@ -115,8 +119,8 @@ export const biddingStateMachine = setup({
after: {
// average block time is 3 seconds, added a bit of buffer here
5000: {
- target: 'success',
- actions: 'refreshPage',
+ target: 'idle',
+ actions: ['refreshPage', 'resetBidAmount'], // Reset bid amount here
},
},
},
diff --git a/src/app/api/v1/indexer/auction-end-events/route.ts b/src/app/api/v1/indexer/auction-end-events/route.ts
index 5c32362..513bd67 100644
--- a/src/app/api/v1/indexer/auction-end-events/route.ts
+++ b/src/app/api/v1/indexer/auction-end-events/route.ts
@@ -7,8 +7,9 @@ import { viemPublicClient } from '@/utilities/viem';
import { Log } from '@/utilities/logger';
import { EVMOS_DECIMALS } from '@/constants';
+const MAX_BLOCKS_PER_REQUEST = 10000;
const FIRST_AUCTION_BLOCK = process.env.FIRST_AUCTION_BLOCK ? BigInt(process.env.FIRST_AUCTION_BLOCK) : BigInt(0);
-const BATCH_SIZE = BigInt(10000);
+const BATCH_SIZE = BigInt(MAX_BLOCKS_PER_REQUEST);
export async function GET() {
try {
@@ -45,6 +46,7 @@ export async function GET() {
},
burned: event.args.burned.toString(),
blockNumber: event.blockNumber.toString(),
+ // eslint-disable-next-line no-magic-numbers
burnedWithoutDecimals: Number(BigInt(event.args.burned) / BigInt(10 ** EVMOS_DECIMALS)),
transactionHash: event.transactionHash,
transactionIndex: event.transactionIndex,
diff --git a/src/app/api/v1/indexer/bid-events/route.ts b/src/app/api/v1/indexer/bid-events/route.ts
index 4c86b4a..d0ebc69 100644
--- a/src/app/api/v1/indexer/bid-events/route.ts
+++ b/src/app/api/v1/indexer/bid-events/route.ts
@@ -6,8 +6,9 @@ import { rpcFetchBiddingHistory } from '@/queries/rpcFetchBiddingHistory';
import { viemPublicClient } from '@/utilities/viem';
import { Log } from '@/utilities/logger';
+const MAX_BLOCKS_PER_REQUEST = 10000;
const FIRST_AUCTION_BLOCK = process.env.FIRST_AUCTION_BLOCK ? BigInt(process.env.FIRST_AUCTION_BLOCK) : BigInt(0);
-const BATCH_SIZE = BigInt(10000);
+const BATCH_SIZE = BigInt(MAX_BLOCKS_PER_REQUEST);
export async function GET() {
try {
diff --git a/src/app/history/[pageNumber]/page.tsx b/src/app/history/[pageNumber]/page.tsx
index af2ecdc..e23a5c4 100644
--- a/src/app/history/[pageNumber]/page.tsx
+++ b/src/app/history/[pageNumber]/page.tsx
@@ -1,10 +1,11 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/burn-auction-dapp/blob/main/LICENSE)
-import { HistoryContent } from '../_components/HistoryContent';
import { fetchAuctionHistory } from '@/queries/fetchAuctionHistory';
import { PAGINATION_ITEMS_PER_PAGE } from '@/constants';
+import { HistoryContent } from '../_components/HistoryContent';
+
const HistoryPaginated = async ({ params }: { params: { pageNumber: number } }) => {
const auctionHistory = await fetchAuctionHistory(params.pageNumber, PAGINATION_ITEMS_PER_PAGE);
diff --git a/src/app/history/_components/HistoryContent.tsx b/src/app/history/_components/HistoryContent.tsx
index 1ec3db4..0665865 100644
--- a/src/app/history/_components/HistoryContent.tsx
+++ b/src/app/history/_components/HistoryContent.tsx
@@ -2,13 +2,14 @@
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/burn-auction-dapp/blob/main/LICENSE)
import Image from 'next/image';
-import { AuctionHistoryTable } from './AuctionHistoryTable';
+
import { formatUnits } from '@/utilities/formatUnits';
-import { EVMOS_DECIMALS } from '@/constants';
-import Pagination from '../_components/Pagination';
import type { AuctionHistory } from '@/types/AuctionHistory';
import { PAGINATION_ITEMS_PER_PAGE } from '@/constants';
+import Pagination from '../_components/Pagination';
+import { AuctionHistoryTable } from './AuctionHistoryTable';
+
export const HistoryContent = ({ auctionHistory, pageNumber }: { auctionHistory: AuctionHistory; pageNumber: number }) => {
return (
diff --git a/src/app/history/_components/Pagination.tsx b/src/app/history/_components/Pagination.tsx
index babfe23..eed2181 100644
--- a/src/app/history/_components/Pagination.tsx
+++ b/src/app/history/_components/Pagination.tsx
@@ -1,10 +1,11 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/burn-auction-dapp/blob/main/LICENSE)
-import { ButtonLink } from '@/components/ui/ButtonLink';
import Image from 'next/image';
import { clsx } from 'clsx';
+import { ButtonLink } from '@/components/ui/ButtonLink';
+
interface PaginationProps {
currentPage: number;
itemsPerPage: number;
diff --git a/src/app/history/page.tsx b/src/app/history/page.tsx
index b62ff6e..b5e0823 100644
--- a/src/app/history/page.tsx
+++ b/src/app/history/page.tsx
@@ -1,19 +1,13 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/burn-auction-dapp/blob/main/LICENSE)
-import Image from 'next/image';
-
-import { fetchAuctionHistory } from '@/queries/fetchAuctionHistory';
-import { formatUnits } from '@/utilities/formatUnits';
-import { EVMOS_DECIMALS } from '@/constants';
-import { HistoryContent } from './_components/HistoryContent';
import { fetchAuctionHistory } from '@/queries/fetchAuctionHistory';
import { PAGINATION_ITEMS_PER_PAGE } from '@/constants';
-import { AuctionHistoryTable } from './_components/AuctionHistoryTable';
+import { HistoryContent } from './_components/HistoryContent';
const History = async () => {
- const auctionHistory = await fetchAuctionHistory(1, PAGINATION_ITEMS_PER_PAGE);
+ let auctionHistory = await fetchAuctionHistory('last', PAGINATION_ITEMS_PER_PAGE);
const totalItems = auctionHistory.totalItems;
const itemsPerPage = PAGINATION_ITEMS_PER_PAGE;
const totalPages = Math.ceil(totalItems / itemsPerPage);
diff --git a/src/constants/index.ts b/src/constants/index.ts
index b3f7226..8a71c39 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -15,4 +15,5 @@ export const UNKNOWN_TOKEN_METADATA_DEFAULT = {
amountWithDecimals: 0,
};
+// eslint-disable-next-line no-magic-numbers
export const PAGINATION_ITEMS_PER_PAGE = process.env.PAGINATION_ITEMS_PER_PAGE ? parseInt(process.env.PAGINATION_ITEMS_PER_PAGE) : 10;
diff --git a/src/queries/__tests__/fetchAuctionHistory.spec.ts b/src/queries/__tests__/fetchAuctionHistory.spec.ts
index 986d950..4beacdf 100644
--- a/src/queries/__tests__/fetchAuctionHistory.spec.ts
+++ b/src/queries/__tests__/fetchAuctionHistory.spec.ts
@@ -4,11 +4,11 @@
import { expect, describe, it, expectTypeOf, beforeEach, afterEach, vi } from 'vitest';
import type { AuctionHistory } from '@/types/AuctionHistory';
+import { EVMOS_DECIMALS } from '@/constants';
import { fetchAuctionHistory } from '../fetchAuctionHistory';
import { mockAuctionEndEvents } from './mockedData';
import * as prismaModule from '../prismaFetchAuctionEvents';
-import { EVMOS_DECIMALS } from '@/constants';
// Mock the entire module
vi.mock('../prismaFetchAuctionEvents');
@@ -30,6 +30,7 @@ afterEach(() => {
vi.clearAllMocks();
});
+/* eslint-disable no-magic-numbers */
describe('fetchAuctionHistory()', () => {
it('should return the auction history and the correct total burned amount', async () => {
mockPrismaFetchAuctionEvents.mockResolvedValue(
diff --git a/src/queries/__tests__/fetchBiddingHistory.spec.ts b/src/queries/__tests__/fetchBiddingHistory.spec.ts
index 8edb38c..9f1d5d1 100644
--- a/src/queries/__tests__/fetchBiddingHistory.spec.ts
+++ b/src/queries/__tests__/fetchBiddingHistory.spec.ts
@@ -6,14 +6,13 @@ import { expect, describe, it, expectTypeOf, beforeEach, afterEach, vi } from 'v
import type { BiddingHistory } from '@/types/BiddingHistory';
import { fetchBiddingHistory } from '../fetchBiddingHistory';
-import { mockBiddingHistoryResponse } from './mockedData';
-import type { BiddingHistory } from '@/types/BiddingHistory';
import { prismaFetchBidEvent } from '../prismaFetchBidEvent';
import { rpcFetchBlockDate } from '../rpcFetchBlockDate';
vi.mock('../prismaFetchBidEvent');
vi.mock('../rpcFetchBlockDate');
+/* eslint-disable no-magic-numbers */
describe('fetchBiddingHistory(round)', () => {
beforeEach(() => {
vi.resetAllMocks();
diff --git a/src/queries/__tests__/fetchCurrentAuction.spec.ts b/src/queries/__tests__/fetchCurrentAuction.spec.ts
index 8bea453..7410035 100644
--- a/src/queries/__tests__/fetchCurrentAuction.spec.ts
+++ b/src/queries/__tests__/fetchCurrentAuction.spec.ts
@@ -3,7 +3,6 @@
import { expect, describe, it, expectTypeOf, beforeEach, afterEach, vi } from 'vitest';
-import { fetchCurrentAuction } from '../fetchCurrentAuction';
import type { AuctionDetailed } from '@/types/AuctionDetailed';
import { fetchCurrentAuction } from '../fetchCurrentAuction';
diff --git a/src/queries/__tests__/fetchPastAuction.spec.ts b/src/queries/__tests__/fetchPastAuction.spec.ts
index b970e45..d1af86b 100644
--- a/src/queries/__tests__/fetchPastAuction.spec.ts
+++ b/src/queries/__tests__/fetchPastAuction.spec.ts
@@ -4,14 +4,13 @@
import { expect, describe, it, expectTypeOf, beforeEach, afterEach, vi } from 'vitest';
import type { AuctionDetailed } from '@/types/AuctionDetailed';
+import { fetchChainRegistryDir } from '@/utilities/fetchChainRegistryDir';
+import { EVMOS_DECIMALS } from '@/constants';
import { fetchPastAuction } from '../fetchPastAuction';
-import { mockCoinGeckoResponse, mockAuctionResponse, epochInfoResponse, mockAuctionEndEventsRound3 } from './mockedData';
import { prismaFetchAuctionEvent } from '../prismaFetchAuctionEvent';
import { fetchAuctionDates } from '../fetchAuctionDates';
import { fetchPastCryptoPrice } from '../fetchPastCryptoPrice';
-import { fetchChainRegistryDir } from '@/utilities/fetchChainRegistryDir';
-import { EVMOS_DECIMALS } from '@/constants';
vi.mock('../prismaFetchAuctionEvent');
vi.mock('../fetchAuctionDates');
@@ -29,6 +28,7 @@ afterEach(() => {
vi.clearAllMocks();
});
+/* eslint-disable no-magic-numbers */
describe('fetchPastAuction()', () => {
it('should return the past auction info of type AuctionDetailed', async () => {
const mockAuctionEvent = {
@@ -52,6 +52,7 @@ describe('fetchPastAuction()', () => {
vi.mocked(prismaFetchAuctionEvent).mockResolvedValue([
{
...mockAuctionEvent,
+ // @ts-ignore
coins: mockAuctionEvent.coins.map((coin) => ({
...coin,
id: 1,
@@ -131,6 +132,7 @@ describe('fetchPastAuction()', () => {
vi.mocked(prismaFetchAuctionEvent).mockResolvedValue([
{
...mockAuctionEvent,
+ // @ts-ignore
coins: mockAuctionEvent.coins.map((coin) => ({
...coin,
id: 1,
@@ -179,6 +181,7 @@ describe('fetchPastAuction()', () => {
vi.mocked(prismaFetchAuctionEvent).mockResolvedValue([
{
...mockAuctionEvent,
+ // @ts-ignore
coins: mockAuctionEvent.coins.map((coin) => ({
...coin,
id: 1,
@@ -192,12 +195,6 @@ describe('fetchPastAuction()', () => {
});
vi.mocked(fetchChainRegistryDir).mockRejectedValue(new Error('Failed to fetch chain registry'));
-describe('fetchPastAuction(5)', async () => {
- it('should return the current auction info of type AuctionDetailed', async () => {
- // eslint-disable-next-line no-magic-numbers
- const result = await fetchPastAuction(BigInt(40));
- expect(result).toBeDefined();
- expectTypeOf(result).toMatchTypeOf();
await expect(fetchPastAuction(BigInt(6))).rejects.toThrow('Failed to fetch chain registry');
});
});
diff --git a/src/queries/__tests__/rpcFetchAuctionEnd.spec.ts b/src/queries/__tests__/rpcFetchAuctionEnd.spec.ts
index f8ef986..91dbdef 100644
--- a/src/queries/__tests__/rpcFetchAuctionEnd.spec.ts
+++ b/src/queries/__tests__/rpcFetchAuctionEnd.spec.ts
@@ -6,7 +6,7 @@ import { expect, describe, it, expectTypeOf, beforeEach, afterEach, vi } from 'v
import type { AuctionEndEvent } from '@/types/AuctionEndEvent';
import { rpcFetchAuctionEnd } from '../rpcFetchAuctionEnd';
-import { mockAuctionEndEvents, mockAuctionEndEventsRound3 } from './mockedData';
+import { mockAuctionEndEvents } from './mockedData';
beforeEach(() => {
vi.mock('../rpcFetchAuctionEnd', async (importOriginal) => {
@@ -14,7 +14,7 @@ beforeEach(() => {
return {
// @ts-ignore
...actual,
- rpcFetchAuctionEnd: vi.fn((from, to) => mockAuctionEndEvents),
+ rpcFetchAuctionEnd: vi.fn(() => mockAuctionEndEvents),
};
});
});
@@ -23,6 +23,7 @@ afterEach(() => {
vi.clearAllMocks();
});
+/* eslint-disable no-magic-numbers */
describe('rpcFetchAuctionEnd(from, to)', async () => {
it('should return all the AuctionEnd events', async () => {
const result = await rpcFetchAuctionEnd(BigInt(1), BigInt(3));
@@ -30,14 +31,3 @@ describe('rpcFetchAuctionEnd(from, to)', async () => {
expectTypeOf(result).toMatchTypeOf();
});
});
-
-describe('rpcFetchAuctionEnd(round)', async () => {
- it('should return a specific AuctionEnd event', async () => {
- // eslint-disable-next-line no-magic-numbers
- const result = await rpcFetchAuctionEnd(BigInt(3));
- expect(result).toBeDefined();
- expect(result.length).toEqual(1);
- expect(result.length).toEqual(2);
- expectTypeOf(result).toMatchTypeOf();
- });
-});
diff --git a/src/queries/__tests__/rpcFetchBiddingHistory.spec.ts b/src/queries/__tests__/rpcFetchBiddingHistory.spec.ts
index 8ffc74b..abd3c28 100644
--- a/src/queries/__tests__/rpcFetchBiddingHistory.spec.ts
+++ b/src/queries/__tests__/rpcFetchBiddingHistory.spec.ts
@@ -21,6 +21,7 @@ afterEach(() => {
vi.clearAllMocks();
});
+/* eslint-disable no-magic-numbers */
describe('rpcFetchBiddingHistory(from, to)', async () => {
it('should return the Bids for a given round number', async () => {
const result = await rpcFetchBiddingHistory(BigInt(1), BigInt(3));
diff --git a/src/queries/fetchAuctionHistory.ts b/src/queries/fetchAuctionHistory.ts
index c87235a..45ac0b4 100644
--- a/src/queries/fetchAuctionHistory.ts
+++ b/src/queries/fetchAuctionHistory.ts
@@ -1,18 +1,23 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/burn-auction-dapp/blob/main/LICENSE)
-
-import { prismaFetchAuctionEvents } from './prismaFetchAuctionEvents';
-
import { E } from '@/utilities/error-handling';
import { Log } from '@/utilities/logger';
import type { AuctionHistory } from '@/types/AuctionHistory';
import { HexAddress } from '@/types/HexAddress';
+import { prismaFetchAuctionEvents } from './prismaFetchAuctionEvents';
-export const fetchAuctionHistory = async (page: number, itemsPerPage: number): Promise => {
- const [error, auctionEvents] = await E.try(() => prismaFetchAuctionEvents(page, itemsPerPage));
+export const fetchAuctionHistory = async (page: number | 'last', itemsPerPage: number): Promise => {
+ const [errorTotalItems, totalItems] = await E.try(() => prismaFetchAuctionEvents.count());
+ if (errorTotalItems) {
+ Log().error('Error fetching total items:', errorTotalItems);
+ throw errorTotalItems;
+ }
+ const lastPage = Math.ceil(totalItems / itemsPerPage);
+
+ const [error, auctionEvents] = await E.try(() => prismaFetchAuctionEvents(page === 'last' ? lastPage : page, itemsPerPage));
if (error) {
Log().error('Error fetching events date:', error);
throw error;
@@ -27,12 +32,6 @@ export const fetchAuctionHistory = async (page: number, itemsPerPage: number): P
};
});
- const [errorTotalItems, totalItems] = await E.try(() => prismaFetchAuctionEvents.count());
- if (errorTotalItems) {
- Log().error('Error fetching total items:', errorTotalItems);
- throw error;
- }
-
const [errorTotalBurned, totalBurned] = await E.try(() => prismaFetchAuctionEvents.totalBurned());
if (errorTotalBurned) {
Log().error('Error fetching total burned:', errorTotalBurned);
diff --git a/src/queries/fetchBiddingHistory.ts b/src/queries/fetchBiddingHistory.ts
index ed15e10..4f9e9cb 100644
--- a/src/queries/fetchBiddingHistory.ts
+++ b/src/queries/fetchBiddingHistory.ts
@@ -1,16 +1,13 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/burn-auction-dapp/blob/main/LICENSE)
-
-import { prismaFetchBidEvent } from './prismaFetchBidEvent';
-import { rpcFetchBlockDate } from './rpcFetchBlockDate';
import { E } from '@/utilities/error-handling';
import { Log } from '@/utilities/logger';
import type { BiddingHistory } from '@/types/BiddingHistory';
import { HexAddress } from '@/types/HexAddress';
import { rpcFetchBlockDate } from './rpcFetchBlockDate';
-import { rpcFetchBiddingHistory } from './rpcFetchBiddingHistory';
+import { prismaFetchBidEvent } from './prismaFetchBidEvent';
export const fetchBiddingHistory = async (round: bigint): Promise => {
const [error, biddingEvents] = await E.try(() => prismaFetchBidEvent(round));
diff --git a/src/queries/fetchCurrentAuction.ts b/src/queries/fetchCurrentAuction.ts
index 43730cb..d06240a 100644
--- a/src/queries/fetchCurrentAuction.ts
+++ b/src/queries/fetchCurrentAuction.ts
@@ -35,7 +35,7 @@ export const fetchCurrentAuction = async (): Promise => {
throw errorEndDate;
}
- const currentAuctionInfo = {
+ const currentAuctionInfo: AuctionDetailed = {
round: {
round: auctionInfo.currentRound,
isLast: true,
@@ -53,6 +53,7 @@ export const fetchCurrentAuction = async (): Promise => {
assets: [] as AuctionnedAsset[],
totalValue: 0,
hasPriceError: false,
+ evmosToUsdRate: 0,
},
};
@@ -103,6 +104,7 @@ export const fetchCurrentAuction = async (): Promise => {
return asset;
});
+ currentAuctionInfo.auction.evmosToUsdRate = prices['evmos']['usd'];
currentAuctionInfo.highestBid.bidInUsd = currentAuctionInfo.highestBid.bidInEvmosWithDecimals * prices['evmos']['usd'];
currentAuctionInfo.auction.totalValue = currentAuctionInfo.auction.assets.reduce((acc, asset) => acc + asset.valueInUsd, 0);
diff --git a/src/queries/fetchCurrentCryptoPrice.ts b/src/queries/fetchCurrentCryptoPrice.ts
index c828fbb..e8d6ea5 100644
--- a/src/queries/fetchCurrentCryptoPrice.ts
+++ b/src/queries/fetchCurrentCryptoPrice.ts
@@ -12,6 +12,7 @@ type CryptoPrice = {
};
const MOCK_COINGECKO_API = process.env.MOCK_COINGECKO_API === 'true';
+const STATUS_OK = 200;
export const fetchCurrentCryptoPrice = async (ids: string[]): Promise => {
// To avoid hitting the rate limit of the Coingecko API
@@ -31,7 +32,7 @@ export const fetchCurrentCryptoPrice = async (ids: string[]): Promise fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${coingeckoIds}&vs_currencies=usd`, { next: { revalidate: 60 } }));
Log().info('Fetching crypto price:', coingeckoIds);
- if (error) {
+ if (error || result.status !== STATUS_OK) {
Log().error('Error fetching crypto price:', error);
return Object.fromEntries(ids.map((id) => [id, { usd: 0, error: true }]));
}
diff --git a/src/queries/fetchPastAuction.ts b/src/queries/fetchPastAuction.ts
index 8c401ee..87ce6fa 100644
--- a/src/queries/fetchPastAuction.ts
+++ b/src/queries/fetchPastAuction.ts
@@ -8,11 +8,11 @@ import { AuctionnedAsset } from '@/types/AuctionnedAsset';
import { fetchChainRegistryDir } from '@/utilities/fetchChainRegistryDir';
import { TokenEntity } from '@/utilities//registry/autogen/token-entity';
import { EVMOS_DECIMALS, UNKNOWN_TOKEN_METADATA_DEFAULT } from '@/constants';
+import type { HexAddress } from '@/types/HexAddress';
+
import { fetchAuctionDates } from './fetchAuctionDates';
-import { rpcFetchAuctionEnd } from './rpcFetchAuctionEnd';
import { fetchPastCryptoPrice } from './fetchPastCryptoPrice';
import { prismaFetchAuctionEvent } from './prismaFetchAuctionEvent';
-import type { HexAddress } from '@/types/HexAddress';
export const fetchPastAuction = async (round: bigint): Promise => {
const [error, auctionEndEvent] = await E.try(() => prismaFetchAuctionEvent(round));
@@ -59,6 +59,7 @@ export const fetchPastAuction = async (round: bigint): Promise
assets: [] as AuctionnedAsset[],
totalValue: 0,
hasPriceError: false,
+ evmosToUsdRate: 0,
},
};
@@ -71,7 +72,7 @@ export const fetchPastAuction = async (round: bigint): Promise
...UNKNOWN_TOKEN_METADATA_DEFAULT,
denom: token.denom,
amount: BigInt(token.amount),
- priceError: true
+ priceError: true,
};
if (!tokenMetadata) {
@@ -108,8 +109,13 @@ export const fetchPastAuction = async (round: bigint): Promise
auctionDetails.auction.assets.push(asset);
}
+ // eslint-disable-next-line no-unused-vars
+ const [_, evmosToUsdRateCoingecko] = await E.try(() => fetchPastCryptoPrice('evmos', dates.end));
+ const evmosToUsdRate = evmosToUsdRateCoingecko ?? 0;
+
+ auctionDetails.auction.evmosToUsdRate = evmosToUsdRate;
auctionDetails.auction.totalValue = totalValue;
- auctionDetails.highestBid.bidInUsd = (await fetchPastCryptoPrice('evmos', dates.end)) * auctionDetails.highestBid.bidInEvmosWithDecimals;
+ auctionDetails.highestBid.bidInUsd = auctionDetails.auction.evmosToUsdRate * auctionDetails.highestBid.bidInEvmosWithDecimals;
return auctionDetails;
};
diff --git a/src/queries/fetchPastCryptoPrice.ts b/src/queries/fetchPastCryptoPrice.ts
index 60839fd..167aa66 100644
--- a/src/queries/fetchPastCryptoPrice.ts
+++ b/src/queries/fetchPastCryptoPrice.ts
@@ -7,6 +7,7 @@ import { Log } from '@/utilities/logger';
const MOCK_COINGECKO_API = process.env.MOCK_COINGECKO_API === 'true';
// eslint-disable-next-line no-magic-numbers
const ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;
+const STATUS_OK = 200;
export const fetchPastCryptoPrice = async (coinId: string, date: Date): Promise => {
// To avoid hitting the rate limit of the Coingecko API
@@ -20,7 +21,7 @@ export const fetchPastCryptoPrice = async (coinId: string, date: Date): Promise<
const [error, result] = await E.try(() => fetch(`https://api.coingecko.com/api/v3/coins/${coinId}/history?date=${formattedDate}`, { next: { revalidate: ONE_YEAR_IN_SECONDS } }));
Log().info('Fetching crypto price:', { coinId, date });
- if (error) {
+ if (error || result.status !== STATUS_OK) {
Log().error('Error fetching crypto price:', error);
throw error;
}
diff --git a/src/queries/prismaFetchAuctionEvent.ts b/src/queries/prismaFetchAuctionEvent.ts
index 2b4dc2f..03655d4 100644
--- a/src/queries/prismaFetchAuctionEvent.ts
+++ b/src/queries/prismaFetchAuctionEvent.ts
@@ -11,9 +11,7 @@ export const prismaFetchAuctionEvent = async (round: bigint) => {
round: 'asc',
},
where: {
- where: {
- round: BigInt(round),
- },
+ round: Number(round),
},
include: {
coins: true,
diff --git a/src/types/AuctionDetailed.ts b/src/types/AuctionDetailed.ts
index 8c636fe..dc002bc 100644
--- a/src/types/AuctionDetailed.ts
+++ b/src/types/AuctionDetailed.ts
@@ -15,6 +15,7 @@ export type AuctionDetailed = {
assets: AuctionnedAsset[];
totalValue: number;
hasPriceError: boolean;
+ evmosToUsdRate: number;
};
highestBid: {
bidInEvmos: bigint;
diff --git a/src/utilities/fetchChainRegistryDir.ts b/src/utilities/fetchChainRegistryDir.ts
index 6ddeff8..38b6972 100644
--- a/src/utilities/fetchChainRegistryDir.ts
+++ b/src/utilities/fetchChainRegistryDir.ts
@@ -4,10 +4,10 @@
'use server';
import { isString } from '@/utilities/assertions';
-const GITHUB_API_PROXY = process.env.GITHUB_API_PROXY;
+const GH_API_PROXY = process.env.GH_API_PROXY;
async function getContent(owner: string, repo: string, path: string, ref: string) {
- return fetch(GITHUB_API_PROXY + 'repos/' + owner + '/' + repo + '/contents/' + path + '?ref=' + ref);
+ return fetch(GH_API_PROXY + 'repos/' + owner + '/' + repo + '/contents/' + path + '?ref=' + ref);
}
export const fetchChainRegistryDir = async (dir: string) => {