Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Calculate collectible price in dutch sell #385

Merged
merged 13 commits into from
May 17, 2019
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ REACT_APP_LOGGER_ID='0x-launch-kit-frontend'
REACT_APP_THEME_NAME='DEFAULT_THEME'
REACT_APP_ENABLE_NO_METAMASK_PROMPT='true'
REACT_APP_COLLECTIBLES_SOURCE='opensea'
REACT_APP_COLLECTIBLE_NAME='Cryptokitties'
REACT_APP_COLLECTIBLE_NAME='CryptoKitties'
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"0x.js": "^6.0.8",
"0x.js": "^6.0.9",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"@0x/connect": "^5.0.8",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: This library also had a release, should we update it?

"@0x/web3-wrapper": "^6.0.6",
"connected-react-router": "^6.2.2",
Expand Down
5 changes: 3 additions & 2 deletions src/components/erc721/collectibles/collectibles_card_list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import styled from 'styled-components';

import { themeBreakPoints } from '../../../themes/commons';
import { getCollectiblePrice } from '../../../util/collectibles';
import { Collectible } from '../../../util/types';

import { CollectibleAssetContainer } from './collectible_details';
Expand Down Expand Up @@ -43,8 +44,8 @@ export const CollectiblesCardList = (props: Props) => {
<CollectiblesListOverflow>
<CollectiblesList>
{collectibles.map((item, index) => {
const { name, image, color, order, tokenId } = item;
const price = order ? order.takerAssetAmount : null;
const { name, image, color, tokenId } = item;
const price = getCollectiblePrice(item);
return (
<CollectibleAssetContainer
color={color}
Expand Down
112 changes: 5 additions & 107 deletions src/components/erc721/marketplace/collectible_description.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { connect } from 'react-redux';
import styled from 'styled-components';

import { getCollectibleById, getEthAccount } from '../../../store/selectors';
import { themeBreakPoints } from '../../../themes/commons';
import { truncateAddress } from '../../../util/number_utils';
import { convertTimeInSecondsToDaysAndHours } from '../../../util/time_utils';
import { Collectible, StoreState } from '../../../util/types';
import { Card } from '../../common/card';
import { OutsideUrlIcon } from '../../common/icons/outside_url_icon';
import { CustomTD, Table, TBody, TR } from '../../common/table';

import { DutchAuctionPriceChartCard } from './dutch_auction_price_chart_card';

const CollectibleDescriptionWrapper = styled.div``;

const CustomTDStyled = styled(CustomTD)`
Expand Down Expand Up @@ -57,7 +57,7 @@ const CollectibleDescriptionTypeImage = styled.span<{ backgroundImage: string }>
width: 16px;
`;

const CollectibleDescriptionInnerTitle = styled.h4`
export const CollectibleDescriptionInnerTitle = styled.h4`
color: ${props => props.theme.componentsTheme.cardTitleColor};
font-size: 14px;
font-weight: 500;
Expand Down Expand Up @@ -99,72 +99,6 @@ const CollectibleOwnerText = styled.p`
margin: 0;
`;

const PriceChartContainer = styled.div`
display: flex;
justify-content: space-between;
flex-direction: column;

@media (min-width: ${themeBreakPoints.xl}) {
flex-direction: row;
}
`;

const PriceChartPriceAndTime = styled.div`
margin-bottom: 25px;
max-width: 150px;
padding-right: 15px;
padding-top: 25px;

@media (min-width: ${themeBreakPoints.xl}) {
margin-bottom: 0;
}
`;

const PriceChartTitle = styled.h5`
color: ${props => props.theme.componentsTheme.cardTitleColor};
font-size: 14px;
font-weight: 400;
line-height: 1.2;
margin: 0 0 6px;
`;

const PriceChartValue = styled.p`
color: #00ae99;
font-size: 14px;
line-height: 1.2;
margin: 0 0 35px;

&:last-child {
margin-bottom: 0;
}
`;

const PriceChartValueNeutral = styled(PriceChartValue)`
color: ${props => props.theme.componentsTheme.cardTitleColor};
`;

const PriceChartGraphWrapper = styled.div`
flex-grow: 1;
padding-bottom: 15px;

@media (min-width: ${themeBreakPoints.xl}) {
max-width: 365px;
}
`;

const PriceChartGraph = styled.div`
background-color: #f5f5f5;
height: 148px;
margin: 0 0 15px;
width: 100%;
`;

const PriceChartGraphValues = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
`;

const TransactionContainerTableWrapper = styled.div`
overflow-x: auto;
width: 100%;
Expand Down Expand Up @@ -203,20 +137,11 @@ const CollectibleDescription = (props: Props) => {
return null;
}

const { currentOwner, description, order, name, assetUrl } = collectible;
const emptyPlaceholder = '----';
const price = order ? order.takerAssetAmount : null;
const { currentOwner, description, name, assetUrl } = collectible;
const tableTitlesStyling = { fontWeight: '500', color: '#0036f4' };
const typeImage = 'https://placeimg.com/32/32/any';
const ownerImage = 'https://placeimg.com/50/50/any';

let timeRemaining = '';

if (order && order.expirationTimeSeconds) {
const daysAndHours = convertTimeInSecondsToDaysAndHours(order.expirationTimeSeconds);
timeRemaining = `${daysAndHours.days} Days ${daysAndHours.hours} Hrs`;
}

const doesBelongToCurrentUser = currentOwner.toLowerCase() === ethAccount.toLowerCase();

return (
Expand Down Expand Up @@ -249,34 +174,7 @@ const CollectibleDescription = (props: Props) => {
</>
) : null}
</Card>
<Card>
<CollectibleDescriptionInnerTitle>Price Chart</CollectibleDescriptionInnerTitle>
<PriceChartContainer>
<PriceChartPriceAndTime>
<PriceChartTitle>Current Price</PriceChartTitle>
<PriceChartValue>
{price ? <span>{price.toString()} ETH</span> : emptyPlaceholder}
</PriceChartValue>
<PriceChartTitle>Time Remaining</PriceChartTitle>
<PriceChartValue>
{timeRemaining ? <span>{timeRemaining}</span> : emptyPlaceholder}
</PriceChartValue>
</PriceChartPriceAndTime>
<PriceChartGraphWrapper>
<PriceChartGraph />
<PriceChartGraphValues>
<div>
<PriceChartTitle>Start Price</PriceChartTitle>
<PriceChartValueNeutral>5.00 ETH</PriceChartValueNeutral>
</div>
<div>
<PriceChartTitle>End Price</PriceChartTitle>
<PriceChartValueNeutral>3.00 ETH</PriceChartValueNeutral>
</div>
</PriceChartGraphValues>
</PriceChartGraphWrapper>
</PriceChartContainer>
</Card>
<DutchAuctionPriceChartCard collectible={collectible} />
<Card>
<CollectibleDescriptionInnerTitle>Transaction history</CollectibleDescriptionInnerTitle>
<TransactionContainerTableWrapper>
Expand Down
127 changes: 127 additions & 0 deletions src/components/erc721/marketplace/dutch_auction_price_chart_card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { BigNumber } from '0x.js';
import React from 'react';
import styled from 'styled-components';

import { ETH_DECIMALS } from '../../../common/constants';
import { themeBreakPoints } from '../../../themes/commons';
import { getCollectiblePrice } from '../../../util/collectibles';
import { getDutchAuctionData, isDutchAuction } from '../../../util/orders';
import { convertTimeInSecondsToDaysAndHours } from '../../../util/time_utils';
import { tokenAmountInUnits } from '../../../util/tokens';
import { Collectible } from '../../../util/types';
import { Card } from '../../common/card';

import { CollectibleDescriptionInnerTitle } from './collectible_description';

const PriceChartContainer = styled.div`
display: flex;
justify-content: space-between;
flex-direction: column;

@media (min-width: ${themeBreakPoints.xl}) {
flex-direction: row;
}
`;

const PriceChartPriceAndTime = styled.div`
margin-bottom: 25px;
max-width: 150px;
padding-right: 15px;
padding-top: 25px;

@media (min-width: ${themeBreakPoints.xl}) {
margin-bottom: 0;
}
`;

export const PriceChartTitle = styled.h5`
color: ${props => props.theme.componentsTheme.cardTitleColor};
font-size: 14px;
font-weight: 400;
line-height: 1.2;
margin: 0 0 6px;
`;

export const PriceChartValue = styled.p`
color: #00ae99;
font-size: 14px;
line-height: 1.2;
margin: 0 0 35px;

&:last-child {
margin-bottom: 0;
}
`;

const PriceChartValueNeutral = styled(PriceChartValue)`
color: ${props => props.theme.componentsTheme.cardTitleColor};
`;

const PriceChartGraphWrapper = styled.div`
flex-grow: 1;
padding-bottom: 15px;

@media (min-width: ${themeBreakPoints.xl}) {
max-width: 365px;
}
`;

const PriceChartGraph = styled.div`
background-color: #f5f5f5;
height: 148px;
margin: 0 0 15px;
width: 100%;
`;

const PriceChartGraphValues = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
`;

interface Props {
collectible: Collectible;
}

export const DutchAuctionPriceChartCard = (props: Props) => {
const { collectible } = props;
const { order } = collectible;
if (order === null || !isDutchAuction(order)) {
return null;
}

const { makerAssetData, expirationTimeSeconds } = order;
const { beginAmount, beginTimeSeconds } = getDutchAuctionData(makerAssetData);
const price = getCollectiblePrice(collectible) as BigNumber;
const { days, hours } = convertTimeInSecondsToDaysAndHours(expirationTimeSeconds.minus(beginTimeSeconds));
return (
<Card>
<CollectibleDescriptionInnerTitle>Price Chart</CollectibleDescriptionInnerTitle>
<PriceChartContainer>
<PriceChartPriceAndTime>
<PriceChartTitle>Current Price</PriceChartTitle>
<PriceChartValue>{tokenAmountInUnits(price, ETH_DECIMALS)} ETH</PriceChartValue>
<PriceChartTitle>Time Remaining</PriceChartTitle>
<PriceChartValue>{`${days} Days ${hours} Hrs`}</PriceChartValue>
</PriceChartPriceAndTime>
<PriceChartGraphWrapper>
<PriceChartGraph />
<PriceChartGraphValues>
<div>
<PriceChartTitle>Start Price</PriceChartTitle>
<PriceChartValueNeutral>
{tokenAmountInUnits(beginAmount, ETH_DECIMALS)} ETH
</PriceChartValueNeutral>
</div>
<div>
<PriceChartTitle>End Price</PriceChartTitle>
<PriceChartValueNeutral>
{tokenAmountInUnits(order.takerAssetAmount, ETH_DECIMALS)} ETH
</PriceChartValueNeutral>
</div>
</PriceChartGraphValues>
</PriceChartGraphWrapper>
</PriceChartContainer>
</Card>
);
};
25 changes: 25 additions & 0 deletions src/util/collectibles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { BigNumber } from '0x.js';

import { getDutchAuctionData } from './orders';
import { todayInSeconds } from './time_utils';
import { Collectible } from './types';

export const getCollectiblePrice = (collectible: Collectible): BigNumber | null => {
const { order } = collectible;
if (order === null) {
return null;
}

try {
const dutchAcutionData = getDutchAuctionData(order.makerAssetData);
const { beginAmount, beginTimeSeconds } = dutchAcutionData;
const endAmount = order.takerAssetAmount;
const startTimeSeconds = order.expirationTimeSeconds;
// Use y = mx + b (linear function)
const m = endAmount.minus(beginAmount).dividedBy(startTimeSeconds.minus(beginTimeSeconds));
const b = beginAmount.minus(beginTimeSeconds.multipliedBy(m));
return m.multipliedBy(todayInSeconds()).plus(b);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW I compared the result using getAuctionDetailsAsync and the amount was the same (the decimal part of the amount was not, but we can ignore it).

} catch (err) {
return order.takerAssetAmount;
}
};
6 changes: 5 additions & 1 deletion src/util/orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,13 @@ export const sumTakerAssetFillableOrders = (
}, new BigNumber(0));
};

export const getDutchAuctionData = (assetData: string) => {
return DutchAuctionWrapper.decodeDutchAuctionData(assetData);
};

export const isDutchAuction = (order: SignedOrder) => {
try {
DutchAuctionWrapper.decodeDutchAuctionData(order.makerAssetData);
getDutchAuctionData(order.makerAssetData);
return true;
} catch (e) {
return false;
Expand Down
Loading