Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent linking to flowscan for unindexed transactions #541

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 29 additions & 4 deletions src/background/controller/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
import eventBus from '@/eventBus';
import { type FeatureFlagKey, type FeatureFlags } from '@/shared/types/feature-types';
import { type TrackingEvents } from '@/shared/types/tracking-types';
import { type TransactionState } from '@/shared/types/transaction-types';
import { type TransferItem, type TransactionState } from '@/shared/types/transaction-types';
import { type LoggedInAccount } from '@/shared/types/wallet-types';
import { ensureEvmAddressPrefix, isValidEthereumAddress, withPrefix } from '@/shared/utils/address';
import { getSignAlgo } from '@/shared/utils/algo';
Expand Down Expand Up @@ -3000,7 +3000,10 @@ export class WalletController extends BaseController {
offset: number,
_expiry = 60000,
forceRefresh = false
) => {
): Promise<{
count: number;
list: TransferItem[];
}> => {
const network = await this.getNetwork();
const now = new Date();
const expiry = transactionService.getExpiry();
Expand All @@ -3014,6 +3017,7 @@ export class WalletController extends BaseController {
const pending = await transactionService.listPending(network);

return {
// NOTE: count is the total number of INDEXED transactions
count: await transactionService.getCount(),
list: pending?.length ? [...pending, ...sealed] : sealed,
};
Expand Down Expand Up @@ -3285,6 +3289,7 @@ export class WalletController extends BaseController {
return;
}
const address = (await this.getCurrentAddress()) || '0x';

const network = await this.getNetwork();
let txHash = txId;
try {
Expand Down Expand Up @@ -3313,8 +3318,28 @@ export class WalletController extends BaseController {
try {
// Send a notification to the user only on success
if (sendNotification) {
const baseURL = this.getFlowscanUrl();
notification.create(`${baseURL}/transaction/${txId}`, title, body, icon);
const baseURL = await this.getFlowscanUrl();
if (baseURL.includes('evm')) {
// It's an EVM transaction
// Look through the events in txStatus
const evmEvent = txStatus.events.find(
(event) => event.type.includes('EVM') && !!event.data?.hash
);
if (evmEvent) {
const hashBytes = evmEvent.data.hash.map((byte) => parseInt(byte));
const hash = '0x' + Buffer.from(hashBytes).toString('hex');
// Link to the account page on EVM otherwise we'll have to look up the EVM tx
notification.create(`${baseURL}/tx/${hash}`, title, body, icon);
} else {
const evmAddress = await this.getEvmAddress();

// Link to the account page on EVM as we don't have a tx hash
notification.create(`${baseURL}/address/${evmAddress}`, title, body, icon);
}
} else {
// It's a Flow transaction
notification.create(`${baseURL}/tx/${txId}`, title, body, icon);
}
}
} catch (err: unknown) {
// We don't want to throw an error if the notification fails
Expand Down
27 changes: 1 addition & 26 deletions src/background/service/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { TransactionStatus } from '@onflow/typedefs';

import { type TransferItem } from '@/shared/types/transaction-types';
import createPersistStore from 'background/utils/persisitStore';
import createSessionStore from 'background/utils/sessionStore';

Expand All @@ -10,30 +11,6 @@ interface TransactionStore {
pendingItem: Record<string, TransferItem[]>;
}

interface TransferItem {
coin: string;
status: string;
sender: string;
receiver: string;
hash: string;
time: number;
interaction: string;
amount: string;
error: boolean;
token: string;
title: string;
additionalMessage: string;
type: number;
transferType: number;
image: string;
// If true, the transaction is indexed
indexed: boolean;
// The cadence transaction id
cadenceTxId?: string;
// The EVM transaction ids
evmTxIds?: string[];
}

const now = new Date();

class Transaction {
Expand Down Expand Up @@ -273,7 +250,6 @@ class Transaction {
// Store the cadence transaction id
transactionHolder.cadenceTxId = pendingItem.cadenceTxId;
transactionHolder.evmTxIds = pendingItem.evmTxIds;
transactionHolder.hash = pendingItem.hash;
} else {
// see if there's an existing transaction with cadenceId in the store
const existingTx = this.store.transactionItem[network]?.find(
Expand All @@ -286,7 +262,6 @@ class Transaction {
// Found existing cadence transaction id
transactionHolder.cadenceTxId = existingTx.cadenceTxId;
transactionHolder.evmTxIds = existingTx.evmTxIds;
transactionHolder.hash = existingTx.hash;
}
}

Expand Down
12 changes: 10 additions & 2 deletions src/background/webapi/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@ const create = (
priority = 0
) => {
const randomId = +new Date();
chrome.notifications.create(url && `${url}_randomId_=${randomId}`, {

const notificationId = url && `${url}?randomId_=${randomId}`;
// Often the registry has a PNG equivalent to the SVG
// This can't be that reliable, but it's the best we can do for now
// Notifications don't support SVGs
// From what I can tell, Flow is the only token that has an SVG logo
const iconUrl = icon.replace(/\.svg$/, '.png');

chrome.notifications.create(notificationId, {
type: 'basic',
title,
iconUrl: icon,
iconUrl,
message,
priority,
});
Expand Down
25 changes: 25 additions & 0 deletions src/shared/types/transaction-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,28 @@ export type TransactionState = {
// The transaction if of the transaction
txId?: string;
};

// The activity item type
export interface TransferItem {
coin: string;
status: string;
sender: string;
receiver: string;
hash: string;
time: number;
interaction: string;
amount: string;
error: boolean;
token: string;
title: string;
additionalMessage: string;
type: number;
transferType: number;
image: string;
// If true, the transaction is indexed
indexed: boolean;
// The cadence transaction id
cadenceTxId?: string;
// The EVM transaction ids
evmTxIds?: string[];
}
8 changes: 4 additions & 4 deletions src/ui/hooks/useTransferListHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ export const useTransferList = () => {
);

setLoading(false);
if (data['count'] > 0) {
setCount(data['count'].toString());
setShowButton(data['count'] > 15);
if (data.count > 0) {
setCount(data.count.toString());
setShowButton(data.count > 15);
}
setTransactions(data['list']);
setTransactions(data.list);
} catch {
setLoading(false);
}
Expand Down
3 changes: 2 additions & 1 deletion src/ui/stores/transferListStore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { create } from 'zustand';

import { type TransferItem } from '@/shared/types/transaction-types';
interface TransferListState {
transactions: any[];
transactions: TransferItem[];
monitor: string;
flowscanURL: string;
viewSourceURL: string;
Expand Down
2 changes: 1 addition & 1 deletion src/ui/views/SendTo/TransferConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const TransferConfirmation = ({
txId,
true,
`${transactionState.amount} ${transactionState.coinInfo.coin} Sent`,
`You have sent ${transactionState.amount} ${transactionState.selectedToken?.symbol} to ${transactionState.toContact?.contact_name}. \nClick to view this transaction.`,
`You have sent ${transactionState.amount} ${transactionState.selectedToken?.symbol} to ${transactionState.toAddress}. \nClick to view this transaction.`,
transactionState.coinInfo.icon
);
// Record the recent contact
Expand Down
33 changes: 18 additions & 15 deletions src/ui/views/Wallet/TransferList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { useTransferList } from '@/ui/hooks/useTransferListHook';
import activity from 'ui/FRWAssets/svg/activity.svg';

import { TokenBalance } from '../TokenDetail/TokenBalance';
import { TokenValue } from '../TokenDetail/TokenValue';

dayjs.extend(relativeTime);

Expand Down Expand Up @@ -215,17 +214,17 @@ const TransferList = () => {
sx={{ paddingRight: '0px' }}
dense={true}
onClick={() => {
{
// Link to the first evm tx if there are multiple. Once the indexer updates, it'll show all the evm transactions
// This is a temporary solution until the indexer updates
const txHash =
(tx.evmTxIds && tx.evmTxIds.length) === 1 ? tx.evmTxIds[0] : tx.hash;
const url =
monitor === 'flowscan'
? `${flowscanURL}/tx/${txHash}`
: `${viewSourceURL}/${txHash}`;
window.open(url);
// Link to the first evm tx if there are multiple. Once the indexer updates, it'll show all the evm transactions
// This is a temporary solution until the indexer updates
if (!tx.indexed) {
return;
}
const txHash = tx.hash;
const url =
monitor === 'flowscan'
? `${flowscanURL}/tx/${txHash}`
: `${viewSourceURL}/${txHash}`;
window.open(url);
}}
>
<ListItemIcon
Expand All @@ -235,10 +234,14 @@ const TransferList = () => {
fontSize="medium"
sx={{ color: '#fff', cursor: 'pointer', border: '1px solid', borderRadius: '35px' }}
/> */}
<CardMedia
sx={{ width: '30px', height: '30px', borderRadius: '15px' }}
image={tx.image}
/>
{tx.image ? (
<CardMedia
sx={{ width: '30px', height: '30px', borderRadius: '15px' }}
image={tx.image}
/>
) : (
<Skeleton variant="circular" width={30} height={30} />
)}
</ListItemIcon>
<StartListItemText
time={tx.time}
Expand Down
Loading