Skip to content

Commit

Permalink
feat: Added support for handling lowercase addresses
Browse files Browse the repository at this point in the history
Will now get checksum addresses from provided addresses
Added some helper libraries to avoid adding additional dependency on ethers
  • Loading branch information
Alex Risch authored and Alex Risch committed Feb 1, 2024
1 parent 670f54d commit c68bcc5
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 6 deletions.
23 changes: 23 additions & 0 deletions example/src/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -869,3 +869,26 @@ test('returns keyMaterial for conversations', async () => {

return true
})

test('correctly handles lowercase addresses', async () => {
const bob = await Client.createRandom({ env: 'local' })
await delayToPropogate()
const alice = await Client.createRandom({ env: 'local' })
await delayToPropogate()
if (bob.address === alice.address) {
throw new Error('bob and alice should be different')
}

const bobConversation = await bob.conversations.newConversation(
alice.address.toLocaleLowerCase()
)
await delayToPropogate()
if (!bobConversation) {
throw new Error('bobConversation should exist')
}
const aliceConversation = (await alice.conversations.list())[0]
if (!aliceConversation) {
throw new Error('aliceConversation should exist')
}
return true
})
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@
"dependencies": {
"@ethersproject/bytes": "^5.7.0",
"@msgpack/msgpack": "^3.0.0-beta2",
"@noble/hashes": "^1.3.3",
"@xmtp/proto": "^3.25.0",
"buffer": "^6.0.3"
"buffer": "^6.0.3",
"text-encoding": "^0.7.0"
},
"devDependencies": {
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
Expand Down
11 changes: 8 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { Conversation } from './lib/Conversation'
import { DecodedMessage } from './lib/DecodedMessage'
import type { Query } from './lib/Query'
import { getAddress } from './utils/address'

export { ReactionCodec } from './lib/NativeCodecs/ReactionCodec'
export { ReplyCodec } from './lib/NativeCodecs/ReplyCodec'
Expand Down Expand Up @@ -105,15 +106,19 @@ export async function canMessage(
clientAddress: string,
peerAddress: string
): Promise<boolean> {
return await XMTPModule.canMessage(clientAddress, peerAddress)
return await XMTPModule.canMessage(clientAddress, getAddress(peerAddress))
}

export async function staticCanMessage(
peerAddress: string,
environment: 'local' | 'dev' | 'production',
appVersion?: string | undefined
): Promise<boolean> {
return await XMTPModule.staticCanMessage(peerAddress, environment, appVersion)
return await XMTPModule.staticCanMessage(
getAddress(peerAddress),
environment,
appVersion
)
}

export async function encryptAttachment(
Expand Down Expand Up @@ -212,7 +217,7 @@ export async function createConversation<ContentTypes>(
JSON.parse(
await XMTPModule.createConversation(
client.address,
peerAddress,
getAddress(peerAddress),
JSON.stringify(context || {})
)
)
Expand Down
4 changes: 3 additions & 1 deletion src/lib/Conversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Conversation } from './Conversation'
import { DecodedMessage } from './DecodedMessage'
import { ConversationContext } from '../XMTP.types'
import * as XMTPModule from '../index'
import { getAddress } from '../utils/address'

export default class Conversations<ContentTypes> {
client: Client<ContentTypes>
Expand Down Expand Up @@ -50,9 +51,10 @@ export default class Conversations<ContentTypes> {
peerAddress: string,
context?: ConversationContext
): Promise<Conversation<ContentTypes>> {
const checksumAddress = getAddress(peerAddress)
return await XMTPModule.createConversation(
this.client,
peerAddress,
checksumAddress,
context
)
}
Expand Down
50 changes: 50 additions & 0 deletions src/utils/address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { keccak_256 } from '@noble/hashes/sha3'
import { TextEncoder } from 'text-encoding'

const addressRegex = /^0x[a-fA-F0-9]{40}$/
const encoder = new TextEncoder()

export function stringToBytes(value: string): Uint8Array {
const bytes = encoder.encode(value)
return bytes
}

export function keccak256(value: Uint8Array): Uint8Array {
const bytes = keccak_256(value)
return bytes
}

export function isAddress(address: string): boolean {
return addressRegex.test(address)
}

export function checksumAddress(address_: string, chainId?: number): string {
const hexAddress = chainId
? `${chainId}${address_.toLowerCase()}`
: address_.substring(2).toLowerCase()
const hash = keccak256(stringToBytes(hexAddress))

const address = (
chainId ? hexAddress.substring(`${chainId}0x`.length) : hexAddress
).split('')
for (let i = 0; i < 40; i += 2) {
if (hash[i >> 1] >> 4 >= 8 && address[i]) {
address[i] = address[i].toUpperCase()
}
if ((hash[i >> 1] & 0x0f) >= 8 && address[i + 1]) {
address[i + 1] = address[i + 1].toUpperCase()
}
}

return `0x${address.join('')}`
}

const addressCache = new Map<string, string>()

export function getAddress(address: string, chainId?: number): string {
if (addressCache.has(address)) return addressCache.get(address) as string
if (!isAddress(address)) throw new Error('Invalid address' + address)
const checksumedAddress = checksumAddress(address, chainId)
addressCache.set(address, checksumedAddress)
return checksumedAddress
}
7 changes: 6 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==

"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2":
"@noble/hashes@^1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
Expand Down Expand Up @@ -7958,6 +7958,11 @@ test-exclude@^6.0.0:
glob "^7.1.4"
minimatch "^3.0.4"

text-encoding@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643"
integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==

text-extensions@^2.0.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34"
Expand Down

0 comments on commit c68bcc5

Please sign in to comment.