Skip to content

Commit

Permalink
Merge branch 'master' into hotfix/toGwei
Browse files Browse the repository at this point in the history
  • Loading branch information
kosecki123 committed Oct 12, 2018
2 parents 4b618ab + 79d7655 commit 102e37c
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 54 deletions.
83 changes: 48 additions & 35 deletions src/EconomicStrategy/EconomicStrategyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class EconomicStrategyManager {
return EconomicStrategyStatus.NOT_PROFITABLE;
}

const enoughBalance = await this.isAboveMinBalanceLimit(nextAccount);
const enoughBalance = await this.isAboveMinBalanceLimit(nextAccount, txRequest);
if (!enoughBalance) {
return EconomicStrategyStatus.INSUFFICIENT_BALANCE;
}
Expand Down Expand Up @@ -137,15 +137,15 @@ export class EconomicStrategyManager {
const reimbursement = txRequest.gasPrice.times(gasAmount);
const deposit = txRequest.requiredDeposit;

const paymentModifier = await txRequest.claimPaymentModifier();
const paymentModifier = (await txRequest.claimPaymentModifier()).dividedBy(100);
const reward = txRequest.bounty.times(paymentModifier);

const gasCost = gasPrice.times(gasAmount);
const expectedReward = deposit.plus(reward).plus(reimbursement);
const shouldExecute = gasCost.lessThanOrEqualTo(expectedReward);

this.logger.debug(
`shouldExecuteTx ret ${shouldExecute} gasCost=${gasCost.toNumber()} expectedReward=${expectedReward.toNumber()}`,
`shouldExecuteTx: gasCost=${gasCost} <= expectedReward=${expectedReward} returns ${shouldExecute}`,
txRequest.address
);

Expand Down Expand Up @@ -182,48 +182,60 @@ export class EconomicStrategyManager {
});
}

