*** UPDATE as of 10/9/19: Please see the New Quickstart Guide***

A complete look at an implementation of “secret auctions” on Enigma’s protocol

Introduction:

Recently, non-fungible cryptoassets have sparked a large ecosystem of auction-based peer-to-peer marketplaces (RareBits, OpenSea, etc.) and DNS services for decentralized protocols (Portal Network). Additionally, auctions are a strong interest in academia and have potential cryptoeconomic applications in areas such as Ad-Tech and beyond. However, similar to blockchain-based voting where votes are exposed on the blockchain, current auction implementations expose user bid values and can lead to bribery and collusion attacks. Additionally, current methods for obfuscating bid values such as commit-reveal schemes are cumbersome for users.

At Enigma, we are building a general protocol for privacy-preserving smart contracts and aim to provide value in areas that necessitate privacy, including auctions. In this article, we present a privacy-preserving auctions contract that encrypts underlying bids and prevents anyone from detecting how a user has bid.

Contract Design:

Diagram showing the design of a secret auction contract.

Auction theory is a complex economics field involving deep academic research. There are many variations of auctions which enable different economic and social behaviors such as all-pay auctions, Vickrey auctions, and Dutch auctions.

However, in order to best highlight privacy in auctions, we have designed a simple sealed-bid auction, which is an auction that protects the value of bids during the bidding process. We also encourage feedback on several of the design choices we made that are limited by the current iteration of the Enigma Protocol.

Here is how the auction contract works:

1 & 2) A user creates a new auction by sending a transaction to an “Auction Factory”, which acts as a proxy for deploying new auction contracts. The Auction Factory also specifies an ERC721 contract which will mint our auction reward.

3) A potential bidder stakes Ether in the auction contract and acts as collateral for a potential bid. This collateral is a promise that the user will pay their bid if selected as a winner. If a user instead directly bidded using tokens, the bidding would not be private, thus the rationale behind the escrow model.

4) Users will send encrypted bids to the contract. Anyone can change their bid during the bidding process.

5) After the time period expires for the bidding process, the creator of the auction will end the auction.

6, 7, & 8) The Enigma Contract will gather the encrypted bids, create a task for the Enigma network, and calculate the winner.

9) The winner of the auction is updated on chain by the Enigma Contract.

10) Users can withdraw their Ether collateral if they did not win the auction. Otherwise, the winner can claim their reward and/or claim the excess collateral which was otherwise not taken by the contract.

11) The creator of the auction can withdraw the winner’s Ether stake.

The Code:

Contract State:

Enum: The state of the auction is defined by an enum called AuctionState. “Calculating” refers to the period when the Enigma network is determining the winner.

Events: Bid refers to individual bids and Winner signals the final update of the winner.

Bidder Struct: Each address has an associated Bidder struct which contains a boolean determining if they have already bidded and their current encrypted bid.

State Variables: Most of the variables are straightforward. Note that stakeAmounts refers to the amount of Ether (in wei) that each address has staked.

The Bidding Process:

A user first stakes Ether in the contract, which acts as a binding commitment towards paying their bid value. The assumption we’re making here is that users will bid an amount less than their deposit in order to obscure their true bid value. Otherwise, the deposit would simply indicate their bid value. Note that a user can also increase their stake anytime during the bidding process.

A user can then bid in the contract. The contract will check if the auction is open for bidding and whether the user has enough stake to fulfill the minimum bid value(which is specified at the creation of the auction). Similar to the staking function, a user can update their bid anytime during the bidding process.

Finally, the creator of the auction will end the auction when the bidding period expires.

Callable and Callback:

After the auction is ended by the owner, the dApp using the contract will submit a task to the Enigma network to calculate the winner. Here, we introduce the standard callable and callback functions which are necessary for privacy-preserving contracts on Enigma.

The callable function is the function that is computed by a randomly selected SGX node on the Enigma network. In our case, this is the function that calculates the highest bidder of the auction. The function simply finds the user with the highest corresponding bid and checks whether the bid value is less than or equal to the amount of Ether that the user has staked. If a user’s bid value is greater than their stake, then the bid is invalid.

The callback function is the function that is called by the Enigma Contract after the callable has finished. This function is computed on Ethereum to update the state of the Auction. In our Auctions contract, the callback will update the state variables: winner, winningPrice, and state, as well as decrease the stake of the winner.

After the Auction:

A user will withdraw all of their stake if they did not win the auction. Otherwise, the winner will withdraw any excess Ether that was not used in paying for their bid.

The winner can claim their reward by calling the claimReward function. The contract simply mints an ERC721 token specified in the Auction Factory. The winner does not need to send any Ether as the contract simply takes the bid amount from their stake.

Finally, the creator of the auction can withdraw the winner’s stake.

Helper Functions (Optional):

Design Considerations:

This design has several limitations. First, the staking mechanism adds complexity for users as it presents an extra step to the bidding process. However, if we did not include this system, an address could otherwise bid an extremely high value, become the winner, and not claim the reward — causing the auction to stay in limbo.

Next, since the callable function cannot access contract state in the current release of Enigma, we have to send the stake amounts of each user as an argument to the callback function. This causes the dApp to become an oracle to the Enigma network since it is responsible for retrieving these stake amounts. In a future release, Enigma nodes will be able to call view functions of Ethereum contracts in order to address this dependency.

Finally, in order to simplify the code, we decided to mint the auction reward. In the future, we expect that this mechanism will include adding an existing NFT to the auction contract as the item being auctioned.

Conclusion:

That’s it for now! We hope you try out this guide to secret auctions for yourself. If you have any solutions to the issues mentioned above or thoughts on our implementation or this walkthrough, we would leave to hear your feedback on our Developer Forum.

If you would like to see the full contract, check out this link: https://github.com/enigmampc/secret-contracts/blob/master/contracts/Auction.sol