Skip to content

Commit

Permalink
feat: lru cache on checksumAddress; note on EIP-1191
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed May 11, 2024
1 parent 5032eeb commit 351a076
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/loud-days-argue.md
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added note on EIP-1191 checksum.
5 changes: 5 additions & 0 deletions .changeset/wet-gorillas-fly.md
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added LRU cache for `checksumAddress`.
14 changes: 10 additions & 4 deletions site/pages/docs/utilities/getAddress.md
Expand Up @@ -19,10 +19,6 @@ import { getAddress } from 'viem'

getAddress('0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac') // [!code focus:2]
// '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'

// EIP-1191 address
getAddress('0x27b1fdb04752bbc536007a920d24acb045561c26', 30)
// '0x27b1FdB04752BBc536007A920D24ACB045561c26'
```

## Returns
Expand All @@ -44,3 +40,13 @@ An Ethereum address.
- **Type:** `number`

The chain ID of the network the address is on. Complies to [EIP-1191](https://eips.ethereum.org/EIPS/eip-1191).

:::warning[Warning]
EIP-1191 checksum addresses are generally not backwards compatible with
the wider Ethereum ecosystem, meaning it will break when validated against
an application/tool that relies on EIP-55 checksum encoding (checksum without chainId).

It is highly recommended to not use this feature unless you know what you are doing.

See more: https://github.com/ethereum/EIPs/issues/1121
:::
35 changes: 33 additions & 2 deletions src/utils/address/getAddress.ts
Expand Up @@ -7,17 +7,33 @@ import {
stringToBytes,
} from '../encoding/toBytes.js'
import { type Keccak256ErrorType, keccak256 } from '../hash/keccak256.js'
import { LruMap } from '../lru.js'
import { type IsAddressErrorType, isAddress } from './isAddress.js'

export const checksumAddressCache = /*#__PURE__*/ new LruMap<Address>(8192)

export type ChecksumAddressErrorType =
| Keccak256ErrorType
| StringToBytesErrorType
| ErrorType

export function checksumAddress(
address_: Address,
/**
* Warning: EIP-1191 checksum addresses are generally not backwards compatible with the
* wider Ethereum ecosystem, meaning it will break when validated against an application/tool
* that relies on EIP-55 checksum encoding (checksum without chainId).
*
* It is highly recommended to not use this feature unless you
* know what you are doing.
*
* See more: https://github.com/ethereum/EIPs/issues/1121
*/
chainId?: number | undefined,
): Address {
if (checksumAddressCache.has(`${address_}.${chainId}`))
return checksumAddressCache.get(`${address_}.${chainId}`)!

const hexAddress = chainId
? `${chainId}${address_.toLowerCase()}`
: address_.substring(2).toLowerCase()
Expand All @@ -35,15 +51,30 @@ export function checksumAddress(
}
}

return `0x${address.join('')}`
const result = `0x${address.join('')}` as const
checksumAddressCache.set(`${address_}.${chainId}`, result)
return result
}

export type GetAddressErrorType =
| ChecksumAddressErrorType
| IsAddressErrorType
| ErrorType

export function getAddress(address: string, chainId?: number): Address {
export function getAddress(
address: string,
/**
* Warning: EIP-1191 checksum addresses are generally not backwards compatible with the
* wider Ethereum ecosystem, meaning it will break when validated against an application/tool
* that relies on EIP-55 checksum encoding (checksum without chainId).
*
* It is highly recommended to not use this feature unless you
* know what you are doing.
*
* See more: https://github.com/ethereum/EIPs/issues/1121
*/
chainId?: number,
): Address {
if (!isAddress(address, { strict: false }))
throw new InvalidAddressError({ address })
return checksumAddress(address, chainId)
Expand Down

0 comments on commit 351a076

Please sign in to comment.