2021-10-21 18:09:25 +02:00

144 lines
5.2 KiB
JavaScript

const name = require( 'random-name' )
const { db } = require( './firebase' )
const { getTotalSupply } = require( './contract' )
// ///////////////////////////////
// Attribute sources
// ///////////////////////////////
const globalAttributes = [
{ trait_type: "Age", display_type: "number", values: [
{ value: 35, probability: .5 },
{ value: 45, probability: .25 },
{ value: 25, probability: .25 }
] }
]
const heavenlyBodies = [ "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", "the Moon", "the Sun" ]
const web2domain = 'https://rocketeer.fans'
const lorem = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
// ///////////////////////////////
// Rocketeer helpers
// ///////////////////////////////
// Pick random item from array with equal probability
const pickRandomArrayEntry = array => array[ Math.floor( Math.random() * array.length ) ]
// Pick random attributes based on global attribute array
function pickRandomAttributes( attributes ) {
// Decimal accuracy, if probabilities have the lowest 0.01 then 100 is enough, for 0.001 1000 is needed
const probabilityDecimals = 3
// Remap the trait so it has a 'lottery ticket box' based on probs
const attributeLottery = attributes.map( ( { values, ...attribute } ) => ( {
// Attribute meta stays the same
...attribute,
// Values are reduced from objects with probabilities to an array with elements
values: values.reduce( ( acc, val ) => {
const { probability, value } = val
// Map probabilities to a flat array of items
const amountToAdd = 10 * probabilityDecimals * probability
for ( let i = 0; i < amountToAdd; i++ ) acc.push( value )
return acc
}, [] )
} ) )
// Pick a random element from the lottery box array items
return attributeLottery.map( ( { values, ...attribute } ) => ( {
// Attribute meta stays the same
...attribute,
// Select random entry from array
value: pickRandomArrayEntry( values )
} ) )
}
// ///////////////////////////////
// Caching
// ///////////////////////////////
async function isInvalidRocketeerId( id, network='mainnet' ) {
// Chech if this is an illegal ID
try {
// Get the last know total supply
const { cachedTotalSupply } = await db.collection( 'meta' ).doc( network ).get().then( doc => doc.data() ) || {}
// If the requested ID is larger than that, check if the new total supply is more
if( !cachedTotalSupply || cachedTotalSupply < id ) {
// Get net total supply through infura, if infura fails, return the cached value just in case
const totalSupply = await getTotalSupply( network )
// Write new value to cache
await db.collection( 'meta' ).doc( network ).set( { cachedTotalSupply: totalSupply }, { merge: true } )
// If the requested ID is larger than total supply, exit
if( totalSupply < id ) throw new Error( `Invalid ID ${ id }, total supply is ${ totalSupply }` )
// If all good, return true
return false
}
} catch( e ) {
return e
}
}
async function getExistingRocketeer( id, network='mainnet' ) {
return db.collection( `${ network }Rocketeers` ).doc( id ).get().then( doc => doc.data() ).catch( f => false )
}
// ///////////////////////////////
// Rocketeer generator
// ///////////////////////////////
async function generateRocketeer( id, network='mainnet' ) {
// The base object of a new Rocketeer
const rocketeer = {
name: `${ name.first() } ${ name.middle() } ${ name.last() } of ${ pickRandomArrayEntry( heavenlyBodies ) }`,
description: lorem,
image: ``,
external_url: `https://viewer.rocketeer.fans/?rocketeer=${ id }` + network == 'mainnet' ? '' : '&testnet=true',
attributes: []
}
// Generate randomized attributes
rocketeer.attributes = pickRandomAttributes( globalAttributes )
// TODO: Generate, compile and upload image
rocketeer.image = `${web2domain}/assets/draft-rocketeer.png`
// Save new Rocketeer
await db.collection( `${ network }Rocketeers` ).doc( id ).set( rocketeer )
return rocketeer
}
async function safelyReturnRocketeer( id, network ) {
// Chech if this is an illegal ID
const invalidId = await isInvalidRocketeerId( id, network )
if( invalidId ) throw invalidId
// Get old rocketeer if it exists
const oldRocketeer = await getExistingRocketeer( id, network )
if( oldRocketeer ) return oldRocketeer
// If no old rocketeer exists, make a new one and save it
return generateRocketeer( id, network )
}
module.exports = {
web2domain: web2domain,
safelyReturnRocketeer: safelyReturnRocketeer
}