Skip to content

Commit

Permalink
feat: properly display finished auctions (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben authored Mar 9, 2022
1 parent d37059a commit 5494c08
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 50 deletions.
42 changes: 36 additions & 6 deletions core/src/auctions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Auction, AuctionInitialInfo, AuctionTransaction, Notifier } from './types';
import type { Auction, AuctionInitialInfo, AuctionTransaction, Notifier, TakeEvent } from './types';
import BigNumber from './bignumber';
import fetchAuctionsByCollateralType, { fetchAuctionStatus } from './fetch';
import { getCalleeData, getMarketPrice } from './calleeFunctions';
Expand All @@ -13,10 +13,12 @@ import {
calculateTransactionGrossProfitDate,
} from './price';
import { getSupportedCollateralTypes } from './addresses';
import { getClipperNameByCollateralType } from './contracts';
import getContract, { getClipperNameByCollateralType } from './contracts';
import convertNumberTo32Bytes from './helpers/convertNumberTo32Bytes';
import { enrichAuctionWithTransactionFees, getApproximateTransactionFees } from './fees';
import getNetworkDate from './date';
import parseAuctionId from './helpers/parseAuctionId';
import { EventFilter } from 'ethers';
import getNetworkDate, { fetchDateByBlockNumber } from './date';

