diff --git a/README.md b/README.md index caeefc79..61cd0179 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # 💳 wallet.universalprofile.cloud -Web app built with [Nuxt.js](https://nuxt.com/). +## Status + +- develop [![Lint, Test, Build](https://github.com/lukso-network/wallet.universalprofile.cloud/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/lukso-network/wallet.universalprofile.cloud/actions/workflows/ci.yml) +- main [![Lint, Test, Build](https://github.com/lukso-network/wallet.universalprofile.cloud/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/lukso-network/wallet.universalprofile.cloud/actions/workflows/ci.yml) Wallet that will let you see the Tokens ([LSP7](https://docs.lukso.tech/standards/nft-2.0/LSP7-Digital-Asset)) and NFTs ([LSP8](https://docs.lukso.tech/standards/nft-2.0/LSP8-Identifiable-Digital-Asset)) associated to a specific LUKSO's address. diff --git a/components/AppFooterNetworkSelect.vue b/components/AppFooterNetworkSelect.vue index 7e2f2beb..36caee31 100644 --- a/components/AppFooterNetworkSelect.vue +++ b/components/AppFooterNetworkSelect.vue @@ -6,7 +6,6 @@ const selectedNetwork = ref() const { currentNetwork, selectedChainId } = storeToRefs(useAppStore()) const { disconnect } = useBrowserExtension() const { isMobileOrTablet } = useDevice() -const isOpen = ref(false) onMounted(() => { networks.value = NETWORKS.map(network => { @@ -37,7 +36,6 @@ const handleNetworkChange = (event: CustomEvent) => { :value="JSON.stringify(selectedNetwork)" :options="JSON.stringify(networks)" :open-top="!isMobileOrTablet ? true : undefined" - :is-open="isOpen ? true : undefined" :is-full-width="isMobileOrTablet ? true : undefined" class="sm:w-40" @on-select="handleNetworkChange" diff --git a/models/image.ts b/models/image.ts index 0460c1fb..be8bc6c3 100644 --- a/models/image.ts +++ b/models/image.ts @@ -1,30 +1,34 @@ import { Item } from 'pinia-orm' +import { ImageMetadata } from '@lukso/lsp-smart-contracts' import { BaseModel } from '@/models/base' export class ImageModel extends BaseModel { static entity = 'images' - static primaryKey = 'hash' static fields() { return { ...super.fields(), + id: this.string(''), width: this.number(0), height: this.number(0), hashFunction: this.string(''), hash: this.string(''), url: this.string(''), base64: this.string(''), + verification: this.attr({}), } } // types + declare id: string declare hash: string declare width?: number declare height?: number declare hashFunction?: string declare url?: string declare base64?: Base64EncodedImage + declare verification?: ImageMetadata['verification'] static piniaOptions = { persist: { diff --git a/package.json b/package.json index 1393e6f8..c39b455d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@formatjs/intl": "^2.9.6", "@lukso/lsp-smart-contracts": "0.12.1", - "@lukso/web-components": "1.49.0", + "@lukso/web-components": "1.49.1", "@nuxt/devtools": "^0.7.6", "@nuxtjs/algolia": "^1.9.0", "@nuxtjs/device": "^3.1.1", diff --git a/pages/[profileAddress]/lyx-details.vue b/pages/[profileAddress]/lyx-details.vue index b33ed3b4..0a24e422 100644 --- a/pages/[profileAddress]/lyx-details.vue +++ b/pages/[profileAddress]/lyx-details.vue @@ -76,7 +76,7 @@ const handleSendLyx = () => { :decimals="ASSET_LYX_DECIMALS" /> diff --git a/pages/[profileAddress]/send.vue b/pages/[profileAddress]/send.vue index 07a4666b..6371e378 100644 --- a/pages/[profileAddress]/send.vue +++ b/pages/[profileAddress]/send.vue @@ -17,7 +17,7 @@ const { isLoadedApp, isConnected } = storeToRefs(useAppStore()) const { setStatus, clearSend } = useSendStore() const { showModal } = useModal() const { formatMessage } = useIntl() -const { sendTransaction, getBalance, contract } = useWeb3(PROVIDERS.INJECTED) +const { sendTransaction, contract } = useWeb3(PROVIDERS.INJECTED) const assetRepository = useRepo(AssetRepository) onMounted(() => { @@ -92,7 +92,7 @@ const handleSend = async () => { } as TransactionConfig await sendTransaction(transaction) - await updateLyxBalance() + await updateLyxBalance(connectedProfile.value?.address) } else { // custom token transfer switch (asset.value?.standard) { diff --git a/shared/config.ts b/shared/config.ts index 43c4fb49..6c738b26 100644 --- a/shared/config.ts +++ b/shared/config.ts @@ -13,7 +13,7 @@ export const NETWORKS: NetworkInfo[] = [ rpcHttp: 'https://rpc.testnet.lukso.network', token: { symbol: 'LYXt', - supply: 42_000_000, + supply: '42000000000000000000000000', name: 'LUKSO', }, indexName: 'prod_testnet_universal_profiles', @@ -24,7 +24,7 @@ export const NETWORKS: NetworkInfo[] = [ rpcHttp: 'https://rpc.mainnet.lukso.network', token: { symbol: 'LYX', - supply: 42_000_000, + supply: '42000000000000000000000000', name: 'LUKSO', }, indexName: 'prod_mainnet_universal_profiles', diff --git a/types/network.ts b/types/network.ts index 96553a22..4dea6f5d 100644 --- a/types/network.ts +++ b/types/network.ts @@ -7,7 +7,7 @@ export interface NetworkInfo { storeUrls?: { [key in BrowserName]: string } token: { symbol: string - supply: number + supply: string name: string } indexName: string diff --git a/utils/fetchLSP7Assets.ts b/utils/fetchLSP7Assets.ts index 88fc0717..2a405804 100644 --- a/utils/fetchLSP7Assets.ts +++ b/utils/fetchLSP7Assets.ts @@ -37,15 +37,11 @@ export const fetchLsp7Assets = async ( const imageIds: string[] = [] images.forEach(image => { - if ('hash' in image) { - image.hash && imageIds.push(image.hash as string) - } else { - image.verification?.data && imageIds.push(image.verification.data) - } + const id = getImageId(image) + id && imageIds.push(id) }) - const iconId = - icon && ('hash' in icon ? (icon?.hash as string) : icon?.verification?.data) + const iconId = getImageId(icon) const creatorIds: string[] = [] creators?.forEach(creator => { diff --git a/utils/fetchLSP8Assets.ts b/utils/fetchLSP8Assets.ts index 476fee12..a1f88ab7 100644 --- a/utils/fetchLSP8Assets.ts +++ b/utils/fetchLSP8Assets.ts @@ -53,16 +53,11 @@ export const fetchLsp8Assets = async ( const imageIds: string[] = [] images.forEach(image => { - if ('hash' in image) { - image.hash && imageIds.push(image.hash as string) - } else { - image.verification?.data && imageIds.push(image.verification.data) - } + const id = getImageId(image) + id && imageIds.push(id) }) - const iconId = - icon && - ('hash' in icon ? (icon?.hash as string) : icon?.verification?.data) + const iconId = getImageId(icon) const creatorIds: string[] = [] creators?.forEach(creator => { diff --git a/utils/fetchLsp3Profile.ts b/utils/fetchLsp3Profile.ts index 4f95db25..8415041f 100644 --- a/utils/fetchLsp3Profile.ts +++ b/utils/fetchLsp3Profile.ts @@ -25,20 +25,10 @@ export const fetchLsp3Profile = async ( lsp3Profile.backgroundImage && (await getAndConvertImage(lsp3Profile.backgroundImage, 800)) - const { getBalance } = useWeb3(PROVIDERS.RPC) // TODO move balance out so it's always fetched + const { getBalance } = useWeb3(PROVIDERS.RPC) const balance = await getBalance(profileAddress) - - const profileImageId = - profileImage && - ('hash' in profileImage - ? (profileImage?.hash as string) - : profileImage?.verification?.data) - - const backgroundImageId = - backgroundImage && - ('hash' in backgroundImage - ? (backgroundImage?.hash as string) - : backgroundImage?.verification?.data) + const profileImageId = getImageId(profileImage) + const backgroundImageId = getImageId(backgroundImage) return { ...lsp3Profile, diff --git a/utils/fetchProfile.ts b/utils/fetchProfile.ts index 6a974047..936444b3 100644 --- a/utils/fetchProfile.ts +++ b/utils/fetchProfile.ts @@ -10,6 +10,8 @@ export const fetchProfile = async (profileAddress: Address) => { const storeProfile = profileRepo.getProfileAndImages(profileAddress) if (storeProfile) { + // refetch LYX balance for cached profile in case it has changed + await updateLyxBalance(profileAddress) return } diff --git a/utils/getImages.ts b/utils/getImages.ts index 872e6e7b..f4ce2277 100644 --- a/utils/getImages.ts +++ b/utils/getImages.ts @@ -92,6 +92,7 @@ export const getAndConvertImage = async ( ...optimalImage, base64: formatUrl(optimalImage.url), // base64: await fetchAndConvertImage(optimalImage.url), // TODO add base when cache storage is added + id: getImageId(optimalImage), } as ImageMetadataEncoded } } diff --git a/utils/updateLyxBalance.ts b/utils/updateLyxBalance.ts new file mode 100644 index 00000000..3cc4174e --- /dev/null +++ b/utils/updateLyxBalance.ts @@ -0,0 +1,7 @@ +export const updateLyxBalance = async (profileAddress?: Address) => { + const { getBalance } = useWeb3(PROVIDERS.RPC) + assertString(profileAddress) + const balance = await getBalance(profileAddress) + + useRepo(ProfileModel).where('address', profileAddress).update({ balance }) +} diff --git a/utils/validateLSP4Metadata.ts b/utils/validateLSP4Metadata.ts index ebb37926..258a9896 100644 --- a/utils/validateLSP4Metadata.ts +++ b/utils/validateLSP4Metadata.ts @@ -12,7 +12,7 @@ export const validateLsp4MetaData = ( images = LSP4MetadataJSON?.LSP4Metadata?.images?.filter((image: any) => { if (!image?.length) return false - return validateImage(image) + return validateImages(image) }) } @@ -24,13 +24,13 @@ export const validateLsp4MetaData = ( if (LSP4MetadataJSON?.LSP4Metadata?.assets?.length) { assets = LSP4MetadataJSON?.LSP4Metadata?.assets.filter((asset: any) => { - return asset?.hash && asset?.url && asset?.hashFunction && asset.fileType + return validateAsset(asset) }) } if (LSP4MetadataJSON?.LSP4Metadata?.icons?.length) { icon = LSP4MetadataJSON?.LSP4Metadata?.icons?.filter((image: any) => { - return validateIcon(image) + return validateImage(image) }) } @@ -45,14 +45,66 @@ export const validateLsp4MetaData = ( } } -const validateIcon = (icon: any) => { - return icon.width && icon.url && icon.hash && icon.hashFunction && icon.height +/** + * Validates if the given image object follows proper structure + * It checks for old format using `hash` property and + * new format using `verification` property. + * + * @param image - image object to be validated + * @returns - true if validation passes, false otherwise + */ +const validateImage = (image: any) => { + return ( + (image.width && + image.height && + image.url && + image.hash && + image.hashFunction) || + (image.width && + image.height && + image.url && + image.verification && + image.verification.data && + image.verification.method) + ) } -export const validateImage = (image: any[]) => { - return image.every(size => { - return ( - size.url && size.hash && size.width && size.height && size.hashFunction - ) +export const validateImages = (images: any[]) => { + return images.every(imageSize => { + return validateImage(imageSize) }) } + +/** + * Get image id from image object + * It checks for old format using `hash` property and + * new format using `verification.data` property. + * + * @param image + * @returns + */ +export const getImageId = (image: any): string | undefined => { + return ( + image && + ('hash' in image && image.hash !== '' + ? image.hash + : image?.verification?.data) + ) +} + +/** + * Validate if the given asset object follows proper structure + * + * @param asset + * @returns + */ +const validateAsset = (asset: any) => { + return ( + (asset.url && asset.fileType && asset.hash && asset.hashFunction) || + (asset.url && + asset.fileType && + asset.verification && + asset.verification.data && + asset.verification.method) + ) +} diff --git a/utils/validateLsp3Metadata.ts b/utils/validateLsp3Metadata.ts index c1146496..f797de39 100644 --- a/utils/validateLsp3Metadata.ts +++ b/utils/validateLsp3Metadata.ts @@ -17,12 +17,12 @@ export const validateLsp3Metadata = ( const description = validateDescription(lsp3Profile.description) if (lsp3Profile?.profileImage?.length) { - const imageIsValid = validateImage(lsp3Profile?.profileImage) + const imageIsValid = validateImages(lsp3Profile?.profileImage) profileImage = imageIsValid ? lsp3Profile?.profileImage : [] } if (lsp3Profile?.backgroundImage?.length) { - const imageIsValid = validateImage(lsp3Profile?.backgroundImage) + const imageIsValid = validateImages(lsp3Profile?.backgroundImage) backgroundImage = imageIsValid ? lsp3Profile?.backgroundImage : [] } diff --git a/yarn.lock b/yarn.lock index 8ddf26c6..b87a937b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1914,12 +1914,12 @@ __metadata: languageName: node linkType: hard -"@lukso/web-components@npm:1.49.0": - version: 1.49.0 - resolution: "@lukso/web-components@npm:1.49.0" +"@lukso/web-components@npm:1.49.1": + version: 1.49.1 + resolution: "@lukso/web-components@npm:1.49.1" dependencies: ethereum-blockies-base64: ^1.0.2 - checksum: 6ad7d2a491d121a9a5a26c1495ed704a635ee181320d994c559c2b60553cedc59be4cd5c33ce31343866530a126f242339f5498c00f04168c85f7f5f4c2afcb2 + checksum: 0c9e7eb9b12f730a9c61eb4b0542f5b5e354df837f6ba64c413b3ac24e0a13c951345113e1fc4f02d4a0e2ba52b33244f67447e7fe0a01899627e8124bc4f762 languageName: node linkType: hard @@ -16387,7 +16387,7 @@ __metadata: "@esbuild-plugins/node-globals-polyfill": 0.2.3 "@formatjs/intl": ^2.9.6 "@lukso/lsp-smart-contracts": 0.12.1 - "@lukso/web-components": 1.49.0 + "@lukso/web-components": 1.49.1 "@nuxt/devtools": ^0.7.6 "@nuxtjs/algolia": ^1.9.0 "@nuxtjs/device": ^3.1.1