UNPKG

@ixily/activ

Version:

Alpha Capture Trade Idea Verification. Blockchain ownership proven trade ideas and strategies.

350 lines (330 loc) 8.93 kB
import { BigNumber } from 'ethers' import { CacheStorageModule, IComputationalCostRecord, IContract, IOperationalCost, PreCacheModule, isNullOrUndefined, LogModule as log, } from '../..' const COMPUTATIONAL_COST_TABLE_NAME = 'coputational_cost_table' const EXPIRATION_FOR_COMPUTATIONAL_COST = 3600 * 24 * 10 // 10 days const COMPUTATIONAL_COST_TABLE_NAME_EXPIRATION = 30 * 1000 // 30s const GAS_PRICE_EXPIRATION = 10 * 1000 // 10s const getEstimatedComputationalRawCost = async ( contract: IContract, ideaCreation: boolean, inBehalfOf: boolean, ): Promise<{ estimatedComputationalRawCost: number costRecords: IComputationalCostRecord }> => { const contractAddress = contract.gate!.address const key = COMPUTATIONAL_COST_TABLE_NAME + '_' + contractAddress + '_' + ideaCreation + '_' + inBehalfOf /* This is for dev for determining values */ // await CacheStorageModule.updateData( // key, // JSON.stringify({ // costs: [500000000], // }), // EXPIRATION_FOR_COMPUTATIONAL_COST, // ) // console.log('key GET') // console.log(key) const slots = PreCacheModule.getExpiringSlots( 'computationalCost', 10, COMPUTATIONAL_COST_TABLE_NAME_EXPIRATION, ) const dataOutdated = slots.get<string>(key) let dataUpdated: string | undefined if (dataOutdated !== undefined) { dataUpdated = dataOutdated } else { dataUpdated = await CacheStorageModule.getData(key) } if (!isNullOrUndefined(dataUpdated)) { // console.log('dataUpdated') // console.log(dataUpdated) const costRecords = JSON.parse(dataUpdated as string) const estimatedComputationalRawCost = mediumCost(costRecords) return { estimatedComputationalRawCost, costRecords, } } else { const estimatedComputationalRawCost = ideaCreation ? contract.recipe.gasUnitsCost.ideaCreation : contract.recipe.gasUnitsCost.ideaStageCreation const costRecords: IComputationalCostRecord = { costs: [estimatedComputationalRawCost], } await CacheStorageModule.addData( key, JSON.stringify(costRecords), EXPIRATION_FOR_COMPUTATIONAL_COST, ) slots.add(key, JSON.stringify(costRecords)) return { estimatedComputationalRawCost, costRecords, } } } const updateEstimatedComputationalRawCost = async ( contractAddress: string, ideaCreation: boolean, inBehalfOf: boolean, updatedValue: IComputationalCostRecord, ) => { const key = COMPUTATIONAL_COST_TABLE_NAME + '_' + contractAddress + '_' + ideaCreation + '_' + inBehalfOf await CacheStorageModule.updateData( key, JSON.stringify(updatedValue), EXPIRATION_FOR_COMPUTATIONAL_COST, ) const slots = PreCacheModule.getExpiringSlots( 'computationalCost', 10, COMPUTATIONAL_COST_TABLE_NAME_EXPIRATION, ) slots.add(key, JSON.stringify(updatedValue)) } const mediumCost = (record: IComputationalCostRecord): number => { const costs = record.costs.length > 10 ? record.costs.slice(-10) : record.costs const sum = costs.reduce((a, b) => a + b, 0) const avg = sum / costs.length || 0 return Math.floor(avg) } const increaseEstimatedComputationalRawCost = async ( contractAddress: string, ideaCreation: boolean, inBehalfOf: boolean, ): Promise<void> => { const key = COMPUTATIONAL_COST_TABLE_NAME + '_' + contractAddress + '_' + ideaCreation + '_' + inBehalfOf const dataUpdated = await CacheStorageModule.getData(key) // console.log('key INCREASE') // console.log(key) if (!isNullOrUndefined(dataUpdated)) { // console.log('dataUpdated:') // console.log(dataUpdated) const dataUpdatedRestored = JSON.parse(dataUpdated as string) let computationalGuess = mediumCost(dataUpdatedRestored) computationalGuess = computationalGuess * 5 const toRecord = { costs: [computationalGuess], } await updateEstimatedComputationalRawCost( contractAddress, ideaCreation, inBehalfOf, toRecord, ) } } const decreaseEstimatedComputationalRawCost = async ( contractAddress: string, ideaCreation: boolean, inBehalfOf: boolean, ): Promise<void> => { const key = COMPUTATIONAL_COST_TABLE_NAME + '_' + contractAddress + '_' + ideaCreation + '_' + inBehalfOf const dataUpdated = await CacheStorageModule.getData(key) if (!isNullOrUndefined(dataUpdated)) { const dataUpdatedRestored = JSON.parse(dataUpdated as string) let computationalGuess = mediumCost(dataUpdatedRestored) computationalGuess = computationalGuess / 5 const toRecord = { costs: [computationalGuess], } await updateEstimatedComputationalRawCost( contractAddress, ideaCreation, inBehalfOf, toRecord, ) } } const IXILY_TAX_EXPIRATION = 10 * 60 * 1000 // 10 minutes const getCurrentIxilyTax = async (contract: IContract): Promise<BigNumber> => { const slots = PreCacheModule.getExpiringSlots( 'ixilyTax', 1, IXILY_TAX_EXPIRATION, ) const savedIxilyTax = slots.get<BigNumber>('tax') if (savedIxilyTax !== undefined) { return savedIxilyTax } if (contract.recipe.isTestnet) { return BigNumber.from(0) } const gWei = await contract.gate!.getIdeaCreationTax() const value = gWei.mul(BigNumber.from(10).pow(9)) slots.add('tax', value) return value } const getEstimatedCosts = async ( contract: IContract, clientInBehalf?: string, newIdea: boolean = true, ): Promise<IOperationalCost> => { const weiBigNumberFee = await getCurrentIxilyTax(contract) log.dev('got weiBigNumberFee:') log.dev(weiBigNumberFee) const balancePrior = await contract.gate!.provider.getBalance( clientInBehalf || (await contract.gate!.signer.getAddress()), ) log.dev('balancePrior:') log.dev(balancePrior) const slots = PreCacheModule.getExpiringSlots( 'gasPrice', 10, GAS_PRICE_EXPIRATION, ) const savedGasPrice = slots.get<BigNumber>(contract.gate!.address) let gasPrice: BigNumber if (savedGasPrice !== undefined) { gasPrice = savedGasPrice } else { gasPrice = await contract.gate!.provider.getGasPrice() slots.add(contract.gate!.address, gasPrice) } log.dev('gasPrice:') log.dev(gasPrice) const { estimatedComputationalRawCost, costRecords } = await getEstimatedComputationalRawCost( contract, newIdea, clientInBehalf !== undefined, ) log.dev('estimatedComputationalRawCost') log.dev(estimatedComputationalRawCost) log.dev('costRecords') log.dev(costRecords) const totalGasCost = gasPrice.mul(estimatedComputationalRawCost) log.dev('totalGasCost') log.dev(totalGasCost) const totalCost = totalGasCost.add(weiBigNumberFee) log.dev('totalCost') log.dev(totalCost) const cost: IOperationalCost = { ixilyTax: { weiBigNumber: weiBigNumberFee, weiHex: weiBigNumberFee.toHexString(), }, walletBalancePrior: { weiBigNumber: balancePrior, weiHex: balancePrior.toHexString(), }, estimatedGasPrice: { weiBigNumber: gasPrice, weiHex: gasPrice.toHexString(), }, estimatedComputationalRawCost, costRecords, estimatedTotalGasCost: { weiBigNumber: totalGasCost, weiHex: totalGasCost.toHexString(), }, estimatedTotalCost: { weiBigNumber: totalCost, weiHex: totalCost.toHexString(), }, haveEnoughForTry: balancePrior.sub(totalCost).gt(0), } log.dev('cost') log.dev(cost) return cost } const getFinalCosts = async < C extends { effectiveGasPrice: BigNumber cumulativeGasUsed: BigNumber }, >( costPrior: IOperationalCost, nftCommitted: C, contract: IContract, clientInBehalf?: string, newIdea: boolean = true, ): Promise<IOperationalCost> => { const balanceAfter = await contract.gate!.provider.getBalance( clientInBehalf || (await contract.gate!.signer.getAddress()), ) costPrior.walletBalanceAfter = { weiBigNumber: balanceAfter, weiHex: balanceAfter.toHexString(), } const totalCost = costPrior.walletBalancePrior.weiBigNumber.sub( costPrior.walletBalanceAfter.weiBigNumber, ) costPrior.totalCost = { weiBigNumber: totalCost, weiHex: totalCost.toHexString(), } const totalGasCost = totalCost.sub(costPrior.ixilyTax.weiBigNumber) costPrior.gasGost = { weiBigNumber: totalGasCost, weiHex: totalGasCost.toHexString(), } // TODO: get real gas price and calculate computational raw cost const effectiveGasPrice = nftCommitted.effectiveGasPrice const cumulativeGasUsed = nftCommitted.cumulativeGasUsed.toNumber() costPrior.gasPrice = { weiBigNumber: effectiveGasPrice, weiHex: effectiveGasPrice.toHexString(), } costPrior.computationalRawCost = cumulativeGasUsed const costTrimmed = costPrior.costRecords.costs.length > 12 ? costPrior.costRecords.costs.slice(-12) : costPrior.costRecords.costs costTrimmed.push(cumulativeGasUsed) const toRecord = { costs: costTrimmed, } await updateEstimatedComputationalRawCost( contract.gate!.address, newIdea, clientInBehalf !== undefined, toRecord, ) return costPrior } export const OperationalCostModule = { getCurrentIxilyTax, increaseEstimatedComputationalRawCost, decreaseEstimatedComputationalRawCost, getEstimatedCosts, getFinalCosts, }