@xyo-network/crypto-nft-collection-diviner-score-plugin 2.71.4 → 2.71.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/cjs/lib/rating/criteria/index.js +1 -1
  2. package/dist/cjs/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.js +3 -0
  3. package/dist/cjs/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.js.map +1 -1
  4. package/dist/cjs/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.js +53 -6
  5. package/dist/cjs/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.js.map +1 -1
  6. package/dist/cjs/lib/rating/criteria/scoring/total.js +19 -5
  7. package/dist/cjs/lib/rating/criteria/scoring/total.js.map +1 -1
  8. package/dist/docs.json +12 -12
  9. package/dist/esm/lib/rating/criteria/index.js +1 -1
  10. package/dist/esm/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.js +3 -0
  11. package/dist/esm/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.js.map +1 -1
  12. package/dist/esm/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.js +53 -6
  13. package/dist/esm/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.js.map +1 -1
  14. package/dist/esm/lib/rating/criteria/scoring/total.js +19 -5
  15. package/dist/esm/lib/rating/criteria/scoring/total.js.map +1 -1
  16. package/dist/types/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.d.ts.map +1 -1
  17. package/dist/types/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.d.ts +20 -0
  18. package/dist/types/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.d.ts.map +1 -1
  19. package/dist/types/lib/rating/criteria/scoring/total.d.ts +12 -0
  20. package/dist/types/lib/rating/criteria/scoring/total.d.ts.map +1 -1
  21. package/package.json +10 -10
  22. package/src/lib/rating/criteria/index.ts +1 -1
  23. package/src/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.ts +2 -0
  24. package/src/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.ts +57 -6
  25. package/src/lib/rating/criteria/scoring/total.ts +19 -6
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.scoringCriteria = void 0;
4
4
  const scoring_1 = require("./scoring");
5
- exports.scoringCriteria = Object.assign(Object.assign({}, scoring_1.scoreMetadata), { Total: { score: scoring_1.scoreTotal, weight: 1 } });
5
+ exports.scoringCriteria = Object.assign(Object.assign({}, scoring_1.scoreMetadata), { Total: { score: scoring_1.scoreTotal, weight: 2 } });
6
6
  //# sourceMappingURL=index.js.map
@@ -5,6 +5,9 @@ const crypto_nft_score_model_1 = require("@xyo-network/crypto-nft-score-model");
5
5
  const maxScore = 10;
