Skip to content

Commit

Permalink
wip: labeling for ethereum tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
mroz22 committed May 19, 2022
1 parent aefe517 commit 148fd78
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 33 deletions.
1 change: 1 addition & 0 deletions packages/blockchain-link/src/types/blockbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export interface Transaction {
name: string;
symbol: string;
decimals?: number;
transferId: string;
}[];
}

Expand Down
1 change: 1 addition & 0 deletions packages/blockchain-link/src/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface TokenTransfer {
amount: string;
from?: string;
to?: string;
transferId?: string;
}

export interface Target {
Expand Down
34 changes: 30 additions & 4 deletions packages/blockchain-link/src/workers/blockbook/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// import crypto from 'crypto';
import BigNumber from 'bignumber.js';
import { Addresses, filterTargets, sumVinVout, transformTarget } from '../utils';
import type {
Expand Down Expand Up @@ -29,13 +30,19 @@ export const transformServerInfo = (payload: ServerInfo) => ({

export const filterTokenTransfers = (
addresses: Addresses,
transfers: BlockbookTransaction['tokenTransfers'],
tx: BlockbookTransaction,
): TokenTransfer[] => {
const { tokenTransfers } = tx;
if (typeof addresses === 'string') {
addresses = [addresses];
}
// neither addresses or transfers are missing
if (!addresses || !Array.isArray(addresses) || !transfers || !Array.isArray(transfers))
if (
!addresses ||
!Array.isArray(addresses) ||
!tokenTransfers ||
!Array.isArray(tokenTransfers)
)
return [];

const all: (string | null)[] = addresses.map(a => {
Expand All @@ -44,7 +51,7 @@ export const filterTokenTransfers = (
return null;
});

return transfers
return tokenTransfers
.filter(tr => {
if (tr && typeof tr === 'object') {
return (tr.from && all.indexOf(tr.from) >= 0) || (tr.to && all.indexOf(tr.to) >= 0);
Expand Down Expand Up @@ -74,15 +81,30 @@ export const filterTokenTransfers = (
amount: tr.value,
from: tr.from,
to: tr.to,
/**
* Synthetic transferId
* We might need a unique identifier for a transfer. There are basically 2 options how to do it:
* 1] ensure that tokenTransfers array is sorted deterministically and use index
* 2] assign an id based on other object properties
* As doing deterministic sorting would need to be based on object properties as well, we decided to go
* with option 2.
*
* Usecases for transferId:
* - metadata (labeling) module for labeling token transfers in transactions list. Unlike with outputs labeling in btc like coins we don't have anything deterministic here by default.
*/
transferId: `address:${tr.token}:value:${tr.value}:from:${tr.from}:to:${tr.to}`,
};
});
// or maybe sort instead of creating synthetic id and use index as id?
// .sort((a, b) => {});
};

export const transformTransaction = (
descriptor: string,
addresses: AccountAddresses | undefined,
tx: BlockbookTransaction,
): Transaction => {
console.log('transform transaction', tx);
// combine all addresses into array
const myAddresses = addresses
? addresses.change.concat(addresses.used, addresses.unused)
Expand All @@ -93,7 +115,7 @@ export const transformTransaction = (
const outgoing = filterTargets(myAddresses, tx.vin);
const incoming = filterTargets(myAddresses, tx.vout);
const internal = addresses ? filterTargets(addresses.change, tx.vout) : [];
const tokens = filterTokenTransfers(myAddresses, tx.tokenTransfers);
const tokens = filterTokenTransfers(myAddresses, tx);
let type: Transaction['type'];
let targets: VinVout[] = [];
let amount = tx.value;
Expand Down Expand Up @@ -198,6 +220,7 @@ export const transformTransaction = (
export const transformTokenInfo = (
tokens: BlockbookAccountInfo['tokens'],
): TokenInfo[] | undefined => {
console.log('transformTokenInfo', tokens);
if (!tokens || !Array.isArray(tokens)) return undefined;
const info = tokens.reduce((arr, t) => {
if (t.type !== 'ERC20') return arr;
Expand Down Expand Up @@ -244,7 +267,10 @@ export const transformAddresses = (
};
};

console.log('utils');

export const transformAccountInfo = (payload: BlockbookAccountInfo): AccountInfo => {
console.log('transformAccountInfo', payload);
let page;
if (typeof payload.page === 'number') {
page = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import TokenTransferAddressLabel from '../TokenTransferAddressLabel';
import TargetAddressLabel from '../TargetAddressLabel';
import BaseTargetLayout from '../BaseTargetLayout';
import { copyToClipboard } from '@suite-utils/dom';
import { AccountMetadata } from '@suite-types/metadata';
import { AccountMetadata, MetadataAddPayload } from '@suite-types/metadata';
import { ExtendedMessageDescriptor } from '@suite-types';

const StyledHiddenPlaceholder = styled(props => <HiddenPlaceholder {...props} />)`
Expand All @@ -23,7 +23,11 @@ const StyledHiddenPlaceholder = styled(props => <HiddenPlaceholder {...props} />
text-overflow: ellipsis;
`;

interface TokenTransferProps {
interface MetadataProps {
isMetadataDisabled: boolean;
metadataPayload: MetadataAddPayload;
}
interface TokenTransferProps extends MetadataProps {
transfer: ArrayElement<WalletAccountTransaction['tokens']>;
transaction: WalletAccountTransaction;
singleRowLayout?: boolean;
Expand All @@ -34,14 +38,44 @@ interface TokenTransferProps {
export const TokenTransfer = ({
transfer,
transaction,

metadataPayload,
isMetadataDisabled,
...baseLayoutProps
}: TokenTransferProps) => {
const operation = getTxOperation(transfer);
return (
<BaseTargetLayout
{...baseLayoutProps}
addressLabel={<TokenTransferAddressLabel transfer={transfer} type={transaction.type} />}
addressLabel={
<MetadataLabeling
isDisabled={isMetadataDisabled}
defaultVisibleValue={
<TokenTransferAddressLabel transfer={transfer} type={transaction.type} />
}
// todo: items in dropdown?
// dropdownOptions={[
// {
// callback: () => {
// if (!target?.addresses) {
// // probably should not happen?
// return addNotification({
// type: 'error',
// error: 'There is nothing to copy',
// });
// }
// const result = copyToClipboard(target.addresses.join(), null);
// if (typeof result === 'string') {
// return addNotification({ type: 'error', error: result });
// }
// return addNotification({ type: 'copy-to-clipboard' });
// },
// label: <Translation id="TR_ADDRESS_MODAL_CLIPBOARD" />,
// key: 'copy-address',
// },
// ]}
payload={metadataPayload}
/>
}
amount={
!baseLayoutProps.singleRowLayout && (
<StyledHiddenPlaceholder>
Expand All @@ -54,7 +88,7 @@ export const TokenTransfer = ({
);
};

interface TargetProps {
interface TargetProps extends MetadataProps {
target: ArrayElement<WalletAccountTransaction['targets']>;
transaction: WalletAccountTransaction;
singleRowLayout?: boolean;
Expand All @@ -69,21 +103,20 @@ export const Target = ({
target,
transaction,
accountMetadata,
accountKey,
isActionDisabled,
metadataPayload,
isMetadataDisabled,
...baseLayoutProps
}: TargetProps) => {
const targetAmount = getTargetAmount(target, transaction);
const operation = getTxOperation(transaction);
const { addNotification } = useActions({ addNotification: notificationActions.addToast });
const targetMetadata = accountMetadata?.outputLabels?.[transaction.txid]?.[target.n];

return (
<BaseTargetLayout
{...baseLayoutProps}
addressLabel={
<MetadataLabeling
isDisabled={isActionDisabled}
isDisabled={isMetadataDisabled}
defaultVisibleValue={
<TargetAddressLabel
accountMetadata={accountMetadata}
Expand Down Expand Up @@ -111,14 +144,7 @@ export const Target = ({
key: 'copy-address',
},
]}
payload={{
type: 'outputLabel',
accountKey,
txid: transaction.txid,
outputIndex: target.n,
defaultValue: `${transaction.txid}-${target.n}`,
value: targetMetadata,
}}
payload={metadataPayload}
/>
}
amount={
Expand Down
52 changes: 40 additions & 12 deletions packages/suite/src/components/wallet/TransactionItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,20 +281,48 @@ const TransactionItem = React.memo(
} // if list of targets is expanded we won't get last item here
accountMetadata={accountMetadata}
accountKey={accountKey}
isActionDisabled={isActionDisabled}
isMetadataDisabled={!!isActionDisabled}
metadataPayload={{
type: 'outputLabel',
accountKey,
txid: transaction.txid,
outputIndex: t.payload.n,
defaultValue: `${transaction.txid}-${t.payload.n}`,
value: accountMetadata?.outputLabels?.[
transaction.txid
]?.[t.payload.n],
}}
/>
) : (
<TokenTransfer
transfer={t.payload}
transaction={transaction}
singleRowLayout={useSingleRowLayout}
isFirst={i === 0}
isLast={
limit > 0
? false
: i === previewTargets.length - 1
}
/>
<>
<TokenTransfer
transfer={t.payload}
transaction={transaction}
singleRowLayout={useSingleRowLayout}
isFirst={i === 0}
isLast={
limit > 0
? false
: i ===
previewTargets.length - 1
}
isMetadataDisabled={!!isActionDisabled}
metadataPayload={{
// todo: outputLabel or create a new category 'tokenLabel' ?
type: 'outputLabel',
accountKey,
txid: transaction.txid,
// or maybe compose transferId here? instead of polluting blockchain-link?
// @ts-expect-error temp. remove
outputIndex: t.payload.transferId,
defaultValue: `${transaction.txid}-${t.payload.transferId}`,
value: accountMetadata
?.outputLabels?.[
transaction.txid
]?.[t.payload.transferId!],
}}
/>
</>
)}
</React.Fragment>
))}
Expand Down

0 comments on commit 148fd78

Please sign in to comment.