-
Notifications
You must be signed in to change notification settings - Fork 16
/
EconomicStrategyHelpers.ts
147 lines (120 loc) · 4.93 KB
/
EconomicStrategyHelpers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { IEconomicStrategy } from './IEconomicStrategy';
import Config from '../Config';
import { BigNumber } from 'bignumber.js';
/**
* Checks whether a transaction requires a deposit that's higher than a
* user-set maximum deposit limit.
* @param {TransactionRequest} txRequest Transaction Request object to check.
* @param {IEconomicStrategy} economicStrategy Economic strategy configuration object.
*/
const exceedsMaxDeposit = (txRequest: any, economicStrategy: IEconomicStrategy): boolean => {
const requiredDeposit = txRequest.requiredDeposit;
const maxDeposit = economicStrategy.maxDeposit;
if (maxDeposit && maxDeposit.gt(0)) {
return requiredDeposit.gt(maxDeposit);
}
return false;
};
/**
* Checks if the balance of the TimeNode is above a set limit.
* @param {Config} config TimeNode configuration object.
*/
const isAboveMinBalanceLimit = async (config: Config): Promise<boolean> => {
const minBalance = config.economicStrategy.minBalance;
const currentBalance = await config.wallet.getBalanceOf(config.wallet.getAddresses()[0]);
if (minBalance) {
return currentBalance.gt(minBalance);
}
return true;
};
/**
* Compares the profitability user settings and checks if the TimeNode
* should claim a transaction.
* @param {TransactionRequest} txRequest Transaction Request object to check.
* @param {IEconomicStrategy} economicStrategy Economic strategy configuration object.
*/
const isProfitable = async (
txRequest: any,
economicStrategy: IEconomicStrategy
): Promise<boolean> => {
const paymentModifier = await txRequest.claimPaymentModifier();
const reward = txRequest.bounty.times(paymentModifier);
const minProfitability = economicStrategy.minProfitability;
if (minProfitability && minProfitability.gt(0)) {
return reward.gt(minProfitability);
}
return true;
};
/**
* Validates all the economic strategy parameters before claiming a certain transaction.
* @param {TransactionRequest} txRequest Transaction Request object to check.
* @param {Config} config Configuration object.
*/
const shouldClaimTx = async (txRequest: any, config: Config): Promise<boolean> => {
if (!config.economicStrategy) {
return true;
}
const profitable = await isProfitable(txRequest, config.economicStrategy);
if (!profitable) {
return false;
}
const enoughBalance = await isAboveMinBalanceLimit(config);
if (!enoughBalance) {
return false;
}
const exceedsDepositLimit = exceedsMaxDeposit(txRequest, config.economicStrategy);
return profitable && enoughBalance && !exceedsDepositLimit;
};
/**
* Calculates the correct gas price to use for execution, taking into consideration
* the economicStrategy `maxGasSubsidy` and the current network conditions.
* @param {TransactionRequest} txRequest Transaction Request object to check.
* @param {Config} config Configuration object.
*/
const getExecutionGasPrice = async (txRequest: any, config: Config): Promise<BigNumber> => {
const currentNetworkPrice = await config.util.networkGasPrice();
if (!config.economicStrategy) {
return currentNetworkPrice;
}
const maxGasSubsidy = config.economicStrategy.maxGasSubsidy;
if (typeof maxGasSubsidy !== 'undefined' && maxGasSubsidy !== null) {
const minGasPrice = txRequest.gasPrice;
const maxGasPrice = minGasPrice.plus(minGasPrice.times(maxGasSubsidy / 100));
if (currentNetworkPrice.lessThan(minGasPrice)) {
return minGasPrice;
} else if (
currentNetworkPrice.greaterThanOrEqualTo(minGasPrice) &&
currentNetworkPrice.lessThan(maxGasPrice)
) {
return currentNetworkPrice;
} else if (currentNetworkPrice.greaterThanOrEqualTo(maxGasPrice)) {
return maxGasPrice;
}
}
return currentNetworkPrice;
};
/**
* Checks if the transaction is profitable to be executed when considering the
* current network gas prices.
* @param {TransactionRequest} txRequest Transaction Request object to check.
* @param {Config} config Configuration object.
*/
const shouldExecuteTx = async (txRequest: any, config: Config): Promise<boolean> => {
const isClaimedByMe = config.wallet.getAddresses().indexOf(txRequest.claimedBy) !== -1;
const gasPrice = await this.getExecutionGasPrice(txRequest, config);
const gasAmount = config.util.calculateGasAmount(txRequest);
const reimbursement = txRequest.gasPrice.times(gasAmount);
const deposit = isClaimedByMe ? txRequest.requiredDeposit : new BigNumber(0);
const paymentModifier = await txRequest.claimPaymentModifier();
const reward = txRequest.bounty.times(paymentModifier);
const gasCost = gasPrice.times(gasAmount);
const expectedReward = deposit.plus(reward).plus(reimbursement);
const shouldExecute = gasCost.lessThanOrEqualTo(expectedReward);
config.logger.debug(
`[${
txRequest.address
}] shouldExecuteTx ret ${shouldExecute} gasCost=${gasCost.toNumber()} expectedReward=${expectedReward.toNumber()}`
);
return shouldExecute;
};
export { shouldClaimTx, shouldExecuteTx, getExecutionGasPrice };