Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Implement Basic Dutch Auction #1225

Merged
merged 12 commits into from
Dec 4, 2018
Merged

Conversation

dekz
Copy link
Member

@dekz dekz commented Nov 7, 2018

Description

Quip doc here for further details.

image

A simple matchOrders in a extension contract that validates the correct amount given the current block timestamp. sellOrder is the smallest possible amount for the asset up for sale. That is the sellOrder.takerAssetAmount is the final amount at the end of the auction. The contract guarantees the incoming buyOrder is for an greater than or equal to the calculated currentAmount. The currentAmount is calculated from the auctionBeginTimeSeconds, auctionBeginAmount, sellOrder.takerAssetAmount aka auctionEndAmount and sellOrder.expiryTimeSeconds aka auctionEndTimeSeconds. currentAmount travels linearly downwards from the auctionBeginAmount to the auctionEndAmount.

Match Orders guarantees the seller gets the minimum reserve amount (sellOrder.takerAssetAmount). When matched the delta between currentAmount and sellOrder.takerAssetAmount is transferred to the seller. Any further excess is returned to the buyer (the delta between buyOrder.makerAssetAmount and currentAmount. This means the buyer can send in any amount safely and be assured they will get the exact price given the current block timestamp.

Testing instructions

Types of changes

Checklist:

  • Prefix PR title with [WIP] if necessary.
  • Prefix PR title with bracketed package name(s) corresponding to the changed package(s). For example: [sol-cov] Fixed bug.
  • Add tests to cover changes as needed.
  • Update documentation as needed.
  • Add new entries to the relevant CHANGELOG.jsons.

@dekz dekz requested a review from albrow as a code owner November 7, 2018 20:37
@coveralls
Copy link

coveralls commented Nov 7, 2018

Coverage Status

Coverage increased (+0.02%) to 85.285% when pulling bb4b516 on feature/contracts/dutch-auction into fc3641b on development.

@dekz dekz force-pushed the feature/contracts/dutch-auction branch from 10cf655 to 287a83b Compare November 7, 2018 20:54
@dekz dekz force-pushed the feature/contracts/dutch-auction branch 3 times, most recently from f7e260a to 06d80cc Compare November 16, 2018 09:45
@dekz dekz requested review from abandeali1 and hysz November 16, 2018 10:56
@dekz dekz added the contracts label Nov 16, 2018
@dekz dekz force-pushed the feature/contracts/dutch-auction branch from cee5bd0 to ea4b21f Compare November 22, 2018 04:41
IExchange internal EXCHANGE;

struct AuctionDetails {
uint256 beginTimeSeconds; // Auction begin time in seconds: sellOrder.makerAssetData
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - specify these are unix timestamps.

const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const DECIMALS_DEFAULT = 18;

describe.only(ContractName.DutchAuction, () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to nix the only before merge.

let buyerOrderFactory: OrderFactory;
let erc20Wrapper: ERC20Wrapper;
let erc20Balances: ERC20BalancesByOwner;
let tenMinutesInSeconds: number;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - some of these could be const like const tenMinutesInSeconds = 10 * 60

expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
});
it('should be be worth the end price at the end of the auction', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - 1000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - could be good to set 1000 and 100 to variables for clarity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll re-use tenMinutesInSeconds

uint256 buyerExcessAmount = buyOrder.makerAssetAmount-auctionDetails.currentAmount;
uint256 sellerExcessAmount = leftMakerAssetSpreadAmount-buyerExcessAmount;
bytes memory assetData = sellOrder.takerAssetData;
address token = assetData.readAddress(16);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - include an offset table for reference. Example.

uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
if (leftMakerAssetSpreadAmount > 0) {
// Calculate the excess from the buy order. This can occur if the buyer sends in a higher
// amount than the calculated current amount
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably use safeMath here or include a comment about why it's definitely not needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with all of the SafeMath comments.

returns (AuctionDetails memory auctionDetails)
{
uint256 makerAssetDataLength = order.makerAssetData.length;
// We assume auctionBeginTimeSeconds and auctionBeginAmount are appended to the makerAssetData
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note as above - should include an offset table for reference. Example.
Could probably just include this once in here then reference it above.

// We assume auctionBeginTimeSeconds and auctionBeginAmount are appended to the makerAssetData
uint256 auctionBeginTimeSeconds = order.makerAssetData.readUint256(makerAssetDataLength-64);
uint256 auctionBeginAmount = order.makerAssetData.readUint256(makerAssetDataLength-32);
require(order.expirationTimeSeconds > auctionBeginTimeSeconds, "INVALID_BEGIN_TIME");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note about safeMath in this function.

EXCHANGE = IExchange(_exchange);
}

/// @dev Matches the buy and sell orders at an amount given the following: the current block time, the auction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

@dekz dekz force-pushed the feature/contracts/dutch-auction branch from 06dab7c to 630aa70 Compare November 27, 2018 04:46
{
AuctionDetails memory auctionDetails = getAuctionDetails(sellOrder);
// Ensure the auction has not yet started
require(auctionDetails.currentTimeSeconds >= auctionDetails.beginTimeSeconds, "AUCTION_NOT_STARTED");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put the revert reasons on a newline.

buySignature,
sellSignature
);
// Return any spread to the seller
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is outdated.

uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
if (leftMakerAssetSpreadAmount > 0) {
// Calculate the excess from the buy order. This can occur if the buyer sends in a higher
// amount than the calculated current amount
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with all of the SafeMath comments.

bytes memory assetData = sellOrder.takerAssetData;
address token = assetData.readAddress(16);
if (sellerExcessAmount > 0) {
address makerAddress = sellOrder.makerAddress;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably don't need to declare makerAddress here since it isn't being reused.

IERC20Token(token).transfer(makerAddress, sellerExcessAmount);
}
if (buyerExcessAmount > 0) {
address takerAddress = buyOrder.makerAddress;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

// | | -32 | 32 | 2. auction begin begin amount |
// ERC20 asset data length is 4+32, 64 for auction details results in min length if 100
require(makerAssetDataLength > 10, "INVALID_ASSET_DATA");
uint256 auctionBeginTimeSeconds = order.makerAssetData.readUint256(makerAssetDataLength-64);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces before/after operators please :) makerAssetDataLength - 64

@dekz dekz force-pushed the feature/contracts/dutch-auction branch from 521e9c1 to 0d814ee Compare November 30, 2018 02:00
@dekz dekz force-pushed the feature/contracts/dutch-auction branch from 420f71c to 271a07a Compare November 30, 2018 02:27
@dekz dekz changed the title [WIP] Implement Basic Dutch Auction Implement Basic Dutch Auction Nov 30, 2018
@dekz dekz force-pushed the feature/contracts/dutch-auction branch 2 times, most recently from e9b30fe to bb4b516 Compare November 30, 2018 05:39
Copy link
Member

@abandeali1 abandeali1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after fixing merge conflicts.

auctionDetails.currentTimeSeconds = timestamp;

uint256 remainingDurationSeconds = order.expirationTimeSeconds-timestamp;
uint256 currentAmount = minAmount + (remainingDurationSeconds*amountDelta/auctionDurationSeconds);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: add spaces in between arithmetic operators

@dekz dekz force-pushed the feature/contracts/dutch-auction branch from 61aa012 to 907b00d Compare December 3, 2018 22:12
@dekz dekz force-pushed the feature/contracts/dutch-auction branch from 907b00d to 247266b Compare December 3, 2018 22:14
@dekz dekz merged commit a1e985a into development Dec 4, 2018
@dekz dekz deleted the feature/contracts/dutch-auction branch December 4, 2018 01:44
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants