Skip to content
This repository has been archived by the owner on Dec 2, 2024. It is now read-only.

Commit

Permalink
feat: verify LSP4 creators (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
dzbo authored Oct 25, 2023
1 parent 68bfd09 commit 7fcc794
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 83 deletions.
22 changes: 11 additions & 11 deletions components/AssetCreator.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<script setup lang="ts">
import { Asset } from '@/types/assets'
import { Creator } from '@/types/profile'
type Props = {
asset: Asset
creator?: Creator
}
const props = defineProps<Props>()
defineProps<Props>()
const handleOpenCreator = (event: Event) => {
const handleOpenCreator = (event: Event, creator?: Creator) => {
try {
event.stopPropagation()
assertAddress(props.asset.creatorAddress)
navigateTo(profileRoute(props.asset.creatorAddress))
assertAddress(creator?.address)
navigateTo(profileRoute(creator.address))
} catch (error) {
console.error(error)
}
Expand All @@ -20,21 +20,21 @@ const handleOpenCreator = (event: Event) => {

<template>
<div
v-if="asset.creatorAddress"
v-if="creator"
class="cursor-pointer shadow-neutral-drop-shadow p-2 pr-6 rounded-4 inline-flex bg-neutral-100 transition hover:scale-105"
@click="handleOpenCreator"
@click="event => handleOpenCreator(event, creator)"
>
<lukso-profile
size="x-small"
:profile-url="asset.creatorProfileImage"
:profile-url="creator.profileImage"
></lukso-profile>
<div class="pl-1">
<div class="text-neutral-60 paragraph-inter-10-semi-bold">
{{ $formatMessage('asset_created_by') }}
</div>
<lukso-username
:name="asset.creatorName"
:address="asset.creatorAddress"
:name="creator.name"
:address="creator.address"
size="x-small"
class="flex"
name-color="neutral-20"
Expand Down
11 changes: 9 additions & 2 deletions components/NftListCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const props = defineProps<Props>()
const { profile: connectedProfile, status } = useConnectedProfileStore()
const { profile: viewedProfile } = useViewedProfileStore()
const verifiedCreator = computed(() => {
return props.asset.creators?.find(creator => creator.isVerified)
})
const handleShowAsset = () => {
try {
assertAddress(viewedProfile.address, 'profile')
Expand Down Expand Up @@ -47,8 +51,11 @@ const handleSendAsset = (event: Event) => {
class="min-h-[260px] bg-neutral-90 w-100 rounded-t-12 bg-center bg-cover"
:style="`background-image: url(${getAssetThumb(asset)});`"
></div>
<div class="p-4 pt-8 relative">
<AssetCreator :asset="asset" class="absolute -top-5" />
<div class="p-4 relative">
<AssetCreator
:creator="verifiedCreator"
class="relative -mt-4 -top-4"
/>
<div>
<div class="paragraph-inter-14-semi-bold">
{{ asset.name }}
Expand Down
4 changes: 2 additions & 2 deletions components/SendCardDraft.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const handleSelectAssets = () => {
<template>
<lukso-card
variant="profile-2"
:background-url="connectedProfile.backgroundImageUrl"
:profile-url="connectedProfile.profileImageUrl"
:background-url="connectedProfile.backgroundImage"
:profile-url="connectedProfile.profileImage"
:profile-address="connectedProfile.address"
is-full-width
>
Expand Down
10 changes: 5 additions & 5 deletions components/profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ const handleCopyAddress = () => {
<div class="relative">
<lukso-card
variant="hero"
:background-url="profile.backgroundImageUrl"
:background-url="profile.backgroundImage"
is-full-width
custom-class="rounded-24 shadow-neutral-drop-shadow"
>
<div slot="content" class="flex flex-col items-center">
<lukso-profile
:profile-url="profile.profileImageUrl"
:profile-url="profile.profileImage"
:profile-address="profile.address"
class="mb-4"
has-identicon
Expand All @@ -33,23 +33,23 @@ const handleCopyAddress = () => {
size="large"
address-color="neutral-100"
max-width="350"
:name-color="profile.backgroundImageUrl ? 'neutral-100' : ''"
:name-color="profile.backgroundImage ? 'neutral-100' : ''"
></lukso-username>
<lukso-username
v-else
:name="$formatMessage('profile_default_name')"
size="large"
address-color="neutral-100"
max-width="350"
:name-color="profile.backgroundImageUrl ? 'neutral-100' : ''"
:name-color="profile.backgroundImage ? 'neutral-100' : ''"
hide-prefix
></lukso-username>
<lukso-username
:address="profile.address"
size="small"
slice-by="40"
:address-color="
profile.backgroundImageUrl ? 'neutral-100' : 'neutral-20'
profile.backgroundImage ? 'neutral-100' : 'neutral-20'
"
class="cursor-pointer mt-2"
@click="handleCopyAddress"
Expand Down
48 changes: 8 additions & 40 deletions composables/useErc725.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ import LSP3ProfileMetadata from '@erc725/erc725.js/schemas/LSP3ProfileMetadata.j
import { LSP3Profile } from '@lukso/lsp-factory.js'
import Web3 from 'web3'
import { LSP4DigitalAssetJSON } from '@lukso/lsp-factory.js/build/main/src/lib/interfaces/lsp4-digital-asset'
import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts'

import { LSP0ERC725Account } from '@/types/contracts/LSP0ERC725Account'
import { Lsp8TokenIdType } from '@/types/assets'
import LSP8IdentifiableDigitalAsset from '@/shared/schemas/LSP8IdentifiableDigitalAsset.json'
import { Creator, Profile } from '@/types/profile'
import { Profile } from '@/types/profile'

export interface LSP3ProfileJSON {
LSP3Profile: LSP3Profile
Expand All @@ -30,12 +28,12 @@ const fetchProfile = async (profileAddress: Address): Promise<Profile> => {
profileAddress,
LSP3ProfileMetadata as ERC725JSONSchema[]
)
const fetchedProfile = await erc725.fetchData('LSP3Profile')
const lsp3Profile = validateLsp3Metadata(fetchedProfile)
const profileImageUrl =
const profileMetadata = await erc725.fetchData('LSP3Profile')
const lsp3Profile = validateLsp3Metadata(profileMetadata)
const profileImage =
lsp3Profile.profileImage &&
(await getAndConvertImage(lsp3Profile.profileImage, 200))
const backgroundImageUrl =
const backgroundImage =
lsp3Profile.backgroundImage &&
(await getAndConvertImage(lsp3Profile.backgroundImage, 800))

Expand All @@ -45,9 +43,10 @@ const fetchProfile = async (profileAddress: Address): Promise<Profile> => {
return {
...lsp3Profile,
address: profileAddress,
profileImageUrl,
backgroundImageUrl,
profileImage,
backgroundImage,
balance,
metadata: lsp3Profile,
}
}

Expand Down Expand Up @@ -146,43 +145,12 @@ const fetchLsp8Metadata = async (
}
}

const fetchLSP4Creator = async (
assetAddress: Address
): Promise<Creator | undefined> => {
const { contract } = useWeb3(PROVIDERS.RPC)

try {
const creator = await contract<LSP0ERC725Account>(getDataABI, assetAddress)
.methods.getData(ERC725YDataKeys.LSP4['LSP4Creators[]'].index)
.call()
assertAddress(creator)
const erc725 = getInstance(
creator,
LSP3ProfileMetadata as ERC725JSONSchema[]
)
const fetchedProfile = await erc725.fetchData('LSP3Profile')
const lsp3Profile = validateLsp3Metadata(fetchedProfile)
const profileImageUrl =
lsp3Profile.profileImage &&
(await getAndConvertImage(lsp3Profile.profileImage, 200))

return {
address: creator,
name: lsp3Profile.name,
profileImageUrl,
}
} catch (error) {
console.error(error)
}
}

const useErc725 = () => {
return {
getInstance,
fetchProfile,
fetchAssets,
fetchLsp8Metadata,
fetchLSP4Creator,
}
}

Expand Down
11 changes: 9 additions & 2 deletions pages/[profileAddress]/nft/[nftAddress]/tokenId/[tokenId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ watchEffect(() => {
nft.value = getNft(nftAddress, tokenId)
})
const verifiedCreator = computed(() => {
return nft.value?.creators?.find(creator => creator.isVerified)
})
const handleSendAsset = (event: Event) => {
try {
event.stopPropagation()
Expand Down Expand Up @@ -50,8 +54,11 @@ const handleSendAsset = (event: Event) => {
class="min-h-[260px] bg-neutral-90 w-100 rounded-t-12 bg-center bg-cover"
:style="`background-image: url(${getAssetThumb(nft)});`"
></div>
<div class="p-4 pt-8 relative">
<AssetCreator v-if="nft" :asset="nft" class="absolute -top-5" />
<div class="p-4 relative">
<AssetCreator
:creator="verifiedCreator"
class="relative -mt-4 -top-4"
/>
<div>
<div class="paragraph-inter-14-semi-bold">
{{ nft?.name }}
Expand Down
6 changes: 3 additions & 3 deletions types/assets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { LinkMetadata } from '@lukso/lsp-factory.js'
import { INTERFACE_IDS } from '@lukso/lsp-smart-contracts'

import { Creator } from './profile'

export type InterfaceId = keyof typeof INTERFACE_IDS

export const tokenStandards: InterfaceId[] = ['LSP7DigitalAsset']
Expand Down Expand Up @@ -40,9 +42,7 @@ export type Asset = {
description?: string
images?: Base64EncodedImage[]
links?: LinkMetadata[]
creatorName?: string
creatorAddress?: Address
creatorProfileImage?: Base64EncodedImage
creators?: Creator[]
tokenId?: string

// custom
Expand Down
23 changes: 15 additions & 8 deletions types/profile.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { LSP3Profile } from '@lukso/lsp-factory.js'

export interface Profile extends LSP3Profile {
backgroundImageUrl?: Base64EncodedImage
profileImageUrl?: Base64EncodedImage
export type Profile = {
address?: Address
name?: string
backgroundImage?: Base64EncodedImage
profileImage?: Base64EncodedImage
balance: string
issuedAssets?: Address[] // LSP12
receivedAssets?: Address[] // LSP5
metadata?: LSP3Profile // LSP3
}

export type Receiver = Partial<Profile> & { isEoa?: boolean }
export type Receiver = Pick<
Profile,
'address' | 'backgroundImage' | 'profileImage'
> & { isEoa?: boolean }

export type Creator = Partial<
Pick<Profile, 'address' | 'profileImageUrl' | 'name'>
>
export type Creator = Pick<Profile, 'address' | 'profileImage' | 'name'> & {
isVerified?: boolean
}

export interface IndexedProfile {
export type IndexedProfile = {
address: Address
profileURL?: string
profileHash?: string
Expand Down
13 changes: 3 additions & 10 deletions utils/fetchLSP8Assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const fetchLsp8Assets = async (
return []
}

const { fetchLsp8Metadata, fetchLSP4Creator } = useErc725() // TODO move to utils
const { fetchLsp8Metadata } = useErc725() // TODO move to utils
// nft metadata is the same for all tokens of same asset
const [name, symbol, nftMetadata] = await fetchLsp4Metadata(address)

Expand All @@ -35,12 +35,7 @@ export const fetchLsp8Assets = async (
icon: metadataIcon,
links,
} = collectionMetadata
const creatorMetadata = await fetchLSP4Creator(address)
const {
name: creatorName,
address: creatorAddress,
profileImageUrl: creatorProfileImage,
} = creatorMetadata || {}
const creators = await fetchLsp4Creators(address)
const icon = await getAndConvertImage(metadataIcon, 200)
const images: Base64EncodedImage[] = []

Expand All @@ -62,9 +57,7 @@ export const fetchLsp8Assets = async (
links,
description,
images,
creatorName,
creatorAddress,
creatorProfileImage,
creators,
metadata: {
nft: nftMetadata.LSP4Metadata,
collection: collectionMetadata,
Expand Down
Loading

0 comments on commit 7fcc794

Please sign in to comment.