Skip to content

Commit

Permalink
feat(authors): add .sol to useResolvedAuthorAddress
Browse files Browse the repository at this point in the history
  • Loading branch information
estebanabaroa committed Mar 26, 2024
1 parent 63833e9 commit 0a3df5c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 25 deletions.
9 changes: 8 additions & 1 deletion config/vitest.setup.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
// add jest setup (jsdom) here
// import crypto from "crypto"

// fix TextDecoder isn't defined in jsdom
const {TextEncoder, TextDecoder} = require('util')
global.TextEncoder = TextEncoder
global.TextDecoder = TextDecoder

// fix TypeError: Failed to execute 'digest' on 'SubtleCrypto': 2nd argument is not instance of ArrayBuffer, Buffer, TypedArray, or DataView.
// fix TypeError: crypto.web.getRandomValues is not a function
// Object.defineProperty(global.self, "crypto", {value: {
// subtle: crypto.webcrypto.subtle,
// getRandomValues: (arr) => crypto.randomBytes(arr.length)
// }})
33 changes: 30 additions & 3 deletions src/hooks/authors/authors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,16 +574,17 @@ describe('authors', () => {
const timeout = 60000

// skip because uses internet and not deterministic
test.skip(
test(
'useResolvedAuthorAddress',
async () => {
const rendered = renderHook<any, any>((author) => useResolvedAuthorAddress({author}))
const waitFor = testUtils.createWaitFor(rendered, {timeout})
expect(rendered.result.current.resolvedAddress).toBe(undefined)

rendered.rerender({address: 'plebbit.eth'})
rendered.rerender({address: 'subplebbit.eth'})
await waitFor(() => typeof rendered.result.current.resolvedAddress === 'string')
expect(rendered.result.current.resolvedAddress).toBe('QmX18Ls7iss1BLXYjZqP5faFoXih7YYSUkADdATHxiXmnu')
console.log(rendered.result.current)
expect(rendered.result.current.resolvedAddress).toBe('resolved author address')
},
{timeout}
)
Expand Down Expand Up @@ -615,6 +616,32 @@ describe('authors', () => {
},
{timeout}
)

test(
'useResolvedAuthorAddress .eth has no error',
async () => {
const rendered = renderHook<any, any>((author) => useResolvedAuthorAddress({author}))
const waitFor = testUtils.createWaitFor(rendered)
expect(rendered.result.current.resolvedAddress).toBe(undefined)

rendered.rerender({address: 'abc.eth'})
expect(rendered.result.current.error).toBe(undefined)
},
{timeout}
)

test(
'useResolvedAuthorAddress .sol has no error',
async () => {
const rendered = renderHook<any, any>((author) => useResolvedAuthorAddress({author}))
const waitFor = testUtils.createWaitFor(rendered)
expect(rendered.result.current.resolvedAddress).toBe(undefined)

rendered.rerender({address: 'abc.sol'})
expect(rendered.result.current.error).toBe(undefined)
},
{timeout}
)
})
})

Expand Down
52 changes: 32 additions & 20 deletions src/hooks/authors/authors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
UseAuthorAddressOptions,
UseAuthorAddressResult,
} from '../../types'
import {resolveEnsTxtRecord, resolveEnsTxtRecordNoCache} from '../../lib/chain'
import {useNftMetadataUrl, useNftImageUrl, useVerifiedAuthorAvatarSignature, useAuthorAvatarIsWhitelisted} from './author-avatars'
import {useComment, useComments} from '../comments'
import {useAuthorCommentsName, usePlebbitAddress} from './utils'
Expand Down Expand Up @@ -348,6 +347,27 @@ export function useResolvedAuthorAddress(options?: UseResolvedAuthorAddressOptio
initialState = 'ready'
}

const isCryptoName = author?.address.includes('.')
const tld = isCryptoName ? author?.address?.split('.').pop() : undefined