const enrichAuctionWithActualNumbers = async function (
network: string,
Expand All @@ -30,7 +32,7 @@ const enrichAuctionWithActualNumbers = async function (
totalPrice: new BigNumber(0),
};
}
const auctionStatus = await fetchAuctionStatus(network, auction.collateralType, auction.auctionId);
const auctionStatus = await fetchAuctionStatus(network, auction.collateralType, auction.index);
return {
...auction,
...auctionStatus,
Expand Down Expand Up @@ -136,14 +138,42 @@ export const enrichAuction = async function (
return auctionWithFees;
};

const enrichTakeEventWithDate = async function (network: string, takeEvent: TakeEvent): Promise<TakeEvent> {
const date = await fetchDateByBlockNumber(network, takeEvent.blockNumber);
return {
...takeEvent,
transactionDate: date,
};
};

export const fetchTakeEvents = async function (network: string, auctionId: string): Promise<Array<TakeEvent>> {
const { collateralType, index } = parseAuctionId(auctionId);
const encodedAuctionIndex = convertNumberTo32Bytes(index);

const contractName = getClipperNameByCollateralType(collateralType);
const contract = await getContract(network, contractName);

const eventFilters: EventFilter = contract.filters.Take(encodedAuctionIndex);
const events = await contract.queryFilter(eventFilters);

return await Promise.all(
events.map(event =>
enrichTakeEventWithDate(network, {
transactionHash: event.transactionHash,
blockNumber: event.blockNumber,
})
)
);
};

export const restartAuction = async function (
network: string,
auction: Auction,
profitAddress: string,
notifier?: Notifier
): Promise<string> {
const contractName = getClipperNameByCollateralType(auction.collateralType);
return executeTransaction(network, contractName, 'redo', [auction.auctionId, profitAddress], notifier, false);
return executeTransaction(network, contractName, 'redo', [auction.index, profitAddress], notifier, false);
};

export const bidOnTheAuction = async function (
Expand All @@ -156,7 +186,7 @@ export const bidOnTheAuction = async function (
const calleeData = await getCalleeData(network, auction.collateralType, profitAddress);
const contractName = getClipperNameByCollateralType(auction.collateralType);
const contractParameters = [
convertNumberTo32Bytes(auction.auctionId),
convertNumberTo32Bytes(auction.index),
auction.collateralAmount.shiftedBy(WAD_NUMBER_OF_DIGITS).toFixed(),
auction.unitPrice.shiftedBy(RAY_NUMBER_OF_DIGITS).toFixed(),
calleeAddress,
Expand Down
9 changes: 7 additions & 2 deletions core/src/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { getNetworkConfigByType } from './constants/NETWORKS';

const CURRENT_BLOCK_DATE_CACHE_EXPIRY_MS = 60 * 1000;

const fetchLatestBlockDate = async function (network: string): Promise<Date> {
export const fetchDateByBlockNumber = async function (network: string, blockNumber: number): Promise<Date> {
const provider = await getProvider(network);
const blockNumber = await provider.getBlockNumber();
const block = await provider.getBlock(blockNumber);
return new Date(block.timestamp * 1000);
};

const fetchLatestBlockDate = async function (network: string): Promise<Date> {
const provider = await getProvider(network);
const blockNumber = await provider.getBlockNumber();
return fetchDateByBlockNumber(network, blockNumber);
};

const _fetchLatestBlockDateAndCacheDate = async function (
network: string
): Promise<{ blockDate: Date; cacheDate: Date }> {
Expand Down
16 changes: 8 additions & 8 deletions core/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,20 @@ export const fetchAuctionStatus = async function (
};
};

const fetchAuctionByCollateralTypeAndAuctionId = async function (
const fetchAuctionByCollateralTypeAndAuctionIndex = async function (
network: string,
collateralType: string,
auctionId: number
auctionIndex: number
): Promise<AuctionInitialInfo> {
const maximumAuctionDurationInSeconds = await fetchMaximumAuctionDurationInSeconds(network, collateralType);
const contract = await getContract(network, getClipperNameByCollateralType(collateralType));
const auctionData = await contract.sales(auctionId);
const auctionData = await contract.sales(auctionIndex);
const startTimestamp = new BigNumber(auctionData.tic._hex).times(1000).toNumber();
const endDate = new Date(startTimestamp + maximumAuctionDurationInSeconds * 1000);
return {
network,
id: `${collateralType}:${auctionId}`,
auctionId,
id: `${collateralType}:${auctionIndex}`,
index: auctionIndex,
collateralType,
collateralSymbol: getCollateralConfigByType(collateralType).symbol,
collateralAmount: new BigNumber(auctionData.lot._hex).div(WAD),
Expand All @@ -72,9 +72,9 @@ const fetchAuctionByCollateralTypeAndAuctionId = async function (

const fetchAuctionsByCollateralType = async function (network: string, collateralType: string) {
const contract = await getContract(network, getClipperNameByCollateralType(collateralType));
const activeAuctionIds = await contract.list();
const activeAuctionPromises = activeAuctionIds.map((auctionId: BigNumber) => {
return fetchAuctionByCollateralTypeAndAuctionId(network, collateralType, auctionId.toNumber());
const activeAuctionIndexes = await contract.list();
const activeAuctionPromises = activeAuctionIndexes.map((auctionIndex: BigNumber) => {
return fetchAuctionByCollateralTypeAndAuctionIndex(network, collateralType, auctionIndex.toNumber());
});
return await Promise.all(activeAuctionPromises);
};
Expand Down
22 changes: 22 additions & 0 deletions core/src/helpers/parseAuctionId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getCollateralConfigByType } from '../constants/COLLATERALS';

function parseAuctionId(id: string): { collateralType: string; index: number } {
const parts = id.split(':');
const collateralType = parts[0];
const index = parts[1];

// Check if we support the CollateralType
getCollateralConfigByType(collateralType);

// Check if auction id is a valid auction id
if (Number.isNaN(parseInt(index))) {
throw new Error(`"${index}" is not a valid Auction Index!`);
}

return {
collateralType,
index: parseInt(index),
};
}

export default parseAuctionId;
8 changes: 7 additions & 1 deletion core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import BigNumber from 'bignumber.js';
export declare interface AuctionInitialInfo {
network: string;
id: string;
auctionId: number;
index: number;
collateralType: string;
collateralSymbol: string;
collateralAmount: BigNumber;
Expand Down Expand Up @@ -114,3 +114,9 @@ export declare interface MessageContent {
export declare interface Notifier {
(messageType: 'loading' | 'error' | 'success' | 'info', messageContent: MessageContent): void;
}

export declare interface TakeEvent {
transactionHash: string;
blockNumber: number;
transactionDate?: Date;
}
35 changes: 28 additions & 7 deletions frontend/components/Auction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,17 @@
</div>
</TextBlock>
</div>
<Loading v-else-if="isAuctionsLoading" is-loading class="w-full self-center Loading h-48" />
<AuctionEventsBlock v-else-if="takeEvents && takeEvents.length > 0" :take-events="takeEvents" />
<Loading
v-else-if="areAuctionsFetching || areTakeEventsFetching"
is-loading
class="w-full self-center Loading h-48"
/>
</TextBlock>
</template>

<script lang="ts">
import type { AuctionTransaction } from 'auctions-core/src/types';
import type { AuctionTransaction, TakeEvent } from 'auctions-core/src/types';
import Vue from 'vue';
import { Alert, Tooltip, Popover } from 'ant-design-vue';
import PriceDropAnimation from './utils/PriceDropAnimation.vue';
Expand All @@ -252,10 +257,12 @@ import Loading from '~/components/common/Loading.vue';
import Explain from '~/components/utils/Explain.vue';
import RestartBlock from '~/components/transaction/RestartBlock.vue';
import TimeTillProfitable from '~/components/utils/TimeTillProfitable.vue';
import AuctionEventsBlock from '~/components/AuctionEventsBlock.vue';
export default Vue.extend({
name: 'Auction',
components: {
AuctionEventsBlock,
PriceDropAnimation,
RestartBlock,
Explain,
Expand All @@ -280,6 +287,10 @@ export default Vue.extend({
type: String,
required: true,
},
takeEvents: {
type: Array as Vue.PropType<TakeEvent[]>,
default: null,
},
error: {
type: String,
default: '',
Expand All @@ -288,7 +299,11 @@ export default Vue.extend({
type: Boolean,
default: true,
},
isAuctionsLoading: {
areAuctionsFetching: {
type: Boolean,
default: false,
},
areTakeEventsFetching: {
type: Boolean,
default: false,
},
Expand All @@ -304,16 +319,17 @@ export default Vue.extend({
},
computed: {
errorText(): string | null {
if (!this.isAuctionsLoading && !this.auction) {
if (!this.areAuctionsFetching && !this.areTakeEventsFetching && !this.auction && !this.takeEvents) {
return 'This auction was not found';
} else if (this.error) {
return this.error;
} else if (this.auction?.isFinished) {
} else if (this.auction?.isFinished || (!this.auction && this.takeEvents)) {
return 'This auction is finished';
} else if (!this.auction?.isActive && !this.isAuctionsLoading) {
} else if (!this.auction?.isActive && !this.areAuctionsFetching && !this.areTakeEventsFetching) {
return 'This auction is inactive and must be restarted';
} else if (
!this.isAuctionsLoading &&
!this.areAuctionsFetching &&
!this.areTakeEventsFetching &&
typeof this.auction?.marketUnitPriceToUnitPriceRatio === 'undefined'
) {
return `Swap transaction is not possible,
Expand All @@ -331,6 +347,11 @@ export default Vue.extend({
}
},
},
areAuctionsFetching(areAuctionsFetching) {
if (!areAuctionsFetching && !this.auction) {
this.$emit('fetchTakeEventsFromAuction', this.auctionId);
}
},
},
methods: {
toggleExpandable(): void {
Expand Down
32 changes: 32 additions & 0 deletions frontend/components/AuctionEventsBlock.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<div class="mt-5">
<p class="mb-2">
The auction was taken via {{ takeEvents.length }} transaction<span v-if="takeEvents.length !== 1">s</span>
at {{ takeEvents[takeEvents.length - 1].transactionDate.toUTCString() }}.
</p>
<ul class="list-disc list-inside">
<li v-for="event of takeEvents" :key="event.transactionHash">
Transaction <FormatAddress :value="event.transactionHash" :shorten="true" />
<span v-if="event.transactionDate"> executed <TimeTill :date="event.transactionDate" /> </span>
</li>
</ul>
</div>
</template>

<script lang="ts">
import Vue from 'vue';
import { TakeEvent } from 'auctions-core/dist/src/types';
import FormatAddress from '~/components/utils/FormatAddress.vue';
import TimeTill from '~/components/common/TimeTill.vue';
export default Vue.extend({
name: 'AuctionEventsBlock',
components: { FormatAddress, TimeTill },
props: {
takeEvents: {
type: Array as Vue.PropType<TakeEvent[]>,
required: true,
},
},
});
</script>
6 changes: 3 additions & 3 deletions frontend/components/AuctionsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ export default Vue.extend({
return [
{
title: 'ID',
dataIndex: 'auctionId',
sorter: compareBy('auctionId'),
title: 'Index',
dataIndex: 'index',
sorter: compareBy('index'),
},
{
title: 'Auction Amount',
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/MainFlow.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ storiesOf('Main Flow', module)
MainFlow,
},
data: () => ({ fakeAuctions, randomSelectedAuctionId }),
template: `<MainFlow :auctions="[]" is-auctions-loading :selectedAuctionId.sync="randomSelectedAuctionId" />`,
template: `<MainFlow :auctions="[]" :are-auctions-fetching="true" :selectedAuctionId.sync="randomSelectedAuctionId" />`,
}))
.add('Selected Auction Expert', () => ({
components: {
Expand Down Expand Up @@ -68,5 +68,5 @@ storiesOf('Main Flow', module)
MainFlow,
},
data: () => ({ fakeAuctions: [], randomSelectedAuctionId }),
template: `<MainFlow :isExplanationsShown="false" />`,
template: `<MainFlow :isExplanationsShown="false" />`,
}));
Loading

0 comments on commit 5494c08

Please sign in to comment.