Skip to content

Commit

Permalink
refactor: fetch-third-party-wearables component
Browse files Browse the repository at this point in the history
  • Loading branch information
aleortega committed Jan 28, 2025
1 parent 9df59bb commit 9819e15
Showing 1 changed file with 31 additions and 69 deletions.
100 changes: 31 additions & 69 deletions src/logic/fetch-elements/fetch-third-party-wearables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ type LinkedWearableAssetEntities = {
entities: Entity[]
}

async function fetchAssetsV2(
async function fetchAssetsRepresentation(
{ contentServerUrl, fetch }: Pick<AppComponents, 'contentServerUrl' | 'fetch' | 'logs' | 'metrics'>,
linkedWearableProvider: ThirdPartyProvider
thirdPartyProvider: ThirdPartyProvider
): Promise<Entity[]> {
const urn = await parseUrn(linkedWearableProvider.id)
const urn = await parseUrn(thirdPartyProvider.id)
if (!urn || urn.type !== URN_THIRD_PARTY_NAME_TYPE) {
throw new Error(`Couldn't parse linked wearable provider id: ${linkedWearableProvider.id}`)
throw new Error(`Couldn't parse linked wearable provider id: ${thirdPartyProvider.id}`)
}

const response = await fetch.fetch(`${contentServerUrl}/entities/active/collections/${linkedWearableProvider.id}`)
const assetsByOwner: LinkedWearableAssetEntities = await response.json()
return assetsByOwner.entities || []
const response = await fetch.fetch(`${contentServerUrl}/entities/active/collections/${thirdPartyProvider.id}`)
const assetsFromThirdPartyCollection: LinkedWearableAssetEntities = await response.json()
return assetsFromThirdPartyCollection.entities || []
}

function groupLinkedWearablesByURN(
Expand Down Expand Up @@ -60,51 +60,6 @@ function groupLinkedWearablesByURN(
return Array.from(wearablesByURN.values())
}

export async function fetchUserThirdPartyAssets(
components: Pick<
AppComponents,
| 'alchemyNftFetcher'
| 'contentServerUrl'
| 'thirdPartyProvidersStorage'
| 'fetch'
| 'logs'
| 'entitiesFetcher'
| 'metrics'
>,
owner: string,
collectionId: string
): Promise<ThirdPartyAsset[]> {
const parts = collectionId.split(':')

// TODO: [TPW] Use urn parser here
if (!(parts.length === 5 || parts.length === 6)) {
throw new Error(`Couldn't parse collectionId ${collectionId}, valid ones are like:
\n - urn:decentraland:{protocol}:collections-thirdparty:{third-party-name}
\n - urn:decentraland:{protocol}:collections-thirdparty:{third-party-name}:{collection-id}`)
}

const thirdPartyId = parts.slice(0, 5).join(':')

const thirdPartyProviders = await components.thirdPartyProvidersStorage.getAll()
const thirdPartyProvider: ThirdPartyProvider | undefined = thirdPartyProviders.find(
(provider) => provider.id === thirdPartyId
)

if (!thirdPartyProvider) {
return []
}

const thirdPartyWearables = await _fetchThirdPartyWearables(components, owner, [thirdPartyProvider])

return thirdPartyWearables.map((tpw) => ({
id: tpw.urn, // TODO check this, not sure id refers to full urn, it might be provider + collection id + item id
amount: tpw.amount,
urn: {
decentraland: tpw.urn
}
}))
}

export async function fetchAllThirdPartyWearables(
components: Pick<
AppComponents,
Expand Down Expand Up @@ -137,12 +92,12 @@ async function _fetchThirdPartyWearables(
owner: string,
thirdParties: ThirdPartyProvider[]
): Promise<ThirdPartyWearable[]> {
async function fetchThirdPartyV2(linkedWearableProviders: ThirdPartyProvider[]) {
if (linkedWearableProviders.length === 0) {
async function fetchThirdPartyWearables(thirdPartyProviders: ThirdPartyProvider[]) {
if (thirdPartyProviders.length === 0) {
return []
}

const contractAddresses = linkedWearableProviders.reduce(
const thirdPartyContractsByNetwork = thirdPartyProviders.reduce(
(carry, provider) => {
;(provider.metadata.thirdParty.contracts || []).forEach((contract) => {
carry[contract.network] = carry[contract.network] || new Set<string>()
Expand All @@ -153,12 +108,12 @@ async function _fetchThirdPartyWearables(
{} as Record<string, Set<string>>
)

const nfts = await components.alchemyNftFetcher.getNFTsForOwner(owner, contractAddresses)
const ownedNftUrns = await components.alchemyNftFetcher.getNFTsForOwner(owner, thirdPartyContractsByNetwork)

const providersThatReturnedNfts = new Set<string>()
for (const nft of nfts) {
const [network, contractAddress] = nft.split(':')
const providers = linkedWearableProviders.filter((provider) =>
for (const urn of ownedNftUrns) {
const [network, contractAddress] = urn.split(':')
const providers = thirdPartyProviders.filter((provider) =>
(provider.metadata.thirdParty.contracts || []).find(
(contract) => contract.network === network && contract.address === contractAddress
)
Expand All @@ -170,23 +125,29 @@ async function _fetchThirdPartyWearables(
}
}

const providersToCheck = linkedWearableProviders.filter((provider) => providersThatReturnedNfts.has(provider.id))
const providersToCheck = thirdPartyProviders.filter((provider) => providersThatReturnedNfts.has(provider.id))

const linkedWearableEntities = (
await Promise.all(providersToCheck.map((provider: ThirdPartyProvider) => fetchAssetsV2(components, provider)))
const thirdPartyEntities = (
await Promise.all(
providersToCheck.map((provider: ThirdPartyProvider) => fetchAssetsRepresentation(components, provider))
)
).flat()

const assignedLinkedWearables: Record<string, { individualData: string[]; entity: Entity }> = {}
for (const entity of linkedWearableEntities) {
for (const entity of thirdPartyEntities) {
const urn = entity.metadata.id
if (!entity.metadata.mappings) {
continue
}

const mappingsHelper = createMappingsHelper(entity.metadata.mappings)
for (const nft of nfts) {
/** MappingHelper:
* Contains the relation between the NFT token id and the Decentraland asset urn
* Multiple token ids can refer to the same asset
*/
const entityMappingHelper = createMappingsHelper(entity.metadata.mappings)
for (const nft of ownedNftUrns) {
const [network, contract, tokenId] = nft.split(':')
if (mappingsHelper.includesNft(network as ContractNetwork, contract, tokenId)) {
if (entityMappingHelper.includesNft(network as ContractNetwork, contract, tokenId)) {
if (assignedLinkedWearables[urn]) {
assignedLinkedWearables[urn].individualData.push(nft)
} else {
Expand All @@ -198,11 +159,12 @@ async function _fetchThirdPartyWearables(

return groupLinkedWearablesByURN(assignedLinkedWearables)
}
const providersV2 = thirdParties.filter((provider) => (provider.metadata.thirdParty.contracts?.length ?? 0) > 0)

const thirdPartyV2 = await fetchThirdPartyV2(providersV2)
const providers = thirdParties.filter((provider) => (provider.metadata.thirdParty.contracts?.length ?? 0) > 0)

const thirdPartyWearables = await fetchThirdPartyWearables(providers)

const thirdPartyWearablesByUrn = thirdPartyV2.reduce(
const thirdPartyWearablesByUrn = thirdPartyWearables.reduce(
(acc, tpw) => {
// If there are repeated wearables, we should merge them
acc[tpw.urn] = tpw
Expand Down

0 comments on commit 9819e15

Please sign in to comment.