const resolveAuthorAddressNoCache = () => {
if (Boolean(resolveAuthorAddressPromises[author?.address])) {
return resolveAuthorAddressPromises[author?.address]
}
log('useResolvedAuthorAddress plebbit.resolveAuthorAddress', {address: author?.address})
resolveAuthorAddressPromises[author?.address] = account.plebbit.resolveAuthorAddress(author?.address)
return resolveAuthorAddressPromises[author?.address]
}
const resolveAuthorAddress = async () => {
const cached = resolvedAuthorAddressCache.get(author?.address)
if (cached) {
return cached
}
const res = await resolveAuthorAddressNoCache()
resolvedAuthorAddressCache.set(author?.address, res)
return res
}

useInterval(
() => {
// no options, do nothing or reset
Expand All @@ -365,7 +385,7 @@ export function useResolvedAuthorAddress(options?: UseResolvedAuthorAddressOptio
}

// address isn't a crypto domain, can't be resolved
if (!author?.address.includes('.')) {
if (!isCryptoName) {
if (state !== 'failed') {
setErrors([Error('not a crypto domain')])
setState('failed')
Expand All @@ -374,8 +394,8 @@ export function useResolvedAuthorAddress(options?: UseResolvedAuthorAddressOptio
return
}

// only support resolving '.eth' for now
if (!author?.address?.endsWith('.eth')) {
// only support resolving '.eth/.sol' for now
if (tld !== 'eth' && tld !== 'sol') {
if (state !== 'failed') {
setErrors([Error('crypto domain type unsupported')])
setState('failed')
Expand All @@ -387,7 +407,12 @@ export function useResolvedAuthorAddress(options?: UseResolvedAuthorAddressOptio
;(async () => {
try {
setState('resolving')
const res = await resolveAuthorAddress(author?.address, chainProviders, cache)
let res
if (cache) {
res = await resolveAuthorAddress()
} else {
res = await resolveAuthorAddressNoCache()
}
setState('succeeded')

// TODO: check if resolved address is the same as author.signer.publicKey
Expand All @@ -408,10 +433,9 @@ export function useResolvedAuthorAddress(options?: UseResolvedAuthorAddressOptio
[author?.address, chainProviders]
)

// log('useResolvedAuthorAddress', {author, state, errors, resolvedAddress, chainProviders})
log('useResolvedAuthorAddress', {author, state, errors, resolvedAddress, chainProviders})

// only support ENS at the moment
const chainProvider = chainProviders?.['eth']
const chainProvider = chainProviders?.[tld]

return useMemo(
() => ({
Expand All @@ -424,15 +448,3 @@ export function useResolvedAuthorAddress(options?: UseResolvedAuthorAddressOptio
[resolvedAddress, chainProvider, state, errors]
)
}

// NOTE: resolveAuthorAddress tests are skipped, if changes are made they must be tested manually
export const resolveAuthorAddress = async (authorAddress: string, chainProviders: ChainProviders, cache?: boolean) => {
let resolvedAuthorAddress
if (authorAddress.endsWith('.eth')) {
const resolve = cache ? resolveEnsTxtRecord : resolveEnsTxtRecordNoCache
resolvedAuthorAddress = await resolve(authorAddress, 'plebbit-author-address', 'eth', chainProviders?.['eth']?.urls?.[0], chainProviders?.['eth']?.chainId)
} else {
throw Error(`resolveAuthorAddress invalid authorAddress '${authorAddress}'`)
}
return resolvedAuthorAddress
}
4 changes: 3 additions & 1 deletion src/lib/plebbit-js/plebbit-js-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export const debugPlebbitJsMock = () => {
}

export class Plebbit extends EventEmitter {
async resolveAuthorAddress(authorAddress: string) {}
async resolveAuthorAddress(authorAddress: string) {
return 'resolved author address'
}

async createSigner() {
return {
Expand Down

0 comments on commit 0a3df5c

Please sign in to comment.