diff --git a/README.md b/README.md index c795319..ceba17d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Avatar resolver library for both nodejs and browser. +## Note!: ENS-Avatar >= 1.0.0 is only compatible with ethers v6. If your project is using v5, keep your ens-avatar on latest 0.x version. + ## Getting started ### Prerequisites diff --git a/package.json b/package.json index 6d38cf1..89cf858 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.3.6", + "version": "1.0.0-alpha.1.ethers.6", "license": "MIT", "main": "dist/index.js", "module": "dist/index.esm.js", @@ -22,7 +22,7 @@ }, "husky": { "hooks": { - "pre-commit": "tsdx lint" + "pre-commit": "tsdx lint src test" } }, "prettier": { @@ -74,6 +74,7 @@ "axios-cache-interceptor": "^0.9.3", "buffer": "^6.0.3", "dompurify": "^3.0.6", + "ethers": "6.12.0", "is-svg": "^4.3.2", "multiformats": "^9.6.2", "url-join": "^4.0.1" diff --git a/src/index.ts b/src/index.ts index 1e4e22d..349a48b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { BaseProvider } from '@ethersproject/providers'; +import { JsonRpcProvider } from 'ethers'; import ERC1155 from './specs/erc1155'; import ERC721 from './specs/erc721'; import URI from './specs/uri'; @@ -23,14 +23,14 @@ export interface UnsupportedNamespace {} export class UnsupportedNamespace extends BaseError {} export interface AvatarResolver { - provider: BaseProvider; + provider: JsonRpcProvider; options?: AvatarResolverOpts; getAvatar(ens: string, data: AvatarRequestOpts): Promise; getMetadata(ens: string): Promise; } export class AvatarResolver implements AvatarResolver { - constructor(provider: BaseProvider, options?: AvatarResolverOpts) { + constructor(provider: JsonRpcProvider, options?: AvatarResolverOpts) { this.provider = provider; this.options = options; if (options?.cache && options?.cache > 0) { diff --git a/src/specs/erc1155.ts b/src/specs/erc1155.ts index 3277d92..f260460 100644 --- a/src/specs/erc1155.ts +++ b/src/specs/erc1155.ts @@ -1,5 +1,4 @@ -import { BaseProvider } from '@ethersproject/providers'; -import { Contract } from '@ethersproject/contracts'; +import { Contract, Provider } from 'ethers'; import { Buffer } from 'buffer/'; import { fetch, resolveURI } from '../utils'; import { AvatarResolverOpts } from '../types'; @@ -21,7 +20,7 @@ function getMarketplaceAPIKey(uri: string, options?: AvatarResolverOpts) { export default class ERC1155 { async getMetadata( - provider: BaseProvider, + provider: Provider, ownerAddress: string | undefined | null, contractAddress: string, tokenID: string, @@ -34,10 +33,10 @@ export default class ERC1155 { const contract = new Contract(contractAddress, abi, provider); const [tokenURI, balance] = await Promise.all([ contract.uri(tokenID), - ownerAddress && contract.balanceOf(ownerAddress, tokenID), + ownerAddress ? contract.balanceOf(ownerAddress, tokenID) : BigInt(0), ]); // if user has valid address and if token balance of given address is greater than 0 - const isOwner = !!(ownerAddress && balance.gt(0)); + const isOwner = !!(ownerAddress && balance > BigInt(0)); const { uri: resolvedURI, isOnChain, isEncoded } = resolveURI( tokenURI, diff --git a/src/specs/erc721.ts b/src/specs/erc721.ts index 50fcf70..28591d0 100644 --- a/src/specs/erc721.ts +++ b/src/specs/erc721.ts @@ -1,5 +1,4 @@ -import { BaseProvider } from '@ethersproject/providers'; -import { Contract } from '@ethersproject/contracts'; +import { Contract, Provider } from 'ethers'; import { Buffer } from 'buffer/'; import { fetch, resolveURI } from '../utils'; import { AvatarResolverOpts } from '../types'; @@ -11,7 +10,7 @@ const abi = [ export default class ERC721 { async getMetadata( - provider: BaseProvider, + provider: Provider, ownerAddress: string | undefined | null, contractAddress: string, tokenID: string, diff --git a/src/types.ts b/src/types.ts index 81158c9..5c02d69 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,8 +1,8 @@ -import { BaseProvider } from '@ethersproject/providers'; +import { Provider } from 'ethers'; export interface Spec { getMetadata: ( - provider: BaseProvider, + provider: Provider, ownerAddress: string | undefined | null, contractAddress: string, tokenID: string, diff --git a/test/resolver.test.ts b/test/resolver.test.ts index 2bd4672..437a13a 100644 --- a/test/resolver.test.ts +++ b/test/resolver.test.ts @@ -1,4 +1,4 @@ -import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { JsonRpcProvider } from 'ethers'; import nock from 'nock'; import { AvatarResolver } from '../src'; @@ -14,252 +14,318 @@ const CORS_HEADERS = { 'access-control-allow-origin': 'http://localhost', }; -function nockInfura(method: string, params: any[], response: any) { +function nockInfuraBatch(body: any[], response: any) { + nock(INFURA_URL.origin) + .persist(false) + .post(INFURA_URL.pathname, body) + .reply(200, response); +} + +function mockInfuraChainId(id: number) { nock(INFURA_URL.origin) - .persist() .post(INFURA_URL.pathname, { - method, - params, + method: 'eth_chainId', + params: [], id: /[0-9]/, jsonrpc: '2.0', }) - .reply(200, response); + .reply( + 200, + { + jsonrpc: '2.0', + id: id, + result: '0x1', + }, + CORS_HEADERS as any + ); } -beforeAll(() => { - nockInfura('eth_chainId', [], { - id: 1, +function ethCallParams(to: string, data: string, id: number) { + return { + method: 'eth_call', + params: [{ to, data }, 'latest'], + id, jsonrpc: '2.0', - result: '0x01', // mainnet - }); - nockInfura('net_version', [], { + }; +} + +function chainIdParams(id: number) { + return { + method: 'eth_chainId', + params: [], + id, jsonrpc: '2.0', - id: 1, - result: '1', - }); - nockInfura( - 'eth_call', - [ - { - to: ENSRegistryWithFallback, - data: /^.*$/, - }, - 'latest', - ], - { - result: `0x${PublicResolver.replace('0x', '').padStart(64, '0')}`, - } - ); -}); + }; +} + +function jsonRPCresult(result: string, id: number) { + return { + jsonrpc: '2.0', + id, + result, + }; +} describe('get avatar', () => { - const provider = new StaticJsonRpcProvider( - 'https://mainnet.infura.io/v3/372375d582d843c48a4eaee6aa5c1b3a' - ); - const avt = new AvatarResolver(provider); - it('retrieves image uri with erc1155 spec', async () => { - nockInfura( - 'eth_call', + const provider = new JsonRpcProvider(INFURA_URL.toString(), 'mainnet'); + const avt = new AvatarResolver(provider, { + apiKey: { + opensea: 'a2b184238ee8460d9d2f58b0d3177c23', + }, + }); + it('retrieves image uri with erc721 spec', async () => { + mockInfuraChainId(1); + + nockInfuraBatch( [ - { - to: PublicResolver.toLowerCase(), - data: - '0x3b3b57de05a67c0ee82964c4f7394cdd47fee7f4d9503a23c09c38341779ea012afe6e00', - }, - 'latest', + chainIdParams(2), + ethCallParams( + ENSRegistryWithFallback, + '0x0178b8bf80ee077a908dffcf32972ba13c2df16b42688e1de21bcf17d3469a8507895eae', + 3 + ), + ethCallParams( + ENSRegistryWithFallback, + '0x0178b8bf80ee077a908dffcf32972ba13c2df16b42688e1de21bcf17d3469a8507895eae', + 4 + ), ], - { - result: - '0x000000000000000000000000b8c2c29ee19d8307cb7255e1cd9cbde883a267d5', - } - ); - nockInfura( - 'eth_call', [ - { - to: PublicResolver.toLowerCase(), - data: - '0x59d1d43c05a67c0ee82964c4f7394cdd47fee7f4d9503a23c09c38341779ea012afe6e00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066176617461720000000000000000000000000000000000000000000000000000', - }, - 'latest', - ], - { - result: - '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000886569703135353a312f657263313135353a3078343935663934373237363734396365363436663638616338633234383432303034356362376235652f38313132333136303235383733393237373337353035393337383938393135313533373332353830313033393133373034333334303438353132333830343930373937303038353531393337000000000000000000000000000000000000000000000000', - } + jsonRPCresult('0x1', 2), + jsonRPCresult( + '0x0000000000000000000000004976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41', + 3 + ), + jsonRPCresult( + '0x0000000000000000000000004976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41', + 4 + ), + ] ); - nockInfura( - 'eth_call', + nockInfuraBatch( [ - { - to: '0x495f947276749ce646f68ac8c248420045cb7b5e', - data: - '0x0e89341c11ef687cfeb2e353670479f2dcc76af2bc6b3935000000000002c40000000001', - }, - 'latest', + ethCallParams( + PublicResolver.toLowerCase(), + '0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000', + 5 + ), + chainIdParams(6), ], - { - result: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005868747470733a2f2f6170692e6f70656e7365612e696f2f6170692f76312f6d657461646174612f3078343935663934373237363734394365363436663638414338633234383432303034356362376235652f30787b69647d0000000000000000', - } - ); - nockInfura( - 'eth_call', [ - { - to: '0x495f947276749ce646f68ac8c248420045cb7b5e', - data: - '0x00fdd58e000000000000000000000000b8c2c29ee19d8307cb7255e1cd9cbde883a267d511ef687cfeb2e353670479f2dcc76af2bc6b3935000000000002c40000000001', - }, - 'latest', - ], - { - result: - '0x0000000000000000000000000000000000000000000000000000000000000001', - } - ); - const MANIFEST_URI_NICK = new URL( - 'https://api.opensea.io/api/v1/metadata/0x495f947276749Ce646f68AC8c248420045cb7b5e/8112316025873927737505937898915153732580103913704334048512380490797008551937' + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000000', + 5 + ), + jsonRPCresult('0x1', 6), + ] ); - nock(MANIFEST_URI_NICK.origin) - .get(MANIFEST_URI_NICK.pathname) - .reply( - 200, - { - name: 'Nick Johnson', - description: null, - external_link: null, - image: - 'https://lh3.googleusercontent.com/hKHZTZSTmcznonu8I6xcVZio1IF76fq0XmcxnvUykC-FGuVJ75UPdLDlKJsfgVXH9wOSmkyHw0C39VAYtsGyxT7WNybjQ6s3fM3macE', - animation_url: null, - }, - CORS_HEADERS as any - ); - expect(await avt.getAvatar('nick.eth')).toEqual( - 'https://lh3.googleusercontent.com/hKHZTZSTmcznonu8I6xcVZio1IF76fq0XmcxnvUykC-FGuVJ75UPdLDlKJsfgVXH9wOSmkyHw0C39VAYtsGyxT7WNybjQ6s3fM3macE' - ); - }); - it('retrieves image uri with erc721 spec', async () => { - nockInfura( - 'eth_call', + nockInfuraBatch( [ - { - to: PublicResolver.toLowerCase(), - data: - '0x3b3b57de43fcd34d8589090581e1d2bdcf5dc17feb05b2006401fb1c3fdded335a465b51', - }, - 'latest', + ethCallParams( + PublicResolver.toLowerCase(), + '0x3b3b57de80ee077a908dffcf32972ba13c2df16b42688e1de21bcf17d3469a8507895eae', + 7 + ), + chainIdParams(8), ], - { - result: - '0x000000000000000000000000983110309620d911731ac0932219af06091b6744', - } + [ + jsonRPCresult( + '0x0000000000000000000000005a384227b65fa093dec03ec34e111db80a040615', + 7 + ), + jsonRPCresult('0x1', 8), + ] ); - nockInfura( - 'eth_call', + nockInfuraBatch( [ - { - to: PublicResolver.toLowerCase(), - data: - '0x59d1d43c43fcd34d8589090581e1d2bdcf5dc17feb05b2006401fb1c3fdded335a465b51000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066176617461720000000000000000000000000000000000000000000000000000', - }, - 'latest', + ethCallParams( + PublicResolver.toLowerCase(), + '0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000', + 9 + ), + chainIdParams(10), ], - { - result: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003f6569703135353a312f6572633732313a3078623746374636433532463265326664623139363345616233303433383032343836346333313346362f3234333000', - } + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000000', + 9 + ), + jsonRPCresult('0x1', 10), + ] ); - nockInfura( - 'eth_call', + nockInfuraBatch( [ - { - to: '0xb7f7f6c52f2e2fdb1963eab30438024864c313f6', - data: - '0xc87b56dd000000000000000000000000000000000000000000000000000000000000097e', - }, - 'latest', + ethCallParams( + PublicResolver.toLowerCase(), + '0x59d1d43c80ee077a908dffcf32972ba13c2df16b42688e1de21bcf17d3469a8507895eae000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066176617461720000000000000000000000000000000000000000000000000000', + 11 + ), + chainIdParams(12), ], - { - result: - '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003568747470733a2f2f7772617070656470756e6b732e636f6d3a333030302f6170692f70756e6b732f6d657461646174612f323433300000000000000000000000', - } + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003f6569703135353a312f6572633732313a3078333133383564333532306263656439346637376161653130346234303639393464386632313638632f3934323100', + 11 + ), + jsonRPCresult('0x1', 12), + ] ); - nockInfura( - 'eth_call', + nockInfuraBatch( [ - { - to: '0xb7f7f6c52f2e2fdb1963eab30438024864c313f6', - data: - '0x6352211e000000000000000000000000000000000000000000000000000000000000097e', - }, - 'latest', + ethCallParams( + '0x31385d3520bced94f77aae104b406994d8f2168c', + '0xc87b56dd00000000000000000000000000000000000000000000000000000000000024cd', + 13 + ), + chainIdParams(14), + ethCallParams( + '0x31385d3520bced94f77aae104b406994d8f2168c', + '0x6352211e00000000000000000000000000000000000000000000000000000000000024cd', + 15 + ), ], - { - result: - '0x000000000000000000000000983110309620d911731ac0932219af06091b6744', - } + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002568747470733a2f2f6170692e6261737461726467616e70756e6b732e636c75622f39343231000000000000000000000000000000000000000000000000000000', + 13 + ), + jsonRPCresult('0x1', 14), + jsonRPCresult( + '0x0000000000000000000000005a384227b65fa093dec03ec34e111db80a040615', + 15 + ), + ] ); - const MANIFEST_URI_BRANTLY = new URL( - 'https://wrappedpunks.com:3000/api/punks/metadata/2430' + + const MANIFEST_URI_MATOKEN = new URL( + 'https://api.bastardganpunks.club/9421' ); - const NFT_URI_BRANTLY = new URL( - 'https://api.wrappedpunks.com/images/punks/2430.png' + const NFT_URI_MATOKEN = new URL( + 'https://ipfs.io/ipfs/QmRagxjj2No4T8gNCjpM42mLZGQE3ZwMYdTFUYe6e6LMBG' ); - nock(MANIFEST_URI_BRANTLY.origin) - .get(MANIFEST_URI_BRANTLY.pathname) + nock(MANIFEST_URI_MATOKEN.origin) + .get(MANIFEST_URI_MATOKEN.pathname) .reply( 200, { - title: 'W#2430', - name: 'W#2430', + tokenId: 9421, + name: 'BASTARD GAN PUNK V2 #9421', description: - 'This Punk was wrapped using Wrapped Punks contract, accessible from https://wrappedpunks.com', - image: 'https://api.wrappedpunks.com/images/punks/2430.png', - external_url: 'https://wrappedpunks.com', + "FOR THE CHANCES\nI HAVEN'T GOT A BURIAL IN MY ARMS\nAND I'VE HAD ENOUGH\nTIME IS NOW\nIT'S TIME\nI'VE GOT NOTHING TO PROVE\nI'VE GOT NOTHING TO LOSE\n", + image: + 'https://ipfs.io/ipfs/QmRagxjj2No4T8gNCjpM42mLZGQE3ZwMYdTFUYe6e6LMBG', + imageArweave: + 'https://arweave.net/ve7z_TcSos6nJpjGyuT423B9yyalq5GR4s7CQWGXHpk', + external_url: 'https://www.bastardganpunks.club/v2/9421', }, CORS_HEADERS as any ); - nock(NFT_URI_BRANTLY.origin) - .head(NFT_URI_BRANTLY.pathname) + nock(NFT_URI_MATOKEN.origin) + .head(NFT_URI_MATOKEN.pathname) .reply(200, {}, { ...CORS_HEADERS, 'content-type': 'image/png', } as any); - expect(await avt.getAvatar('brantly.eth')).toEqual( - 'https://api.wrappedpunks.com/images/punks/2430.png' + expect(await avt.getAvatar('matoken.eth')).toEqual( + 'https://ipfs.io/ipfs/QmRagxjj2No4T8gNCjpM42mLZGQE3ZwMYdTFUYe6e6LMBG' ); }); it('retrieves image uri with custom spec', async () => { - nockInfura( - 'eth_call', + mockInfuraChainId(16); + + nockInfuraBatch( [ - { - to: PublicResolver.toLowerCase(), - data: - '0x3b3b57deb47a0edaf3c702800c923ca4c44a113d0d718cb1f42ecdce70c5fd05fa36a63f', - }, - 'latest', + ethCallParams( + ENSRegistryWithFallback.toString(), + '0x0178b8bfb47a0edaf3c702800c923ca4c44a113d0d718cb1f42ecdce70c5fd05fa36a63f', + 17 + ), + chainIdParams(18), + ethCallParams( + ENSRegistryWithFallback.toString(), + '0x0178b8bfb47a0edaf3c702800c923ca4c44a113d0d718cb1f42ecdce70c5fd05fa36a63f', + 19 + ), ], - { - result: + [ + jsonRPCresult( + '0x0000000000000000000000004976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41', + 17 + ), + jsonRPCresult('0x1', 18), + jsonRPCresult( + '0x0000000000000000000000004976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41', + 19 + ), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + PublicResolver.toLowerCase(), + '0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000', + 20 + ), + chainIdParams(21), + ], + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000000', + 20 + ), + jsonRPCresult('0x1', 21), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + PublicResolver.toLowerCase(), + '0x3b3b57deb47a0edaf3c702800c923ca4c44a113d0d718cb1f42ecdce70c5fd05fa36a63f', + 22 + ), + chainIdParams(23), + ], + [ + jsonRPCresult( '0x0000000000000000000000000d59d0f7dcc0fbf0a3305ce0261863aaf7ab685c', - } + 22 + ), + jsonRPCresult('0x1', 23), + ] ); - nockInfura( - 'eth_call', + nockInfuraBatch( [ - { - to: PublicResolver.toLowerCase(), - data: - '0x59d1d43cb47a0edaf3c702800c923ca4c44a113d0d718cb1f42ecdce70c5fd05fa36a63f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066176617461720000000000000000000000000000000000000000000000000000', - }, - 'latest', + ethCallParams( + PublicResolver.toLowerCase(), + '0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000', + 24 + ), + chainIdParams(25), ], - { - result: + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000000', + 24 + ), + jsonRPCresult('0x1', 25), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + PublicResolver.toLowerCase(), + '0x59d1d43cb47a0edaf3c702800c923ca4c44a113d0d718cb1f42ecdce70c5fd05fa36a63f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066176617461720000000000000000000000000000000000000000000000000000', + 26 + ), + chainIdParams(27), + ], + [ + jsonRPCresult( '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004368747470733a2f2f697066732e696f2f697066732f516d55536867666f5a5153484b3354517975546655707363385566654e6644384b77505576444255645a346e6d520000000000000000000000000000000000000000000000000000000000', - } + 26 + ), + jsonRPCresult('0x1', 27), + ] ); const MANIFEST_URI_TANRIKULU = new URL( 'https://ipfs.io/ipfs/QmUShgfoZQSHK3TQyuTfUpsc8UfeNfD8KwPUvDBUdZ4nmR' @@ -282,6 +348,177 @@ describe('get avatar', () => { 'https://ipfs.io/ipfs/QmUShgfoZQSHK3TQyuTfUpsc8UfeNfD8KwPUvDBUdZ4nmR' ); }); + it('retrieves image uri with erc1155 spec', async () => { + mockInfuraChainId(28); + + nockInfuraBatch( + [ + ethCallParams( + ENSRegistryWithFallback.toLowerCase(), + '0x0178b8bf05a67c0ee82964c4f7394cdd47fee7f4d9503a23c09c38341779ea012afe6e00', + 29 + ), + chainIdParams(30), + ethCallParams( + ENSRegistryWithFallback.toLowerCase(), + '0x0178b8bf05a67c0ee82964c4f7394cdd47fee7f4d9503a23c09c38341779ea012afe6e00', + 31 + ), + ], + [ + jsonRPCresult( + '0x0000000000000000000000004976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41', + 29 + ), + jsonRPCresult('0x1', 30), + jsonRPCresult( + '0x0000000000000000000000004976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41', + 31 + ), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + PublicResolver.toLowerCase(), + '0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000', + 32 + ), + chainIdParams(33), + ], + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000000', + 32 + ), + jsonRPCresult('0x1', 33), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + PublicResolver.toLowerCase(), + '0x3b3b57de05a67c0ee82964c4f7394cdd47fee7f4d9503a23c09c38341779ea012afe6e00', + 34 + ), + chainIdParams(35), + ], + [ + jsonRPCresult( + '0x000000000000000000000000b8c2c29ee19d8307cb7255e1cd9cbde883a267d5', + 34 + ), + jsonRPCresult('0x1', 35), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + PublicResolver.toLowerCase(), + '0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000', + 36 + ), + chainIdParams(37), + ], + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000000', + 36 + ), + jsonRPCresult('0x1', 37), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + PublicResolver.toLowerCase(), + '0x59d1d43c05a67c0ee82964c4f7394cdd47fee7f4d9503a23c09c38341779ea012afe6e00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066176617461720000000000000000000000000000000000000000000000000000', + 38 + ), + chainIdParams(39), + ], + [ + jsonRPCresult( + '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000886569703135353a312f657263313135353a3078343935663934373237363734396365363436663638616338633234383432303034356362376235652f38313132333136303235383733393237373337353035393337383938393135313533373332353830313033393133373034333334303438353132333830343930373937303038353531393337000000000000000000000000000000000000000000000000', + 38 + ), + jsonRPCresult('0x1', 39), + ] + ); + nockInfuraBatch( + [ + ethCallParams( + '0x495f947276749ce646f68ac8c248420045cb7b5e', + '0x0e89341c11ef687cfeb2e353670479f2dcc76af2bc6b3935000000000002c40000000001', + 40 + ), + chainIdParams(41), + ethCallParams( + '0x495f947276749ce646f68ac8c248420045cb7b5e', + '0x00fdd58e000000000000000000000000b8c2c29ee19d8307cb7255e1cd9cbde883a267d511ef687cfeb2e353670479f2dcc76af2bc6b3935000000000002c40000000001', + 42 + ), + ], + [ + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005868747470733a2f2f6170692e6f70656e7365612e696f2f6170692f76312f6d657461646174612f3078343935663934373237363734394365363436663638414338633234383432303034356362376235652f30787b69647d0000000000000000', + 40 + ), + jsonRPCresult('0x1', 41), + jsonRPCresult( + '0x0000000000000000000000000000000000000000000000000000000000000001', + 42 + ), + ] + ); + const MANIFEST_URI_NICK = new URL( + 'https://api.opensea.io/api/v1/metadata/0x495f947276749Ce646f68AC8c248420045cb7b5e/8112316025873927737505937898915153732580103913704334048512380490797008551937' + ); + const NFT_URI_NICK = new URL( + 'https://i.seadn.io/gae/hKHZTZSTmcznonu8I6xcVZio1IF76fq0XmcxnvUykC-FGuVJ75UPdLDlKJsfgVXH9wOSmkyHw0C39VAYtsGyxT7WNybjQ6s3fM3macE?w=500&auto=format' + ); + nock(MANIFEST_URI_NICK.origin) + .options(MANIFEST_URI_NICK.pathname) + .reply(200, {}, { + ...CORS_HEADERS, + 'access-control-allow-headers': + 'accept, authorization, content-type, user-agent, x-csrftoken, x-requested-with, x-datadog-origin, x-datadog-parent-id, x-datadog-sampled, x-datadog-sampling-priority, x-datadog-trace-id, i196zqqsyk-a0, i196zqqsyk-a1, i196zqqsyk-a2, i196zqqsyk-a, i196zqqsyk-b, i196zqqsyk-c, i196zqqsyk-d, i196zqqsyk-f, i196zqqsyk-z, x-readme-api-explorer, x-api-key, x-build-id, x-signed-query, x-cache-skip, x-app-id, solana-client', + 'access-control-allow-methods': + 'DELETE, GET, OPTIONS, PATCH, POST, PUT', + 'access-control-max-age': '86400', + 'content-type': 'text/html; charset=utf-8', + 'transfer-encoding': 'chunked', + vary: 'origin', + 'x-content-type-options': 'nosniff', + } as any); + nock(NFT_URI_NICK.origin) + .head(NFT_URI_NICK.pathname + '?' + NFT_URI_NICK.searchParams) + .reply( + 200, + {}, + { + 'accept-ranges': 'bytes', + 'access-control-allow-origin': '*', + 'access-control-expose-headers': '*', + 'content-length': '7229', + 'content-type': 'image/png', + } + ); + nock(MANIFEST_URI_NICK.origin) + .get(MANIFEST_URI_NICK.pathname) + .reply( + 200, + { + name: 'Nick Johnson', + description: null, + external_link: null, + image: NFT_URI_NICK.toString(), + animation_url: null, + }, + CORS_HEADERS as any + ); + expect(await avt.getAvatar('nick.eth')).toEqual(NFT_URI_NICK.toString()); + }); it('sets cache to 1 sec', async () => { const avt = new AvatarResolver(provider, { cache: 1 }); diff --git a/yarn.lock b/yarn.lock index aa17e24..b281d76 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.5.5": version "7.16.7" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz" @@ -1480,6 +1485,18 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -1788,6 +1805,11 @@ resolved "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz" integrity sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz" @@ -1918,6 +1940,11 @@ acorn@^7.1.0, acorn@^7.1.1: resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -3427,6 +3454,19 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +ethers@6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.0.tgz#b0c2ce207ae5a3b5125be966e32ffea7c1f2481a" + integrity sha512-zL5NlOTjML239gIvtVJuaSk0N9GQLi1Hom3ZWUszE5lDTQE/IVB62mrPkQ2W1bGcZwVGSLaetQbWNQSvI4rGDQ== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + exec-sh@^0.3.2: version "0.3.6" resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz" @@ -5167,11 +5207,6 @@ lodash.merge@^4.6.2: resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.set@^4.3.2: - version "4.3.2" - resolved "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz" - integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= - lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz" @@ -5440,13 +5475,12 @@ no-case@^3.0.4: tslib "^2.0.3" nock@^13.2.2: - version "13.2.2" - resolved "https://registry.npmjs.org/nock/-/nock-13.2.2.tgz" - integrity sha512-PcBHuvl9i6zfaJ50A7LS55oU+nFLv8htXIhffJO+FxyfibdZ4jEvd9kTuvkrJireBFIGMZ+oUIRpMK5gU9h//g== + version "13.5.0" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.0.tgz#82cd33b0dba6095d3f5a28d0ff2edac970fa05ec" + integrity sha512-9hc1eCS2HtOz+sE9W7JQw/tXJktg0zoPSu48s/pYe73e25JW9ywiowbqnUSd7iZPeVawLcVpPZeZS312fwSY+g== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" - lodash.set "^4.3.2" propagate "^2.0.0" node-int64@^0.4.0: @@ -7031,6 +7065,11 @@ tslib@2.0.1: resolved "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz" integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" @@ -7386,6 +7425,11 @@ ws@7.4.6, ws@^7.0.0: resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz"