Repository navigation
feat: make reserved name releasable - #334
Conversation
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
CI Summary
|
Signed-off-by: GHkrishna <krishna@parity.io>
re-gius
left a comment
There was a problem hiding this comment.
The description could say that the fix covers new mints, and that testnet names minted through registerReserved before this upgrade stay unreleasable. Two reclaim cases have no test: a reclaim under Root (the existing test reclaims through a grant), and reclaiming a long label that still holds a refundable deposit, which should credit the previous holder's pull-payment balance.
| registration, labelhash, node, 0, false, IDotnsReverseResolver(address(0)), isReclaim | ||
| ); | ||
|
|
||
| // One deliberate divergence from @custom:function register, which also clears a sibling |
There was a problem hiding this comment.
registerReserved should clear a stale base-name reservation on reclaim, the same way register does, before _reclaimFromEscrow. Root calling this function doesn't prevent that: PopRules sees this controller as msg.sender, and releaseReservationForReclaim already accepts registrar controllers. This frame still must not read msg.sender, so read the escrow position's recipient first (reclaim deletes the position) and clear only when that recipient owns the reservation.
Otherwise the previous holder's slot stays live for up to 12 weeks after the name moved on.
The comment above this block should go too, since the Root constraint it describes doesn't apply.
I would suggest moving register's clean-up into a shared helper that both paths call before reclaiming, so they cannot drift apart again, and a test that reclaims through registerReserved under both Root and a grant would cover it.
There was a problem hiding this comment.
Nice catch. Agreed.
Added _clearStaleReservation as a separate helper that both paths call, rather than folding it into _reclaimFromEscrow. In register it has to run before the price check, because priceWithCheck enforces reservations against the new owner and a leftover slot would revert the registration, while _reclaimFromEscrow runs after pricing. In registerReserved it runs right before the reclaim. Also removed the Root comment and added tests for reclaim under Root and a grant, the stale reservation being cleared, a reservation held by someone else surviving, and a long label’s deposit being credited to the previous holder.
Signed-off-by: GHkrishna <krishna@parity.io>
Signed-off-by: GHkrishna <krishna@parity.io>
Description
A name issued through a governance grant could never be released by its holder.
registerReservedminted the name and stopped there. It never opened an escrow release position, andDotnsNameEscrow.releaserefuses any token that has no position recorded against it. So the holder was stuck with the name whether they wanted it or not, which means it never became reclaimable and into circulation. That matters most for short names, because a grant is the only way to mint them.The fix is to seed a zero-amount position on the mint, which is exactly what the cross-payer branch of
registeralready does. A grant is free, so there is no deposit to lock, but the position is also the marker that says "this name has a lifecycle", andreleasereads it.There is a second part.
availablereports true both for a label nobody has minted and for one the escrow is still holding after its redeem window closed, andDotnsRegistrar.registerrefuses to mint an id the escrow holds. SoregisterReservedwould have reverted on a name that had come back around. Seeding the position without fixing that would have left reserved-tier labels sitting in escrow, advertised as free, with nothing able to take them, becauseregisterturns those labels away.registerReservednow reclaims from escrow when the token already exists, the same wayregisterdoes.While doing that, the reclaim sequence and the position seeding were pulled into two small shared helpers (
_reclaimFromEscrowand_seedReleasePosition) so both registration paths go through one copy of each. The reclaim ordering is load bearing: the registry write has to come afterescrow.reclaim, becausesetOwnerchecksownerOfand would otherwise see the escrow. Keeping one copy means one place to get that right. It also took about 290 bytes off the controller.This fixes new mints only. Names minted through registerReserved before this upgrade have no escrow position and stay unreleasable, and there is no way to backfill one.
Type
Scope
Related Issues
#330
Fixes
Fixes #330
Checklist
Code
forge buildpassesforge testpassesTesting
Security
selfdestructordelegatecallDocumentation
Breaking Changes
Breaking changes:
How to test
Notes
registerReservednow reads the escrow, sonameEscrowhas to be set in the protocol registry or it reverts withEscrowNotConfigured. The wiring stage already sets it, so a normal deploy is fine.DEPLOYMENT_CHECKLIST.mdnow lists it next to thenameWhitelistcheck.No new fuzz tests. The property here is that a piece of state exists after a mint, not that some input range behaves, so the coverage is an invariant over the whole minted set plus unit tests.
One difference from
registeron purpose: that path also clears a sibling controller's stale base-name reservation before reclaiming, and this one does not. Doing it would mean readingIPopRulesfromregisterReserved, which would cost the function its Root callability. It is commented at the reclaim branch.No
owner != escrowguard on the reclaim branch because it is not reachable:reclaimmoves the token withsafeTransferFrom, which fires the escrow's ownonERC721Received, and that requires a positionreclaimhas already deleted, so the call revertsUnsolicitedDeposit.A reclaim through registerReserved now clears a base-name reservation that the previous holder still owns, the same as register. Both paths share one helper.