From 14e453ac3150e6c9ca277e605d5df9389ac7eea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Uhl=C3=AD=C5=99?= Date: Mon, 16 Oct 2023 11:14:02 +0200 Subject: [PATCH] feat: partial payouts for cancelled requests (#69) --- contracts/Marketplace.sol | 42 +++++++++++++++--- contracts/Requests.sol | 3 +- test/Marketplace.test.js | 89 +++++++++++++++++++++++++++++---------- test/Proofs.test.js | 50 ++++++++++++++-------- test/evm.js | 39 +++++++++++++---- test/marketplace.js | 6 +-- test/requests.js | 1 + 7 files changed, 171 insertions(+), 59 deletions(-) diff --git a/contracts/Marketplace.sol b/contracts/Marketplace.sol index f02c560..9fae544 100644 --- a/contracts/Marketplace.sol +++ b/contracts/Marketplace.sol @@ -25,6 +25,10 @@ contract Marketplace is Proofs, StateRetrieval { struct RequestContext { RequestState state; uint256 slotsFilled; + + /// @notice Tracks how much funds should be returned when Request expires to the Request creator + /// @dev The sum is deducted every time a host fills a Slot by precalculated amount that he should receive if the Request expires + uint256 expiryFundsWithdraw; uint256 startedAt; uint256 endsAt; } @@ -32,7 +36,12 @@ contract Marketplace is Proofs, StateRetrieval { struct Slot { SlotState state; RequestId requestId; + + /// @notice Timestamp that signals when slot was filled + /// @dev Used for partial payouts when Requests expires and Hosts are paid out only the time they host the content. + uint256 filledAt; uint256 slotIndex; + /// @notice Tracks the current amount of host's collateral that is to be payed out at the end of Slot's lifespan. /// @dev When Slot is filled, the collateral is collected in amount of request.ask.collateral /// @dev When Host is slashed for missing a proof the slashed amount is reflected in this variable @@ -80,6 +89,7 @@ contract Marketplace is Proofs, StateRetrieval { _addToMyRequests(request.client, id); uint256 amount = request.price(); + _requestContexts[id].expiryFundsWithdraw = amount; _marketplaceTotals.received += amount; _transferFrom(msg.sender, amount); @@ -106,8 +116,10 @@ contract Marketplace is Proofs, StateRetrieval { slot.host = msg.sender; slot.state = SlotState.Filled; + slot.filledAt = block.timestamp; RequestContext storage context = _requestContexts[requestId]; context.slotsFilled += 1; + context.expiryFundsWithdraw -= _expiryPayoutAmount(requestId, block.timestamp); // Collect collateral uint256 collateralAmount = request.ask.collateral; @@ -133,6 +145,8 @@ contract Marketplace is Proofs, StateRetrieval { if (state == SlotState.Finished) { _payoutSlot(slot.requestId, slotId); + } else if (state == SlotState.Cancelled) { + _payoutCancelledSlot(slot.requestId, slotId); } else if (state == SlotState.Failed) { _removeFromMySlots(msg.sender, slotId); } else if (state == SlotState.Filled) { @@ -207,6 +221,19 @@ contract Marketplace is Proofs, StateRetrieval { assert(token.transfer(slot.host, amount)); } + function _payoutCancelledSlot( + RequestId requestId, + SlotId slotId + ) private requestIsKnown(requestId) { + Slot storage slot = _slots[slotId]; + _removeFromMySlots(slot.host, slotId); + + uint256 amount = _expiryPayoutAmount(requestId, slot.filledAt) + slot.currentCollateral; + _marketplaceTotals.sent += amount; + slot.state = SlotState.Paid; + assert(token.transfer(slot.host, amount)); + } + /// @notice Withdraws storage request funds back to the client that deposited them. /// @dev Request must be expired, must be in RequestState.New, and the transaction must originate from the depositer address. /// @param requestId the id of the request @@ -224,10 +251,7 @@ contract Marketplace is Proofs, StateRetrieval { emit RequestCancelled(requestId); - // TODO: To be changed once we start paying out hosts for the time they - // fill a slot. The amount that we paid to hosts will then have to be - // deducted from the price. - uint256 amount = request.price(); + uint256 amount = context.expiryFundsWithdraw; _marketplaceTotals.sent += amount; assert(token.transfer(msg.sender, amount)); } @@ -268,6 +292,14 @@ contract Marketplace is Proofs, StateRetrieval { } } + /// @notice Calculates the amount that should be payed out to a host if a request expires based on when the host fills the slot + function _expiryPayoutAmount(RequestId requestId, uint256 startingTimestamp) private view returns (uint256) { + Request storage request = _requests[requestId]; + require(startingTimestamp < request.expiry, "Start not before expiry"); + + return (request.expiry - startingTimestamp) * request.ask.reward; + } + function getHost(SlotId slotId) public view returns (address) { return _slots[slotId].host; } @@ -300,7 +332,7 @@ contract Marketplace is Proofs, StateRetrieval { return SlotState.Paid; } if (reqState == RequestState.Cancelled) { - return SlotState.Finished; + return SlotState.Cancelled; } if (reqState == RequestState.Finished) { return SlotState.Finished; diff --git a/contracts/Requests.sol b/contracts/Requests.sol index da730f8..71c7fe3 100644 --- a/contracts/Requests.sol +++ b/contracts/Requests.sol @@ -51,7 +51,8 @@ enum SlotState { Filled, // host has filled slot Finished, // successfully completed Failed, // the request has failed - Paid // host has been paid + Paid, // host has been paid + Cancelled // when request was cancelled then slot is cancelled as well } library Requests { diff --git a/test/Marketplace.test.js b/test/Marketplace.test.js index 4b170c4..a3416ed 100644 --- a/test/Marketplace.test.js +++ b/test/Marketplace.test.js @@ -24,11 +24,13 @@ const { revert, mine, ensureMinimumBlockHeight, - advanceTime, - advanceTimeTo, + advanceTimeForNextBlock, + advanceTimeToForNextBlock, currentTime, } = require("./evm") +const ACCOUNT_STARTING_BALANCE = 1_000_000_000 + describe("Marketplace constructor", function () { let Marketplace, token, config @@ -90,8 +92,8 @@ describe("Marketplace", function () { const TestToken = await ethers.getContractFactory("TestToken") token = await TestToken.deploy() - for (account of [client, host1, host2, host3]) { - await token.mint(account.address, 1_000_000_000) + for (let account of [client, host1, host2, host3]) { + await token.mint(account.address, ACCOUNT_STARTING_BALANCE) } const Marketplace = await ethers.getContractFactory("TestMarketplace") @@ -320,6 +322,7 @@ describe("Marketplace", function () { it("sets request end time to the past once cancelled", async function () { await marketplace.fillSlot(slot.request, slot.index, proof) await waitUntilCancelled(request) + await mine() const now = await currentTime() await expect(await marketplace.requestEnd(requestId(request))).to.be.eq( now - 1 @@ -329,6 +332,7 @@ describe("Marketplace", function () { it("checks that request end time is in the past once finished", async function () { await waitUntilStarted(marketplace, request, proof, token) await waitUntilFinished(marketplace, requestId(request)) + await mine() const now = await currentTime() // in the process of calling currentTime and requestEnd, // block.timestamp has advanced by 1, so the expected proof end time will @@ -403,12 +407,17 @@ describe("Marketplace", function () { }) it("pays the host when contract was cancelled", async function () { + // Lets move the time into middle of the expiry window + const fillTimestamp = await currentTime() + Math.floor((request.expiry - await currentTime()) / 2) - 1 + await advanceTimeToForNextBlock(fillTimestamp) + await marketplace.fillSlot(slot.request, slot.index, proof) await waitUntilCancelled(request) - const startBalance = await token.balanceOf(host.address) await marketplace.freeSlot(slotId(slot)) + const endBalance = await token.balanceOf(host.address) - expect(endBalance).to.be.gt(startBalance) + const expectedPartialPayout = (request.expiry - fillTimestamp) * request.ask.reward + expect(endBalance - ACCOUNT_STARTING_BALANCE).to.be.equal(expectedPartialPayout) }) it("does not pay when the contract hasn't ended", async function () { @@ -542,6 +551,19 @@ describe("Marketplace", function () { const endBalance = await token.balanceOf(client.address) expect(endBalance - startBalance).to.equal(price(request)) }) + + it("withdraws to the client for cancelled requests lowered by hosts payout", async function () { + const fillTimestamp = await currentTime() + Math.floor((request.expiry - await currentTime()) / 2) + await advanceTimeToForNextBlock(fillTimestamp) + await marketplace.fillSlot(slot.request, slot.index, proof) + await waitUntilCancelled(request) + const expectedPartialHostPayout = (request.expiry - fillTimestamp) * request.ask.reward + + switchAccount(client) + await marketplace.withdrawFunds(slot.request) + const endBalance = await token.balanceOf(client.address) + expect(ACCOUNT_STARTING_BALANCE - endBalance).to.equal(expectedPartialHostPayout) + }) }) describe("request state", function () { @@ -561,6 +583,7 @@ describe("Marketplace", function () { it("changes to 'Cancelled' once request is cancelled", async function () { await waitUntilCancelled(request) + await mine() expect(await marketplace.requestState(slot.request)).to.equal(Cancelled) }) @@ -579,6 +602,7 @@ describe("Marketplace", function () { it("changes to 'Failed' once too many slots are freed", async function () { await waitUntilStarted(marketplace, request, proof, token) await waitUntilFailed(marketplace, request) + await mine() expect(await marketplace.requestState(slot.request)).to.equal(Failed) }) @@ -601,6 +625,7 @@ describe("Marketplace", function () { it("changes to 'Finished' when the request ends", async function () { await waitUntilStarted(marketplace, request, proof, token) await waitUntilFinished(marketplace, requestId(request)) + await mine() expect(await marketplace.requestState(slot.request)).to.equal(Finished) }) @@ -613,7 +638,7 @@ describe("Marketplace", function () { }) describe("slot state", function () { - const { Free, Filled, Finished, Failed, Paid } = SlotState + const { Free, Filled, Finished, Failed, Paid, Cancelled } = SlotState let period, periodEnd beforeEach(async function () { @@ -628,14 +653,16 @@ describe("Marketplace", function () { }) async function waitUntilProofIsRequired(id) { - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await advanceTimeToForNextBlock(periodEnd(periodOf(await currentTime()))) + await mine() while ( !( (await marketplace.isProofRequired(id)) && (await marketplace.getPointer(id)) < 250 ) ) { - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() } } @@ -651,13 +678,15 @@ describe("Marketplace", function () { it("changes to 'Finished' when request finishes", async function () { await waitUntilStarted(marketplace, request, proof, token) await waitUntilFinished(marketplace, slot.request) + await mine() expect(await marketplace.slotState(slotId(slot))).to.equal(Finished) }) - it("changes to 'Finished' when request is cancelled", async function () { + it("changes to 'Cancelled' when request is cancelled", async function () { await marketplace.fillSlot(slot.request, slot.index, proof) await waitUntilCancelled(request) - expect(await marketplace.slotState(slotId(slot))).to.equal(Finished) + await mine() + expect(await marketplace.slotState(slotId(slot))).to.equal(Cancelled) }) it("changes to 'Free' when host frees the slot", async function () { @@ -671,7 +700,8 @@ describe("Marketplace", function () { while ((await marketplace.slotState(slotId(slot))) === Filled) { await waitUntilProofIsRequired(slotId(slot)) const missedPeriod = periodOf(await currentTime()) - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() await marketplace.markProofAsMissing(slotId(slot), missedPeriod) } expect(await marketplace.slotState(slotId(slot))).to.equal(Free) @@ -680,6 +710,7 @@ describe("Marketplace", function () { it("changes to 'Failed' when request fails", async function () { await waitUntilStarted(marketplace, request, proof, token) await waitUntilSlotFailed(marketplace, request, slot) + await mine() expect(await marketplace.slotState(slotId(slot))).to.equal(Failed) }) @@ -712,14 +743,15 @@ describe("Marketplace", function () { } async function waitUntilProofIsRequired(id) { - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await advanceTimeToForNextBlock(periodEnd(periodOf(await currentTime()))) while ( !( (await marketplace.isProofRequired(id)) && (await marketplace.getPointer(id)) < 250 ) ) { - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() } } @@ -734,7 +766,8 @@ describe("Marketplace", function () { await marketplace.fillSlot(slot.request, slot.index, proof) await waitUntilProofWillBeRequired(id) await expect(await marketplace.willProofBeRequired(id)).to.be.true - await advanceTimeTo(request.expiry + 1) + await waitUntilCancelled(request) + await mine() await expect(await marketplace.willProofBeRequired(id)).to.be.false }) @@ -743,7 +776,8 @@ describe("Marketplace", function () { await marketplace.fillSlot(slot.request, slot.index, proof) await waitUntilProofIsRequired(id) await expect(await marketplace.isProofRequired(id)).to.be.true - await advanceTimeTo(request.expiry + 1) + await waitUntilCancelled(request) + await mine() await expect(await marketplace.isProofRequired(id)).to.be.false }) @@ -751,9 +785,11 @@ describe("Marketplace", function () { const id = slotId(slot) await marketplace.fillSlot(slot.request, slot.index, proof) await waitUntilProofIsRequired(id) + await mine() const challenge1 = await marketplace.getChallenge(id) expect(BigNumber.from(challenge1).gt(0)) - await advanceTimeTo(request.expiry + 1) + await waitUntilCancelled(request) + await mine() const challenge2 = await marketplace.getChallenge(id) expect(BigNumber.from(challenge2).isZero()) }) @@ -762,9 +798,11 @@ describe("Marketplace", function () { const id = slotId(slot) await marketplace.fillSlot(slot.request, slot.index, proof) await waitUntilProofIsRequired(id) + await mine() const challenge1 = await marketplace.getChallenge(id) expect(BigNumber.from(challenge1).gt(0)) - await advanceTimeTo(request.expiry + 1) + await waitUntilCancelled(request) + await mine() const challenge2 = await marketplace.getChallenge(id) expect(BigNumber.from(challenge2).isZero()) }) @@ -785,14 +823,16 @@ describe("Marketplace", function () { }) async function waitUntilProofIsRequired(id) { - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await advanceTimeToForNextBlock(periodEnd(periodOf(await currentTime()))) + await mine() while ( !( (await marketplace.isProofRequired(id)) && (await marketplace.getPointer(id)) < 250 ) ) { - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() } } @@ -813,7 +853,7 @@ describe("Marketplace", function () { for (let i = 0; i < slashCriterion; i++) { await waitUntilProofIsRequired(id) let missedPeriod = periodOf(await currentTime()) - await advanceTime(period) + await advanceTimeForNextBlock(period+1) await marketplace.markProofAsMissing(id, missedPeriod) } const expectedBalance = @@ -841,7 +881,7 @@ describe("Marketplace", function () { ) await waitUntilProofIsRequired(slotId(slot)) const missedPeriod = periodOf(await currentTime()) - await advanceTime(period) + await advanceTimeForNextBlock(period+1) await marketplace.markProofAsMissing(slotId(slot), missedPeriod) } expect(await marketplace.slotState(slotId(slot))).to.equal(SlotState.Free) @@ -865,7 +905,7 @@ describe("Marketplace", function () { ) await waitUntilProofIsRequired(slotId(slot)) const missedPeriod = periodOf(await currentTime()) - await advanceTime(period) + await advanceTimeForNextBlock(period+1) expect(await marketplace.missingProofs(slotId(slot))).to.equal( missedProofs ) @@ -896,6 +936,7 @@ describe("Marketplace", function () { it("keeps request in list when cancelled", async function () { await marketplace.requestStorage(request) await waitUntilCancelled(request) + await mine() expect(await marketplace.myRequests()).to.deep.equal([requestId(request)]) }) @@ -911,6 +952,7 @@ describe("Marketplace", function () { switchAccount(host) await waitUntilStarted(marketplace, request, proof, token) await waitUntilFailed(marketplace, request) + await mine() switchAccount(client) expect(await marketplace.myRequests()).to.deep.equal([requestId(request)]) }) @@ -963,6 +1005,7 @@ describe("Marketplace", function () { await token.approve(marketplace.address, request.ask.collateral) await marketplace.fillSlot(slot.request, slot1.index, proof) await waitUntilCancelled(request) + await mine() expect(await marketplace.mySlots()).to.have.members([ slotId(slot), slotId(slot1), diff --git a/test/Proofs.test.js b/test/Proofs.test.js index 13b646e..4631391 100644 --- a/test/Proofs.test.js +++ b/test/Proofs.test.js @@ -7,8 +7,8 @@ const { mine, ensureMinimumBlockHeight, currentTime, - advanceTime, - advanceTimeTo, + advanceTimeForNextBlock, + advanceTimeToForNextBlock, } = require("./evm") const { periodic } = require("./time") const { SlotState } = require("./requests") @@ -44,13 +44,15 @@ describe("Proofs", function () { const samples = 256 // 256 samples avoids bias due to pointer downtime await proofs.startRequiringProofs(slotId, probability) - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() let amount = 0 for (let i = 0; i < samples; i++) { if (await proofs.isProofRequired(slotId)) { amount += 1 } - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() } const p = 1 / probability // expected probability @@ -62,7 +64,8 @@ describe("Proofs", function () { it("supports probability 1 (proofs are always required)", async function () { await proofs.startRequiringProofs(slotId, 1) - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() while ((await proofs.getPointer(slotId)) < downtime) { await mine() } @@ -75,7 +78,8 @@ describe("Proofs", function () { await proofs.startRequiringProofs(slotId, probability) while (Math.floor((await currentTime()) / period) == startPeriod) { expect(await proofs.isProofRequired(slotId)).to.be.false - await advanceTime(Math.floor(period / 10)) + await advanceTimeForNextBlock(Math.floor(period / 10)) + await mine() } }) @@ -92,12 +96,14 @@ describe("Proofs", function () { req1 = await proofs.isProofRequired(id1) req2 = await proofs.isProofRequired(id2) req3 = await proofs.isProofRequired(id3) - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() } }) it("moves pointer one block at a time", async function () { - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await advanceTimeToForNextBlock(periodEnd(periodOf(await currentTime()))) + await mine() for (let i = 0; i < 256; i++) { let previous = await proofs.getPointer(slotId) await mine() @@ -117,7 +123,7 @@ describe("Proofs", function () { beforeEach(async function () { await proofs.setSlotState(slotId, SlotState.Filled) await proofs.startRequiringProofs(slotId, probability) - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await advanceTimeToForNextBlock(periodEnd(periodOf(await currentTime()))) await waitUntilProofWillBeRequired() }) @@ -154,14 +160,17 @@ describe("Proofs", function () { }) async function waitUntilProofIsRequired(slotId) { - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await advanceTimeToForNextBlock(periodEnd(periodOf(await currentTime()))) + await mine() + while ( !( (await proofs.isProofRequired(slotId)) && (await proofs.getPointer(slotId)) < 250 ) ) { - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() } } @@ -199,7 +208,7 @@ describe("Proofs", function () { }) it("fails proof submission when already submitted", async function () { - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) + await advanceTimeToForNextBlock(periodEnd(periodOf(await currentTime()))) await proofs.submitProof(slotId, proof) await expect(proofs.submitProof(slotId, proof)).to.be.revertedWith( "Proof already submitted" @@ -210,7 +219,8 @@ describe("Proofs", function () { expect(await proofs.missingProofs(slotId)).to.equal(0) await waitUntilProofIsRequired(slotId) let missedPeriod = periodOf(await currentTime()) - await advanceTimeTo(periodEnd(missedPeriod)) + await advanceTimeToForNextBlock(periodEnd(missedPeriod)) + await mine() await proofs.markProofAsMissing(slotId, missedPeriod) expect(await proofs.missingProofs(slotId)).to.equal(1) }) @@ -226,7 +236,7 @@ describe("Proofs", function () { it("does not mark a proof as missing after timeout", async function () { await waitUntilProofIsRequired(slotId) let currentPeriod = periodOf(await currentTime()) - await advanceTimeTo(periodEnd(currentPeriod) + timeout) + await advanceTimeToForNextBlock(periodEnd(currentPeriod) + timeout) await expect( proofs.markProofAsMissing(slotId, currentPeriod) ).to.be.revertedWith("Validation timed out") @@ -236,7 +246,8 @@ describe("Proofs", function () { await waitUntilProofIsRequired(slotId) let submittedPeriod = periodOf(await currentTime()) await proofs.submitProof(slotId, proof) - await advanceTimeTo(periodEnd(submittedPeriod)) + await advanceTimeToForNextBlock(periodEnd(submittedPeriod)) + await mine() await expect( proofs.markProofAsMissing(slotId, submittedPeriod) ).to.be.revertedWith("Proof was submitted, not missing") @@ -244,10 +255,12 @@ describe("Proofs", function () { it("does not mark proof as missing when not required", async function () { while (await proofs.isProofRequired(slotId)) { - await advanceTime(period) + await advanceTimeForNextBlock(period) + await mine() } let currentPeriod = periodOf(await currentTime()) - await advanceTimeTo(periodEnd(currentPeriod)) + await advanceTimeToForNextBlock(periodEnd(currentPeriod)) + await mine() await expect( proofs.markProofAsMissing(slotId, currentPeriod) ).to.be.revertedWith("Proof was not required") @@ -256,7 +269,8 @@ describe("Proofs", function () { it("does not mark proof as missing twice", async function () { await waitUntilProofIsRequired(slotId) let missedPeriod = periodOf(await currentTime()) - await advanceTimeTo(periodEnd(missedPeriod)) + await advanceTimeToForNextBlock(periodEnd(missedPeriod)) + await mine() await proofs.markProofAsMissing(slotId, missedPeriod) await expect( proofs.markProofAsMissing(slotId, missedPeriod) diff --git a/test/evm.js b/test/evm.js index adaf8c6..e02c4fc 100644 --- a/test/evm.js +++ b/test/evm.js @@ -14,6 +14,13 @@ async function revert() { await ethers.provider.send("evm_setNextBlockTimestamp", [time + 1]) } +/** + * Mines new block. + * + * This call increases the block's timestamp by 1! + * + * @returns {Promise} + */ async function mine() { await ethers.provider.send("evm_mine") } @@ -29,16 +36,30 @@ async function currentTime() { return block.timestamp } -async function advanceTime(seconds) { +/** + * Function that advances time by adding seconds to current timestamp for **next block**. + * + * If you need the timestamp to be already applied for current block then mine a new block with `mine()` after this call. + * This is mainly needed when doing assertions on top of view calls that does not create transactions and mine new block. + * + * @param timestamp + * @returns {Promise} + */ +async function advanceTimeForNextBlock(seconds) { await ethers.provider.send("evm_increaseTime", [seconds]) - await mine() } -async function advanceTimeTo(timestamp) { - if ((await currentTime()) !== timestamp) { - await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]) - await mine() - } +/** + * Function that sets specific timestamp for **next block**. + * + * If you need the timestamp to be already applied for current block then mine a new block with `mine()` after this call. + * This is mainly needed when doing assertions on top of view calls that does not create transactions and mine new block. + * + * @param timestamp + * @returns {Promise} + */ +async function advanceTimeToForNextBlock(timestamp) { + await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]) } module.exports = { @@ -47,6 +68,6 @@ module.exports = { mine, ensureMinimumBlockHeight, currentTime, - advanceTime, - advanceTimeTo, + advanceTimeForNextBlock, + advanceTimeToForNextBlock, } diff --git a/test/marketplace.js b/test/marketplace.js index ba8254b..8cae999 100644 --- a/test/marketplace.js +++ b/test/marketplace.js @@ -1,9 +1,9 @@ -const { advanceTimeTo } = require("./evm") +const { advanceTimeToForNextBlock, currentTime } = require("./evm") const { slotId, requestId } = require("./ids") const {price} = require("./price"); async function waitUntilCancelled(request) { - await advanceTimeTo(request.expiry + 1) + await advanceTimeToForNextBlock(request.expiry + 1) } async function waitUntilStarted(contract, request, proof, token) { @@ -16,7 +16,7 @@ async function waitUntilStarted(contract, request, proof, token) { async function waitUntilFinished(contract, requestId) { const end = (await contract.requestEnd(requestId)).toNumber() - await advanceTimeTo(end + 1) + await advanceTimeToForNextBlock(end + 1) } async function waitUntilFailed(contract, request) { diff --git a/test/requests.js b/test/requests.js index 7396a2c..e9c7fb2 100644 --- a/test/requests.js +++ b/test/requests.js @@ -14,6 +14,7 @@ const SlotState = { Finished: 2, Failed: 3, Paid: 4, + Cancelled: 5, } const enableRequestAssertions = function () {