diff --git a/packages/bridge-ui-v2/__mocks__/parseNFTMetadata.ts b/packages/bridge-ui-v2/__mocks__/parseNFTMetadata.ts new file mode 100644 index 00000000000..85bd5c786bb --- /dev/null +++ b/packages/bridge-ui-v2/__mocks__/parseNFTMetadata.ts @@ -0,0 +1,3 @@ +import { vi } from 'vitest'; + +export const parseNFTMetadata = vi.fn(); diff --git a/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.test.ts b/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.test.ts index 8c84e456976..70ad866fc0a 100644 --- a/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.test.ts +++ b/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.test.ts @@ -1,13 +1,29 @@ import { fetchToken, type FetchTokenResult, readContract } from '@wagmi/core'; import { type Address, zeroAddress } from 'viem'; +import { customToken } from '$customToken'; import { UnknownTokenTypeError } from '$libs/error'; +import { parseNFTMetadata } from '$libs/util/parseNFTMetadata'; import { detectContractType } from './detectContractType'; import { getTokenWithInfoFromAddress } from './getTokenWithInfoFromAddress'; import { TokenType } from './types'; vi.mock('@wagmi/core'); +vi.mock('../util/parseNFTMetadata'); + +vi.mock('../../generated/customTokenConfig', () => { + const mockToken = { + name: 'Mock Token', + addresses: { '1': zeroAddress }, + symbol: 'MTF', + decimals: 18, + type: 'ERC20', + }; + return { + customToken: [mockToken], // mockToken is your mocked token object + }; +}); vi.mock('./errors', () => { return { @@ -36,24 +52,16 @@ describe('getTokenWithInfoFromAddress', () => { const address: Address = zeroAddress; vi.mocked(detectContractType).mockResolvedValue(TokenType.ERC20); vi.mocked(fetchToken).mockResolvedValue({ - name: 'MockToken', - symbol: 'MTK', - decimals: 18, + name: customToken[0].name, + symbol: customToken[0].symbol, + decimals: customToken[0].decimals, } as FetchTokenResult); // When const result = await getTokenWithInfoFromAddress({ contractAddress: address, srcChainId: 1 }); // Then - expect(result).toEqual({ - addresses: { - 1: address, - }, - name: 'MockToken', - symbol: 'MTK', - decimals: 18, - type: TokenType.ERC20, - }); + expect(result).toEqual(customToken[0]); expect(fetchToken).toHaveBeenCalledOnce(); expect(fetchToken).toHaveBeenCalledWith({ @@ -91,14 +99,23 @@ describe('getTokenWithInfoFromAddress', () => { }); }); describe('ERC1155', () => { + const mockedMetadata = { + description: 'Mock Description', + external_url: 'https://example.com/mock-url', + image: 'https://example.com/mock-image.png', + name: 'Mock Meta Name', + }; + it('should return correct token details for ERC1155 tokens', async () => { // Given + const address: Address = zeroAddress; vi.mocked(detectContractType).mockResolvedValue(TokenType.ERC1155); vi.mocked(readContract) .mockResolvedValueOnce('Mock1155') .mockResolvedValueOnce('some/uri/123') .mockResolvedValueOnce(1337n); + vi.mocked(parseNFTMetadata).mockResolvedValue(mockedMetadata); // When const result = await getTokenWithInfoFromAddress({ contractAddress: address, @@ -117,17 +134,46 @@ describe('getTokenWithInfoFromAddress', () => { name: 'Mock1155', balance: 1337n, type: TokenType.ERC1155, + metadata: mockedMetadata, }); }); it('should return correct token details for ERC1155 tokens with no owner passed', async () => { + // Given + const address: Address = zeroAddress; + vi.mocked(detectContractType).mockResolvedValue(TokenType.ERC1155); + vi.mocked(readContract).mockResolvedValueOnce('Mock1155').mockResolvedValueOnce('some/uri/123'); + + vi.mocked(parseNFTMetadata).mockResolvedValue(mockedMetadata); + + // When + const result = await getTokenWithInfoFromAddress({ contractAddress: address, srcChainId: 1, tokenId: 123 }); + + // Then + expect(result).toEqual({ + addresses: { + 1: address, + }, + uri: 'some/uri/123', + tokenId: 123, + name: 'Mock1155', + balance: 0, + type: TokenType.ERC1155, + metadata: mockedMetadata, + }); + }); + + it('should return correct token details for ERC1155 tokens with uri function req. tokenId', async () => { // Given const address: Address = zeroAddress; vi.mocked(detectContractType).mockResolvedValue(TokenType.ERC1155); vi.mocked(readContract) .mockResolvedValueOnce('Mock1155') - .mockResolvedValueOnce('some/uri/123') - .mockResolvedValueOnce(1337n); + .mockResolvedValueOnce(null) // first uri call + .mockResolvedValueOnce('some/uri/123'); + + vi.mocked(parseNFTMetadata).mockResolvedValue(mockedMetadata); + // When const result = await getTokenWithInfoFromAddress({ contractAddress: address, srcChainId: 1, tokenId: 123 }); @@ -141,6 +187,7 @@ describe('getTokenWithInfoFromAddress', () => { name: 'Mock1155', balance: 0, type: TokenType.ERC1155, + metadata: mockedMetadata, }); }); }); diff --git a/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.ts b/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.ts index 1a40642d31f..58b2b3aa34d 100644 --- a/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.ts +++ b/packages/bridge-ui-v2/src/libs/token/getTokenWithInfoFromAddress.ts @@ -33,44 +33,7 @@ export const getTokenWithInfoFromAddress = async ({ } else if (tokenType === TokenType.ERC1155) { return getERC1155Info(contractAddress, srcChainId, owner, tokenId, tokenType); } else if (tokenType === TokenType.ERC721) { - const name = await readContract({ - address: contractAddress, - abi: erc721ABI, - functionName: 'name', - chainId: srcChainId, - }); - - const symbol = await readContract({ - address: contractAddress, - abi: erc721ABI, - functionName: 'symbol', - chainId: srcChainId, - }); - - let uri; - - if (tokenId) { - uri = await safeReadContract({ - address: contractAddress, - abi: erc721ABI, - functionName: 'tokenURI', - args: [BigInt(tokenId)], - chainId: srcChainId, - }); - } - - const token = { - type: tokenType, - addresses: { - [srcChainId]: contractAddress, - }, - name, - symbol, - tokenId: tokenId ?? 0, - uri: uri ? uri.toString() : undefined, - } as NFT; - - return token; + return getERC721Info(contractAddress, srcChainId, tokenId, tokenType); } else { throw new Error('Unsupported token type'); } @@ -118,6 +81,7 @@ const getERC1155Info = async ( functionName: 'uri', chainId: srcChainId, }); + if (tokenId && !uri) uri = await safeReadContract({ address: contractAddress, @@ -161,3 +125,48 @@ const getERC1155Info = async ( } throw new Error('Error getting token info'); }; + +const getERC721Info = async ( + contractAddress: Address, + srcChainId: number, + tokenId: number | undefined, + type: TokenType, +) => { + const name = await readContract({ + address: contractAddress, + abi: erc721ABI, + functionName: 'name', + chainId: srcChainId, + }); + + const symbol = await readContract({ + address: contractAddress, + abi: erc721ABI, + functionName: 'symbol', + chainId: srcChainId, + }); + + let uri; + + if (tokenId) { + uri = await safeReadContract({ + address: contractAddress, + abi: erc721ABI, + functionName: 'tokenURI', + args: [BigInt(tokenId)], + chainId: srcChainId, + }); + } + + const token = { + type, + addresses: { + [srcChainId]: contractAddress, + }, + name, + symbol, + tokenId: tokenId ?? 0, + uri: uri ? uri.toString() : undefined, + } as NFT; + return token; +};