6
6
  const scoreIndividualAttributes = (info) => {
7
7
  const { attributes } = info.metrics.metadata;
8
+ const entries = Object.entries(attributes);
9
+ if (entries.length === 0)
10
+ return [0, maxScore];
8
11
  const scores = Object.entries(attributes)
9
12
  .map(([_trait, { values }]) => {
10
13
  return Object.entries(values).map(([_traitValue, metrics]) => {
@@ -1 +1 @@
1
- {"version":3,"file":"scoreIndividualAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.ts"],"names":[],"mappings":";;;AACA,gFAAsE;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEZ,MAAM,yBAAyB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACtF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;QAC5B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAQ,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE;YAClE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAA;YAClF,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC;SACD,IAAI,EAAE,CAAA;IACT,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,IAAA,kCAAS,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA;AAZY,QAAA,yBAAyB,6BAYrC"}
1
+ {"version":3,"file":"scoreIndividualAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.ts"],"names":[],"mappings":";;;AACA,gFAAsE;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEZ,MAAM,yBAAyB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACtF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAC1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;QAC5B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAQ,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE;YAClE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAA;YAClF,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC;SACD,IAAI,EAAE,CAAA;IACT,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,IAAA,kCAAS,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA;AAdY,QAAA,yBAAyB,6BAcrC"}
@@ -3,14 +3,61 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.scoreTotalAttributes = void 0;
4
4
  const crypto_nft_score_model_1 = require("@xyo-network/crypto-nft-score-model");
5
5
  const maxScore = 10;
6
+ /**
7
+ * Mean: What value is the distribution centered around
8
+ */
9
+ const defaultMu = 0.15;
10
+ /**
11
+ * Standard Deviation: How spread out is the distribution
12
+ */
13
+ const defaultSigma = 0.1;
14
+ /**
15
+ * Calculates the Gaussian probability density
16
+ * @param x
17
+ * @param mu Mean
18
+ * @param sigma Standard Deviation
19
+ * @returns
20
+ */
21
+ const gaussianProbabilityDensity = (x, mu = defaultMu, sigma = defaultSigma) => {
22
+ const sqrtTwoPi = Math.sqrt(2 * Math.PI);
23
+ const denominator = sigma * sqrtTwoPi;
24
+ const power = -0.5 * Math.pow((x - mu) / sigma, 2);
25
+ return (1 / denominator) * Math.exp(power);
26
+ };
27
+ /**
28
+ * For a Gaussian distribution, the peak of the distribution is the mean
29
+ */
30
+ const maxProbabilityDensity = gaussianProbabilityDensity(defaultMu);
31
+ /**
32
+ * We're working on some assumptions here:
33
+ *
34
+ * - If you have a 100% chance of getting a trait, everyone get's a trophy
35
+ * - If you have a 50% chance of getting a trait, it's not rare
36
+ * - If you have a 0% chance of getting a trait, it's not fun
37
+ *
38
+ * So we're looking for something Pareto-ish (somewhere between
39
+ * 80/20 or 90/10) as that's a good & sustainable model for the
40
+ * distribution of many traits in real life.
41
+ * However, we also don't want to maximally reward collections
42
+ * that have a lot of single attributes distributed uniformly
43
+ * (basically a 0% trait probably) as that's perfectly entropic
44
+ * but not very interesting (some overlap is desirable).
45
+ * So we're using a Gaussian distribution to model the
46
+ * probability density of the joint probability of all traits
47
+ * centered around 15%.
48
+ * @param info
49
+ * @returns
50
+ */
6
51
  const scoreTotalAttributes = (info) => {
7
52
  const { attributes } = info.metrics.metadata;
8
- const scores = Object.entries(attributes).map(([_trait, { metrics }]) => {
9
- const rarity = Math.floor((1 - metrics.binomial.p) * 100);
10
- return [rarity, 100];
11
- });
12
- const total = scores.reduce(([a, b], [c, d]) => [a + c, b + d], [0, 0]);
13
- return (0, crypto_nft_score_model_1.normalize)(total, maxScore);
53
+ // This has somewhat of a filtering function by causing anything with 100% probability to
54
+ // add no value to the end score
55
+ const jointProbability = Object.entries(attributes).reduce((acc, [_trait, { metrics }]) => {
56
+ return acc * metrics.binomial.p;
57
+ }, 1);
58
+ const probabilityDensity = gaussianProbabilityDensity(jointProbability);
59
+ const score = [probabilityDensity, maxProbabilityDensity];
60
+ return (0, crypto_nft_score_model_1.normalize)(score, maxScore);
14
61
  };
15
62
  exports.scoreTotalAttributes = scoreTotalAttributes;
16
63
  //# sourceMappingURL=scoreTotalAttributes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scoreTotalAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.ts"],"names":[],"mappings":";;;AACA,gFAAsE;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEZ,MAAM,oBAAoB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACjF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;QAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QACzD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACtB,CAAC,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,IAAA,kCAAS,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA;AARY,QAAA,oBAAoB,wBAQhC"}
1
+ {"version":3,"file":"scoreTotalAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.ts"],"names":[],"mappings":";;;AACA,gFAAsE;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB;;GAEG;AACH,MAAM,SAAS,GAAG,IAAI,CAAA;AAEtB;;GAEG;AACH,MAAM,YAAY,GAAG,GAAG,CAAA;AAExB;;;;;;GAMG;AACH,MAAM,0BAA0B,GAAG,CAAC,CAAS,EAAE,KAAa,SAAS,EAAE,QAAgB,YAAY,EAAU,EAAE;IAC7G,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;IACxC,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,CAAA;IACrC,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;IAClD,OAAO,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAC5C,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,qBAAqB,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAA;AAEnE;;;;;;;;;;;;;;;;;;;GAmBG;AACI,MAAM,oBAAoB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACjF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,yFAAyF;IACzF,gCAAgC;IAChC,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;QACxF,OAAO,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjC,CAAC,EAAE,CAAC,CAAC,CAAA;IACL,MAAM,kBAAkB,GAAG,0BAA0B,CAAC,gBAAgB,CAAC,CAAA;IACvE,MAAM,KAAK,GAAU,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAA;IAChE,OAAO,IAAA,kCAAS,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA;AAVY,QAAA,oBAAoB,wBAUhC"}
@@ -2,12 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.scoreTotal = void 0;
4
4
  const crypto_nft_score_model_1 = require("@xyo-network/crypto-nft-score-model");
5
- const median = 100000;
5
+ /**
6
+ * This "magic" value was obtained using Solver in Excel
7
+ * to find the median, with mu/sigma fixed, which maximizes
8
+ * the distribution (the mode for lognormal) at 10,000
9
+ */
10
+ const median = 81030839.8217352;
6
11
  const defaultMu = Math.log(median);
7
- const defaultSigma = 2;
8
- // const mean = Math.exp(defaultMu + Math.pow(defaultSigma, 2) / 2)
12
+ const defaultSigma = 3;
9
13
  const mode = Math.exp(defaultMu - Math.pow(defaultSigma, 2));
10
- // console.log(`mean: ${mean} median: ${median} mode: ${mode}`)
11
14
  /**
12
15
  * Calculates the log-normal probability density
13
16
  * @param x the value at which you want to calculate the probability density
@@ -25,8 +28,19 @@ const logNormalProbabilityDensity = (x, mu = defaultMu, sigma = defaultSigma) =>
25
28
  * For a lognormal distribution, the peak of the distribution is the mode
26
29
  */
27
30
  const maxProbabilityDensity = logNormalProbabilityDensity(mode);
28
- // console.log(`mode: ${mode} maxDensity: ${maxProbabilityDensity}`)
29
31
  const maxScore = 10;
32
+ /**
33
+ * We're working on some assumptions here:
34
+ * - If there's < 1000 NFTs in your collection it starts becoming too niche
35
+ * - If there's > 20,000 NFTs in your collection it starts becoming too broad
36
+ * So there's a sweet spot somewhere between 2000 and 10,000
37
+ * where a collection has enough NFTs to be interesting, but
38
+ * not so many that it's teetering on a diluted money grab.
39
+ * To model that we're using a log-normal distribution optimized
40
+ * to maximally reward collections in the aforementioned range
41
+ * @param nft
42
+ * @returns
43
+ */
30
44
  const scoreTotal = (nft) => {
31
45
  const density = logNormalProbabilityDensity(nft.total);
32
46
  const score = [density, maxProbabilityDensity];
@@ -1 +1 @@
1
- {"version":3,"file":"total.js","sourceRoot":"","sources":["../../../../../../src/lib/rating/criteria/scoring/total.ts"],"names":[],"mappings":";;;AACA,gFAAsE;AAEtE,MAAM,MAAM,GAAG,MAAM,CAAA;AACrB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;AAClC,MAAM,YAAY,GAAG,CAAC,CAAA;AACtB,mEAAmE;AACnE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAA;AAC5D,+DAA+D;AAE/D;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAG,CAAC,CAAS,EAAE,KAAa,SAAS,EAAE,QAAgB,YAAY,EAAU,EAAE;IAC9G,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACxB,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;AACvG,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,qBAAqB,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAA;AAC/D,oEAAoE;AAEpE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEZ,MAAM,UAAU,GAAG,CAAC,GAAuB,EAAS,EAAE;IAC3D,MAAM,OAAO,GAAG,2BAA2B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACtD,MAAM,KAAK,GAAU,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAA;IACrD,OAAO,IAAA,kCAAS,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA;AAJY,QAAA,UAAU,cAItB"}
1
+ {"version":3,"file":"total.js","sourceRoot":"","sources":["../../../../../../src/lib/rating/criteria/scoring/total.ts"],"names":[],"mappings":";;;AACA,gFAAsE;AAEtE;;;;GAIG;AACH,MAAM,MAAM,GAAG,gBAAgB,CAAA;AAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;AAClC,MAAM,YAAY,GAAG,CAAC,CAAA;AACtB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAA;AAC5D;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAG,CAAC,CAAS,EAAE,KAAa,SAAS,EAAE,QAAgB,YAAY,EAAU,EAAE;IAC9G,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACxB,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;AACvG,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,qBAAqB,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAA;AAE/D,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB;;;;;;;;;;;GAWG;AACI,MAAM,UAAU,GAAG,CAAC,GAAuB,EAAS,EAAE;IAC3D,MAAM,OAAO,GAAG,2BAA2B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACtD,MAAM,KAAK,GAAU,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAA;IACrD,OAAO,IAAA,kCAAS,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA;AAJY,QAAA,UAAU,cAItB"}
package/dist/docs.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/index.ts",
17
17
  "line": 9,
18
18
  "character": 0,
19
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/index.ts#L9"
19
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/index.ts#L9"
20
20
  }
21
21
  ],
22
22
  "target": 1
@@ -3966,7 +3966,7 @@
3966
3966
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts",
3967
3967
  "line": 29,
3968
3968
  "character": 18,
3969
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L29"
3969
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L29"
3970
3970
  }
