diff --git a/packages/bridge-ui/package.json b/packages/bridge-ui/package.json index 30353d0cb9..ae8dba9275 100644 --- a/packages/bridge-ui/package.json +++ b/packages/bridge-ui/package.json @@ -60,6 +60,7 @@ }, "type": "module", "dependencies": { + "@moralisweb3/common-evm-utils": "^2.26.1", "@wagmi/connectors": "^4.1.18", "@wagmi/core": "^2.6.9", "@walletconnect/ethereum-provider": "^2.12.2", @@ -70,6 +71,7 @@ "buffer": "^6.0.3", "debug": "^4.3.4", "events": "^3.3.0", + "moralis": "^2.26.1", "object-hash": "^3.0.0", "svelte-i18n": "^3.7.4", "viem": "^2.7.11" diff --git a/packages/bridge-ui/src/libs/bridge/fetchNFTs.ts b/packages/bridge-ui/src/libs/bridge/fetchNFTs.ts index af2a75504c..74f8572892 100644 --- a/packages/bridge-ui/src/libs/bridge/fetchNFTs.ts +++ b/packages/bridge-ui/src/libs/bridge/fetchNFTs.ts @@ -1,95 +1,118 @@ import type { Address } from 'viem'; -import { eventIndexerApiServices } from '$libs/eventIndexer/initEventIndexer'; -import { type NFT, TokenType } from '$libs/token'; -import { checkOwnershipOfNFTs } from '$libs/token/checkOwnership'; -import { fetchNFTImageUrl } from '$libs/token/fetchNFTImageUrl'; -import { getTokenWithInfoFromAddress } from '$libs/token/getTokenWithInfoFromAddress'; -import { getLogger } from '$libs/util/logger'; - -const log = getLogger('bridge:fetchNFTs'); - -function deduplicateNFTs(nftArrays: NFT[][]): NFT[] { - const nftMap: Map = new Map(); - nftArrays.flat().forEach((nft) => { - Object.entries(nft.addresses).forEach(([chainID, address]) => { - const uniqueKey = `${address}-${chainID}-${nft.tokenId}`; - - if (!nftMap.has(uniqueKey)) { - nftMap.set(uniqueKey, nft); - } - }); - }); - return Array.from(nftMap.values()); -} +import type { NFT } from '$libs/token'; +// import { checkOwnershipOfNFTs } from '$libs/token/checkOwnership'; +// import { fetchNFTImageUrl } from '$libs/token/fetchNFTImageUrl'; +// import { getTokenWithInfoFromAddress } from '$libs/token/getTokenWithInfoFromAddress'; +// import { getLogger } from '$libs/util/logger'; + +// const log = getLogger('bridge:fetchNFTs'); + +// function deduplicateNFTs(nftArrays: NFT[][]): NFT[] { +// const nftMap: Map = new Map(); +// nftArrays.flat().forEach((nft) => { +// Object.entries(nft.addresses).forEach(([chainID, address]) => { +// const uniqueKey = `${address}-${chainID}-${nft.tokenId}`; + +// if (!nftMap.has(uniqueKey)) { +// nftMap.set(uniqueKey, nft); +// } +// }); +// }); +// return Array.from(nftMap.values()); +// } export async function fetchNFTs( userAddress: Address, srcChainId: number, ): Promise<{ nfts: NFT[]; error: Error | null }> { - let error: Error | null = null; + // const error: Error | null = null; - // Fetch from all indexers - const indexerPromises: Promise[] = eventIndexerApiServices.map(async (eventIndexerApiService) => { - const { items: result } = await eventIndexerApiService.getAllNftsByAddressFromAPI(userAddress, BigInt(srcChainId), { - page: 0, - size: 100, - }); - - const nftsPromises: Promise[] = result.map(async (nft) => { - const type: TokenType = TokenType[nft.contractType as keyof typeof TokenType]; - return getTokenWithInfoFromAddress({ - contractAddress: nft.contractAddress, - srcChainId, - owner: userAddress, - tokenId: Number(nft.tokenID), - type, - }) as Promise; + try { + const moralisResponse = await fetch('/api/nft', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ address: userAddress, chainId: srcChainId }), }); - const nftsSettled = await Promise.allSettled(nftsPromises); - const nfts = nftsSettled - .filter((result) => result.status === 'fulfilled') - .map((result) => (result as PromiseFulfilledResult).value); + if (moralisResponse.ok) { + const responseData = await moralisResponse.json(); - return nfts; - }); + const { nfts } = responseData; - let nftArrays: NFT[][] = []; - try { - nftArrays = await Promise.all(indexerPromises); - } catch (e) { - log('error fetching nfts from indexer services', e); - error = e as Error; - } - - // Deduplicate based on address and chainID - const deduplicatedNfts = deduplicateNFTs(nftArrays); - - // Fetch image for each NFT - const promises = Promise.all( - deduplicatedNfts.map(async (nft) => { - const nftWithImage = await fetchNFTImageUrl(nft); - return nftWithImage; - }), - ); - const nftsWithImage = await promises; - - // Double check the ownership - const ownsAllNfts = await checkOwnershipOfNFTs(nftsWithImage, userAddress, srcChainId); - log(`user ${userAddress} owns all NFTs:`, ownsAllNfts); - // filter out the NFTs that the user doesn't own - const filteredNfts = nftsWithImage.filter((nft) => { - const isOwned = ownsAllNfts.successfulOwnershipChecks.find((result) => result.tokenId === nft.tokenId); - return isOwned; - }); - - if (filteredNfts.length !== nftsWithImage.length) { - //TODO: handle this case differently? maybe show a warning to the user? - log(`found ${nftsWithImage.length - filteredNfts.length} tokens that the user doesn't own`); + return { nfts, error: null }; + } else { + console.error('HTTP error:', moralisResponse.statusText); + return { nfts: [], error: new Error(moralisResponse.statusText) }; + } + } catch (error) { + console.error('Fetch error:', error); + return { nfts: [], error: new Error('') }; } - - log(`found ${filteredNfts.length} unique NFTs from all indexers`, filteredNfts); - - return { nfts: filteredNfts, error }; } +// // Fetch from all indexers +// const indexerPromises: Promise[] = eventIndexerApiServices.map(async (eventIndexerApiService) => { +// const { items: result } = await eventIndexerApiService.getAllNftsByAddressFromAPI(userAddress, BigInt(srcChainId), { +// page: 0, +// size: 100, +// }); + +// const nftsPromises: Promise[] = result.map(async (nft) => { +// const type: TokenType = TokenType[nft.contractType as keyof typeof TokenType]; +// return getTokenWithInfoFromAddress({ +// contractAddress: nft.contractAddress, +// srcChainId, +// owner: userAddress, +// tokenId: Number(nft.tokenID), +// type, +// }) as Promise; +// }); + +// const nftsSettled = await Promise.allSettled(nftsPromises); +// const nfts = nftsSettled +// .filter((result) => result.status === 'fulfilled') +// .map((result) => (result as PromiseFulfilledResult).value); + +// return nfts; +// }); + +// let nftArrays: NFT[][] = []; +// try { +// nftArrays = await Promise.all(indexerPromises); +// } catch (e) { +// log('error fetching nfts from indexer services', e); +// error = e as Error; +// } + +// // Deduplicate based on address and chainID +// const deduplicatedNfts = deduplicateNFTs(nftArrays); + +// // Fetch image for each NFT +// const promises = Promise.all( +// deduplicatedNfts.map(async (nft) => { +// const nftWithImage = await fetchNFTImageUrl(nft); +// return nftWithImage; +// }), +// ); +// const nftsWithImage = await promises; + +// // Double check the ownership +// const ownsAllNfts = await checkOwnershipOfNFTs(nftsWithImage, userAddress, srcChainId); +// log(`user ${userAddress} owns all NFTs:`, ownsAllNfts); +// // filter out the NFTs that the user doesn't own +// const filteredNfts = nftsWithImage.filter((nft) => { +// const isOwned = ownsAllNfts.successfulOwnershipChecks.find((result) => result.tokenId === nft.tokenId); +// return isOwned; +// }); + +// if (filteredNfts.length !== nftsWithImage.length) { +// //TODO: handle this case differently? maybe show a warning to the user? +// log(`found ${nftsWithImage.length - filteredNfts.length} tokens that the user doesn't own`); +// } + +// log(`found ${filteredNfts.length} unique NFTs from all indexers`, filteredNfts); + +// return { nfts: filteredNfts, error }; +// } diff --git a/packages/bridge-ui/src/routes/api/nft/+server.ts b/packages/bridge-ui/src/routes/api/nft/+server.ts new file mode 100644 index 0000000000..d92670334e --- /dev/null +++ b/packages/bridge-ui/src/routes/api/nft/+server.ts @@ -0,0 +1,28 @@ +import type { RequestHandler } from '@sveltejs/kit'; +import { NFTService } from 'src/thirdparty/domain/services/NFTService'; +import moralisRepository from 'src/thirdparty/infrastructure/api/MoralisNFTRepository.server'; + +const nftService = new NFTService(moralisRepository); + +export const POST: RequestHandler = async ({ request }) => { + try { + const { address, chainId } = await request.json(); + + const nfts = await nftService.fetchNFTsByAddress(address, chainId); + + return new Response(JSON.stringify({ nfts }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + console.error('Failed to fetch NFTs:', error); + return new Response(JSON.stringify({ error: 'Failed to retrieve NFT data' }), { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }); + } +}; diff --git a/packages/bridge-ui/src/thirdparty/domain/interfaces/INFTRepository.ts b/packages/bridge-ui/src/thirdparty/domain/interfaces/INFTRepository.ts new file mode 100644 index 0000000000..0be9b33e73 --- /dev/null +++ b/packages/bridge-ui/src/thirdparty/domain/interfaces/INFTRepository.ts @@ -0,0 +1,5 @@ +import type { NFT } from '../models/NFT'; + +export interface INFTRepository { + findByAddress(address: string, chainId: number): Promise; +} diff --git a/packages/bridge-ui/src/thirdparty/domain/models/NFT.ts b/packages/bridge-ui/src/thirdparty/domain/models/NFT.ts new file mode 100644 index 0000000000..f8be3a1a6c --- /dev/null +++ b/packages/bridge-ui/src/thirdparty/domain/models/NFT.ts @@ -0,0 +1,17 @@ +import type { Address } from 'viem'; + +import type { NFTMetadata, TokenType } from '$libs/token'; + +export interface NFT { + type: TokenType; + name: string; + symbol: string; + addresses: Record; + owner: Address; + imported?: boolean; + mintable?: boolean; + balance?: bigint; + tokenId: number | string; + uri?: string; + metadata?: NFTMetadata; +} diff --git a/packages/bridge-ui/src/thirdparty/domain/services/NFTService.ts b/packages/bridge-ui/src/thirdparty/domain/services/NFTService.ts new file mode 100644 index 0000000000..316fc33c34 --- /dev/null +++ b/packages/bridge-ui/src/thirdparty/domain/services/NFTService.ts @@ -0,0 +1,10 @@ +import type { INFTRepository } from '../interfaces/INFTRepository'; +import type { NFT } from '../models/NFT'; + +export class NFTService { + constructor(private repository: INFTRepository) {} + + async fetchNFTsByAddress(address: string, chainId: number): Promise { + return await this.repository.findByAddress(address, chainId); + } +} diff --git a/packages/bridge-ui/src/thirdparty/infrastructure/api/MoralisNFTRepository.server.ts b/packages/bridge-ui/src/thirdparty/infrastructure/api/MoralisNFTRepository.server.ts new file mode 100644 index 0000000000..89a0e695b3 --- /dev/null +++ b/packages/bridge-ui/src/thirdparty/infrastructure/api/MoralisNFTRepository.server.ts @@ -0,0 +1,46 @@ +// src/lib/infrastructure/api/NFTRepository.server.ts +import Moralis from 'moralis'; +import type { Address } from 'viem'; + +import { MORALIS_API_KEY } from '$env/static/private'; + +import type { INFTRepository } from '../../domain/interfaces/INFTRepository'; +import type { NFT } from '../../domain/models/NFT'; +import { mapToNFTFromMoralis } from '../mappers/nft/MoralisNFTMapper'; +import type { NFTApiData } from '../types/moralis'; + +class MoralisNFTRepository implements INFTRepository { + private static instance: MoralisNFTRepository; + + private constructor() { + Moralis.start({ + apiKey: MORALIS_API_KEY, + }).catch(console.error); + } + + public static getInstance(): MoralisNFTRepository { + if (!MoralisNFTRepository.instance) { + MoralisNFTRepository.instance = new MoralisNFTRepository(); + } + return MoralisNFTRepository.instance; + } + + async findByAddress(address: Address, chainId: number): Promise { + try { + const response = await Moralis.EvmApi.nft.getWalletNFTs({ + chain: chainId, + format: 'decimal', + excludeSpam: true, + mediaItems: false, + address: address, + }); + + return response.result.map((nft) => mapToNFTFromMoralis(nft as unknown as NFTApiData, chainId)); + } catch (e) { + console.error('Failed to fetch NFTs from Moralis:', e); + return []; + } + } +} + +export default MoralisNFTRepository.getInstance(); diff --git a/packages/bridge-ui/src/thirdparty/infrastructure/mappers/nft/MoralisNFTMapper.ts b/packages/bridge-ui/src/thirdparty/infrastructure/mappers/nft/MoralisNFTMapper.ts new file mode 100644 index 0000000000..db781a15c2 --- /dev/null +++ b/packages/bridge-ui/src/thirdparty/infrastructure/mappers/nft/MoralisNFTMapper.ts @@ -0,0 +1,20 @@ +import type { NFT } from 'src/thirdparty/domain/models/NFT'; +import type { Address } from 'viem'; + +import type { TokenType } from '$libs/token'; + +import type { NFTApiData } from '../../types/moralis'; + +export function mapToNFTFromMoralis(apiData: NFTApiData, chainId: number): NFT { + return { + tokenId: apiData.tokenId, + uri: apiData.tokenUri, + owner: apiData.ownerOf as Address, + name: apiData.name, + symbol: apiData.symbol, + type: apiData.contractType as TokenType, + addresses: { + [chainId]: apiData.tokenAddress as Address, + }, + }; +} diff --git a/packages/bridge-ui/src/thirdparty/infrastructure/types/moralis.ts b/packages/bridge-ui/src/thirdparty/infrastructure/types/moralis.ts new file mode 100644 index 0000000000..848e078a6c --- /dev/null +++ b/packages/bridge-ui/src/thirdparty/infrastructure/types/moralis.ts @@ -0,0 +1,21 @@ +import type { LimitNumberError } from 'ajv/dist/vocabularies/validation/limitNumber'; +import type { Address } from 'viem'; + +export interface NFTApiData { + tokenId: string | number; + contractType: string; + chain: LimitNumberError; + tokenUri: string; + tokenAddress: Address; + tokenHash: string; + metadata: string; + name: string; + symbol: string; + ownerOf: Address; + blockNumberMinted: bigint; + blockNumber: bigint; + lastMetadataSync: Date; + lastTokenUriSync: Date; + amount: number | string; + possibleSpam: boolean; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8609a3395f..9330db4039 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,9 @@ importers: packages/bridge-ui: dependencies: + '@moralisweb3/common-evm-utils': + specifier: ^2.26.1 + version: 2.26.1(debug@4.3.4) '@wagmi/connectors': specifier: ^4.1.18 version: 4.1.18(@wagmi/core@2.6.9)(react-native@0.73.4)(react@18.2.0)(typescript@5.4.3)(viem@2.7.11) @@ -51,6 +54,9 @@ importers: events: specifier: ^3.3.0 version: 3.3.0 + moralis: + specifier: ^2.26.1 + version: 2.26.1(debug@4.3.4) object-hash: specifier: ^3.0.0 version: 3.0.0 @@ -2780,7 +2786,6 @@ packages: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 hash.js: 1.1.7 - dev: true /@ethersproject/signing-key@5.7.0: resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} @@ -3624,6 +3629,145 @@ packages: - supports-color dev: false + /@moralisweb3/api-utils@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-xG2rEvv7MEGiLwz6YkHeWnRToP9xiwtzdesgpYcbOMfEhO0dOF5NMhey9F4NS3l4p+ei8liLQAmFRUehyojbWg==} + dependencies: + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-evm-utils': 2.26.1(debug@4.3.4) + axios: 1.6.7(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/aptos-api@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-LClXb88MtC8kAkuWgJ5PlvjBnY9wCd3fBMa+FbOvIlKgMDHjNizDzFCVAX/f6lF884/XBzpxq0QyoFcvYx0RFQ==} + dependencies: + '@moralisweb3/api-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-aptos-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/auth@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-PUIm67hPOI0ThyUJ851Bq0i1Y0A7cFSR7wILwM0Ye1W1IOoygAI2Ls7Zyy9HK9aRUV3J1Sqek49azjNfmXQ0QA==} + dependencies: + '@moralisweb3/api-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-aptos-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-auth-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-evm-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-sol-utils': 2.26.1(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/common-aptos-utils@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-02c4zgksBzlM9zZgeDLvPQ/+yDjVAWRnkbXP2Hnow19PSIqUJb/RkHclqm3+623tH4JJwgbqei3wrQZigNQAWg==} + dependencies: + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@noble/hashes': 1.3.3 + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/common-auth-utils@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-g2FrjZKqjxitd4aDbJjdIwLXDYYa8a3sMRL31jynyblIfz2OTXJ5YZj86n8aENY+1t8BOcLwixzsRHRDiHnbog==} + dependencies: + '@ethersproject/abi': 5.7.0 + '@moralisweb3/common-aptos-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-evm-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-sol-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/streams-typings': 1.0.7 + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/common-core@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-HbsSjBZuicoKyJxlWNl0YV6YolGQ0bWT2jbPwMGvLrtbeeRTT3rE2IrIh9nSe7z9pWVvXfU3t+4oXkisY+8dJg==} + dependencies: + axios: 1.6.7(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/common-evm-utils@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-Gr4qJmGhr5ixSeysg4CjZBZexeTzHqPYPE1YuaGAmD4dmW2OMpN2mRwXYnJmKNtML45XfTy4bCfeoTER7xBCWA==} + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/common-sol-utils@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-68VaTLpTvWljzaWsb7bHd7IOPHraT5pqfQG/rs5pOZQ846/nWe8bWzCT619aKAiS54WEhkg3lgqE58mISiTmCw==} + dependencies: + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + bn.js: 5.2.1 + bs58: 5.0.0 + buffer: 6.0.3 + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/common-streams-utils@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-dhUrGoeBW1xfokQNRhr7AfejEBA/jOwIp3uyaw19M1eQcw0v+ekhgWvglSEDp0Fp3AouZFUAgkX1pOz/BziuCw==} + dependencies: + '@ethersproject/abi': 5.7.0 + '@moralisweb3/common-aptos-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-evm-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/streams-typings': 1.0.7 + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/evm-api@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-1A92tQsM/K9wMVpciziPmy8s258en+KN9CIIBNj+6AqXS+yjvd6Fbh//0ZGpKmsBu862ULfb8EnrmeYQBoSEbw==} + dependencies: + '@moralisweb3/api-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-evm-utils': 2.26.1(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/sol-api@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-Wvpg8soLyb5DRR2R/v3ociFVI4I4EH1SsCU7Ah53tfmX/gDl5qs9FFdOMR/gYhS0vZXFN0f2jW+6I9ml1A9bDw==} + dependencies: + '@moralisweb3/api-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-sol-utils': 2.26.1(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@moralisweb3/streams-typings@1.0.7: + resolution: {integrity: sha512-ShbVqil0KLOTyTjO6z9JewPcVVE3S6kzkQFnW2flGBRsGdKucpkUdOx1HijOLoaikz/9gH92n+lzTvRFIj0AoA==} + dev: false + + /@moralisweb3/streams@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-YyF3w8jKYw06ihKSi7LsG2L7FmOXDZarufQdYFhFFlNflprJG+ENorAp8NX9CfSoPzbLkF5NTDug22lehNqWTA==} + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@moralisweb3/api-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-evm-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-streams-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/streams-typings': 1.0.7 + ethereumjs-util: 7.1.5 + web3-eth-abi: 1.10.4 + transitivePeerDependencies: + - debug + dev: false + /@motionone/animation@10.16.3: resolution: {integrity: sha512-QUGWpLbMFLhyqKlngjZhjtxM8IqiJQjLK0DF+XOF6od9nhSvlaeEpOY/UMCRVcZn/9Tr2rZO22EkuCIjYdI74g==} dependencies: @@ -4944,6 +5088,12 @@ packages: resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} dev: true + /@types/bn.js@5.1.5: + resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} + dependencies: + '@types/node': 20.11.30 + dev: false + /@types/chai-subset@1.3.5: resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==} dependencies: @@ -5054,6 +5204,12 @@ packages: resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} dev: false + /@types/pbkdf2@3.1.2: + resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + dependencies: + '@types/node': 20.11.30 + dev: false + /@types/pug@2.0.10: resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} dev: true @@ -5115,7 +5271,7 @@ packages: ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.6.0 - ts-api-utils: 1.2.1(typescript@5.4.3) + ts-api-utils: 1.3.0(typescript@5.4.3) typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -5222,7 +5378,7 @@ packages: '@typescript-eslint/utils': 7.4.0(eslint@8.55.0)(typescript@5.4.3) debug: 4.3.4 eslint: 8.55.0 - ts-api-utils: 1.2.1(typescript@5.4.3) + ts-api-utils: 1.3.0(typescript@5.4.3) typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -6724,6 +6880,16 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /base-x@4.0.0: + resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + dev: false + /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -6760,6 +6926,10 @@ packages: readable-stream: 3.6.2 dev: true + /blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + dev: false + /blob-to-it@2.0.6: resolution: {integrity: sha512-xveo/z3QNilIJgCZAjzvx2uWWVHE4JzOy7eMp45zkuBsmwZMgjfhn2h/+BsZPaByVFa3u1W/OBUleNiqgMtVpQ==} dependencies: @@ -6816,6 +6986,17 @@ packages: resolution: {integrity: sha512-csJm66U/gTC6VHjeaOaziK6Y6ENdrzlNLdXnsdnvGX+3hGvedkxTyiMk2WbgKR8F15ACxDLJhDuE/cmovLPBQQ==} dev: false + /browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + /browserslist@4.23.0: resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -6826,6 +7007,26 @@ packages: node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) + /bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + dependencies: + base-x: 3.0.9 + dev: false + + /bs58@5.0.0: + resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + dependencies: + base-x: 4.0.0 + dev: false + + /bs58check@2.1.2: + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + dependencies: + bs58: 4.0.1 + create-hash: 1.2.0 + safe-buffer: 5.2.1 + dev: false + /bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} dependencies: @@ -6844,6 +7045,10 @@ packages: resolution: {integrity: sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==} dev: false + /buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + dev: false + /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: @@ -7097,6 +7302,13 @@ packages: engines: {node: '>=8'} dev: false + /cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + /citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} dependencies: @@ -7401,6 +7613,27 @@ packages: hasBin: true dev: false + /create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + dev: false + + /create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + dev: false + /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true @@ -8809,6 +9042,26 @@ packages: js-sha3: 0.8.0 dev: false + /ethereum-cryptography@0.1.3: + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + dependencies: + '@types/pbkdf2': 3.1.2 + '@types/secp256k1': 4.0.6 + blakejs: 1.2.1 + browserify-aes: 1.2.0 + bs58check: 2.1.2 + create-hash: 1.2.0 + create-hmac: 1.1.7 + hash.js: 1.1.7 + keccak: 3.0.4 + pbkdf2: 3.1.2 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + scrypt-js: 3.0.1 + secp256k1: 4.0.3 + setimmediate: 1.0.5 + dev: false + /ethereum-cryptography@1.2.0: resolution: {integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==} dependencies: @@ -8836,6 +9089,17 @@ packages: '@scure/bip39': 1.2.2 dev: false + /ethereumjs-util@7.1.5: + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} + dependencies: + '@types/bn.js': 5.1.5 + bn.js: 5.2.1 + create-hash: 1.2.0 + ethereum-cryptography: 0.1.3 + rlp: 2.2.7 + dev: false + /ethers@5.7.2: resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} dependencies: @@ -8907,6 +9171,13 @@ packages: engines: {node: '>=0.8.x'} dev: false + /evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + dev: false + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -9473,6 +9744,15 @@ packages: dependencies: has-symbols: 1.0.3 + /hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + dev: false + /hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} dependencies: @@ -11016,6 +11296,14 @@ packages: resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} dev: false + /md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} @@ -11429,6 +11717,26 @@ packages: pkg-types: 1.0.3 ufo: 1.4.0 + /moralis@2.26.1(debug@4.3.4): + resolution: {integrity: sha512-6aY1D/ZJwpys3H1tKhxbuRvnHXTOK07uqPrBQS2OPbCyxYjW33NFJPJXiLRXsmpDjFM+xq6vYRKrQSy5Zf4yog==} + dependencies: + '@moralisweb3/api-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/aptos-api': 2.26.1(debug@4.3.4) + '@moralisweb3/auth': 2.26.1(debug@4.3.4) + '@moralisweb3/common-aptos-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-auth-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-core': 2.26.1(debug@4.3.4) + '@moralisweb3/common-evm-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-sol-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/common-streams-utils': 2.26.1(debug@4.3.4) + '@moralisweb3/evm-api': 2.26.1(debug@4.3.4) + '@moralisweb3/sol-api': 2.26.1(debug@4.3.4) + '@moralisweb3/streams': 2.26.1(debug@4.3.4) + '@moralisweb3/streams-typings': 1.0.7 + transitivePeerDependencies: + - debug + dev: false + /motion@10.16.2: resolution: {integrity: sha512-p+PurYqfUdcJZvtnmAqu5fJgV2kR0uLFQuBKtLeFVTrYEVllI99tiOTSefVNYuip9ELTEkepIIDftNdze76NAQ==} dependencies: @@ -12068,6 +12376,17 @@ packages: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true + /pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + dev: false + /periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} dependencies: @@ -12953,6 +13272,20 @@ packages: dependencies: glob: 7.2.3 + /ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + dev: false + + /rlp@2.2.7: + resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} + hasBin: true + dependencies: + bn.js: 5.2.1 + dev: false + /rollup-plugin-visualizer@5.12.0: resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==} engines: {node: '>=14'} @@ -13087,7 +13420,16 @@ packages: /scrypt-js@3.0.1: resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - dev: true + + /secp256k1@4.0.3: + resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} + engines: {node: '>=10.0.0'} + requiresBuild: true + dependencies: + elliptic: 6.5.4 + node-addon-api: 2.0.2 + node-gyp-build: 4.8.0 + dev: false /secp256k1@5.0.0: resolution: {integrity: sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==} @@ -13188,6 +13530,10 @@ packages: has-property-descriptors: 1.0.2 dev: true + /setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + dev: false + /setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: false @@ -14192,15 +14538,6 @@ packages: engines: {node: '>=0.6'} dev: false - /ts-api-utils@1.2.1(typescript@5.4.3): - resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - dependencies: - typescript: 5.4.3 - dev: true - /ts-api-utils@1.3.0(typescript@5.4.3): resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} @@ -15050,6 +15387,14 @@ packages: dependencies: defaults: 1.0.4 + /web3-eth-abi@1.10.4: + resolution: {integrity: sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==} + engines: {node: '>=8.0.0'} + dependencies: + '@ethersproject/abi': 5.7.0 + web3-utils: 1.10.4 + dev: false + /web3-utils@1.10.3: resolution: {integrity: sha512-OqcUrEE16fDBbGoQtZXWdavsPzbGIDc5v3VrRTZ0XrIpefC/viZ1ZU9bGEemazyS0catk/3rkOOxpzTfY+XsyQ==} engines: {node: '>=8.0.0'} @@ -15064,6 +15409,20 @@ packages: utf8: 3.0.0 dev: false + /web3-utils@1.10.4: + resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} + engines: {node: '>=8.0.0'} + dependencies: + '@ethereumjs/util': 8.1.0 + bn.js: 5.2.1 + ethereum-bloom-filters: 1.0.10 + ethereum-cryptography: 2.1.3 + ethjs-unit: 0.1.6 + number-to-bn: 1.7.0 + randombytes: 2.1.0 + utf8: 3.0.0 + dev: false + /webextension-polyfill-ts@0.25.0: resolution: {integrity: sha512-ikQhwwHYkpBu00pFaUzIKY26I6L87DeRI+Q6jBT1daZUNuu8dSrg5U9l/ZbqdaQ1M/TTSPKeAa3kolP5liuedw==} deprecated: This project has moved to @types/webextension-polyfill