Skip to content

Commit

Permalink
fix: support erc20 contracts with symbol method returning bytes32 type (
Browse files Browse the repository at this point in the history
  • Loading branch information
chidg authored Dec 1, 2023
1 parent d4f08b1 commit 8d5d7cd
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 13 deletions.
60 changes: 49 additions & 11 deletions apps/extension/src/core/util/getErc20ContractData.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,64 @@
import { Client, getContract, parseAbi } from "viem"
import {
Abi,
Client,
ContractFunctionExecutionError,
getContract,
hexToString,
parseAbi,
} from "viem"

const ABI_ERC20 = [
"function symbol() view returns (string)",
"function decimals() view returns (uint8)",
] as const
const DECIMALS_ABI_METHOD = "function decimals() view returns (uint8)"
const ABI_ERC20 = ["function symbol() view returns (string)", DECIMALS_ABI_METHOD] as const

const PARSED_ABI_ERC20 = parseAbi(ABI_ERC20)

const ABI_ERC20_BYTES_SYMBOL = [
"function symbol() view returns (bytes32)",
DECIMALS_ABI_METHOD,
] as const

const PARSED_ABI_ERC20_BYTES_SYMBOL = parseAbi(ABI_ERC20_BYTES_SYMBOL)

export type Erc20ContractData = {
symbol: string
decimals: number
}

const getErc20Contract =
(client: Client, contractAddress: `0x${string}`) =>
<TAbi extends Abi>(abi: TAbi) =>
getContract({
address: contractAddress,
abi,
publicClient: client,
})

export const getErc20ContractData = async (
client: Client,
contractAddress: `0x${string}`
): Promise<Erc20ContractData> => {
const contract = getContract({
address: contractAddress,
abi: PARSED_ABI_ERC20,
publicClient: client,
})
const [symbol, decimals] = await Promise.all([contract.read.symbol(), contract.read.decimals()])
const getEr20ContractFn = getErc20Contract(client, contractAddress)

try {
const contract = getEr20ContractFn(PARSED_ABI_ERC20)

// eslint-disable-next-line no-var
var [symbol, decimals] = await Promise.all([contract.read.symbol(), contract.read.decimals()])
} catch (e) {
if (e instanceof ContractFunctionExecutionError) {
// try to perform the contract read with bytes32 symbol
const contract = getEr20ContractFn(PARSED_ABI_ERC20_BYTES_SYMBOL)

// eslint-disable-next-line no-var
var [bytesSymbol, decimals] = await Promise.all([
contract.read.symbol(),
contract.read.decimals(),
])
symbol = hexToString(bytesSymbol)
} else {
throw e
}
}

return { symbol, decimals }
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ export const AddCustomTokenPage = () => {
)

const addressErrorMessage = useMemo(() => {
// error code may be filled by ethers provider
// error code may be filled by viem provider
const error = tokenInfoError as Error & { code?: string }

if (error?.code === "NETWORK_ERROR") return t("Failed to connect")
else if (error) return t("Invalid address")
else if (error) return t("Not a valid token address")
else return undefined
}, [t, tokenInfoError])

Expand Down

0 comments on commit 8d5d7cd

Please sign in to comment.