private async isAboveMinBalanceLimit(nextAccount: Address): Promise<boolean> {
private async isAboveMinBalanceLimit(
nextAccount: Address,
txRequest: ITxRequest
): Promise<boolean> {
let minBalance = this.strategy.minBalance || new BigNumber(0);

// Determine the next batter up to claim.
const currentBalance = await this.util.balanceOf(nextAccount);

// Subtract the maximum gas costs of executing all currently claimed
// transactions. This is to ensure that a TimeNode does not fail to execute
// because it ran out of funds.
const txRequestsClaimed: string[] = this.getTxRequestsClaimedBy(nextAccount);

this.logger.debug(`txRequestClaimed=${txRequestsClaimed}`);

const gasPrices: BigNumber[] = await Promise.all(
txRequestsClaimed.map(async (address: string) => {
const txRequest = await this.eac.transactionRequest(address);
await txRequest.refreshData();
const tx = await this.eac.transactionRequest(address);
await tx.refreshData();

return txRequest.gasPrice;
return tx.gasPrice;
})
);
let costOfExecutingFutureTransactions = new BigNumber(0);

if (gasPrices.length) {
const maxGasSubsidy = (this.strategy.maxGasSubsidy || 0) / 100;
const subsidyFactor = maxGasSubsidy + 1;
const costOfExecutingFutureTransactions = gasPrices.reduce(
(sum: BigNumber, current: BigNumber) => sum.add(current.times(subsidyFactor))
costOfExecutingFutureTransactions = gasPrices.reduce((sum: BigNumber, current: BigNumber) =>
sum.add(current.times(subsidyFactor))
);

minBalance = minBalance.add(costOfExecutingFutureTransactions);
}

return currentBalance.gt(minBalance);
const isAboveMinBalanceLimit = currentBalance.gt(minBalance);

this.logger.debug(
`isAboveMinBalanceLimit: currentBalance=${currentBalance} > minBalance=${minBalance} + costOfExecutingFutureTransactions=${costOfExecutingFutureTransactions} returns ${isAboveMinBalanceLimit}`,
txRequest.address
);

return isAboveMinBalanceLimit;
}

private async isClaimingProfitable(txRequest: ITxRequest, gasPrice: BigNumber): Promise<boolean> {
const paymentModifier = await txRequest.claimPaymentModifier();
const paymentModifier = (await txRequest.claimPaymentModifier()).dividedBy(100);
const claimingGasCost = gasPrice.times(CLAIMING_GAS_ESTIMATE);
const reward = txRequest.bounty.times(paymentModifier).minus(claimingGasCost);
const minProfitability = this.strategy.minProfitability || new BigNumber(0);

return reward.gte(minProfitability);
const isProfitable = reward.greaterThanOrEqualTo(minProfitability);

this.logger.debug(
`isClaimingProfitable: paymentModifier=${paymentModifier} gasPrice=${gasPrice} bounty=${
txRequest.bounty
} reward=${reward} >= minProfitability=${minProfitability} returns ${isProfitable}`,
txRequest.address
);

return isProfitable;
}

private normalizeWaitTimes = (temporalUnit: number, stats: EthGasStationInfo) => {
Expand Down Expand Up @@ -270,20 +282,21 @@ export class EconomicStrategyManager {

const { temporalUnit } = txRequest;
const normTimes = this.normalizeWaitTimes(temporalUnit, gasStats);
// Reserved, need to send transaction before it goes to general window.
if (await txRequest.inReservedWindow()) {
let timeLeftInReservedWindow = (await txRequest.now()).sub(txRequest.reservedWindowEnd);
if (temporalUnit === 1) {
timeLeftInReservedWindow = timeLeftInReservedWindow.mul(gasStats.blockTime);
}
return this.returnRightGas(timeLeftInReservedWindow, normTimes, gasStats);
} else {
// No longer reserved, just send it before it times out.
let timeLeftInExecutionWindow = (await txRequest.now()).sub(txRequest.executionWindowEnd);
if (temporalUnit === 1) {
timeLeftInExecutionWindow = timeLeftInExecutionWindow.mul(gasStats.blockTime);
}
return this.returnRightGas(timeLeftInExecutionWindow, normTimes, gasStats);
}
const now = await txRequest.now();
const inReservedWindow = await txRequest.inReservedWindow();

const timeLeft = inReservedWindow
? now.sub(txRequest.reservedWindowEnd)
: now.sub(txRequest.executionWindowEnd);
const normalizedTimeLeft = temporalUnit === 1 ? timeLeft.mul(gasStats.blockTime) : timeLeft;

const gasEstimation = this.returnRightGas(normalizedTimeLeft, normTimes, gasStats);

this.logger.debug(
`smartGasEstimation: inReservedWindow=${inReservedWindow} timeLeft=${timeLeft} normalizedTimeLeft=${normalizedTimeLeft} returns ${gasEstimation}`,
txRequest.address
);

return gasEstimation;
}
}
76 changes: 57 additions & 19 deletions test/unit/UnitTestEconomicStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@ describe('Economic Strategy Tests', () => {
const defaultBalance = MWei;
const defaultBounty = MWei.times(1000);
const defaultGasPrice = new BigNumber(1000);
const CLAIMING_GAS_ESTIMATE = 100000;

const defaultClaimingCost = defaultGasPrice.mul(CLAIMING_GAS_ESTIMATE);
const defaultPaymentModifier = new BigNumber(10); //10%
const defaultZeroProfitabilityBounty = defaultClaimingCost.times(100).div(defaultPaymentModifier);

const createTxRequest = (
gasPrice = defaultGasPrice,
bounty = defaultBounty,
claimedBy = account
claimedBy = account,
paymentModifier = defaultPaymentModifier
) => {
const txRequest = TypeMoq.Mock.ofType<ITxRequest>();
txRequest.setup(tx => tx.gasPrice).returns(() => gasPrice);
Expand All @@ -34,9 +40,7 @@ describe('Economic Strategy Tests', () => {
txRequest.setup(tx => tx.executionWindowEnd).returns(() => new BigNumber(23423));
txRequest.setup(tx => tx.bounty).returns(() => bounty);
txRequest.setup(tx => tx.requiredDeposit).returns(() => MWei);
txRequest
.setup(tx => tx.claimPaymentModifier())
.returns(() => Promise.resolve(new BigNumber(1)));
txRequest.setup(tx => tx.claimPaymentModifier()).returns(async () => paymentModifier);
txRequest.setup(tx => tx.claimedBy).returns(() => claimedBy);
txRequest.setup(tx => tx.address).returns(() => '0x987654321');

Expand Down Expand Up @@ -66,6 +70,25 @@ describe('Economic Strategy Tests', () => {
const cache = TypeMoq.Mock.ofType<Cache<ICachedTxDetails>>();
cache.setup(c => c.stored()).returns(() => []);

const shouldClaimTx = async (
minProfitability: BigNumber,
bounty: BigNumber
): Promise<EconomicStrategyStatus> => {
const strategy: IEconomicStrategy = {
minProfitability
};

economicStrategyManager = new EconomicStrategyManager(
strategy,
defaultUtil,
cache.object,
null
);
const txRequest = createTxRequest(defaultGasPrice, bounty);
const gasPrice = await defaultUtil.getAdvancedNetworkGasPrice();
return economicStrategyManager.shouldClaimTx(txRequest.object, account, gasPrice.average);
};

describe('shouldClaimTx()', () => {
it('returns CLAIM if economic strategy not set or default', async () => {
economicStrategyManager = new EconomicStrategyManager(null, defaultUtil, cache.object, null);
Expand Down Expand Up @@ -122,24 +145,39 @@ describe('Economic Strategy Tests', () => {
});

it('returns NOT_PROFITABLE if reward lower than minProfitability', async () => {
const strategy: IEconomicStrategy = {
minProfitability: defaultBounty.times(10)
};
const expectedProfitability = new BigNumber(1000);
const bounty = defaultZeroProfitabilityBounty.plus(
expectedProfitability.times(defaultPaymentModifier)
);
const minProfitability = expectedProfitability.plus(1);

economicStrategyManager = new EconomicStrategyManager(
strategy,
defaultUtil,
cache.object,
null
const shouldClaimStatus = await shouldClaimTx(minProfitability, bounty);

assert.equal(shouldClaimStatus, EconomicStrategyStatus.NOT_PROFITABLE);
});

it('returns CLAIM if reward equals minProfitability', async () => {
const expectedProfitability = new BigNumber(1000);
const bounty = defaultZeroProfitabilityBounty.plus(
expectedProfitability.times(defaultPaymentModifier)
);
const txRequest = createTxRequest();
const gasPrice = await defaultUtil.getAdvancedNetworkGasPrice();
const shouldClaimStatus = await economicStrategyManager.shouldClaimTx(
txRequest.object,
account,
gasPrice.average
const minProfitability = expectedProfitability;

const shouldClaimStatus = await shouldClaimTx(minProfitability, bounty);

assert.equal(shouldClaimStatus, EconomicStrategyStatus.CLAIM);
});

it('returns CLAIM if reward greater than minProfitability', async () => {
const expectedProfitability = new BigNumber(1000);
const bounty = defaultZeroProfitabilityBounty.plus(
expectedProfitability.times(defaultPaymentModifier)
);
assert.equal(shouldClaimStatus, EconomicStrategyStatus.NOT_PROFITABLE);
const minProfitability = expectedProfitability.minus(1);

const shouldClaimStatus = await shouldClaimTx(minProfitability, bounty);

assert.equal(shouldClaimStatus, EconomicStrategyStatus.CLAIM);
});

it('returns WINDOW_TOO_SHORT if reserved window in timestamp is too short', async () => {
Expand Down

0 comments on commit 102e37c

Please sign in to comment.