Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch Auction Bid & Settlement #20

Merged
merged 124 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 108 commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
d01ceec
feat: off-chain auction settlement first pass
Oighty Jan 11, 2024
50ddf94
refactor: make settle params into struct
Oighty Jan 11, 2024
e582077
chore: run linter
Oighty Jan 11, 2024
209414d
wip: separate external and local settlement
Oighty Jan 17, 2024
c25ee5f
Merge branch 'jem/atomic-auctions' into jem/batch-auctions
0xJem Jan 18, 2024
ff5319d
Use pre-defined transfer functions. Linting. Compile fixes.
0xJem Jan 18, 2024
6d388ad
Rename internal function
0xJem Jan 18, 2024
82b2ef5
Comment improvements
0xJem Jan 18, 2024
3605cde
Extract shared functions. Partial implementation of AuctionHouse.bid()
0xJem Jan 18, 2024
9ea9196
Reconcile signatures for bid functions
0xJem Jan 18, 2024
7bc9988
Add settle function for local storage, external settlement
0xJem Jan 18, 2024
be3c092
Shift to _isAllowed() function
0xJem Jan 18, 2024
b9f3479
Shift fee implementation
0xJem Jan 18, 2024
824eb90
Adjust bid/settle signatures. Remove unused functions.
0xJem Jan 19, 2024
c7b701c
wip: initial LSBBA implementation (not complete)
Oighty Jan 19, 2024
0506ec1
feat: LSBBA updates
Oighty Jan 20, 2024
4b97dcb
feat: add priority queue implementation to LSSBA
Oighty Jan 20, 2024
eb9c1ae
feat: add settlement function to LSBBA
Oighty Jan 20, 2024
55acd28
feat: add auction, cancelAuction, and claimRefund functions to LSBBA
Oighty Jan 21, 2024
5fb4ca4
Notes
0xJem Jan 22, 2024
c7c6911
Merge branch 'jem/batch-auctions' of github.com:Bond-Protocol/moonrak…
0xJem Jan 22, 2024
89e47c2
chore: linting
0xJem Jan 22, 2024
8ff6fc7
Complete migration of lotId to uint96. Fix compilation errors.
0xJem Jan 22, 2024
114334a
Fix stack too deep error
0xJem Jan 22, 2024
681be7b
Rename test file
0xJem Jan 22, 2024
5651472
Revert "Rename test file"
0xJem Jan 22, 2024
214a6f5
Tests for bid()
0xJem Jan 22, 2024
9df2923
Adjust type for auctionParam
0xJem Jan 22, 2024
bbb1f80
Documentation
0xJem Jan 22, 2024
11803e3
Document behaviour
0xJem Jan 22, 2024
da6dbe6
Add stub for claimRefund(). Consistent type for bidId.
0xJem Jan 22, 2024
09e0e24
Test for cancelBid()
0xJem Jan 22, 2024
84183c6
Remove redundant parameter to bid()
0xJem Jan 23, 2024
1a2793d
Merge branch 'master' into jem/batch-auctions
0xJem Jan 23, 2024
97808e0
Merge pull request #23 from Bond-Protocol/jem/batch-auctions
0xJem Jan 23, 2024
adf0c55
Finish tests for cancelBid()
0xJem Jan 23, 2024
f578982
Modifiers
0xJem Jan 23, 2024
5b9a305
Prevent auction lot cancellation when active. Fixes tests.
0xJem Jan 23, 2024
9e5c17c
Completes tests for cancelBid
0xJem Jan 23, 2024
740a210
Rename function
0xJem Jan 23, 2024
5182254
Revert "Prevent auction lot cancellation when active. Fixes tests."
0xJem Jan 23, 2024
5a0b303
Prevent LSBBA from being cancelled after start
0xJem Jan 23, 2024
5a7fbfc
Implement pre-funding when the auction module supports it
0xJem Jan 23, 2024
c56142b
Prevent double-transfer when purchasing from a pre-funded auction
0xJem Jan 23, 2024
31ebe35
chore: linting
0xJem Jan 23, 2024
bc0981a
Implementation and tests for claimBidRefund()
0xJem Jan 23, 2024
cd14b71
Stubs for claimAuctionRefund()
0xJem Jan 23, 2024
2aad0d2
Rename claimRefund() to claimBidRefund()
0xJem Jan 23, 2024
2a12f31
Stub for claimAuctionRefund()
0xJem Jan 23, 2024
0c09112
Comment
0xJem Jan 23, 2024
6438e0f
review: comments and minor changes
Oighty Jan 23, 2024
5f1ca55
Refund bids at the time of cancellation
0xJem Jan 24, 2024
69c2c22
Auction cancellation returns the pre-funded amount to the owner
0xJem Jan 24, 2024
f7daf58
Rename test file
0xJem Jan 24, 2024
988e2f6
Check for non-zero remaining capacity
0xJem Jan 24, 2024
96b6e75
Documentation
0xJem Jan 24, 2024
c196041
Implement pattern for implementation-specific logic with AuctionModule
0xJem Jan 24, 2024
838ba91
Implement pattern for standard and implementation logic when calling …
0xJem Jan 24, 2024
2880ed0
Remove redundant modifiers
0xJem Jan 24, 2024
8738b33
Implement standard and implementation-logic pattern for atomic purchases
0xJem Jan 24, 2024
9a18fad
Remove redundant settle() code
0xJem Jan 24, 2024
b71f3a4
Remove obsolete settle() function. Implement implementation-logic pat…
0xJem Jan 24, 2024
11fa1d7
Documentation
0xJem Jan 24, 2024
728ed12
Fix stack too deep error in RSA library
0xJem Jan 24, 2024
4cf3985
Tests for LSBBA auction creation
0xJem Jan 24, 2024
05299ca
feat: update and add event
Oighty Jan 24, 2024
cabed45
Shift auction creation to onlyInternal
0xJem Jan 25, 2024
3cf5659
LSBBA: Add tests for cancelAuction()
0xJem Jan 25, 2024
bf02f3f
Tests for LSBBA.bid()
0xJem Jan 25, 2024
ab859d1
chore: linting
0xJem Jan 25, 2024
ed3522b
Update TODOs
0xJem Jan 25, 2024
adcf9ff
Correct suffix
0xJem Jan 25, 2024
45b59d4
LSBBA: tests for cancelBid()
0xJem Jan 25, 2024
2fa8637
LSBBA: WIP tests for bid decryption
0xJem Jan 25, 2024
6e58aa0
Fix compiler error
0xJem Jan 25, 2024
843362a
fix: RSA impl errors
Oighty Jan 25, 2024
b0306f0
test: initial roundtrip test
Oighty Jan 25, 2024
e53ed4e
fix: minor simplification and linter
Oighty Jan 25, 2024
50f7499
fix: sorted function ref and sort ordering
Oighty Jan 25, 2024
71fdab1
test: fix decrypt and sort tests
Oighty Jan 25, 2024
7ccb23c
chore: run linter
Oighty Jan 25, 2024
8f109ac
feat: change encrypted bid storage design
Oighty Jan 26, 2024
d167173
chore: change lot and bid ids to be uint96
Oighty Jan 26, 2024
5200937
fix: add bid Id to array in _bid
Oighty Jan 26, 2024
bb49e73
test: decrypt test updates
Oighty Jan 26, 2024
678a314
note: TODO on minpriorityqueue
Oighty Jan 26, 2024
11bd95a
test: fix cancel test
Oighty Jan 26, 2024
a7c0fc6
chore: run linter
Oighty Jan 26, 2024
35d515c
Merge pull request #26 from Bond-Protocol/rsa-tests
0xJem Jan 26, 2024
269a76a
Cleanup, documentation
0xJem Jan 26, 2024
5628597
Add tests for MinPriorityQueue
0xJem Jan 26, 2024
39a0fc6
Corrections
0xJem Jan 26, 2024
5b33684
LSBBA: add tests for getNextBidsToDecrypt()
0xJem Jan 26, 2024
1c6206a
LSBBA: tests for settle()
0xJem Jan 26, 2024
54269ee
Trying to figure out MinPriorityQueue
0xJem Jan 26, 2024
a3db271
Add more extensive tests for MinPriorityQueue
0xJem Jan 26, 2024
59956a4
fix: rename queue to max
Oighty Jan 26, 2024
835ec70
feat: replace priority queue implementation
Oighty Jan 26, 2024
d62aa37
Add test for partial fill
0xJem Jan 29, 2024
def3a85
Function documentation. Tests for isLive()
0xJem Jan 29, 2024
7a9fb97
Remove remaining uint256 lotId references
0xJem Jan 29, 2024
cba176b
chore: linting
0xJem Jan 29, 2024
99dc9f0
Tests for settle() on AuctionHouse. partial fill remaining.
0xJem Jan 29, 2024
b2b9c77
Handle partial fills during settlement
0xJem Jan 29, 2024
9c2849d
Add refund of base token
0xJem Jan 29, 2024
5a344a7
Test for decimals
0xJem Jan 29, 2024
fc5d339
Add tests for different decimals
0xJem Jan 29, 2024
5d3115c
chore: cleanup TODOs in LSBBA
Oighty Jan 29, 2024
92f090b
Add tests for smaller and larger decimals
0xJem Jan 30, 2024
c678992
Pass quote and base token decimals to the auction module upon creation
0xJem Jan 30, 2024
c2779f7
Working decimals
0xJem Jan 30, 2024
7d4771e
De-uglify decimal code
0xJem Jan 30, 2024
57af8f2
Implement suggestion
0xJem Jan 30, 2024
d0034d5
Typo
0xJem Jan 30, 2024
f12e9b7
feat: add single getter for decrypt data
Oighty Jan 30, 2024
a1a27f1
Merge branch 'batch-auctions' of https://github.com/Bond-Protocol/moo…
Oighty Jan 30, 2024
c28eb65
refactor: pack variables in Lot struct
Oighty Jan 30, 2024
42c5c4f
refactor: simplify decimal scaling
Oighty Jan 30, 2024
63d5e7c
chore: remove unused file
Oighty Jan 30, 2024
e767184
Restore function documentation
0xJem Jan 31, 2024
af979c4
Add additional checks when pre-funding for capacityInQuote
0xJem Jan 31, 2024
be60e9d
chore: remove unused auction files
Oighty Jan 31, 2024
9ea5dae
Merge branch 'batch-auctions' of https://github.com/Bond-Protocol/moo…
Oighty Jan 31, 2024
a97c0ca
refactor: capacityInQuote + prefunding to Auctioneer
Oighty Jan 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
483 changes: 375 additions & 108 deletions src/AuctionHouse.sol

