@ixily/activ
Version:
Alpha Capture Trade Idea Verification. Blockchain ownership proven trade ideas and strategies.
350 lines (330 loc) • 8.93 kB
text/typescript
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,
}