Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for linked wearables urns #188

Merged
merged 11 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 127 additions & 1 deletion src/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import {
BlockchainCollectionThirdPartyName,
EntityV3Asset,
BlockchainCollectionV1Item,
BlockchainCollectionV2Item
BlockchainCollectionV2Item,
BlockchainCollectionLinkedWearablesProvider,
BlockchainCollectionLinkedWearablesCollection,
BlockchainCollectionLinkedWearablesAsset,
BlockchainCollectionLinkedWearablesItem
} from './types'

/**
Expand Down Expand Up @@ -53,13 +57,27 @@ export const resolvers: RouteMap<DecentralandAssetIdentifier> = {
'decentraland:{network}:collections-v2:{contract(0x[a-fA-F0-9]+)}': resolveCollectionV2,
// resolve LAND by position
'decentraland:{network}:LAND:{position}': resolveLandAsset,

// resolve third party names
'decentraland:{network}:collections-thirdparty:{thirdPartyName}': resolveThirdPartyCollectionName,
// resolve third party collections
'decentraland:{network}:collections-thirdparty:{thirdPartyName}:{collectionId}':
resolveThirdPartyCollectionOnlyCollection,
// resolve third party assets
'decentraland:{network}:collections-thirdparty:{thirdPartyName}:{collectionId}:{itemId}': resolveThirdPartyCollection,

// resolve linked wearable provider names
'decentraland:{network}:collections-linked-wearables:{linkedWearableProvider}': resolveLinkedWearableProvider,
// resolve linked wearable collections
'decentraland:{network}:collections-linked-wearables:{linkedWearableProvider}:{contractAddressChain}:{collectionId(0x[a-fA-F0-9]+)}':
resolveLinkedWearableCollection,
// resolve linked wearable assets
'decentraland:{network}:collections-linked-wearables:{linkedWearableProvider}:{contractAddressChain}:{collectionId(0x[a-fA-F0-9]+)}:{itemId}':
resolveLinkedWearableAsset,
// resolve linked wearable items
'decentraland:{network}:collections-linked-wearables:{linkedWearableProvider}:{contractAddressChain}:{collectionId(0x[a-fA-F0-9]+)}:{itemId}:{tokenId([0-9]+)}':
resolveLinkedWearableItem,

// resolve 721 assets
'decentraland:{network}:erc721:{contract(0x[a-fA-F0-9]+)}:{tokenId}': resolveErc721Asset
}
Expand Down Expand Up @@ -512,3 +530,111 @@ export async function resolveThirdPartyCollectionOnlyCollection(

return result
}

export async function resolveLinkedWearableProvider(
uri: URL,
groups: Record<'network' | 'linkedWearableProvider', string>
): Promise<BlockchainCollectionLinkedWearablesProvider | undefined> {
let result: BlockchainCollectionLinkedWearablesProvider | undefined = undefined
if (!isValidNetwork(groups.network)) return

const contract = await getContract(groups.network, 'TPR')

if (contract) {
result = {
namespace: 'decentraland',
uri,
blockchain: 'ethereum',
type: 'blockchain-collection-linked-wearables-provider',
network: groups.network === 'ethereum' ? 'mainnet' : groups.network.toLowerCase(),
linkedWearableProvider: groups.linkedWearableProvider,
contractAddress: contract
}
}

return result
}

export async function resolveLinkedWearableCollection(
uri: URL,
groups: Record<'network' | 'linkedWearableProvider' | 'contractAddressChain' | 'collectionId', string>
): Promise<BlockchainCollectionLinkedWearablesCollection | undefined> {
let result: BlockchainCollectionLinkedWearablesCollection | undefined = undefined
if (!isValidNetwork(groups.network)) return

const contract = await getContract(groups.network, 'TPR')

if (contract) {
result = {
namespace: 'decentraland',
uri,
blockchain: 'ethereum',
type: 'blockchain-collection-linked-wearables-collection',
contractAddress: contract,
network: groups.network === 'ethereum' ? 'mainnet' : groups.network.toLowerCase(),
linkedWearableProvider: groups.linkedWearableProvider,
linkedWearableContractAddressChain: groups.contractAddressChain,
linkedWearableContractAddress: groups.collectionId
}
}

return result
}

export async function resolveLinkedWearableAsset(
uri: URL,
groups: Record<'network' | 'linkedWearableProvider' | 'contractAddressChain' | 'collectionId' | 'itemId', string>
): Promise<BlockchainCollectionLinkedWearablesAsset | undefined> {
let result: BlockchainCollectionLinkedWearablesAsset | undefined = undefined
if (!isValidNetwork(groups.network)) return

const contract = await getContract(groups.network, 'TPR')

if (contract) {
result = {
namespace: 'decentraland',
uri,
blockchain: 'ethereum',
type: 'blockchain-collection-linked-wearables-asset',
network: groups.network === 'ethereum' ? 'mainnet' : groups.network.toLowerCase(),
contractAddress: contract,
linkedWearableProvider: groups.linkedWearableProvider,
linkedWearableContractAddressChain: groups.contractAddressChain,
linkedWearableContractAddress: groups.collectionId,
id: groups.itemId
}
}

return result
}

export async function resolveLinkedWearableItem(
uri: URL,
groups: Record<
'network' | 'linkedWearableProvider' | 'contractAddressChain' | 'collectionId' | 'itemId' | 'tokenId',
string
>
): Promise<BlockchainCollectionLinkedWearablesItem | undefined> {
let result: BlockchainCollectionLinkedWearablesItem | undefined = undefined
if (!isValidNetwork(groups.network)) return

const contract = await getContract(groups.network, 'TPR')

if (contract) {
result = {
namespace: 'decentraland',
uri,
blockchain: 'ethereum',
type: 'blockchain-collection-linked-wearables-item',
network: groups.network === 'ethereum' ? 'mainnet' : groups.network.toLowerCase(),
contractAddress: contract,
linkedWearableProvider: groups.linkedWearableProvider,
linkedWearableContractAddressChain: groups.contractAddressChain,
linkedWearableContractAddress: groups.collectionId,
id: groups.itemId,
tokenId: groups.tokenId
}
}

return result
}
58 changes: 57 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* @public
*/

