-
Notifications
You must be signed in to change notification settings - Fork 3
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
feat(PE-6656) - return initiated dutch auctions #92
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #92 +/- ##
===========================================
+ Coverage 89.50% 90.07% +0.57%
===========================================
Files 8 9 +1
Lines 1724 1834 +110
===========================================
+ Hits 1543 1652 +109
- Misses 181 182 +1 ☔ View full report in Codecov by Sentry. |
This is so we can discern where tokens go when auctions (and other events) happen.
80b9792
to
6749531
Compare
General request to add events for this flow when the PR is approaching readiness for review. |
We will add the settings to the auction, including decayRate and scalingExponent so clients can dynamically compute prices.
@@ -278,7 +279,7 @@ function arns.assertValidBuyRecord(name, years, purchaseType, processId) | |||
assert(name:match("^%w") and name:match("%w$") and name:match("^[%w-]+$"), "Name pattern is invalid.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we have a util for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eventually
--- @param name string The name of the auction | ||
--- @param timestamp number The timestamp to start the auction | ||
--- @param initiator string The address of the initiator of the auction | ||
--- @return Auction|nil The auction instance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
function arns.getAuction(name) | ||
return NameRegistry.auctions[name] | ||
end | ||
|
||
function arns.getAuctions() | ||
return NameRegistry.auctions or {} | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the or {}
implies auctions could be undefined which would indicate that NameRegistry.auctions[name]
could attempt to index a nil value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it can be, if we don't update the state manually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we don't update the state manually
Is that the plan?
81070a3
to
aec2ee4
Compare
end) | ||
end) | ||
|
||
describe("getAuction", function() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could add a test for a missing auction
then | ||
local record = arns.getRecord(name) | ||
local isPermabuy = record ~= nil and record.type == "permabuy" | ||
local isActiveLease = record ~= nil and (record.endTimestamp or 0) + constants.gracePeriodMs > timestamp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: asserting the existence of the endTimestamp might be a little more robust.
@@ -48,18 +50,17 @@ function arns.buyRecord(name, purchaseType, years, from, timestamp, processId) | |||
type = purchaseType, | |||
undernameLimit = constants.DEFAULT_UNDERNAME_COUNT, | |||
purchasePrice = totalRegistrationFee, | |||
endTimestamp = purchaseType == "lease" and timestamp + constants.oneYearMs * years or nil, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lua's control flow in these scenarios freaks me out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I realize it's just a ternary but I wish they'd just use the same control characters as everyone else)
-- AUCTIONS | ||
|
||
--- Creates an auction for a given name | ||
--- @param name string The name of the auction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "the name being auctioned" otherwise this reads like it's an auction title
end | ||
|
||
-- assert the bid is between auction start and end timestamps | ||
if timestamp < auction.startTimestamp or timestamp > auction.endTimestamp then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should endTimestamp be inclusive?
|
||
-- assert the bid is between auction start and end timestamps | ||
if timestamp < auction.startTimestamp or timestamp > auction.endTimestamp then | ||
-- TODO: we should likely clean up the auction if it is outside of the time range |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prune should catch that IFF the endTimestamp is exclusive (i.e. prune would end an auction AT the end timestamp if they overlapped).
error("Bid timestamp is outside of auction start and end timestamps") | ||
end | ||
local requiredBid = auction:getPriceForAuctionAtTimestamp(timestamp, type, years) | ||
local requiredOrBidAmount = bidAmount or requiredBid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the objective here? Let callers NOT supply a bidAmount?
processId = processId, | ||
startTimestamp = timestamp, | ||
endTimestamp = type == "lease" and timestamp + constants.oneYearMs * years or nil, | ||
undernameLimit = constants.DEFAULT_UNDERNAME_COUNT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the record had previously increased its undername limit, is that lost in transition here?
arns.removeAuction(name) | ||
arns.addRecord(name, record) | ||
-- make sure we tally name purchase given, even though only half goes to protocol | ||
-- TODO: DO WE WANT TO TALLY THE ENTIRE AMOUNT OR JUST THE REWARD FOR THE PROTOCOL? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Entire amount IMO
function arns.pruneAuctions(currentTimestamp) | ||
local prunedAuctions = {} | ||
for name, auction in pairs(arns.getAuctions()) do | ||
if auction.endTimestamp <= currentTimestamp then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note here to make sure that end timestamp is handled consistently in various functions (inclusively or exclusively during bidding, pruning, etc.)
-- Default Auction Settings | ||
AuctionSettings = { | ||
durationMs = 60 * 1000 * 60 * 24 * 14, -- 14 days in milliseconds | ||
decayRate = 0.000000000016847809193121693, -- 0.02037911 / durationMs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this is 27 digits after the decimal so keep that in mind if passing across process boundaries.
}, | ||
} | ||
setmetatable(auction, self) | ||
self.__index = self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems there's some nuances to setting up the class this way (in the constructor) vs. separately. Will share chatGPT thread with you separately about it.
--- Computes the prices for the auction. | ||
--- @param type string The type of auction | ||
--- @param years number The number of years for calculation | ||
--- @param intervalMs number The interval in milliseconds, must be at least 15 minutes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to double check where the 15 minutes is enforced.
@@ -676,7 +679,14 @@ addEventingHandler(ActionMap.BuyRecord, utils.hasMatchingTag("Action", ActionMap | |||
ao.send({ | |||
Target = msg.From, | |||
Tags = { Action = "Buy-Record-Notice", Name = msg.Tags.Name }, | |||
Data = json.encode(record), | |||
Data = json.encode({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the material difference here?
local name = msg.Tags.Name | ||
local processId = msg.From | ||
local record = arns.getRecord(name) | ||
local initiator = msg.Tags.Initiator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we be getting this from a Forwarded-For tag or similar that's provided by the MU during message forwarding?
end | ||
|
||
-- we should be able to create the auction here | ||
local status, auctionOrError = pcall(arns.createAuction, name, tonumber(msg.Timestamp), initiator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's pretty much free to do these as eventingPcall
s now since we wrapped all the handlers.
return | ||
end | ||
|
||
local auction = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this step necessary?
local timestamp = tonumber(msg.Tags.Timestamp or msg.Timestamp) | ||
local type = msg.Tags.Type or "permabuy" | ||
local years = msg.Tags.Years and tonumber(msg.Tags.Years) or nil | ||
local intervalMs = msg.Tags["Price-Interval-Ms"] and tonumber(msg.Tags["Price-Interval-Ms"]) or 15 * 60 * 1000 -- 15 minute intervals by default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should enforce a minimum interval.
}) | ||
end) | ||
|
||
addEventingHandler("auctionBid", utils.hasMatchingTag("Action", ActionMap.AuctionBid), function(msg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we move away from Buy-Record as the one true path for acquiring names?
Summary:
Introduces and
Auction
object class that is used to store auctions on theNameRegistry
. We should look towards using more of these classes to leverage some better static analysis and type enforcement on functions. The class is responsible for computing prices based on the initialization details (baseFee, demandFactor, etc.). Auctions are stored as instances of this class, and returned as simple table (excluding function) so clients can compute prices themselves.This initial implementation includes handler support for ANTs returning
permabuy
name registrations. In a separate PR we'll introduce Lease-Expiration-Intiated-Auctions where a name will go in to auction after the grace period has ended.Checklist:
Release-Name
that allows integration with ANTsAuction-Info
to get auction information of a given nameAuction-Bid
to submit bid to acquire name in auction and update arns registryRelease-Name
handler that forwards to this processRelease-Name
notice to the pr… ar-io-ant-process#23TODOs:
Data
ends up being an empty table - not sure if this is a bug in AO or we are hitting a memory limit). it also costs ~600KiB to store those values in state, which could bloat our memory when several auctions are in process. we could consider just storing the settings of the auction pricing in state, and use that to calculate prices when necessary (still have to create the table, but response doesn't need to contain it). need to think more about this and what is necessary for clients to be able to showing pricing charts.Here is the sequence diagram for a permabuy initiated auction