3971
3971
  ],
3972
3972
  "type": {
@@ -7567,7 +7567,7 @@
7567
7567
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts",
7568
7568
  "line": 31,
7569
7569
  "character": 21,
7570
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L31"
7570
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L31"
7571
7571
  }
7572
7572
  ],
7573
7573
  "signatures": [
@@ -7582,7 +7582,7 @@
7582
7582
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts",
7583
7583
  "line": 31,
7584
7584
  "character": 37,
7585
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L31"
7585
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L31"
7586
7586
  }
7587
7587
  ],
7588
7588
  "parameters": [
@@ -16213,7 +16213,7 @@
16213
16213
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts",
16214
16214
  "line": 26,
16215
16215
  "character": 13,
16216
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L26"
16216
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L26"
16217
16217
  }
16218
16218
  ],
16219
16219
  "typeParameters": [
@@ -16268,7 +16268,7 @@
16268
16268
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts",
16269
16269
  "line": 8,
16270
16270
  "character": 12,
16271
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L8"
16271
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L8"
16272
16272
  }
16273
16273
  ],
16274
16274
  "type": {
@@ -16302,7 +16302,7 @@
16302
16302
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts",
16303
16303
  "line": 18,
16304
16304
  "character": 12,
16305
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L18"
16305
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Diviner.ts#L18"
16306
16306
  }