export type BaseBlockchainAsset = {
namespace: 'decentraland'
uri: URL
Expand Down Expand Up @@ -167,6 +166,59 @@ export type BlockchainCollectionThirdPartyName = BaseBlockchainAsset & {
thirdPartyName: string
}

/**
* @alpha
*/
export type BlockchainCollectionLinkedWearablesProvider = BaseBlockchainAsset & {
namespace: 'decentraland'
type: 'blockchain-collection-linked-wearables-provider'

/**
* Third Linked Wearable Provider (as defined in the TPR smart contract: thirdPartyName)
*/
linkedWearableProvider: string
}

/**
* @alpha
*/
export type BlockchainCollectionLinkedWearablesCollection = Omit<
BlockchainCollectionLinkedWearablesProvider,
'type'
> & {
namespace: 'decentraland'
type: 'blockchain-collection-linked-wearables-collection'

/**
* The blockchain where the contract is deployed
*/
linkedWearableContractAddressChain: string
/**
* Contract address of the collection
*/
linkedWearableContractAddress: string
}

/**
* @alpha
*/
export type BlockchainCollectionLinkedWearablesAsset = Omit<BlockchainCollectionLinkedWearablesCollection, 'type'> & {
namespace: 'decentraland'
type: 'blockchain-collection-linked-wearables-asset'

id: string
}

/**
* @alpha
*/
export type BlockchainCollectionLinkedWearablesItem = Omit<BlockchainCollectionLinkedWearablesAsset, 'type'> & {
namespace: 'decentraland'
type: 'blockchain-collection-linked-wearables-item'

tokenId: string
}

/**
* @public
*/
Expand Down Expand Up @@ -218,3 +270,7 @@ export type DecentralandAssetIdentifier =
| BlockchainCollectionThirdPartyName
| BlockchainCollectionThirdPartyCollection
| BlockchainCollectionThirdParty
| BlockchainCollectionLinkedWearablesProvider
| BlockchainCollectionLinkedWearablesCollection
| BlockchainCollectionLinkedWearablesAsset
| BlockchainCollectionLinkedWearablesItem
6 changes: 3 additions & 3 deletions test/collection-items-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('isExtendedUrn should', () => {

it('return true when passing a Collection V2 Item URN', async () => {
const parsedUrn = await parseUrn(
'urn:decentraland:mumbai:collections-v2:0x02101c138653a0af06a45b729d9c5d6ba27b8f4a:0:1'
'urn:decentraland:amoy:collections-v2:0x02101c138653a0af06a45b729d9c5d6ba27b8f4a:0:1'
)
expect(isExtendedUrn(parsedUrn)).toBe(true)
})
Expand All @@ -20,7 +20,7 @@ describe('isExtendedUrn should', () => {

it('return false when passing a Collection V2 Asset URN', async () => {
const parsedUrn = await parseUrn(
'urn:decentraland:mumbai:collections-v2:0x02101c138653a0af06a45b729d9c5d6ba27b8f4a:0'
'urn:decentraland:amoy:collections-v2:0x02101c138653a0af06a45b729d9c5d6ba27b8f4a:0'
)
expect(isExtendedUrn(parsedUrn)).toBe(false)
})
Expand Down Expand Up @@ -52,7 +52,7 @@ describe('getTokenIdAndAssetUrn should', () => {
})

it('correctly return the urn from the token id when splitting an Collection V2 Item URN', () => {
const expectedUrn = 'urn:decentraland:mumbai:collections-v2:0x02101c138653a0af06a45b729d9c5d6ba27b8f4a:0'
const expectedUrn = 'urn:decentraland:amoy:collections-v2:0x02101c138653a0af06a45b729d9c5d6ba27b8f4a:0'
const expectedTokenId = '1'
const { assetUrn, tokenId } = getTokenIdAndAssetUrn(`${expectedUrn}:${expectedTokenId}`)

Expand Down
94 changes: 0 additions & 94 deletions test/content-url.spec.ts

This file was deleted.

Loading
Loading