@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
JavaScript
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;
}
}