16307
16307
  ],
16308
16308
  "type": {
@@ -16348,7 +16348,7 @@
16348
16348
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts",
16349
16349
  "line": 6,
16350
16350
  "character": 12,
16351
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L6"
16351
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L6"
16352
16352
  }
16353
16353
  ],
16354
16354
  "type": {
@@ -16393,7 +16393,7 @@
16393
16393
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Plugin.ts",
16394
16394
  "line": 7,
16395
16395
  "character": 13,
16396
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Plugin.ts#L7"
16396
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Plugin.ts#L7"
16397
16397
  }
16398
16398
  ],
16399
16399
  "signatures": [
@@ -16408,7 +16408,7 @@
16408
16408
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Plugin.ts",
16409
16409
  "line": 7,
16410
16410
  "character": 47,
16411
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Plugin.ts#L7"
16411
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/Plugin.ts#L7"
16412
16412
  }
16413
16413
  ],
16414
16414
  "type": {
@@ -17983,7 +17983,7 @@
17983
17983
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts",
17984
17984
  "line": 12,
17985
17985
  "character": 13,
17986
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L12"
17986
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L12"
17987
17987
  }
17988
17988
  ],
17989
17989
  "signatures": [
@@ -17998,7 +17998,7 @@
17998
17998
  "fileName": "plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts",
17999
17999
  "line": 12,
18000
18000
  "character": 36,
18001
- "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/a0f34ef7cfcd4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L12"
18001
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/blob/746cc37b4/packages/plugins/packages/payloadset/packages/crypto/packages/nft/packages/collection/diviner/src/lib/rating/analyzeNftCollection.ts#L12"
18002
18002
  }
18003
18003
  ],
