From 321c65f193283e43cf86c7aec9366da627a53b4b Mon Sep 17 00:00:00 2001 From: Alejo Thomas Ortega Date: Mon, 14 Aug 2023 20:58:50 -0300 Subject: [PATCH] feat: add utils functions to handle ERC-721 URNs --- etc/urn-resolver.api.md | 9 +++++++++ src/collection-items-utils.ts | 20 ++++++++++++++++++++ src/index.ts | 2 ++ src/resolvers.ts | 15 +++++++-------- src/types.ts | 6 ++++++ 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 src/collection-items-utils.ts diff --git a/etc/urn-resolver.api.md b/etc/urn-resolver.api.md index 95ed693..6afc4e7 100644 --- a/etc/urn-resolver.api.md +++ b/etc/urn-resolver.api.md @@ -110,6 +110,15 @@ export type EntityV3Asset = { baseUrl?: string; }; +// @public +export function getTokenIdAndAssetUrn(completeUrn: string): { + assetUrn: string; + tokenId: string; +}; + +// @public +export function isExtendedUrn(asset: DecentralandAssetIdentifier): boolean; + // @public (undocumented) export namespace LandUtils { // (undocumented) diff --git a/src/collection-items-utils.ts b/src/collection-items-utils.ts new file mode 100644 index 0000000..cbb8da7 --- /dev/null +++ b/src/collection-items-utils.ts @@ -0,0 +1,20 @@ +import { DecentralandAssetIdentifier } from './types' + +/** + * Checks if the URN follows the standard ERC-721 by having the tokenId identifier at the end + * @public + */ +export function isExtendedUrn(asset: DecentralandAssetIdentifier): boolean { + return ['blockchain-collection-v1-item', 'blockchain-collection-v2-item'].includes(asset.type) +} + +/** + * Takes an URN adhering to the ERC-721 standard and resolves both its asset URN and token identity + * WARNING: it assumes the URN received follows the ERC-721 standard and that its last part refers to the token id + * @public + */ +export function getTokenIdAndAssetUrn(completeUrn: string): { assetUrn: string; tokenId: string } { + const lastColonIndex = completeUrn.lastIndexOf(':') + const urnValue = completeUrn.slice(0, lastColonIndex) + return { assetUrn: urnValue, tokenId: completeUrn.slice(lastColonIndex + 1) } +} diff --git a/src/index.ts b/src/index.ts index 0f00426..d75998c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,8 @@ export * from './types' export { LandUtils } from './land-utils' import { resolveContentUrl, ResolversOptions } from './content-url-resolver' export { resolveContentUrl, ResolversOptions } +export { isExtendedUrn, getTokenIdAndAssetUrn } from './collection-items-utils' + /** * Function that parses an URN and returns a DecentralandAssetIdentifier record or null. * @public diff --git a/src/resolvers.ts b/src/resolvers.ts index 24fe0eb..f5db739 100644 --- a/src/resolvers.ts +++ b/src/resolvers.ts @@ -29,23 +29,22 @@ export const resolvers: RouteMap = { // collections v1 asset (by contract) 'decentraland:{network}:collections-v1:{contract(0x[a-fA-F0-9]+)}:{name}': resolveCollectionV1Asset, // collections v1 item (by asset name and token id) - 'decentraland:{network}:collections-v1:{contract(0x[a-fA-F0-9]+)}:{name}:{tokenId([0-9]+)}': - resolveCollectionV1AssetTokenId, + 'decentraland:{network}:collections-v1:{contract(0x[a-fA-F0-9]+)}:{name}:{tokenId([0-9]+)}': resolveCollectionV1Item, // collections v1 asset (by name) 'decentraland:{network}:collections-v1:{collectionName}:{name}': resolveCollectionV1AssetByCollectionName, // collections v1 item (by asset name and token id) 'decentraland:{network}:collections-v1:{collectionName}:{name}:{tokenId([0-9]+)}': - resolveCollectionV1AssetByCollectionNameTokenId, + resolveCollectionV1ItemByCollectionName, // collections v2 asset (hex) 'decentraland:{network}:collections-v2:{contract(0x[a-fA-F0-9]+)}:{id(0x[a-fA-F0-9]+)}': resolveCollectionV2Asset, // collections v2 item (by collection hex and token id) 'decentraland:{network}:collections-v2:{contract(0x[a-fA-F0-9]+)}:{id(0x[a-fA-F0-9]+)}:{tokenId([0-9]+)}': - resolveCollectionV2AssetTokenId, + resolveCollectionV2Item, // collections v2 asset (id) 'decentraland:{network}:collections-v2:{contract(0x[a-fA-F0-9]+)}:{id([0-9]+)}': resolveCollectionV2Asset, // collections v2 item (by collection asset and token id) 'decentraland:{network}:collections-v2:{contract(0x[a-fA-F0-9]+)}:{id([0-9]+)}:{tokenId([0-9]+)}': - resolveCollectionV2AssetTokenId, + resolveCollectionV2Item, // collections v1 (by contract) 'decentraland:{network}:collections-v1:{contract(0x[a-fA-F0-9]+)}': resolveCollectionV1, // collections v1 (by name) @@ -234,7 +233,7 @@ export async function resolveCollectionV1AssetByCollectionName( } } -export async function resolveCollectionV1AssetByCollectionNameTokenId( +export async function resolveCollectionV1ItemByCollectionName( uri: URL, groups: Record<'network' | 'collectionName' | 'name' | 'tokenId', string> ): Promise { @@ -283,7 +282,7 @@ export async function resolveCollectionV1Asset( return result } -export async function resolveCollectionV1AssetTokenId( +export async function resolveCollectionV1Item( uri: URL, groups: Record<'network' | 'contract' | 'name' | 'tokenId', string> ): Promise { @@ -335,7 +334,7 @@ export async function resolveCollectionV2Asset( return result } -export async function resolveCollectionV2AssetTokenId( +export async function resolveCollectionV2Item( uri: URL, groups: Record<'network' | 'contract' | 'id' | 'tokenId', string> ): Promise { diff --git a/src/types.ts b/src/types.ts index 51817f4..3716a65 100644 --- a/src/types.ts +++ b/src/types.ts @@ -70,6 +70,9 @@ export type BlockchainCollectionV1Asset = { */ export type BlockchainCollectionV1Item = Omit & { type: 'blockchain-collection-v1-item' + /** + * Asset identifier for ERC721 contracts + */ tokenId: string } @@ -113,6 +116,9 @@ export type BlockchainCollectionV2Asset = BaseBlockchainAsset & { */ export type BlockchainCollectionV2Item = Omit & { type: 'blockchain-collection-v2-item' + /** + * Asset identifier for ERC721 contracts + */ tokenId: string }