diff options
author | Jacob Evans <jacob@dekz.net> | 2018-11-16 08:37:05 +0800 |
---|---|---|
committer | Jacob Evans <jacob@dekz.net> | 2018-12-04 06:13:58 +0800 |
commit | 98d9a9c6482e2170192f66350448703d2801d122 (patch) | |
tree | 4a96e579c74c2e87f0ea50c4eea95b511cc00273 | |
parent | da8c27c286321af759125d7777f1c84d34498214 (diff) | |
download | dexon-0x-contracts-98d9a9c6482e2170192f66350448703d2801d122.tar dexon-0x-contracts-98d9a9c6482e2170192f66350448703d2801d122.tar.gz dexon-0x-contracts-98d9a9c6482e2170192f66350448703d2801d122.tar.bz2 dexon-0x-contracts-98d9a9c6482e2170192f66350448703d2801d122.tar.lz dexon-0x-contracts-98d9a9c6482e2170192f66350448703d2801d122.tar.xz dexon-0x-contracts-98d9a9c6482e2170192f66350448703d2801d122.tar.zst dexon-0x-contracts-98d9a9c6482e2170192f66350448703d2801d122.zip |
chore: time movement for geth
-rw-r--r-- | packages/contracts/contracts/extensions/DutchAuction/DutchAuction.sol | 26 | ||||
-rw-r--r-- | packages/contracts/test/extensions/dutch_auction.ts | 73 |
2 files changed, 68 insertions, 31 deletions
diff --git a/packages/contracts/contracts/extensions/DutchAuction/DutchAuction.sol b/packages/contracts/contracts/extensions/DutchAuction/DutchAuction.sol index ed4158c25..bb75fc188 100644 --- a/packages/contracts/contracts/extensions/DutchAuction/DutchAuction.sol +++ b/packages/contracts/contracts/extensions/DutchAuction/DutchAuction.sol @@ -86,11 +86,9 @@ contract DutchAuction { { AuctionDetails memory auctionDetails = getAuctionDetails(sellOrder); // Ensure the auction has not yet started - // solhint-disable-next-line not-rely-on-time - require(block.timestamp >= auctionDetails.beginTime, "AUCTION_NOT_STARTED"); + require(auctionDetails.currentTime >= auctionDetails.beginTime, "AUCTION_NOT_STARTED"); // Ensure the auction has not expired. This will fail later in 0x but we can save gas by failing early - // solhint-disable-next-line not-rely-on-time - require(sellOrder.expirationTimeSeconds > block.timestamp, "AUCTION_EXPIRED"); + require(sellOrder.expirationTimeSeconds > auctionDetails.currentTime, "AUCTION_EXPIRED"); // Ensure the auction goes from high to low require(auctionDetails.beginPrice > auctionDetails.endPrice, "INVALID_PRICE"); // Validate the buyer amount is greater than the current auction price @@ -141,20 +139,24 @@ contract DutchAuction { (uint256 auctionBeginTimeSeconds, uint256 auctionBeginPrice) = decodeParameters(order.salt); require(order.expirationTimeSeconds > auctionBeginTimeSeconds, "INVALID_BEGIN_TIME"); uint256 auctionDurationSeconds = order.expirationTimeSeconds-auctionBeginTimeSeconds; - // solhint-disable-next-line not-rely-on-time - uint256 currentDurationSeconds = order.expirationTimeSeconds-block.timestamp; uint256 minPrice = order.takerAssetAmount; - uint256 priceDiff = auctionBeginPrice-minPrice; - uint256 currentPrice = minPrice + (currentDurationSeconds*priceDiff/auctionDurationSeconds); - + // solhint-disable-next-line not-rely-on-time + uint256 timestamp = block.timestamp; auctionDetails.beginTime = auctionBeginTimeSeconds; auctionDetails.endTime = order.expirationTimeSeconds; auctionDetails.beginPrice = auctionBeginPrice; auctionDetails.endPrice = minPrice; + auctionDetails.currentTime = timestamp; + + uint256 remainingDurationSeconds = order.expirationTimeSeconds-timestamp; + uint256 priceDelta = auctionBeginPrice-minPrice; + uint256 currentPrice = minPrice + (remainingDurationSeconds*priceDelta/auctionDurationSeconds); + // If the auction has not yet begun the current price is the auctionBeginPrice + currentPrice = timestamp < auctionBeginTimeSeconds ? auctionBeginPrice : currentPrice; + // If the auction has ended the current price is the minPrice + // auction end time is guaranteed by 0x Exchange to fail due to the order expiration + currentPrice = timestamp >= order.expirationTimeSeconds ? minPrice : currentPrice; auctionDetails.currentPrice = currentPrice; - // solhint-disable-next-line not-rely-on-time - auctionDetails.currentTime = block.timestamp; - return auctionDetails; } } diff --git a/packages/contracts/test/extensions/dutch_auction.ts b/packages/contracts/test/extensions/dutch_auction.ts index c61faf9d7..6a1e3ed45 100644 --- a/packages/contracts/test/extensions/dutch_auction.ts +++ b/packages/contracts/test/extensions/dutch_auction.ts @@ -27,7 +27,7 @@ const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); const DECIMALS_DEFAULT = 18; -describe(ContractName.DutchAuction, () => { +describe.only(ContractName.DutchAuction, () => { let makerAddress: string; let owner: string; let takerAddress: string; @@ -49,11 +49,26 @@ describe(ContractName.DutchAuction, () => { let tenMinutesInSeconds: number; let currentBlockTimestamp: number; let auctionBeginTime: BigNumber; + let auctionEndTime: BigNumber; let auctionBeginPrice: BigNumber; + let auctionEndPrice: BigNumber; let encodedParams: BigNumber; let sellOrder: SignedOrder; let buyOrder: SignedOrder; let erc721MakerAssetIds: BigNumber[]; + async function increaseTimeAsync(): Promise<void> { + const timestampBefore = await getLatestBlockTimestampAsync(); + await web3Wrapper.increaseTimeAsync(5); + const timestampAfter = await getLatestBlockTimestampAsync(); + // HACK send some transactions + if (timestampAfter === timestampBefore) { + await web3Wrapper.sendTransactionAsync({ to: makerAddress, from: makerAddress, value: new BigNumber(1) }); + await web3Wrapper.sendTransactionAsync({ to: makerAddress, from: makerAddress, value: new BigNumber(1) }); + await web3Wrapper.sendTransactionAsync({ to: makerAddress, from: makerAddress, value: new BigNumber(1) }); + await web3Wrapper.sendTransactionAsync({ to: makerAddress, from: makerAddress, value: new BigNumber(1) }); + await web3Wrapper.sendTransactionAsync({ to: makerAddress, from: makerAddress, value: new BigNumber(1) }); + } + } before(async () => { await blockchainLifecycle.startAsync(); @@ -132,12 +147,19 @@ describe(ContractName.DutchAuction, () => { web3Wrapper.abiDecoder.addABI(exchangeInstance.abi); web3Wrapper.abiDecoder.addABI(zrxToken.abi); erc20Wrapper.addTokenOwnerAddress(dutchAuctionContract.address); + tenMinutesInSeconds = 10 * 60; currentBlockTimestamp = await getLatestBlockTimestampAsync(); + // Default auction begins 10 minutes ago auctionBeginTime = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds); + // Default auction ends 10 from now + auctionEndTime = new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds); auctionBeginPrice = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT); + auctionEndPrice = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT); encodedParams = await dutchAuctionContract.encodeParameters.callAsync(auctionBeginTime, auctionBeginPrice); + const zero = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT); + // Default sell order and buy order are exact mirrors const sellerDefaultOrderParams = { salt: encodedParams, // Set the encoded params as the salt for the seller order exchangeAddress: exchangeInstance.address, @@ -147,18 +169,23 @@ describe(ContractName.DutchAuction, () => { makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), DECIMALS_DEFAULT), - makerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT), - takerFee: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), DECIMALS_DEFAULT), + takerAssetAmount: auctionEndPrice, + expirationTimeSeconds: auctionEndTime, + makerFee: zero, + takerFee: zero, }; + // Default buy order is for the auction begin price const buyerDefaultOrderParams = { ...sellerDefaultOrderParams, makerAddress: takerAddress, makerAssetData: sellerDefaultOrderParams.takerAssetData, takerAssetData: sellerDefaultOrderParams.makerAssetData, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT), + makerAssetAmount: auctionBeginPrice, takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT), }; + + encodedParams = await dutchAuctionContract.encodeParameters.callAsync(auctionBeginTime, auctionBeginPrice); + const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams); @@ -170,11 +197,6 @@ describe(ContractName.DutchAuction, () => { beforeEach(async () => { await blockchainLifecycle.startAsync(); erc20Balances = await erc20Wrapper.getBalancesAsync(); - tenMinutesInSeconds = 10 * 60; - currentBlockTimestamp = await getLatestBlockTimestampAsync(); - auctionBeginTime = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds); - auctionBeginPrice = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT); - encodedParams = await dutchAuctionContract.encodeParameters.callAsync(auctionBeginTime, auctionBeginPrice); sellOrder = await sellerOrderFactory.newSignedOrderAsync(); buyOrder = await buyerOrderFactory.newSignedOrderAsync(); }); @@ -183,6 +205,7 @@ describe(ContractName.DutchAuction, () => { }); describe('matchOrders', () => { it('should encode and decode parameters', async () => { + encodedParams = await dutchAuctionContract.encodeParameters.callAsync(auctionBeginTime, auctionBeginPrice); const [decodedBegin, decodedBeginPrice] = await dutchAuctionContract.decodeParameters.callAsync( encodedParams, ); @@ -190,9 +213,6 @@ describe(ContractName.DutchAuction, () => { expect(decodedBeginPrice).to.be.bignumber.equal(auctionBeginPrice); }); it('should be worth the begin price at the begining of the auction', async () => { - // TODO this is flakey - currentBlockTimestamp = await web3Wrapper.getBlockTimestampAsync('latest'); - await web3Wrapper.increaseTimeAsync(1); auctionBeginTime = new BigNumber(currentBlockTimestamp + 2); encodedParams = await dutchAuctionContract.encodeParameters.callAsync(auctionBeginTime, auctionBeginPrice); sellOrder = await sellerOrderFactory.newSignedOrderAsync({ @@ -202,6 +222,18 @@ describe(ContractName.DutchAuction, () => { expect(auctionDetails.currentPrice).to.be.bignumber.equal(auctionBeginPrice); expect(auctionDetails.beginPrice).to.be.bignumber.equal(auctionBeginPrice); }); + it('should be be worth the end price at the end of the auction', async () => { + auctionBeginTime = new BigNumber(currentBlockTimestamp - 1000); + auctionEndTime = new BigNumber(currentBlockTimestamp - 100); + encodedParams = await dutchAuctionContract.encodeParameters.callAsync(auctionBeginTime, auctionBeginPrice); + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + salt: encodedParams, + expirationTimeSeconds: auctionEndTime, + }); + const auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); + expect(auctionDetails.currentPrice).to.be.bignumber.equal(auctionEndPrice); + expect(auctionDetails.beginPrice).to.be.bignumber.equal(auctionBeginPrice); + }); it('should match orders and send excess to seller', async () => { const txHash = await dutchAuctionContract.matchOrders.sendTransactionAsync( buyOrder, @@ -224,11 +256,11 @@ describe(ContractName.DutchAuction, () => { it('should have valid getAuctionDetails at a block in the future', async () => { let auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); const beforePrice = auctionDetails.currentPrice; - // Increase block time - await web3Wrapper.increaseTimeAsync(60); + await increaseTimeAsync(); auctionDetails = await dutchAuctionContract.getAuctionDetails.callAsync(sellOrder); const currentPrice = auctionDetails.currentPrice; expect(beforePrice).to.be.bignumber.greaterThan(currentPrice); + buyOrder = await buyerOrderFactory.newSignedOrderAsync({ makerAssetAmount: currentPrice, }); @@ -248,8 +280,12 @@ describe(ContractName.DutchAuction, () => { ); }); it('should revert when auction expires', async () => { - // Increase block time - await web3Wrapper.increaseTimeAsync(tenMinutesInSeconds); + auctionEndTime = new BigNumber(currentBlockTimestamp - 100); + encodedParams = await dutchAuctionContract.encodeParameters.callAsync(auctionBeginTime, auctionBeginPrice); + sellOrder = await sellerOrderFactory.newSignedOrderAsync({ + salt: encodedParams, + expirationTimeSeconds: auctionEndTime, + }); return expectTransactionFailedAsync( dutchAuctionContract.matchOrders.sendTransactionAsync( buyOrder, @@ -264,8 +300,7 @@ describe(ContractName.DutchAuction, () => { ); }); it('cannot be filled for less than the current price', async () => { - // Increase block time - await web3Wrapper.increaseTimeAsync(60); + await increaseTimeAsync(); buyOrder = await buyerOrderFactory.newSignedOrderAsync({ makerAssetAmount: sellOrder.takerAssetAmount, }); |