@unique-nft/api
Version:
Definitely typed JS API for the Unique Network blockchain
279 lines (221 loc) • 10.4 kB
text/typescript
import {Address} from '../utils'
import {ExtrinsicTransferCoinsOptions, ExtrinsicTransferCoinsParams} from "./extrinsics/common/ExtrinsicTransferCoins";
import {ExtrinsicOptions} from "./extrinsics/AbstractExtrinsic";
import {
ExtrinsicCreateCollection,
ExtrinsicCreateCollectionParams
} from "./extrinsics/unique/ExtrinsicCreateCollection";
import {SubstrateCommon} from "./SubstrateCommon";
import {
ExtrinsicAddCollectionAdmin,
ExtrinsicAddCollectionAdminParams
} from "./extrinsics/unique/ExtrinsicAddCollectionAdmin";
import {
ExtrinsicRemoveCollectionAdmin,
ExtrinsicRemoveCollectionAdminParams
} from "./extrinsics/unique/ExtrinsicRemoveCollectionAdmin"
import {
ExtrinsicSetCollectionSponsor,
ExtrinsicSetCollectionSponsorParams
} from './extrinsics/unique/ExtrinsicSetCollectionSponsor';
import {
ExtrinsicConfirmSponsorship,
ExtrinsicConfirmSponsorshipParams
} from './extrinsics/unique/ExtrinsicConfirmSponsorship'
import {
ExtrinsicChangeCollectionOwner,
ExtrinsicChangeCollectionOwnerParams
} from './extrinsics/unique/ExtrinsicChangeCollectionOwner'
import {
ExtrinsicRemoveCollectionSponsor,
ExtrinsicRemoveCollectionSponsorParams
} from './extrinsics/unique/ExtrinsicRemoveCollectionSponsor'
import {
ExtrinsicRemoveFromAllowList,
ExtrinsicRemoveFromAllowListParams
} from './extrinsics/unique/ExtrinsicRemoveFromAllowList'
import {ExtrinsicAddToAllowList, ExtrinsicAddToAllowListParams} from './extrinsics/unique/ExtrinsicAddToAllowList';
import {ExtrinsicCreateNftToken, ExtrinsicCreateNftTokenParams} from "./extrinsics/unique/ExtrinsicCreateNftToken";
import {
ExtrinsicCreateMultipleNftTokens,
ExtrinsicCreateMultipleNftTokensParams
} from "./extrinsics/unique/ExtrinsicCreateMultipleNftTokens";
import {StringUtils} from "../utils";
import {SchemaTools, UniqueCollectionSchemaDecoded, UniqueTokenDecoded} from "../schema";
import {
CollectionLimits,
CollectionPermissions,
CollectionSponsorship,
CollectionTokenPropertyPermissions
} from "./extrinsics/unique/types";
import {CrossAccountId, PropertiesArray,} from "../types";
import {ValidationError} from "../utils/errors";
import {Bytes} from "@polkadot/types";
import {DecodingResult} from "../schema/schemaUtils";
import {substrateNormalizedWithMirrorIfEthereum} from "../utils/address/crossAccountId";
type TokenOwner = { substrate: string, ethereum?: undefined } | { ethereum: string, substrate?: undefined }
export interface IGetCollectionOptions {
fetchAll?: boolean
fetchEffectiveLimits?: boolean
fetchAdmins?: boolean
fetchNextTokenId?: boolean
}
export interface IGetTokenOptions {
uniqueSchema?: UniqueCollectionSchemaDecoded | null
}
export type ParsedCollection = NonNullable<Awaited<ReturnType<SubstrateUnique['getCollection']>>>
export type ParsedToken = NonNullable<Awaited<ReturnType<SubstrateUnique['getToken']>>>
export interface ConnectToSubstrateOptions {
dontAwaitApiIsReady?: boolean
}
const parseBytesToString = (bytes: Bytes): string => {
return Array.from(bytes.toU8a()).map(el => String.fromCharCode(el)).join('')
}
const parseProperties = (rawProperties: PropertiesArray): PropertiesArray => {
return rawProperties.map(property => {
return {
key: StringUtils.hexStringToString(property.key),
value: StringUtils.hexStringToString(property.value)
}
})
}
const parseTokenPropertyPermissions = (tokenPropertyPermissions: any): CollectionTokenPropertyPermissions => {
if (!Array.isArray(tokenPropertyPermissions)) {
return []
}
return tokenPropertyPermissions.map(tpp => {
return {
key: StringUtils.hexStringToString(tpp.key),
permission: tpp.permission
}
})
}
export class SubstrateUnique extends SubstrateCommon {
//////////////////////////////////////////
// common methods
//////////////////////////////////////////
async getBalance(address: string): Promise<bigint> {
const substrateAddress = Address.to.substrateNormalizedOrMirrorIfEthereum(address)
return await super.getBalance(substrateAddress)
}
async getCollection(collectionId: number, options?: IGetCollectionOptions) {
const superRawCollection = await this.api.rpc.unique.collectionById(collectionId)
if (!superRawCollection) {
return null
}
const rawCollection = superRawCollection.toJSON() as any
const collection = {
id: collectionId,
collectionId,
owner: rawCollection.owner as string,
ownerNormalized: Address.normalize.substrateAddress(rawCollection.owner) as string,
mode: rawCollection.mode as string,
name: StringUtils.vec2str(rawCollection.name),
description: StringUtils.vec2str(rawCollection.description),
tokenPrefix: StringUtils.hexStringToString(rawCollection.tokenPrefix),
sponsorship: rawCollection.sponsorship as CollectionSponsorship,
limits: rawCollection.limits as CollectionLimits,
permissions: rawCollection.permissions as CollectionPermissions,
tokenPropertyPermissions: parseTokenPropertyPermissions(rawCollection.tokenPropertyPermissions),
properties: parseProperties(rawCollection.properties || []),
readOnly: rawCollection.readOnly as boolean,
effectiveLimits: null as CollectionLimits | null,
adminList: [] as Array<CrossAccountId>,
lastTokenId: null as number | null,
uniqueSchema: null as UniqueCollectionSchemaDecoded | null,
uniqueSchemaDecodingError: null as ValidationError | null,
get raw() {
return superRawCollection
},
get human() {
return superRawCollection.toHuman()
},
}
const uniqueSchema = await SchemaTools.decode.collectionSchema(collectionId, collection.properties)
collection.uniqueSchema = uniqueSchema.result
collection.uniqueSchemaDecodingError = uniqueSchema.error
if (options?.fetchAll || options?.fetchEffectiveLimits) {
collection.effectiveLimits = (await this.api.rpc.unique.effectiveCollectionLimits(collectionId)).toHuman() as CollectionLimits
}
if (options?.fetchAll || options?.fetchAdmins) {
collection.adminList = (await this.api.rpc.unique.adminlist(collectionId)).toHuman() as Array<CrossAccountId>
}
if (options?.fetchAll || options?.fetchNextTokenId) {
collection.lastTokenId = (await this.api.rpc.unique.lastTokenId(collectionId)).toNumber()
}
return collection
}
async getToken(collectionId: number, tokenId: number, options?: IGetTokenOptions) {
const superRawToken = await this.api.rpc.unique.tokenData(collectionId, tokenId)
if (!superRawToken || !superRawToken.owner) return null
const rawToken = superRawToken.toJSON() as { owner: TokenOwner, properties: PropertiesArray }
const owner: CrossAccountId = Address.extract.crossAccountIdFromObject(rawToken.owner)
const ownerNormalized: CrossAccountId = Address.extract.crossAccountIdFromObjectNormalized(rawToken.owner)
const uniqueToken: DecodingResult<UniqueTokenDecoded> = options?.uniqueSchema
? await SchemaTools.decode.token(collectionId, tokenId, superRawToken, options?.uniqueSchema)
: {result: null, error: new ValidationError('token parsing: no schema passed')}
const token = {
collectionId,
tokenId,
owner,
ownerNormalized,
properties: parseProperties(rawToken.properties),
uniqueToken: uniqueToken.result,
uniqueTokenDecodingError: uniqueToken.error,
get raw() {
return superRawToken
},
get human() {
return superRawToken.toHuman()
},
}
return token
}
//////////////////////////////////////////
// common extrinsics
//////////////////////////////////////////
//@overrides because it eats ethereum address too
transferCoins(params: ExtrinsicTransferCoinsParams, options?: ExtrinsicTransferCoinsOptions) {
const toAddress = Address.to.substrateNormalizedOrMirrorIfEthereum(params.toAddress)
return super.transferCoins({...params, toAddress}, options)
}
//////////////////////////////////////////
// collection extrinsics
//////////////////////////////////////////
createCollection(params: ExtrinsicCreateCollectionParams, options?: ExtrinsicOptions) {
return new ExtrinsicCreateCollection(this.api, params, options)
}
addCollectionAdmin(params: ExtrinsicAddCollectionAdminParams, options?: ExtrinsicOptions) {
return new ExtrinsicAddCollectionAdmin(this.api, params, options)
}
removeCollectionAdmin(params: ExtrinsicRemoveCollectionAdminParams, options?: ExtrinsicOptions) {
return new ExtrinsicRemoveCollectionAdmin(this.api, params, options)
}
setCollectionSponsor(params: ExtrinsicSetCollectionSponsorParams, options?: ExtrinsicOptions) {
return new ExtrinsicSetCollectionSponsor(this.api, params, options)
}
confirmSponsorship(params: ExtrinsicConfirmSponsorshipParams, options?: ExtrinsicOptions) {
return new ExtrinsicConfirmSponsorship(this.api, params, options)
}
changeCollectionOwner(params: ExtrinsicChangeCollectionOwnerParams, options?: ExtrinsicOptions) {
return new ExtrinsicChangeCollectionOwner(this.api, params, options)
}
removeCollectionSponsor(params: ExtrinsicRemoveCollectionSponsorParams, options?: ExtrinsicOptions) {
return new ExtrinsicRemoveCollectionSponsor(this.api, params, options)
}
addToAllowList(params: ExtrinsicAddToAllowListParams, options?: ExtrinsicOptions) {
return new ExtrinsicAddToAllowList(this.api, params, options)
}
removeFromAllowList(params: ExtrinsicRemoveFromAllowListParams, options?: ExtrinsicOptions) {
return new ExtrinsicRemoveFromAllowList(this.api, params, options)
}
//////////////////////////////////////////
// token extrinsics
//////////////////////////////////////////
createNftToken(params: ExtrinsicCreateNftTokenParams, options?: ExtrinsicOptions) {
return new ExtrinsicCreateNftToken(this.api, params, options)
}
createMultipleNftTokens(params: ExtrinsicCreateMultipleNftTokensParams, options?: ExtrinsicOptions) {
return new ExtrinsicCreateMultipleNftTokens(this.api, params, options)
}
}