UNPKG

@nftgo/gorarity

Version:

An algorithm to calculate rarity of NFT(how special it is), based on Jaccard Distance.

88 lines (87 loc) 3.4 kB
import { StringTrait } from './token-metadata'; import { normalizeAttributeString } from './utils/attribute-utils'; export class Collection { _name; _tokens; _traitsFrequencyCounts; constructor(tokens, name = '') { this._name = name; this._tokens = tokens; this._traitsFrequencyCounts = this.deriveNormalizedTraitsFrequencyCounts(); } get name() { return this._name; } get tokens() { return this._tokens; } get tokenTotalSupply() { return this._tokens.length; } get traitsFrequencyCounts() { return this._traitsFrequencyCounts; } tokenStandards() { const tokenStandards = new Set(); this._tokens.forEach((token) => { tokenStandards.add(token.tokenStandard); }); return Array.from(tokenStandards.values()); } /** * @description Return the number of tokens owning the trait. * @param trait */ totalTokensWithTrait(trait) { return this._traitsFrequencyCounts.get(trait.name)?.get(trait.value) || 0; } extractNullTraits() { const result = new Map(); Array.from(this._traitsFrequencyCounts.entries()).forEach(([traitName, traitValues]) => { let totalTraitCount = 0; Array.from(traitValues.values()).forEach((traitCount) => (totalTraitCount += traitCount)); const assetsWithoutTrait = this.tokenTotalSupply - totalTraitCount; if (assetsWithoutTrait > 0) { result.set(traitName, { trait: new StringTrait(traitName, 'Null'), totalTokens: assetsWithoutTrait }); } }); return result; } extractCollectionTraits() { const result = new Map(); Array.from(this._traitsFrequencyCounts.entries()).forEach(([traitName, traitValues]) => { Array.from(traitValues.entries()).forEach(([traitValue, traitCount]) => { const arr = result.get(traitName); if (arr) { arr.push({ trait: new StringTrait(traitName, traitValue), totalTokens: traitCount }); result.set(traitName, arr); } else { result.set(traitName, new Array({ trait: new StringTrait(traitName, traitValue), totalTokens: traitCount })); } }); }); return result; } /** * @description Count the number of occurrence of each trait. Use traitName and traitValue to uniquely identify a trait. */ deriveNormalizedTraitsFrequencyCounts() { const traitsFrequencyCounts = new Map(); for (const token of this._tokens) { Array.from(token.metadata.stringTraits.entries()).forEach(([traitName, strTrait]) => { const normalizedName = normalizeAttributeString(traitName); const map = traitsFrequencyCounts.get(normalizedName); if (map) { const currentCount = map.get(strTrait.value) || 0; map.set(strTrait.value, currentCount + 1); traitsFrequencyCounts.set(normalizedName, map); } else { traitsFrequencyCounts.set(normalizedName, new Map().set(strTrait.value, 1)); } }); } return traitsFrequencyCounts; } }