18004
18004
  "parameters": [
@@ -1,6 +1,6 @@
1
1
  import { scoreMetadata, scoreTotal } from './scoring';
2
2
  export const scoringCriteria = {
3
3
  ...scoreMetadata,
4
- Total: { score: scoreTotal, weight: 1 },
4
+ Total: { score: scoreTotal, weight: 2 },
5
5
  };
6
6
  //# sourceMappingURL=index.js.map
@@ -2,6 +2,9 @@ import { normalize } from '@xyo-network/crypto-nft-score-model';
2
2
  const maxScore = 10;
3
3
  export const scoreIndividualAttributes = (info) => {
4
4
  const { attributes } = info.metrics.metadata;
5
+ const entries = Object.entries(attributes);
6
+ if (entries.length === 0)
7
+ return [0, maxScore];
5
8
  const scores = Object.entries(attributes)
6
9
  .map(([_trait, { values }]) => {
7
10
  return Object.entries(values).map(([_traitValue, metrics]) => {
@@ -1 +1 @@
1
- {"version":3,"file":"scoreIndividualAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAS,MAAM,qCAAqC,CAAA;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACtF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;QAC5B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAQ,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE;YAClE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAA;YAClF,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC;SACD,IAAI,EAAE,CAAA;IACT,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA"}
1
+ {"version":3,"file":"scoreIndividualAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAS,MAAM,qCAAqC,CAAA;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACtF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAC1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;QAC5B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAQ,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE;YAClE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAA;YAClF,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC;SACD,IAAI,EAAE,CAAA;IACT,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA"}
@@ -1,12 +1,59 @@
1
1
  import { normalize } from '@xyo-network/crypto-nft-score-model';
2
2
  const maxScore = 10;
3
+ /**
4
+ * Mean: What value is the distribution centered around
5
+ */
6
+ const defaultMu = 0.15;
7
+ /**
8
+ * Standard Deviation: How spread out is the distribution
9
+ */
10
+ const defaultSigma = 0.1;
11
+ /**
12
+ * Calculates the Gaussian probability density
13
+ * @param x
14
+ * @param mu Mean
15
+ * @param sigma Standard Deviation
16
+ * @returns
17
+ */
18
+ const gaussianProbabilityDensity = (x, mu = defaultMu, sigma = defaultSigma) => {
19
+ const sqrtTwoPi = Math.sqrt(2 * Math.PI);
20
+ const denominator = sigma * sqrtTwoPi;
21
+ const power = -0.5 * Math.pow((x - mu) / sigma, 2);
22
+ return (1 / denominator) * Math.exp(power);
23
+ };
24
+ /**
25
+ * For a Gaussian distribution, the peak of the distribution is the mean
26
+ */
27
+ const maxProbabilityDensity = gaussianProbabilityDensity(defaultMu);
28
+ /**
29
+ * We're working on some assumptions here:
30
+ *
31
+ * - If you have a 100% chance of getting a trait, everyone get's a trophy
32
+ * - If you have a 50% chance of getting a trait, it's not rare
33
+ * - If you have a 0% chance of getting a trait, it's not fun
34
+ *
35
+ * So we're looking for something Pareto-ish (somewhere between
36
+ * 80/20 or 90/10) as that's a good & sustainable model for the
37
+ * distribution of many traits in real life.
38
+ * However, we also don't want to maximally reward collections
39
+ * that have a lot of single attributes distributed uniformly
40
+ * (basically a 0% trait probably) as that's perfectly entropic
41
+ * but not very interesting (some overlap is desirable).
42
+ * So we're using a Gaussian distribution to model the
43
+ * probability density of the joint probability of all traits
44
+ * centered around 15%.
45
+ * @param info
46
+ * @returns
47
+ */
3
48
  export const scoreTotalAttributes = (info) => {
4
49
  const { attributes } = info.metrics.metadata;
5
- const scores = Object.entries(attributes).map(([_trait, { metrics }]) => {
6
- const rarity = Math.floor((1 - metrics.binomial.p) * 100);
7
- return [rarity, 100];
8
- });
9
- const total = scores.reduce(([a, b], [c, d]) => [a + c, b + d], [0, 0]);
10
- return normalize(total, maxScore);
50
+ // This has somewhat of a filtering function by causing anything with 100% probability to
51
+ // add no value to the end score
52
+ const jointProbability = Object.entries(attributes).reduce((acc, [_trait, { metrics }]) => {
53
+ return acc * metrics.binomial.p;
54
+ }, 1);
55
+ const probabilityDensity = gaussianProbabilityDensity(jointProbability);
56
+ const score = [probabilityDensity, maxProbabilityDensity];
57
+ return normalize(score, maxScore);
11
58
  };
12
59
  //# sourceMappingURL=scoreTotalAttributes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scoreTotalAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAS,MAAM,qCAAqC,CAAA;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACjF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;QAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QACzD,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACtB,CAAC,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA"}
1
+ {"version":3,"file":"scoreTotalAttributes.js","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAS,MAAM,qCAAqC,CAAA;AAEtE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB;;GAEG;AACH,MAAM,SAAS,GAAG,IAAI,CAAA;AAEtB;;GAEG;AACH,MAAM,YAAY,GAAG,GAAG,CAAA;AAExB;;;;;;GAMG;AACH,MAAM,0BAA0B,GAAG,CAAC,CAAS,EAAE,KAAa,SAAS,EAAE,QAAgB,YAAY,EAAU,EAAE;IAC7G,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;IACxC,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,CAAA;IACrC,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;IAClD,OAAO,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;AAC5C,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,qBAAqB,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAA;AAEnE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,IAAmC,EAAS,EAAE;IACjF,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;IAC5C,yFAAyF;IACzF,gCAAgC;IAChC,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;QACxF,OAAO,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IACjC,CAAC,EAAE,CAAC,CAAC,CAAA;IACL,MAAM,kBAAkB,GAAG,0BAA0B,CAAC,gBAAgB,CAAC,CAAA;IACvE,MAAM,KAAK,GAAU,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAA;IAChE,OAAO,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA"}
@@ -1,10 +1,13 @@
1
1
  import { normalize } from '@xyo-network/crypto-nft-score-model';
2
- const median = 100000;
2
+ /**
3
+ * This "magic" value was obtained using Solver in Excel
4
+ * to find the median, with mu/sigma fixed, which maximizes
5
+ * the distribution (the mode for lognormal) at 10,000
6
+ */
7
+ const median = 81030839.8217352;
3
8
  const defaultMu = Math.log(median);
4
- const defaultSigma = 2;
5
- // const mean = Math.exp(defaultMu + Math.pow(defaultSigma, 2) / 2)
9
+ const defaultSigma = 3;
6
10
  const mode = Math.exp(defaultMu - Math.pow(defaultSigma, 2));
7
- // console.log(`mean: ${mean} median: ${median} mode: ${mode}`)
8
11
  /**
9
12
  * Calculates the log-normal probability density
10
13
  * @param x the value at which you want to calculate the probability density
@@ -22,8 +25,19 @@ const logNormalProbabilityDensity = (x, mu = defaultMu, sigma = defaultSigma) =>
22
25
  * For a lognormal distribution, the peak of the distribution is the mode
23
26
  */
24
27
  const maxProbabilityDensity = logNormalProbabilityDensity(mode);
25
- // console.log(`mode: ${mode} maxDensity: ${maxProbabilityDensity}`)
26
28
  const maxScore = 10;
29
+ /**
30
+ * We're working on some assumptions here:
31
+ * - If there's < 1000 NFTs in your collection it starts becoming too niche
32
+ * - If there's > 20,000 NFTs in your collection it starts becoming too broad
33
+ * So there's a sweet spot somewhere between 2000 and 10,000
34
+ * where a collection has enough NFTs to be interesting, but
35
+ * not so many that it's teetering on a diluted money grab.
36
+ * To model that we're using a log-normal distribution optimized
37
+ * to maximally reward collections in the aforementioned range
38
+ * @param nft
39
+ * @returns
40
+ */
27
41
  export const scoreTotal = (nft) => {
28
42
  const density = logNormalProbabilityDensity(nft.total);
29
43
  const score = [density, maxProbabilityDensity];
@@ -1 +1 @@
1
- {"version":3,"file":"total.js","sourceRoot":"","sources":["../../../../../../src/lib/rating/criteria/scoring/total.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAS,MAAM,qCAAqC,CAAA;AAEtE,MAAM,MAAM,GAAG,MAAM,CAAA;AACrB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;AAClC,MAAM,YAAY,GAAG,CAAC,CAAA;AACtB,mEAAmE;AACnE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAA;AAC5D,+DAA+D;AAE/D;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAG,CAAC,CAAS,EAAE,KAAa,SAAS,EAAE,QAAgB,YAAY,EAAU,EAAE;IAC9G,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACxB,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;AACvG,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,qBAAqB,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAA;AAC/D,oEAAoE;AAEpE,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAuB,EAAS,EAAE;IAC3D,MAAM,OAAO,GAAG,2BAA2B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACtD,MAAM,KAAK,GAAU,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAA;IACrD,OAAO,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA"}
1
+ {"version":3,"file":"total.js","sourceRoot":"","sources":["../../../../../../src/lib/rating/criteria/scoring/total.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAS,MAAM,qCAAqC,CAAA;AAEtE;;;;GAIG;AACH,MAAM,MAAM,GAAG,gBAAgB,CAAA;AAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;AAClC,MAAM,YAAY,GAAG,CAAC,CAAA;AACtB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAA;AAC5D;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAG,CAAC,CAAS,EAAE,KAAa,SAAS,EAAE,QAAgB,YAAY,EAAU,EAAE;IAC9G,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACxB,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;AACvG,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,qBAAqB,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAA;AAE/D,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAuB,EAAS,EAAE;IAC3D,MAAM,OAAO,GAAG,2BAA2B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACtD,MAAM,KAAK,GAAU,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAA;IACrD,OAAO,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACnC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"scoreIndividualAttributes.d.ts","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAA;AACjG,OAAO,EAAa,KAAK,EAAE,MAAM,qCAAqC,CAAA;AAItE,eAAO,MAAM,yBAAyB,SAAU,6BAA6B,KAAG,KAY/E,CAAA"}
1
+ {"version":3,"file":"scoreIndividualAttributes.d.ts","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreIndividualAttributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAA;AACjG,OAAO,EAAa,KAAK,EAAE,MAAM,qCAAqC,CAAA;AAItE,eAAO,MAAM,yBAAyB,SAAU,6BAA6B,KAAG,KAc/E,CAAA"}
@@ -1,4 +1,24 @@
1
1
  import { NftCollectionAttributeMetrics } from '@xyo-network/crypto-nft-collection-payload-plugin';
2
2
  import { Score } from '@xyo-network/crypto-nft-score-model';
3
+ /**
4
+ * We're working on some assumptions here:
5
+ *
6
+ * - If you have a 100% chance of getting a trait, everyone get's a trophy
7
+ * - If you have a 50% chance of getting a trait, it's not rare
8
+ * - If you have a 0% chance of getting a trait, it's not fun
9
+ *
10
+ * So we're looking for something Pareto-ish (somewhere between
11
+ * 80/20 or 90/10) as that's a good & sustainable model for the
12
+ * distribution of many traits in real life.
13
+ * However, we also don't want to maximally reward collections
14
+ * that have a lot of single attributes distributed uniformly
15
+ * (basically a 0% trait probably) as that's perfectly entropic
16
+ * but not very interesting (some overlap is desirable).
17
+ * So we're using a Gaussian distribution to model the
18
+ * probability density of the joint probability of all traits
19
+ * centered around 15%.
20
+ * @param info
21
+ * @returns
22
+ */
3
23
  export declare const scoreTotalAttributes: (info: NftCollectionAttributeMetrics) => Score;
4
24
  //# sourceMappingURL=scoreTotalAttributes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scoreTotalAttributes.d.ts","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAA;AACjG,OAAO,EAAa,KAAK,EAAE,MAAM,qCAAqC,CAAA;AAItE,eAAO,MAAM,oBAAoB,SAAU,6BAA6B,KAAG,KAQ1E,CAAA"}
1
+ {"version":3,"file":"scoreTotalAttributes.d.ts","sourceRoot":"","sources":["../../../../../../../src/lib/rating/criteria/scoring/metadata/scoreTotalAttributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAA;AACjG,OAAO,EAAa,KAAK,EAAE,MAAM,qCAAqC,CAAA;AAiCtE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,SAAU,6BAA6B,KAAG,KAU1E,CAAA"}
@@ -1,4 +1,16 @@
1
1
  import { NftCollectionCount } from '@xyo-network/crypto-nft-collection-payload-plugin';
2
2
  import { Score } from '@xyo-network/crypto-nft-score-model';
3
+ /**
4
+ * We're working on some assumptions here:
5
+ * - If there's < 1000 NFTs in your collection it starts becoming too niche
6
+ * - If there's > 20,000 NFTs in your collection it starts becoming too broad
7
+ * So there's a sweet spot somewhere between 2000 and 10,000
8
+ * where a collection has enough NFTs to be interesting, but
9
+ * not so many that it's teetering on a diluted money grab.
10
+ * To model that we're using a log-normal distribution optimized
11
+ * to maximally reward collections in the aforementioned range
12
+ * @param nft
13
+ * @returns
14
+ */
3
15
  export declare const scoreTotal: (nft: NftCollectionCount) => Score;
4
16
  //# sourceMappingURL=total.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"total.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/rating/criteria/scoring/total.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAA;AACtF,OAAO,EAAa,KAAK,EAAE,MAAM,qCAAqC,CAAA;AA8BtE,eAAO,MAAM,UAAU,QAAS,kBAAkB,KAAG,KAIpD,CAAA"}
1
+ {"version":3,"file":"total.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/rating/criteria/scoring/total.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAA;AACtF,OAAO,EAAa,KAAK,EAAE,MAAM,qCAAqC,CAAA;AA+BtE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,QAAS,kBAAkB,KAAG,KAIpD,CAAA"}
package/package.json CHANGED
@@ -10,15 +10,15 @@
10
10
  "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/issues"
11
11
  },
12
12
  "dependencies": {
13
- "@xyo-network/abstract-diviner": "~2.71.4",
14
- "@xyo-network/core": "~2.71.4",
15
- "@xyo-network/crypto-nft-collection-payload-plugin": "~2.71.4",
16
- "@xyo-network/crypto-nft-payload-plugin": "~2.71.4",
17
- "@xyo-network/crypto-nft-score-model": "~2.71.4",
18
- "@xyo-network/diviner-model": "~2.71.4",
19
- "@xyo-network/module": "~2.71.4",
20
- "@xyo-network/payload-model": "~2.71.4",
21
- "@xyo-network/payloadset-plugin": "~2.71.4"
13
+ "@xyo-network/abstract-diviner": "~2.71.5",
14
+ "@xyo-network/core": "~2.71.5",
15
+ "@xyo-network/crypto-nft-collection-payload-plugin": "~2.71.5",
16
+ "@xyo-network/crypto-nft-payload-plugin": "~2.71.5",
17
+ "@xyo-network/crypto-nft-score-model": "~2.71.5",
18
+ "@xyo-network/diviner-model": "~2.71.5",
19
+ "@xyo-network/module": "~2.71.5",
20
+ "@xyo-network/payload-model": "~2.71.5",
21
+ "@xyo-network/payloadset-plugin": "~2.71.5"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@xylabs/jest-helpers": "^2.9.3",
@@ -61,5 +61,5 @@
61
61
  },
62
62
  "sideEffects": false,
63
63
  "types": "dist/types/index.d.ts",
64
- "version": "2.71.4"
64
+ "version": "2.71.5"
65
65
  }
@@ -5,5 +5,5 @@ import { scoreMetadata, scoreTotal } from './scoring'
5
5
 
6
6
  export const scoringCriteria: { [key: string]: WeightedScoringCriteria<NftCollectionInfo> } = {
7
7
  ...scoreMetadata,
8
- Total: { score: scoreTotal, weight: 1 },
8
+ Total: { score: scoreTotal, weight: 2 },
9
9
  }
@@ -5,6 +5,8 @@ const maxScore = 10
5
5
 
6
6
  export const scoreIndividualAttributes = (info: NftCollectionAttributeMetrics): Score => {
7
7
  const { attributes } = info.metrics.metadata
8
+ const entries = Object.entries(attributes)
9
+ if (entries.length === 0) return [0, maxScore]
8
10
  const scores = Object.entries(attributes)
9
11
  .map(([_trait, { values }]) => {
10
12
  return Object.entries(values).map<Score>(([_traitValue, metrics]) => {
@@ -3,12 +3,63 @@ import { normalize, Score } from '@xyo-network/crypto-nft-score-model'
3
3
 
4
4
  const maxScore = 10
5
5
 
6
+ /**
7
+ * Mean: What value is the distribution centered around
8
+ */
9
+ const defaultMu = 0.15
10
+
11
+ /**
12
+ * Standard Deviation: How spread out is the distribution
13
+ */
14
+ const defaultSigma = 0.1
15
+
16
+ /**
17
+ * Calculates the Gaussian probability density
18
+ * @param x
19
+ * @param mu Mean
20
+ * @param sigma Standard Deviation
21
+ * @returns
22
+ */
23
+ const gaussianProbabilityDensity = (x: number, mu: number = defaultMu, sigma: number = defaultSigma): number => {
24
+ const sqrtTwoPi = Math.sqrt(2 * Math.PI)
25
+ const denominator = sigma * sqrtTwoPi
26
+ const power = -0.5 * Math.pow((x - mu) / sigma, 2)
27
+ return (1 / denominator) * Math.exp(power)
28
+ }
29
+
30
+ /**
31
+ * For a Gaussian distribution, the peak of the distribution is the mean
32
+ */
33
+ const maxProbabilityDensity = gaussianProbabilityDensity(defaultMu)
34
+
35
+ /**
36
+ * We're working on some assumptions here:
37
+ *
38
+ * - If you have a 100% chance of getting a trait, everyone get's a trophy
39
+ * - If you have a 50% chance of getting a trait, it's not rare
40
+ * - If you have a 0% chance of getting a trait, it's not fun
41
+ *
42
+ * So we're looking for something Pareto-ish (somewhere between
43
+ * 80/20 or 90/10) as that's a good & sustainable model for the
44
+ * distribution of many traits in real life.
45
+ * However, we also don't want to maximally reward collections
46
+ * that have a lot of single attributes distributed uniformly
47
+ * (basically a 0% trait probably) as that's perfectly entropic
48
+ * but not very interesting (some overlap is desirable).
49
+ * So we're using a Gaussian distribution to model the
50
+ * probability density of the joint probability of all traits
51
+ * centered around 15%.
52
+ * @param info
53
+ * @returns
54
+ */
6
55
  export const scoreTotalAttributes = (info: NftCollectionAttributeMetrics): Score => {
7
56
  const { attributes } = info.metrics.metadata
8
- const scores = Object.entries(attributes).map<Score>(([_trait, { metrics }]) => {
9
- const rarity = Math.floor((1 - metrics.binomial.p) * 100)
10
- return [rarity, 100]
11
- })
12
- const total = scores.reduce<Score>(([a, b], [c, d]) => [a + c, b + d], [0, 0])
13
- return normalize(total, maxScore)
57
+ // This has somewhat of a filtering function by causing anything with 100% probability to
58
+ // add no value to the end score
59
+ const jointProbability = Object.entries(attributes).reduce((acc, [_trait, { metrics }]) => {
60
+ return acc * metrics.binomial.p
61
+ }, 1)
62
+ const probabilityDensity = gaussianProbabilityDensity(jointProbability)
63
+ const score: Score = [probabilityDensity, maxProbabilityDensity]
64
+ return normalize(score, maxScore)
14
65
  }
@@ -1,13 +1,15 @@
1
1
  import { NftCollectionCount } from '@xyo-network/crypto-nft-collection-payload-plugin'
2
2
  import { normalize, Score } from '@xyo-network/crypto-nft-score-model'
3
3
 
4
- const median = 100000
4
+ /**
5
+ * This "magic" value was obtained using Solver in Excel
6
+ * to find the median, with mu/sigma fixed, which maximizes
7
+ * the distribution (the mode for lognormal) at 10,000
8
+ */
9
+ const median = 81030839.8217352
5
10
  const defaultMu = Math.log(median)
6
- const defaultSigma = 2
7
- // const mean = Math.exp(defaultMu + Math.pow(defaultSigma, 2) / 2)
11
+ const defaultSigma = 3
8
12
  const mode = Math.exp(defaultMu - Math.pow(defaultSigma, 2))
9
- // console.log(`mean: ${mean} median: ${median} mode: ${mode}`)
10
-
11
13
  /**
12
14
  * Calculates the log-normal probability density
13
15
  * @param x the value at which you want to calculate the probability density
@@ -25,10 +27,21 @@ const logNormalProbabilityDensity = (x: number, mu: number = defaultMu, sigma: n
25
27
  * For a lognormal distribution, the peak of the distribution is the mode
26
28
  */
27
29
  const maxProbabilityDensity = logNormalProbabilityDensity(mode)
28
- // console.log(`mode: ${mode} maxDensity: ${maxProbabilityDensity}`)
29
30
 
30
31
  const maxScore = 10
31
32
 
33
+ /**
34
+ * We're working on some assumptions here:
35
+ * - If there's < 1000 NFTs in your collection it starts becoming too niche
36
+ * - If there's > 20,000 NFTs in your collection it starts becoming too broad
37
+ * So there's a sweet spot somewhere between 2000 and 10,000
38
+ * where a collection has enough NFTs to be interesting, but
39
+ * not so many that it's teetering on a diluted money grab.
40
+ * To model that we're using a log-normal distribution optimized
41
+ * to maximally reward collections in the aforementioned range
42
+ * @param nft
43
+ * @returns
44
+ */
32
45
  export const scoreTotal = (nft: NftCollectionCount): Score => {
33
46
  const density = logNormalProbabilityDensity(nft.total)
34
47
  const score: Score = [density, maxProbabilityDensity]