Skip to content

Commit

Permalink
displaying completed orders
Browse files Browse the repository at this point in the history
  • Loading branch information
vsubhuman committed May 8, 2024
1 parent 32624de commit def7ca6
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Box, Typography } from '@mui/material';
import Separator from '../separator/Separator';

type Props = {|
columnKeys?: Array<string>,
columnNames: Array<string>,
gridTemplateColumns: string,
children: Node,
Expand All @@ -18,6 +19,7 @@ export default function Table({
children,
rowGap,
columnGap,
columnKeys,
columnNames,
gridTemplateColumns,
columnAlignment = ['left'],
Expand All @@ -38,7 +40,7 @@ export default function Table({
<Typography
component="div"
variant="body2"
key={name}
key={columnKeys?.[i] ?? name}
textAlign={columnAlignment[i] ? columnAlignment[i] : 'right'}
pt="13px"
pb="5px" // 5px + 8px of gap = 13px
Expand Down
23 changes: 22 additions & 1 deletion packages/yoroi-extension/app/containers/swap/hooks.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
//@flow
import { useState } from 'react';
import { useSwap, useSwapOrdersByStatusOpen, useSwapPoolsByPair, useSwapTokensOnlyVerified } from '@yoroi/swap';
import {
useSwap,
useSwapOrdersByStatusCompleted,
useSwapOrdersByStatusOpen,
useSwapPoolsByPair,
useSwapTokensOnlyVerified
} from '@yoroi/swap';
import { Quantities } from '../../utils/quantities';
import { useSwapForm } from './context/swap-form';
import type { RemoteTokenInfo } from '../../api/ada/lib/state-fetch/types';
Expand Down Expand Up @@ -106,3 +112,18 @@ export function useRichOpenOrders(): Array<any> {
};
})
}

export function useRichCompletedOrders(): Array<any> {
const completedOrders = useSwapOrdersByStatusCompleted();
const { onlyVerifiedTokens } = useSwapTokensOnlyVerified();
const tokensMap = onlyVerifiedTokens.reduce((map, t) => ({ ...map, [t.id]: t }), {});
return completedOrders.map(o => {
const fromToken = tokensMap[o.from.tokenId];
const toToken = tokensMap[o.to.tokenId];
return {
txHash: o.txHash,
from: { quantity: o.from.quantity, token: fromToken },
to: { quantity: o.to.quantity, token: toToken },
};
})
}
157 changes: 118 additions & 39 deletions packages/yoroi-extension/app/containers/swap/orders/OrdersPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,59 @@ import Table from '../../../components/common/table/Table';
import CancelSwapOrderDialog from '../../../components/swap/CancelOrderDialog';
import AssetPair from '../../../components/common/assets/AssetPair';
import Tabs from '../../../components/common/tabs/Tabs';
import { useRichOpenOrders } from '../hooks';
import { useRichCompletedOrders, useRichOpenOrders } from '../hooks';
import type { StoresAndActionsProps } from '../../../types/injectedProps.types';
import { SwapPoolLabel } from '../../../components/swap/SwapPoolComponents';
import ExplorableHashContainer from '../../widgets/ExplorableHashContainer';
import { truncateAddressShort } from '../../../utils/formatters';
import { Quantities } from '../../../utils/quantities';
import { PRICE_PRECISION } from '../../../components/swap/common';
import { fail, forceNonNull, maybe } from '../../../coreUtils';
import { fail, forceNonNull, mapFilterNonNull, maybe } from '../../../coreUtils';
import type { RemoteTokenInfo } from '../../../api/ada/lib/state-fetch/types';
import { useSwap } from '@yoroi/swap';
import { addressBech32ToHex } from '../../../api/ada/lib/cardanoCrypto/utils';
import {
getTransactionFeeFromCbor,
getTransactionTotalOutputFromCbor,
} from '../../../api/ada/transactions/utils';
import { SelectedExplorer } from '../../../domain/SelectedExplorer';

const orderColumns = [
'Pair (From / To)',
'Asset price',
'Asset amount',
'Total',
'DEX',
'Time created',
'Transaction ID',
{
name: 'Pair (From / To)',
align: 'left',
width: '176px',
},
{
name: 'Asset price',
width: '150px',
},
{
name: 'Asset amount',
width: '166px'
},
{
name: 'Total',
width: '150px',
openOrdersOnly: true,
},
{
name: 'DEX',
align: 'left',
leftPadding: '32px',
width: '176px',
openOrdersOnly: true,
},
{
name: 'Time created',
align: 'left',
width: '240px',
},
{
name: 'Transaction ID',
align: 'left',
width: 'auto',
},
];

export type FormattedTokenValue = {|
Expand Down Expand Up @@ -77,21 +106,16 @@ function createFormattedTokenValues({
return formattedTokenValues;
}

function mapOrder(
function mapOrderAssets(
order: any,
defaultTokenInfo: RemoteTokenInfo
): {|
utxo: string,
sender: string,
txId: string,
price: string,
amount: string,
totalValues: Array<FormattedTokenValue>,
provider: string,
totalValues: ?Array<FormattedTokenValue>,
from: any,
to: any,
|} {
const txId = order.utxo.split('#')[0];
const price = Quantities.quotient(order.from.quantity, order.to.quantity);
const priceDenomination = order.from.token.decimals - order.to.token.decimals;
const formattedPrice = Quantities.format(price, priceDenomination, PRICE_PRECISION);
Expand All @@ -100,24 +124,56 @@ function mapOrder(
order.to.token.decimals,
order.to.token.decimals
);
const formattedAttachedValues = createFormattedTokenValues({
entries: order.valueAttached.map(({ token: id, amount }) => ({ id, amount })),
const formattedAttachedValues = maybe(order.valueAttached, val => createFormattedTokenValues({
entries: val.map(({ token: id, amount }) => ({ id, amount })),
order,
defaultTokenInfo,
});
}));
return {
utxo: order.utxo,
sender: order.sender,
txId,
price: formattedPrice,
amount: formattedToQuantity,
totalValues: formattedAttachedValues,
provider: order.provider,
from: order.from,
to: order.to,
};
}

type MappedOrder = {|
txId: string,
utxo?: string,
sender?: string,
provider?: string,
price: string,
amount: string,
totalValues: ?Array<FormattedTokenValue>,
from: any,
to: any,
|};

function mapOpenOrder(
order: any,
defaultTokenInfo: RemoteTokenInfo
): MappedOrder {
const txId = order.utxo.split('#')[0];
return {
txId,
utxo: order.utxo,
sender: order.sender,
provider: order.provider,
...mapOrderAssets(order, defaultTokenInfo),
};
}

function mapCompletedOrder(
order: any,
defaultTokenInfo: RemoteTokenInfo
): MappedOrder {
return {
txId: order.txHash,
...mapOrderAssets(order, defaultTokenInfo),
};
}

export default function SwapOrdersPage(props: StoresAndActionsProps): Node {
const {
order: { cancel: swapCancelOrder },
Expand All @@ -140,14 +196,19 @@ export default function SwapOrdersPage(props: StoresAndActionsProps): Node {
props.stores.explorers.selectedExplorer.get(network.NetworkId) ??
fail('No explorer for wallet network');

const openOrders = useRichOpenOrders().map(o => mapOrder(o, defaultTokenInfo));
const openOrders = useRichOpenOrders().map(o => mapOpenOrder(o, defaultTokenInfo));
const completedOrders = useRichCompletedOrders().map(o => mapCompletedOrder(o, defaultTokenInfo));

const handleCancelRequest = order => {
const sender = order.sender;
if (sender == null) {
throw new Error('Cannot cancel a completed order (sender == null)');
}
props.stores.substores.ada.swapStore
.getUtxoHexForCancelCollateral({ wallet })
.then(utxoHex => {
return swapCancelOrder({
address: addressBech32ToHex(order.sender),
address: addressBech32ToHex(sender),
utxos: {
order: order.utxo,
collateral: utxoHex,
Expand Down Expand Up @@ -212,6 +273,12 @@ export default function SwapOrdersPage(props: StoresAndActionsProps): Node {
setCancellationState(null);
};

const columnKeys = orderColumns.map(({ name }) => name);
const columnNames = orderColumns.map(({ name, openOrdersOnly }) => showCompletedOrders && openOrdersOnly ? '' : name);
const columnAlignment = orderColumns.map(({ align }) => align ?? '');
const columnLeftPaddings = orderColumns.map(({ leftPadding }) => leftPadding ?? '');
const gridTemplateColumns = orderColumns.map(({ width }) => width ?? 'auto').join(' ');

return (
<>
<Box sx={{ mx: '24px' }}>
Expand All @@ -225,22 +292,22 @@ export default function SwapOrdersPage(props: StoresAndActionsProps): Node {
},
{
label: 'Completed orders',
isActive: false,
isActive: showCompletedOrders,
onClick: () => setShowCompletedOrders(true),
disabled: true,
},
]}
/>
</Box>
<Table
columnNames={orderColumns}
columnAlignment={['left', '', '', '', 'left', 'left', 'left']}
columnLeftPaddings={['', '', '', '', '32px']}
gridTemplateColumns="176px 150px 166px 150px 176px 240px auto"
columnKeys={columnKeys}
columnNames={columnNames}
columnAlignment={columnAlignment}
columnLeftPaddings={columnLeftPaddings}
gridTemplateColumns={gridTemplateColumns}
columnGap="0px"
>
{showCompletedOrders
? mockCompletedOrders.map(order => (
? completedOrders.map(order => (
<OrderRow
key={order.txId}
order={order}
Expand All @@ -251,10 +318,10 @@ export default function SwapOrdersPage(props: StoresAndActionsProps): Node {
: openOrders.map(order => (
<OrderRow
key={order.utxo}
handleCancel={() => handleCancelRequest(order)}
order={order}
defaultTokenInfo={defaultTokenInfo}
selectedExplorer={selectedExplorer}
handleCancel={() => handleCancelRequest(order)}
/>
))}
</Table>
Expand All @@ -276,7 +343,17 @@ export default function SwapOrdersPage(props: StoresAndActionsProps): Node {
);
}

const OrderRow = ({ handleCancel = null, order, defaultTokenInfo, selectedExplorer }) => {
const OrderRow = ({
order,
defaultTokenInfo,
selectedExplorer,
handleCancel,
}: {|
order: MappedOrder,
defaultTokenInfo: RemoteTokenInfo,
selectedExplorer: SelectedExplorer,
handleCancel?: () => void,
|}) => {
return (
<>
<AssetPair
Expand All @@ -288,14 +365,16 @@ const OrderRow = ({ handleCancel = null, order, defaultTokenInfo, selectedExplor
<Box textAlign="right">{order.price}</Box>
<Box textAlign="right">{order.amount}</Box>
<Box textAlign="right">
{order.totalValues.map(v => (
{(order.totalValues??[]).map(v => (
<Box>
{v.formattedValue} {v.ticker}
</Box>
))}
</Box>
<Box display="flex" pl="32px" justifyContent="flex-start" alignItems="center" gap="8px">
<SwapPoolLabel provider={order.provider} />
{maybe(order.provider, provider => (
<SwapPoolLabel provider={provider}/>
))}
</Box>
<Box textAlign="left">-</Box>
<Box display="flex" justifyContent="space-between" alignItems="center" gap="12px">
Expand All @@ -306,13 +385,13 @@ const OrderRow = ({ handleCancel = null, order, defaultTokenInfo, selectedExplor
>
<span>{truncateAddressShort(order.txId)}</span>
</ExplorableHashContainer>
{handleCancel == null ? null : (
{maybe(handleCancel, f => (
<Box>
<Button onClick={handleCancel} variant="tertiary" color="grayscale">
<Button onClick={f} variant="tertiary" color="grayscale">
Cancel
</Button>
</Box>
)}
))}
</Box>
</>
);
Expand Down

0 comments on commit def7ca6

Please sign in to comment.