aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Evans <jacob@dekz.net>2018-11-16 08:37:05 +0800
committerJacob Evans <jacob@dekz.net>2018-12-04 06:13:58 +0800
commit98d9a9c6482e2170192f66350448703d2801d122 (patch)
tree4a96e579c74c2e87f0ea50c4eea95b511cc00273
parentda8c27c286321af759125d7777f1c84d34498214 (diff)
downloaddexon-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.sol26
-rw-r--r--packages/contracts/test/extensions/dutch_auction.ts73
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,
});