mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
implement listTransactions and neccessary changes for it
This commit is contained in:
parent
b02c38d635
commit
11d61dde2e
@ -1,29 +1,42 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { ObjectType, Field, Int } from 'type-graphql'
|
import { ObjectType, Field, Int } from 'type-graphql'
|
||||||
|
import { Transaction } from '../../typeorm/entity/Transaction'
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class Decay {
|
export class Decay {
|
||||||
constructor(json: any) {
|
constructor()
|
||||||
|
constructor(json?: any) {
|
||||||
|
if (json) {
|
||||||
this.balance = Number(json.balance)
|
this.balance = Number(json.balance)
|
||||||
this.decayStart = json.decay_start
|
this.decayStart = json.decay_start
|
||||||
this.decayEnd = json.decay_end
|
this.decayEnd = json.decay_end
|
||||||
this.decayDuration = json.decay_duration
|
this.decayDuration = json.decay_duration
|
||||||
this.decayStartBlock = json.decay_start_block
|
this.decayStartBlock = json.decay_start_block
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getDecayStartBlock(): Promise<Transaction | undefined> {
|
||||||
|
if (!this.decayStartBlockTransaction) {
|
||||||
|
this.decayStartBlockTransaction = await Transaction.getDecayStartBlock()
|
||||||
|
}
|
||||||
|
return this.decayStartBlockTransaction
|
||||||
|
}
|
||||||
|
|
||||||
@Field(() => Number)
|
@Field(() => Number)
|
||||||
balance: number
|
balance: number
|
||||||
|
|
||||||
@Field(() => Int, { nullable: true })
|
@Field(() => Int, { nullable: true })
|
||||||
decayStart?: number
|
decayStart: number
|
||||||
|
|
||||||
@Field(() => Int, { nullable: true })
|
@Field(() => Int, { nullable: true })
|
||||||
decayEnd?: number
|
decayEnd: number
|
||||||
|
|
||||||
@Field(() => String, { nullable: true })
|
@Field(() => String, { nullable: true })
|
||||||
decayDuration?: string
|
decayDuration?: number
|
||||||
|
|
||||||
@Field(() => Int, { nullable: true })
|
@Field(() => Int, { nullable: true })
|
||||||
decayStartBlock?: number
|
decayStartBlock?: number
|
||||||
|
|
||||||
|
static decayStartBlockTransaction: Transaction | undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export class Transaction {
|
|||||||
this.balance = Number(json.balance)
|
this.balance = Number(json.balance)
|
||||||
this.decayStart = json.decay_start
|
this.decayStart = json.decay_start
|
||||||
this.decayEnd = json.decay_end
|
this.decayEnd = json.decay_end
|
||||||
this.decayDuration = json.decay_duration
|
this.decayDuration = parseFloat(json.decay_duration)
|
||||||
this.memo = json.memo
|
this.memo = json.memo
|
||||||
this.transactionId = json.transaction_id
|
this.transactionId = json.transaction_id
|
||||||
this.name = json.name
|
this.name = json.name
|
||||||
@ -44,7 +44,7 @@ export class Transaction {
|
|||||||
decayEnd?: number
|
decayEnd?: number
|
||||||
|
|
||||||
@Field({ nullable: true })
|
@Field({ nullable: true })
|
||||||
decayDuration?: string
|
decayDuration?: number
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
memo: string
|
memo: string
|
||||||
|
|||||||
@ -19,7 +19,9 @@ export class BalanceResolver {
|
|||||||
const now = new Date()
|
const now = new Date()
|
||||||
return new Balance({
|
return new Balance({
|
||||||
balance: roundFloorFrom4(balanceEntity.amount),
|
balance: roundFloorFrom4(balanceEntity.amount),
|
||||||
decay: roundFloorFrom4(calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now)),
|
decay: roundFloorFrom4(
|
||||||
|
await calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now),
|
||||||
|
),
|
||||||
decay_date: now.toString(),
|
decay_date: now.toString(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,8 @@ import { User as dbUser } from '../../typeorm/entity/User'
|
|||||||
import { TransactionList, Transaction } from '../models/Transaction'
|
import { TransactionList, Transaction } from '../models/Transaction'
|
||||||
import { UserTransaction as dbUserTransaction } from '../../typeorm/entity/UserTransaction'
|
import { UserTransaction as dbUserTransaction } from '../../typeorm/entity/UserTransaction'
|
||||||
import { Transaction as dbTransaction } from '../../typeorm/entity/Transaction'
|
import { Transaction as dbTransaction } from '../../typeorm/entity/Transaction'
|
||||||
import { TransactionSendCoin as dbTransactionSendCoin} from '../../typeorm/entity/TransactionSendCoin'
|
import { Decay } from '../models/Decay'
|
||||||
import { TransactionCreation as dbTransactionCreation} from '../../typeorm/entity/TransactionCreation'
|
import { calculateDecayWithInterval } from '../../util/decay'
|
||||||
import calculateDecay from '../../util/decay'
|
|
||||||
import { roundFloorFrom4 } from '../../util/round'
|
import { roundFloorFrom4 } from '../../util/round'
|
||||||
|
|
||||||
async function calculateAndAddDecayTransactions(
|
async function calculateAndAddDecayTransactions(
|
||||||
@ -13,9 +12,9 @@ async function calculateAndAddDecayTransactions(
|
|||||||
decay: boolean,
|
decay: boolean,
|
||||||
skipFirstTransaction: boolean,
|
skipFirstTransaction: boolean,
|
||||||
): Promise<Transaction[]> {
|
): Promise<Transaction[]> {
|
||||||
let finalTransactions: Transaction[] = []
|
const finalTransactions: Transaction[] = []
|
||||||
let transactionIds: number[] = []
|
const transactionIds: number[] = []
|
||||||
let involvedUserIds: number[] = []
|
const involvedUserIds: number[] = []
|
||||||
|
|
||||||
userTransactions.forEach((userTransaction: dbUserTransaction) => {
|
userTransactions.forEach((userTransaction: dbUserTransaction) => {
|
||||||
transactionIds.push(userTransaction.transactionId)
|
transactionIds.push(userTransaction.transactionId)
|
||||||
@ -24,39 +23,120 @@ async function calculateAndAddDecayTransactions(
|
|||||||
// remove duplicates
|
// remove duplicates
|
||||||
// https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
|
// https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates
|
||||||
const involvedUsersUnique = involvedUserIds.filter((v, i, a) => a.indexOf(v) === i)
|
const involvedUsersUnique = involvedUserIds.filter((v, i, a) => a.indexOf(v) === i)
|
||||||
const userIndiced = dbUser.getUsersIndiced(involvedUsersUnique)
|
const userIndiced = await dbUser.getUsersIndiced(involvedUsersUnique)
|
||||||
|
|
||||||
const transactions = await dbTransaction
|
const transactions = await dbTransaction
|
||||||
.createQueryBuilder('transaction')
|
.createQueryBuilder('transaction')
|
||||||
.where('transaction.id IN (:...transactions)', { transactions: transactionIds })
|
.where('transaction.id IN (:...transactions)', { transactions: transactionIds })
|
||||||
.leftJoinAndSelect('transaction.sendCoin', 'transactionSendCoin', 'transactionSendCoin.transactionid = transaction.id')
|
.leftJoinAndSelect(
|
||||||
.leftJoinAndSelect('transaction.creation', 'transactionCreation', 'transactionSendCoin.transactionid = transaction.id')
|
'transaction.sendCoin',
|
||||||
|
'transactionSendCoin',
|
||||||
|
'transactionSendCoin.transactionid = transaction.id',
|
||||||
|
)
|
||||||
|
.leftJoinAndSelect(
|
||||||
|
'transaction.creation',
|
||||||
|
'transactionCreation',
|
||||||
|
'transactionSendCoin.transactionid = transaction.id',
|
||||||
|
)
|
||||||
.getMany()
|
.getMany()
|
||||||
|
|
||||||
let transactionIndiced: dbTransaction[] = []
|
const transactionIndiced: dbTransaction[] = []
|
||||||
transactions.forEach((transaction: dbTransaction) => {
|
transactions.forEach((transaction: dbTransaction) => {
|
||||||
transactionIndiced[transaction.id] = transaction
|
transactionIndiced[transaction.id] = transaction
|
||||||
})
|
})
|
||||||
|
|
||||||
const decayStartTransaction = await dbTransaction.createQueryBuilder('transaction')
|
const decayStartTransaction = await Decay.getDecayStartBlock()
|
||||||
.where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: 9})
|
|
||||||
.orderBy('received', 'ASC')
|
|
||||||
.getOne()
|
|
||||||
|
|
||||||
userTransactions.forEach((userTransaction: dbUserTransaction, i:number) => {
|
userTransactions.forEach(async (userTransaction: dbUserTransaction, i: number) => {
|
||||||
const transaction = transactionIndiced[userTransaction.transactionId]
|
const transaction = transactionIndiced[userTransaction.transactionId]
|
||||||
let finalTransaction = new Transaction
|
const finalTransaction = new Transaction()
|
||||||
finalTransaction.transactionId = transaction.id
|
finalTransaction.transactionId = transaction.id
|
||||||
finalTransaction.date = transaction.received.toString()
|
finalTransaction.date = transaction.received.toString()
|
||||||
finalTransaction.memo = transaction.memo
|
finalTransaction.memo = transaction.memo
|
||||||
|
finalTransaction.totalBalance = roundFloorFrom4(userTransaction.balance)
|
||||||
|
|
||||||
let prev = i > 0 ? userTransactions[i-1] : null
|
const prev = i > 0 ? userTransactions[i - 1] : null
|
||||||
if (prev && prev.balance > 0) {
|
if (prev && prev.balance > 0) {
|
||||||
|
const current = userTransaction
|
||||||
|
const decay = await calculateDecayWithInterval(
|
||||||
|
prev.balance,
|
||||||
|
prev.balanceDate,
|
||||||
|
current.balanceDate,
|
||||||
|
)
|
||||||
|
const balance = prev.balance - decay.balance
|
||||||
|
|
||||||
|
if (balance) {
|
||||||
|
finalTransaction.decay = decay
|
||||||
|
finalTransaction.decay.balance = roundFloorFrom4(finalTransaction.decay.balance)
|
||||||
|
finalTransaction.decay.balance = roundFloorFrom4(balance)
|
||||||
|
if (
|
||||||
|
decayStartTransaction &&
|
||||||
|
prev.transactionId < decayStartTransaction.id &&
|
||||||
|
current.transactionId > decayStartTransaction.id
|
||||||
|
) {
|
||||||
|
finalTransaction.decay.decayStartBlock = decayStartTransaction.received.getTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
// sender or receiver when user has sended money
|
||||||
|
// group name if creation
|
||||||
|
// type: gesendet / empfangen / geschöpft
|
||||||
|
// transaktion nr / id
|
||||||
|
// date
|
||||||
|
// balance
|
||||||
|
if (userTransaction.transactionTypeId === 1) {
|
||||||
|
// creation
|
||||||
|
const creation = transaction.transactionCreation
|
||||||
|
|
||||||
|
finalTransaction.name = 'Gradido Akademie'
|
||||||
|
finalTransaction.type = 'creation'
|
||||||
|
// finalTransaction.targetDate = creation.targetDate
|
||||||
|
finalTransaction.balance = roundFloorFrom4(creation.amount)
|
||||||
|
} else if (userTransaction.transactionTypeId === 2) {
|
||||||
|
// send coin
|
||||||
|
const sendCoin = transaction.transactionSendCoin
|
||||||
|
let otherUser: dbUser | undefined
|
||||||
|
finalTransaction.balance = roundFloorFrom4(sendCoin.amount)
|
||||||
|
if (sendCoin.userId === user.id) {
|
||||||
|
finalTransaction.type = 'send'
|
||||||
|
otherUser = userIndiced[sendCoin.recipiantUserId]
|
||||||
|
// finalTransaction.pubkey = sendCoin.recipiantPublic
|
||||||
|
} else if (sendCoin.recipiantUserId === user.id) {
|
||||||
|
finalTransaction.type = 'receive'
|
||||||
|
otherUser = userIndiced[sendCoin.userId]
|
||||||
|
// finalTransaction.pubkey = sendCoin.senderPublic
|
||||||
|
} else {
|
||||||
|
throw new Error('invalid transaction')
|
||||||
|
}
|
||||||
|
if (otherUser) {
|
||||||
|
finalTransaction.name = otherUser.firstName + ' ' + otherUser.lastName
|
||||||
|
finalTransaction.email = otherUser.email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i > 0 || !skipFirstTransaction) {
|
||||||
|
finalTransactions.push(finalTransaction)
|
||||||
|
}
|
||||||
|
if (i === userTransactions.length - 1 && decay) {
|
||||||
|
const now = new Date()
|
||||||
|
const decay = await calculateDecayWithInterval(
|
||||||
|
userTransaction.balance,
|
||||||
|
userTransaction.balanceDate,
|
||||||
|
now.getTime(),
|
||||||
|
)
|
||||||
|
const balance = userTransaction.balance - decay.balance
|
||||||
|
if (balance) {
|
||||||
|
const decayTransaction = new Transaction()
|
||||||
|
decayTransaction.type = 'decay'
|
||||||
|
decayTransaction.balance = roundFloorFrom4(balance)
|
||||||
|
decayTransaction.decayDuration = decay.decayDuration
|
||||||
|
decayTransaction.decayStart = decay.decayStart
|
||||||
|
decayTransaction.decayEnd = decay.decayEnd
|
||||||
|
finalTransactions.push(decayTransaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return finalTransactions
|
||||||
|
})
|
||||||
|
|
||||||
return finalTransactions
|
return finalTransactions
|
||||||
}
|
}
|
||||||
@ -78,7 +158,7 @@ export default async function listTransactions(
|
|||||||
if (offset && order === 'ASC') {
|
if (offset && order === 'ASC') {
|
||||||
offset--
|
offset--
|
||||||
}
|
}
|
||||||
let [userTransactions, userTransactionsCount] = await UserTransaction.findByUserPaged(
|
let [userTransactions, userTransactionsCount] = await dbUserTransaction.findByUserPaged(
|
||||||
user.id,
|
user.id,
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
@ -86,12 +166,12 @@ export default async function listTransactions(
|
|||||||
)
|
)
|
||||||
skipFirstTransaction = userTransactionsCount > offset + limit
|
skipFirstTransaction = userTransactionsCount > offset + limit
|
||||||
const decay = !(firstPage > 1)
|
const decay = !(firstPage > 1)
|
||||||
const transactions: Transaction[] = []
|
let transactions: Transaction[] = []
|
||||||
if (userTransactions.length) {
|
if (userTransactions.length) {
|
||||||
if (order === 'DESC') {
|
if (order === 'DESC') {
|
||||||
userTransactions = userTransactions.reverse()
|
userTransactions = userTransactions.reverse()
|
||||||
}
|
}
|
||||||
let transactions = calculateAndAddDecayTransactions(
|
transactions = await calculateAndAddDecayTransactions(
|
||||||
userTransactions,
|
userTransactions,
|
||||||
user,
|
user,
|
||||||
decay,
|
decay,
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp } from 'typeorm'
|
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne } from 'typeorm'
|
||||||
|
import { TransactionCreation } from './TransactionCreation'
|
||||||
|
import { TransactionSendCoin } from './TransactionSendCoin'
|
||||||
|
|
||||||
@Entity('transactions')
|
@Entity('transactions')
|
||||||
export class Transaction extends BaseEntity {
|
export class Transaction extends BaseEntity {
|
||||||
@ -15,16 +17,29 @@ export class Transaction extends BaseEntity {
|
|||||||
memo: string
|
memo: string
|
||||||
|
|
||||||
@Column({ type: 'timestamp' })
|
@Column({ type: 'timestamp' })
|
||||||
received: Timestamp
|
received: Date
|
||||||
|
|
||||||
@Column({ name: 'blockchain_type_id' })
|
@Column({ name: 'blockchain_type_id' })
|
||||||
blockchainTypeId: number
|
blockchainTypeId: number
|
||||||
|
|
||||||
|
@OneToOne(() => TransactionSendCoin, (transactionSendCoin) => transactionSendCoin.transaction)
|
||||||
|
transactionSendCoin: TransactionSendCoin
|
||||||
|
|
||||||
|
@OneToOne(() => TransactionCreation, (transactionCreation) => transactionCreation.transaction)
|
||||||
|
transactionCreation: TransactionCreation
|
||||||
|
|
||||||
static async findByTransactionTypeId(transactionTypeId: number): Promise<Transaction[]> {
|
static async findByTransactionTypeId(transactionTypeId: number): Promise<Transaction[]> {
|
||||||
return this.createQueryBuilder('transaction')
|
return this.createQueryBuilder('transaction')
|
||||||
.where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: transactionTypeId})
|
.where('transaction.transactionTypeId = :transactionTypeId', {
|
||||||
|
transactionTypeId: transactionTypeId,
|
||||||
|
})
|
||||||
.getMany()
|
.getMany()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getDecayStartBlock(): Promise<Transaction | undefined> {
|
||||||
|
return this.createQueryBuilder('transaction')
|
||||||
|
.where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: 9 })
|
||||||
|
.orderBy('received', 'ASC')
|
||||||
|
.getOne()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,12 @@
|
|||||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp, OneToOne, JoinColumn } from 'typeorm'
|
import {
|
||||||
|
BaseEntity,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
Timestamp,
|
||||||
|
OneToOne,
|
||||||
|
JoinColumn,
|
||||||
|
} from 'typeorm'
|
||||||
import { Transaction } from './Transaction'
|
import { Transaction } from './Transaction'
|
||||||
|
|
||||||
@Entity('transaction_creations')
|
@Entity('transaction_creations')
|
||||||
@ -21,5 +29,4 @@ export class TransactionCreation extends BaseEntity {
|
|||||||
@OneToOne(() => Transaction)
|
@OneToOne(() => Transaction)
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
transaction: Transaction
|
transaction: Transaction
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,5 +27,4 @@ export class TransactionSendCoin extends BaseEntity {
|
|||||||
@OneToOne(() => Transaction)
|
@OneToOne(() => Transaction)
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
transaction: Transaction
|
transaction: Transaction
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ export class User extends BaseEntity {
|
|||||||
.select(['user.id', 'user.firstName', 'user.lastName', 'user.email'])
|
.select(['user.id', 'user.firstName', 'user.lastName', 'user.email'])
|
||||||
.where('user.id IN (:...users)', { users: userIds })
|
.where('user.id IN (:...users)', { users: userIds })
|
||||||
.getMany()
|
.getMany()
|
||||||
let usersIndiced: User[] = []
|
const usersIndiced: User[] = []
|
||||||
users.forEach((value, index) => {
|
users.forEach((value, index) => {
|
||||||
usersIndiced[index] = value
|
usersIndiced[index] = value
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp } from 'typeorm'
|
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
|
||||||
|
|
||||||
@Entity('state_user_transactions')
|
@Entity('state_user_transactions')
|
||||||
export class UserTransaction extends BaseEntity {
|
export class UserTransaction extends BaseEntity {
|
||||||
@ -18,7 +18,7 @@ export class UserTransaction extends BaseEntity {
|
|||||||
balance: number
|
balance: number
|
||||||
|
|
||||||
@Column({ name: 'balance_date', type: 'timestamp' })
|
@Column({ name: 'balance_date', type: 'timestamp' })
|
||||||
balanceDate: Timestamp
|
balanceDate: number
|
||||||
|
|
||||||
static findByUserPaged(
|
static findByUserPaged(
|
||||||
userId: number,
|
userId: number,
|
||||||
|
|||||||
@ -1,6 +1,53 @@
|
|||||||
export default function (amount: number, from: Date, to: Date): number {
|
import { Decay } from '../graphql/models/Decay'
|
||||||
|
|
||||||
|
function decayFormula(amount: number, durationInSeconds: number): number {
|
||||||
|
return amount * Math.pow(0.99999997802044727, durationInSeconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function calculateDecay(amount: number, from: Date, to: Date): Promise<number> {
|
||||||
|
// load decay start block
|
||||||
|
const decayStartBlock = await Decay.getDecayStartBlock()
|
||||||
|
|
||||||
|
// if decay hasn't started yet we return input amount
|
||||||
|
if (!decayStartBlock) return amount
|
||||||
|
|
||||||
// what happens when from > to
|
// what happens when from > to
|
||||||
// Do we want to have negative decay?
|
// Do we want to have negative decay?
|
||||||
const decayDuration = (to.getTime() - from.getTime()) / 1000
|
const decayDuration = (to.getTime() - from.getTime()) / 1000
|
||||||
return amount * Math.pow(0.99999997802044727, decayDuration)
|
return decayFormula(amount, decayDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function calculateDecayWithInterval(
|
||||||
|
amount: number,
|
||||||
|
from: number,
|
||||||
|
to: number,
|
||||||
|
): Promise<Decay> {
|
||||||
|
const decayStartBlock = await Decay.getDecayStartBlock()
|
||||||
|
const result = new Decay()
|
||||||
|
result.balance = amount
|
||||||
|
result.decayStart = from
|
||||||
|
result.decayEnd = from
|
||||||
|
|
||||||
|
// (amount, from.getTime(), to.getTime())
|
||||||
|
|
||||||
|
// if no decay start block exist or decay startet after end date
|
||||||
|
if (decayStartBlock === undefined || decayStartBlock.received.getTime() > to) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// if decay start date is before start date we calculate decay for full duration
|
||||||
|
if (decayStartBlock.received.getTime() < from) {
|
||||||
|
result.decayDuration = to - from
|
||||||
|
}
|
||||||
|
// if decay start in between start date and end date we caculcate decay from decay start time to end date
|
||||||
|
else {
|
||||||
|
result.decayDuration = to - decayStartBlock.received.getTime()
|
||||||
|
}
|
||||||
|
// js use timestamp in milliseconds but we calculate with seconds
|
||||||
|
result.decayDuration /= 1000
|
||||||
|
result.balance = decayFormula(amount, result.decayDuration)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export { calculateDecay, calculateDecayWithInterval }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user