Axis-Fi / axis-core

Axis Protocol
https://axis.finance
Other
6 stars 1 forks source link

Auction House: Auction Creation and Management #5

Closed Oighty closed 7 months ago

Oighty commented 9 months ago

Auction creation is the process for token sellers on the platform. While the platform is designed to support a variety of Auctions and Derivatives, the core auction creation process is the same for them all.

The auction function takes two inputs: RoutingParams and AuctionParams.

RoutingParams are defined on the Auctioneer abstract and implemented on the AuctionHouse. Each auction must specify a quote token (that the buyer will provide) and a base token (that the seller will provide). In addition to the tokens, every auction has routing data that must be provided, much of which is optional, including a Hooks implementation, Allowlist, and Derivative type & data. Routing data is stored on the AuctionHouse.

AuctionParams are defined in the Auction module abstract and include data only needed by the Auction module to determine payout and other output calculations. The common fields across all Auction types are: start, conclusion, capacity, and amounts sold/purchased. Each auction implementation can also specify additional fields that are required as parameters and stored on the Auction module.

The cancel function is used to immediately stop an active Auction. In the case of an Atomic auction, no more purchases can be made. In the case of a Batch auction, the auction cannot be settled.

0xJem commented 8 months ago

I'm working my way through auction (creation) and have a few questions/comments:

1. I think it makes sense for the modules to have a validate function (DerivativeModule already has it) that revert if there's an issue

2. How do you think the CondenserModule should check for compatibility? We did discuss approaches, but I don't think we decided.

Options:

  1. Auctioneer has a mapping of compatible AuctionModule and DerivativeModule Veecode pairings for each CondenserModule
  2. Each individual CondenserModule has a mapping

Approach 2 seems to make it more self-contained.

The other approach is to select the CondenserModule based on the AuctionModule and DerivativeModule specified.

3. We could additionally implement a validate function on the CondenserModule. Any thoughts on what it would take as parameters? AuctionModule Veecode and DerivativeModule Veecode, for starters.

4. Do the validate functions on the AuctionModule and DerivativeModule need to be generic bytes, or can it be more specific structs? I would think AuctionModule would need the auction parameters and DerivativeModule the derivative parameters, which means we could add the struct type to the function parameter.

Oighty commented 8 months ago

Going to reply in order:

  1. The Auction modules don't need a validate function because they are being called directly with module.auction and can validate the inputs in that function. The reason we need it on the Derivative is so that we can confirm the parameters are valid before the Auction is actually created (the auction function doesn't create a derivative or call the derivative module otherwise).
  2. I may be misunderstanding the options, but my gut is neither. I think we should just track a mapping of Auction => Derivative => Condenser on the AuctionHouse. Therefore, each combination has a single canonical condenser that maps the inputs. If no Condenser is installed, it's assumed the pair doesn't need one. We would maybe need another function on the AuctionHouse called setCondenser(Module auction_, Module derivative_) to set this data.
  3. I'm not sure this is needed. Will think about it more though.
  4. The reason I had made derivative.validate accept generic bytes is because you don't know what the inputs are to any given derivative. Auctions have some standard parameters, but I mentioned above that we can validate these when calling auction.

I had made some changes to these contracts in the clean-up branch that had also included some other stuff. I'm going to compare those and your branch this afternoon. I will probably make a few commits that will clarify some of this.

0xJem commented 8 months ago

On the condenser... if there's an auction keycode -> derivative keycode -> condenser keycode mapping, isn't the condenser type (keycode) as part of the routing parameters redundant?

Or is it more like one can specify the condenser (as an override), but if it is not defined, the default lookup will be used?

If so, and the condenser is defined, how can we be sure that it is compatible with the auction and derivative modules? Or we assume that it will fail...?

0xJem commented 8 months ago

Allowlist:

0xJem commented 8 months ago

Hooks:

Oighty commented 8 months ago

On the condenser... if there's an auction keycode -> derivative keycode -> condenser keycode mapping, isn't the condenser type (keycode) as part of the routing parameters redundant?

Or is it more like one can specify the condenser (as an override), but if it is not defined, the default lookup will be used?

If so, and the condenser is defined, how can we be sure that it is compatible with the auction and derivative modules? Or we assume that it will fail...?

Yeah, this is a good callout. I ended up adding the mapping and removing this on the clean-up branch.

Oighty commented 8 months ago

For both Allowlist and Hooks, I was planning to treat them as we treated Callbacks in the past, which is that the user is responsible for making sure they conform to the interface and function as expected. We treat them as a black box.

On the Allowlist specifically, we will need to update the user-facing functions (purchase, bid, settle variant that accepts bids) to take inputs that can be used to do allowlist verification, specifically a bytes proof parameter that could be used to pass in something like a Merkle Proof. See https://github.com/Bond-Protocol/options/blob/033a67da8a592847994e27f431cd0c480e01db93/src/fixed-strike/liquidity-mining/OLM.sol#L310.

Oighty commented 8 months ago

I need to think through a specific scenario where a seller could prevent a batch auction from settling by invalidating the allowlist. It may be better in that case to check it off-line before accepting bids into the off-chain database, but that might have issues as well.

Oighty commented 8 months ago
  • Do you expect the auction to register the lotId with the allowlist by calling register(lotId, params)?

Yes, there is a placeholder for this at the bottom of the Auctioneer.auction function.

Oighty commented 7 months ago

It turns out that for Batch Auctions, we're going to need the creator (seller) to fund the auction up front (either directly or via hook). The reason is that they can brick the auction later if they decide they don't want to do it. This has some ramifications on the createAuction function and creates a notion of Auctions that must be pre-funded vs. those that don't. I haven't thought through the different solutions, but an option is to return a flag from the module.createAuction call on whether pre-funding is required.

Separately, we determined it would be best to only allow cancellations on a batch auction before it has started. This is to not cause users to waste gas and have to force them to claim refunds (you can't force seller to on cancel because it could run out of gas).

0xJem commented 7 months ago

Separately, we determined it would be best to only allow cancellations on a batch auction before it has started. This is to not cause users to waste gas and have to force them to claim refunds (you can't force seller to on cancel because it could run out of gas).

This is done.

Actually... I misread your comment about it being batch auctions only (😭). This has been implemented in LSBBA._cancelAuction() instead.

0xJem commented 7 months ago

It turns out that for Batch Auctions, we're going to need the creator (seller) to fund the auction up front (either directly or via hook). The reason is that they can brick the auction later if they decide they don't want to do it. This has some ramifications on the createAuction function and creates a notion of Auctions that must be pre-funded vs. those that don't. I haven't thought through the different solutions, but an option is to return a flag from the module.createAuction call on whether pre-funding is required.

Agreed on the module.createAuction return value.

If an auction is pre-funded, can it be cancelled? There would need to be a mechanism to claim the pre-funded amount. If an auction is pre-funded and the full capacity is not utilised, there would need to be a mechanism to claim the un-utilised amount.

0xJem commented 7 months ago

Pre-funding upon auction creation (if required by the auction module) is done. If a lot is pre-funded and atomic, at the time of purchase it also will not transfer the payout token from the owner again. It will also respect this when settling a batch auction, but that isn't yet tested.