Skip to content

Commit

Permalink
Migrate from Ethers to Viem
Browse files Browse the repository at this point in the history
  • Loading branch information
rkalis committed Nov 6, 2023
1 parent 81daa66 commit e290911
Show file tree
Hide file tree
Showing 28 changed files with 441 additions and 687 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"@metamask/post-message-stream": "^5.0.0",
"@revoke.cash/chains": "^11.0.0",
"eth-rpc-errors": "^4.0.3",
"ethers": "^5.6.9",
"extension-port-stream": "^2.0.1",
"i18next": "^21.10.0",
"object-hash": "^3.0.0",
Expand All @@ -35,6 +34,7 @@
"react-switch": "^6.1.0",
"stream-browserify": "^3.0.0",
"tailwind-merge": "^1.12.0",
"viem": "^1.18.6",
"webextension-polyfill": "^0.9.0"
},
"devDependencies": {
Expand Down Expand Up @@ -65,7 +65,8 @@
"style-loader": "^3.3.1",
"tailwindcss": "^3.1.6",
"ts-loader": "^8.0.0",
"typescript": "^4.4.3 ",
"ts-node": "^10.9.1",
"typescript": "^5.2.2",
"web-ext": "^7.1.1",
"webpack": "^5.61.0",
"webpack-cli": "^4.0.0",
Expand Down
10 changes: 5 additions & 5 deletions scripts/get-new-potential-scam-transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ const getTransactions = async () => {
// SecurityUpdates() and ClaimRewards() type scam transactions often look like this:
const filteredTransactions = transactions.filter((transaction) => {
return (
transaction.value?.gt(0) &&
transaction.data.length >= 10 &&
transaction.data.length < 50 &&
!ignoredSignatures.includes(transaction.data.slice(0, 10))
transaction.value > 0n &&
transaction.input.length >= 10 &&
transaction.input.length < 50 &&
!ignoredSignatures.includes(transaction.input.slice(0, 10))
);
});

console.log(`${filteredTransactions.length}/${transactions.length} in the last ${blockCount} blocks`);

filteredTransactions.forEach((transaction) =>
console.log(transaction.hash, transaction.data.slice(0, 10), transaction.to)
console.log(transaction.hash, transaction.input.slice(0, 10), transaction.to)
);

return filteredTransactions;
Expand Down
6 changes: 3 additions & 3 deletions scripts/get-signature-transactions.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { Interface } from 'ethers/lib/utils';
import { getTransactionsInBlocks } from './utils/transactions';
import { keccak256, toBytes } from 'viem';

const [_executable, _file, fragment, blockCountStr] = process.argv;

const signature = new Interface([`function ${fragment}`]).getSighash(fragment);
const signature = keccak256(toBytes(fragment)).slice(0, 10);
const blockCount = Number(blockCountStr) || 1;

const getTransactions = async () => {
const transactions = await getTransactionsInBlocks(blockCount);

const filteredTransactions = transactions.filter((transaction) => {
return transaction.data?.startsWith(signature);
return transaction.input?.startsWith(signature);
});

console.log(
Expand Down
4 changes: 2 additions & 2 deletions scripts/get-signature.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Interface } from 'ethers/lib/utils';
import { keccak256, toBytes } from 'viem';

const fragment = process.argv[2];

const signature = new Interface([`function ${fragment}`]).getSighash(fragment);
const signature = keccak256(toBytes(fragment)).slice(0, 10);
console.log(signature);
10 changes: 6 additions & 4 deletions scripts/utils/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getChainProvider } from '../../src/lib/utils/chains';
import { createViemPublicClientForChain } from '../../src/lib/utils/chains';

// Inclusive range
const range = (start: number, end: number): number[] => {
Expand All @@ -7,13 +7,15 @@ const range = (start: number, end: number): number[] => {
};

export const getTransactionsInBlocks = async (blockCount: number = 1) => {
const provider = getChainProvider(1);
const client = createViemPublicClientForChain(1);

const toBlock = await provider.getBlockNumber();
const toBlock = Number(await client.getBlockNumber());
const fromBlock = toBlock - blockCount + 1;

const blocks = await Promise.all(
range(fromBlock, toBlock).map((blockNumber) => provider.getBlockWithTransactions(blockNumber))
range(fromBlock, toBlock).map((blockNumber) =>
client.getBlock({ blockNumber: BigInt(blockNumber), includeTransactions: true })
)
);

const transactions = blocks.flatMap((block) => block.transactions);
Expand Down
5 changes: 3 additions & 2 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { HashDecoder } from './lib/decoders/untyped-signature/HashDecoder';
import { Message, MessageResponse, WarningData } from './lib/types';
import { randomId } from './lib/utils/misc';
import { getStorage, setStorage } from './lib/utils/storage';
import { Hash } from 'viem';

// This is technically async, but it's safe to assume that this will complete before any tracking occurs
if (process.env.AMPLITUDE_API_KEY) {
Expand All @@ -41,8 +42,8 @@ if (process.env.AMPLITUDE_API_KEY) {

// Note that these messages will be periodically cleared due to the background service shutting down
// after 5 minutes of inactivity (see Manifest v3 docs).
const messagePorts: { [index: string]: Browser.Runtime.Port } = {};
const approvedMessages: string[] = [];
const messagePorts: Record<string, Browser.Runtime.Port> = {};
const approvedMessages: Array<Hash> = [];

const transactionDecoders = [
new ApproveDecoder(),
Expand Down
3 changes: 2 additions & 1 deletion src/components/common/AddressOrDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import { Address } from 'viem';
import { getChainExplorerUrl } from '../../lib/utils/chains';
import Href from './Href';

interface Props {
chainId: number;
address?: string;
address?: Address;
display?: string;
}

Expand Down
9 changes: 5 additions & 4 deletions src/components/confirm/AllowanceAsset.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import React from 'react';
import { useAsync } from 'react-async-hook';
import { getChainProvider } from '../../lib/utils/chains';
import { Address } from 'viem';
import { createViemPublicClientForChain } from '../../lib/utils/chains';
import { getTokenData } from '../../lib/utils/tokens';
import { AddressOrDisplay } from '../common/AddressOrDisplay';
import Loadable from '../common/Loadable';

interface Props {
chainId: number;
address: string;
address: Address;
}

const AllowanceAsset = ({ address, chainId }: Props) => {
const provider = getChainProvider(chainId);
const { result, loading } = useAsync(() => getTokenData(address, provider), []);
const client = createViemPublicClientForChain(chainId);
const { result, loading } = useAsync(() => getTokenData(address, client), []);

const { name, symbol } = result ?? {};
const assetDisplay = name && symbol ? `${name} (${symbol})` : name || symbol || address;
Expand Down
3 changes: 2 additions & 1 deletion src/components/confirm/AllowanceSpender.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import { useAsync } from 'react-async-hook';
import { Address } from 'viem';
import { getSpenderData } from '../../lib/utils/whois';
import { AddressOrDisplay } from '../common/AddressOrDisplay';
import Loadable from '../common/Loadable';

interface Props {
chainId: number;
address: string;
address: Address;
}

const AllowanceSpender = ({ address, chainId }: Props) => {
Expand Down
6 changes: 3 additions & 3 deletions src/components/confirm/ListingAsset.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { useAsync } from 'react-async-hook';
import { NftListingItem } from '../../lib/types';
import { getChainProvider } from '../../lib/utils/chains';
import { createViemPublicClientForChain } from '../../lib/utils/chains';
import { getNftListingItemTokenData } from '../../lib/utils/tokens';
import { AddressOrDisplay } from '../common/AddressOrDisplay';
import Loadable from '../common/Loadable';
Expand All @@ -12,8 +12,8 @@ interface Props {
}

const ListingAsset = ({ item, chainId }: Props) => {
const provider = getChainProvider(chainId);
const { result, loading } = useAsync(() => getNftListingItemTokenData(item, provider), []);
const client = createViemPublicClientForChain(chainId);
const { result, loading } = useAsync(() => getNftListingItemTokenData(item, client), []);

return (
<Loadable loading={loading}>
Expand Down
3 changes: 2 additions & 1 deletion src/components/confirm/WarningControls.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import { Hash } from 'viem';
import Browser from 'webextension-polyfill';
import { useTranslation } from '../../i18n';
import Button from '../common/Button';

interface Props {
requestId: string;
requestId: Hash;
bypassed: boolean;
}

Expand Down
26 changes: 13 additions & 13 deletions src/injected/proxy-injected-providers.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { WindowPostMessageStream } from '@metamask/post-message-stream';
import { ethErrors } from 'eth-rpc-errors';
import { providers } from 'ethers';
import { createWalletClient, custom } from 'viem';
import { Identifier, RequestType } from '../lib/constants';
import { sendToStreamAndAwaitResponse } from '../lib/utils/messages';

Expand Down Expand Up @@ -54,10 +54,10 @@ const proxyEthereumProvider = (ethereumProvider: any, name: string) => {
if (!transaction) return Reflect.apply(target, thisArg, argumentsList);

const type = RequestType.TRANSACTION;
const provider = new providers.Web3Provider(ethereumProvider);
provider
.getNetwork()
.then(({ chainId }) => sendToStreamAndAwaitResponse(stream, { type, transaction, chainId }))
const client = createWalletClient({ transport: custom(ethereumProvider) });
client
.getChainId()
.then((chainId) => sendToStreamAndAwaitResponse(stream, { type, transaction, chainId }))
.then((isOk) => {
if (isOk) {
return Reflect.apply(target, thisArg, argumentsList);
Expand All @@ -80,10 +80,10 @@ const proxyEthereumProvider = (ethereumProvider: any, name: string) => {
const typedData = JSON.parse(typedDataStr);

const type = RequestType.TYPED_SIGNATURE;
const provider = new providers.Web3Provider(ethereumProvider);
provider
.getNetwork()
.then(({ chainId }) => sendToStreamAndAwaitResponse(stream, { type, address, typedData, chainId }))
const client = createWalletClient({ transport: custom(ethereumProvider) });
client
.getChainId()
.then((chainId) => sendToStreamAndAwaitResponse(stream, { type, address, typedData, chainId }))
.then((isOk) => {
if (isOk) {
return Reflect.apply(target, thisArg, argumentsList);
Expand Down Expand Up @@ -136,8 +136,8 @@ const proxyEthereumProvider = (ethereumProvider: any, name: string) => {
const [transaction] = request?.params ?? [];
if (!transaction) return Reflect.apply(target, thisArg, argumentsList);

const provider = new providers.Web3Provider(ethereumProvider);
const { chainId } = await provider.getNetwork();
const client = createWalletClient({ transport: custom(ethereumProvider) });
const chainId = await client.getChainId();

const type = RequestType.TRANSACTION;
const isOk = await sendToStreamAndAwaitResponse(stream, { type, transaction, chainId });
Expand All @@ -151,8 +151,8 @@ const proxyEthereumProvider = (ethereumProvider: any, name: string) => {

const typedData = JSON.parse(typedDataStr);

const provider = new providers.Web3Provider(ethereumProvider);
const { chainId } = await provider.getNetwork();
const client = createWalletClient({ transport: custom(ethereumProvider) });
const chainId = await client.getChainId();

const type = RequestType.TYPED_SIGNATURE;
const isOk = await sendToStreamAndAwaitResponse(stream, { type, address, typedData, chainId });
Expand Down
18 changes: 9 additions & 9 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export const Urls = {
DISCORD: 'https://discord.gg/revoke-cash',
TWITTER: 'https://twitter.com/RevokeCash',
GITHUB: 'https://github.com/RevokeCash/browser-extension',
};
} as const;

export const Identifier = {
INPAGE: 'revoke-inpage',
Expand All @@ -13,14 +13,14 @@ export const Identifier = {
METAMASK_CONTENT_SCRIPT: 'metamask-contentscript',
METAMASK_PROVIDER: 'metamask-provider',
COINBASE_WALLET_REQUEST: 'extensionUIRequest',
};
} as const;

export const SignatureIdentifier = {
approve: '0x095ea7b3',
permit2Approve: '0x87517c45',
increaseAllowance: '0x39509351',
setApprovalForAll: '0xa22cb465',
};
} as const;

export const potentialScamSignatures = [
'0x5fba79f5', // SecurityUpdate()
Expand All @@ -44,11 +44,11 @@ export const Signature = {
permit2Approve: 'approve(address,address,uint160,uint48)',
increaseAllowance: 'increaseAllowance(address,uint256)',
setApprovalForAll: 'setApprovalForAll(address,bool)',
};
} as const;

export const Address = {
ZERO: '0x0000000000000000000000000000000000000000',
};
} as const;

export enum RequestType {
TRANSACTION = 'transaction',
Expand All @@ -71,24 +71,24 @@ export const OpenSeaItemType = {
ERC721_CRITERIA: '4',
ERC1155_CRITERIA: '5',
UNKNOWN: '-1',
};
} as const;

export const PlaceHolderItem = {
UNKNOWN: {
itemType: OpenSeaItemType.UNKNOWN,
token: 'unknown',
token: Address.ZERO,
identifierOrCriteria: 'unknown',
startAmount: 'unknown',
endAmount: 'unknown',
},
ZERO_ETH: {
itemType: OpenSeaItemType.ETHER,
token: '',
token: Address.ZERO,
identifierOrCriteria: '',
startAmount: '0',
endAmount: '0',
},
};
} as const;

export const HostnameAllowList: Record<WarningType, string[]> = {
[WarningType.ALLOWANCE]: [],
Expand Down
14 changes: 8 additions & 6 deletions src/lib/decoders/transaction/ApproveDecoder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { BigNumber } from 'ethers';
import { Interface } from 'ethers/lib/utils';
import { decodeFunctionData, parseAbi } from 'viem';
import { Address, Signature, SignatureIdentifier, WarningType } from '../../constants';
import { AllowanceWarningData, TransactionMessage } from '../../types';
import { TransactionDecoder } from './TransactionDecoder';
Expand All @@ -11,12 +10,15 @@ export class ApproveDecoder implements TransactionDecoder {
if (!data || !user || !asset) return undefined;
if (!data.startsWith(SignatureIdentifier.approve)) return undefined;

const iface = new Interface([`function ${Signature.approve}`]);
const decoded = iface.decodeFunctionData(Signature.approve, data);
const [spender, approval] = Array.from(decoded);
const decoded = decodeFunctionData({
abi: parseAbi([`function ${Signature.approve}`]),
data,
});

const [spender, approval] = decoded.args;

try {
if (BigNumber.from(approval).isZero() || spender === Address.ZERO) return undefined;
if (approval === 0n || spender === Address.ZERO) return undefined;
} catch {
return undefined;
}
Expand Down
14 changes: 8 additions & 6 deletions src/lib/decoders/transaction/IncreaseAllowanceDecoder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { BigNumber } from 'ethers';
import { Interface } from 'ethers/lib/utils';
import { decodeFunctionData, parseAbi } from 'viem';
import { Signature, SignatureIdentifier, WarningType } from '../../constants';
import { AllowanceWarningData, TransactionMessage } from '../../types';
import { TransactionDecoder } from './TransactionDecoder';
Expand All @@ -11,12 +10,15 @@ export class IncreaseAllowanceDecoder implements TransactionDecoder {
if (!data || !user || !asset) return undefined;
if (!data.startsWith(SignatureIdentifier.increaseAllowance)) return undefined;

const iface = new Interface([`function ${Signature.increaseAllowance}`]);
const decoded = iface.decodeFunctionData(Signature.increaseAllowance, data);
const [spender, approval] = Array.from(decoded);
const decoded = decodeFunctionData({
abi: parseAbi([`function ${Signature.increaseAllowance}`]),
data,
});

const [spender, approval] = decoded.args;

try {
if (BigNumber.from(approval).isZero()) return undefined;
if (approval === 0n) return undefined;
} catch {
return undefined;
}
Expand Down
Loading

0 comments on commit e290911

Please sign in to comment.