Large diffs are not rendered by default.

150 changes: 115 additions & 35 deletions src/bases/Auctioneer.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.19;

import {ERC20} from "lib/solmate/src/tokens/ERC20.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";

import {
fromKeycode,
Expand All @@ -27,30 +28,48 @@ import {IAllowlist} from "src/interfaces/IAllowlist.sol";
/// - Cancelling auction lots
/// - Storing information about how to handle inputs and outputs for auctions ("routing")
abstract contract Auctioneer is WithModules {
using SafeTransferLib for ERC20;

// ========= ERRORS ========= //

error InvalidParams();
error InvalidLotId(uint256 id_);
error InvalidLotId(uint96 id_);
error InvalidModuleType(Veecode reference_);
error NotAuctionOwner(address caller_);
error InvalidHook();
error UnsupportedToken(address token_);

// ========= EVENTS ========= //

event AuctionCreated(uint256 id, address baseToken, address quoteToken);
event AuctionCreated(
uint96 id, Veecode indexed auctionRef, address baseToken, address quoteToken
);
event AuctionCancelled(uint96 id, Veecode indexed auctionRef);

// ========= DATA STRUCTURES ========== //

/// @notice Auction routing information for a lot
/// @notice Auction routing information for a lot
/// @param auctionReference Auction module, represented by its Veecode
/// @param owner Lot owner
/// @param baseToken Token provided by seller
/// @param quoteToken Token to accept as payment
/// @param hooks (optional) Address to call for any hooks to be executed
/// @param allowlist (optional) Contract that implements an allowlist for the auction lot
/// @param derivativeReference (optional) Derivative module, represented by its Veecode
/// @param derivativeParams (optional) abi-encoded data to be used to create payout derivatives on a purchase
/// @param wrapDerivative (optional) Whether to wrap the derivative in a ERC20 token instead of the native ERC6909 format
/// @param prefunded Set by the auction module if the auction is prefunded
struct Routing {
Veecode auctionReference; // auction module, represented by its Veecode
address owner; // market owner. sends payout tokens, receives quote tokens
ERC20 baseToken; // token provided by seller
ERC20 quoteToken; // token to accept as payment
IHooks hooks; // (optional) address to call for any hooks to be executed on a purchase. Must implement IHooks.
IAllowlist allowlist; // (optional) contract that implements an allowlist for the market, based on IAllowlist
Veecode derivativeReference; // (optional) derivative module, represented by its Veecode. If not set, no derivative will be created.
bytes derivativeParams; // (optional) abi-encoded data to be used to create payout derivatives on a purchase
bool wrapDerivative; // (optional) whether to wrap the derivative in a ERC20 token instead of the native ERC6909 format.
Veecode auctionReference;
address owner;
ERC20 baseToken;
ERC20 quoteToken;
IHooks hooks;
IAllowlist allowlist;
Veecode derivativeReference;
bytes derivativeParams;
bool wrapDerivative;
bool prefunded;
}

/// @notice Auction routing information provided as input parameters
Expand All @@ -74,10 +93,10 @@ abstract contract Auctioneer is WithModules {
uint48 internal constant _ONE_HUNDRED_PERCENT = 1e5;

/// @notice Counter for auction lots
uint256 public lotCounter;
uint96 public lotCounter;

/// @notice Mapping of lot IDs to their auction type (represented by the Keycode for the auction submodule)
mapping(uint256 lotId => Routing) public lotRouting;
mapping(uint96 lotId => Routing) public lotRouting;

/// @notice Mapping auction and derivative references to the condenser that is used to pass data between them
mapping(Veecode auctionRef => mapping(Veecode derivativeRef => Veecode condenserRef)) public
Expand All @@ -89,13 +108,22 @@ abstract contract Auctioneer is WithModules {
/// @dev Reverts if the lot ID is invalid
///
/// @param lotId_ ID of the auction lot
modifier isValidLot(uint256 lotId_) {
modifier isLotValid(uint96 lotId_) {
if (lotId_ >= lotCounter) revert InvalidLotId(lotId_);

if (lotRouting[lotId_].owner == address(0)) revert InvalidLotId(lotId_);
_;
}

/// @notice Checks that the caller is the auction owner
/// @dev Reverts if the caller is not the auction owner
///
/// @param lotId_ ID of the auction lot
modifier isLotOwner(uint96 lotId_) {
if (msg.sender != lotRouting[lotId_].owner) revert NotAuctionOwner(msg.sender);
_;
}

// ========== AUCTION MANAGEMENT ========== //

/// @notice Creates a new auction lot
Expand All @@ -116,7 +144,7 @@ abstract contract Auctioneer is WithModules {
function auction(
RoutingParams calldata routing_,
Auction.AuctionParams calldata params_
) external returns (uint256 lotId) {
) external returns (uint96 lotId) {
// Load auction type module, this checks that it is installed.
// We load it here vs. later to avoid two checks.
AuctionModule auctionModule = AuctionModule(_getLatestModuleIfActive(routing_.auctionType));
Expand All @@ -131,9 +159,11 @@ abstract contract Auctioneer is WithModules {
lotId = lotCounter++;

// Auction Module
bool requiresPrefunding;
uint256 lotCapacity;
{
// Call module auction function to store implementation-specific data
auctionModule.auction(lotId, params_);
(requiresPrefunding, lotCapacity) = auctionModule.auction(lotId, params_);
}

// Validate routing parameters
Expand Down Expand Up @@ -231,24 +261,74 @@ abstract contract Auctioneer is WithModules {
routing.hooks = routing_.hooks;
}

emit AuctionCreated(lotId, address(routing.baseToken), address(routing.quoteToken));
// Perform pre-funding, if needed
if (requiresPrefunding) {
// Store pre-funding information
routing.prefunded = true;

// TODO copied from AuctionHouse. Consider consolidating.
// Get the balance of the base token before the transfer
uint256 balanceBefore = routing_.baseToken.balanceOf(address(this));

// Call hook on hooks contract if provided
if (address(routing_.hooks) != address(0)) {
// The pre-auction create hook should transfer the base token to this contract
routing_.hooks.preAuctionCreate(lotId);

// Check that the hook transferred the expected amount of base tokens
if (routing_.baseToken.balanceOf(address(this)) < balanceBefore + lotCapacity) {
revert InvalidHook();
}
}
// Otherwise fallback to a standard ERC20 transfer
else {
// Transfer the base token from the auction owner
// `safeTransferFrom()` will revert upon failure or the lack of allowance or balance
routing_.baseToken.safeTransferFrom(msg.sender, address(this), lotCapacity);

// Check that it is not a fee-on-transfer token
if (routing_.baseToken.balanceOf(address(this)) < balanceBefore + lotCapacity) {
revert UnsupportedToken(address(routing_.baseToken));
}
}
}

emit AuctionCreated(
lotId, auctionRef, address(routing_.baseToken), address(routing_.quoteToken)
);
}

/// @notice Cancels an auction lot
/// @dev The function reverts if:
/// - The caller is not the auction owner
/// @dev This function performs the following:
/// - Checks that the lot ID is valid
/// - Checks that caller is the auction owner
/// - Calls the auction module to validate state, update records and determine the amount to be refunded
/// - If prefunded, sends the refund of payout tokens to the owner
///
/// The function reverts if:
/// - The lot ID is invalid
/// - The caller is not the auction owner
/// - The respective auction module reverts
/// - The transfer of payout tokens fails
///
/// @param lotId_ ID of the auction lot
function cancel(uint256 lotId_) external isValidLot(lotId_) {
// Check that caller is the auction owner
if (msg.sender != lotRouting[lotId_].owner) revert NotAuctionOwner(msg.sender);

function cancel(uint96 lotId_) external isLotValid(lotId_) isLotOwner(lotId_) {
AuctionModule module = _getModuleForId(lotId_);

// Get remaining capacity from module
uint256 lotRemainingCapacity = module.remainingCapacity(lotId_);

// Cancel the auction on the module
module.cancel(lotId_);
module.cancelAuction(lotId_);

// If the auction is prefunded, transfer the remaining capacity to the owner
if (lotRouting[lotId_].prefunded && lotRemainingCapacity > 0) {
// Transfer payout tokens to the owner
Routing memory routing = lotRouting[lotId_];
routing.baseToken.safeTransfer(routing.owner, lotRemainingCapacity);
0xJem marked this conversation as resolved.
Show resolved Hide resolved
}

emit AuctionCancelled(lotId_, lotRouting[lotId_].auctionReference);
}

// ========== AUCTION INFORMATION ========== //
Expand All @@ -259,56 +339,56 @@ abstract contract Auctioneer is WithModules {
///
/// @param id_ ID of the auction lot
/// @return routing Routing information for the auction lot
function getRouting(uint256 id_) external view isValidLot(id_) returns (Routing memory) {
function getRouting(uint96 id_) external view isLotValid(id_) returns (Routing memory) {
// Get routing from lot routing
return lotRouting[id_];
}

// TODO need to add the fee calculations back in at this level for all of these functions
function payoutFor(uint256 id_, uint256 amount_) external view returns (uint256) {
function payoutFor(uint96 id_, uint256 amount_) external view returns (uint256) {
AuctionModule module = _getModuleForId(id_);

// Get payout from module
return module.payoutFor(id_, amount_);
}

function priceFor(uint256 id_, uint256 payout_) external view returns (uint256) {
function priceFor(uint96 id_, uint256 payout_) external view returns (uint256) {
AuctionModule module = _getModuleForId(id_);

// Get price from module
return module.priceFor(id_, payout_);
}

function maxPayout(uint256 id_) external view returns (uint256) {
function maxPayout(uint96 id_) external view returns (uint256) {
AuctionModule module = _getModuleForId(id_);

// Get max payout from module
return module.maxPayout(id_);
}

function maxAmountAccepted(uint256 id_) external view returns (uint256) {
function maxAmountAccepted(uint96 id_) external view returns (uint256) {
AuctionModule module = _getModuleForId(id_);

// Get max amount accepted from module
return module.maxAmountAccepted(id_);
}

function isLive(uint256 id_) external view returns (bool) {
function isLive(uint96 id_) external view returns (bool) {
AuctionModule module = _getModuleForId(id_);

// Get isLive from module
return module.isLive(id_);
}

function ownerOf(uint256 id_) external view returns (address) {
function ownerOf(uint96 id_) external view returns (address) {
// Check that lot ID is valid
if (id_ >= lotCounter) revert InvalidLotId(id_);

// Get owner from lot routing
return lotRouting[id_].owner;
}

function remainingCapacity(uint256 id_) external view returns (uint256) {
function remainingCapacity(uint96 id_) external view returns (uint256) {
AuctionModule module = _getModuleForId(id_);

// Get remaining capacity from module
Expand All @@ -323,7 +403,7 @@ abstract contract Auctioneer is WithModules {
/// - The module for the auction type is not installed
///
/// @param lotId_ ID of the auction lot
function _getModuleForId(uint256 lotId_) internal view returns (AuctionModule) {
function _getModuleForId(uint96 lotId_) internal view returns (AuctionModule) {
// Confirm lot ID is valid
if (lotId_ >= lotCounter) revert InvalidLotId(lotId_);

Expand Down
2 changes: 1 addition & 1 deletion src/bases/Derivatizer.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.19;

import {WithModules, Veecode} from "src/modules/Modules.sol";
import {WithModules} from "src/modules/Modules.sol";

abstract contract Derivatizer is WithModules {
// ========== DERIVATIVE MANAGEMENT ========== //
Expand Down
13 changes: 10 additions & 3 deletions src/interfaces/IHooks.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ pragma solidity >=0.8.0;
/// @title IHooks
/// @notice Interface for hook contracts to be called during auction payment and payout
interface IHooks {
/// @notice Called before auction creation
/// @notice Requirements:
/// - If the lot is pre-funded, the hook must ensure that the auctioneer has the required balance of base tokens
///
/// @param lotId_ The auction's lot ID
function preAuctionCreate(uint96 lotId_) external;

/// @notice Called before payment and payout
/// TODO define expected state, invariants
function pre(uint256 lotId_, uint256 amount_) external;
function pre(uint96 lotId_, uint256 amount_) external;

/// @notice Called after payment and before payout
/// TODO define expected state, invariants
function mid(uint256 lotId_, uint256 amount_, uint256 payout_) external;
function mid(uint96 lotId_, uint256 amount_, uint256 payout_) external;

/// @notice Called after payment and after payout
/// TODO define expected state, invariants
function post(uint256 lotId_, uint256 payout_) external;
function post(uint96 lotId_, uint256 payout_) external;
}
Loading
Loading