Settle Auction
This guide will provide steps for settling a batch auction through direct integration with the contracts. This particular guide will use the EncryptedMarginalPrice auction module, which keeps the amount out of each bid a secret until after the conclusion of the auction lot.
Setup
First, define the BatchAuctionHouse that will be used. This should correspond to the same BatchAuctionHouse in which the auction lot was created.
// Define the deployed BatchAuctionHouse
IBatchAuctionHouse auctionHouse = IBatchAuctionHouse(_batchAuctionHouse);
Inputs
We obtain from the LOT_ID
environment variable the lot ID that identifies
each auction lot. The lot ID is a uint96
number, so should be checked before
being downcast.
// Obtain the lot from the environment variable
uint256 lotIdRaw = vm.envUint("LOT_ID");
if (lotIdRaw > type(uint96).max) {
revert("LOT_ID must be less than uint96 max");
}
uint96 lotId = uint96(lotIdRaw);
The lot ID is returned from the auction creation function. See the Create Auction Guide for more details.
Private Key Submission
The auction module (in this case, EncryptedMarginalPrice
) will be used
a few times, so cache the module address.
// Load the EMP module
address moduleAddress = address(auctionHouse.getModuleForId(lotId));
EncryptedMarginalPrice auctions require the auction's private key to be submitted after conclusion of the auction. This enables bid decryption and eventual settlement. Axis provides a key management service that custodies the key and exposes it at the appropriate time.
Assuming that the key has been released, we submit the key to the auction module:
// Submit the private key
// The call can be performed by anyone
{
uint256 privateKey = vm.envUint("AUCTION_PRIVATE_KEY");
// Submit private key can decrypt the bids, but we will skip this
uint64 submitNumBids;
bytes32[] memory submitSortHints;
IEncryptedMarginalPrice(moduleAddress).submitPrivateKey(
lotId, privateKey, submitNumBids, submitSortHints
);
}
Bid Decryption
The next step is to decrypt the bids.
We first determine the number of bids to decrypt, as the result will be used a few times.
// Get the number of bids
uint256 numBids = IBatchAuction(moduleAddress).getNumBids(lotId);
In case there are a large number of bids, we divide the bids into batches of 100:
uint64 bidsPerBatch = 100;
After each bid is decrypted, it is inserted into a queue and sorted. Sort hints are used to reduce the gas consumption. We need to prepare an array of sort hints for each batch, set to the start (highest priority) in the queue.
// Prepare the sort hints
// This will not result in optimal gas usage
bytes32 queueStart =
0x0000000000000000ffffffffffffffffffffffff000000000000000000000001;
bytes32[] memory sortHints = new bytes32[](bidsPerBatch);
for (uint64 i = 0; i < bidsPerBatch; i++) {
sortHints[i] = queueStart;
}
In order to obtain the optimal hints, you can decrypt locally, iteratively build a copy of the bid queue and then find where the bid will be slotted in.
Alternatively, the Cloak API handles this.
We then decrypt and sort the bids:
// Decrypt the bids in 100-bid batches
// If the number of bids is less than 100,
// numBatches will be 0 due to integer division and rounding down
IEncryptedMarginalPrice empModule = IEncryptedMarginalPrice(moduleAddress);
uint256 numBatches = numBids / bidsPerBatch;
for (uint64 i = 0; i <= numBatches; i++) {
// The call can be performed by anyone
empModule.decryptAndSortBids(lotId, bidsPerBatch, sortHints);
}
Contract Call
The settle()
function calls the onSettle
callback, which may take input data.
As the callback is unused in this example, it can remain empty.
// Define callback data (unused)
bytes memory callbackData = abi.encode("");
Lastly, we call the settle()
function:
// Perform the settlement
// The call can be performed by anyone
auctionHouse.settle(lotId, numBids, callbackData);
console2.log("Settlement completed. Lot ID:", lotId);
It is worthwhile noting that the settle call may fail for the following reasons:
- The lot ID is invalid
- The lot is in a state that does not support settlement
Source Code
The source code for the guide is located in the settle.s.sol file.