Skip to content

feat(escrow): make every transfer free, fund cross-payer deposits, and let Root withdraw protocol fees - #338

Open
re-gius wants to merge 3 commits into
masterfrom
re-gius/deposits-only
Open

re-gius wants to merge 3 commits into
masterfrom
re-gius/deposits-only

Conversation

@re-gius

@re-gius re-gius commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Fixes #337. Fees went into DotnsNameEscrow.protocolFees, which nothing could spend. This removes every source of that pot and gives governance a way to move out what is already there (30 DOT on Polkadot Asset Hub, 20 PAS on Paseo).

Cross-payer registrations lock a deposit for the owner. When someone pays for another account's registration, the price used to go to the fee pot and the owner got a zero-amount position. _settleEscrow now locks the charge as the owner's refundable deposit, whoever pays. depositProtocolFee and ProtocolFeeDepositParams are removed.

Every transfer is free. A transfer no longer costs the name's price when the recipient is below the name's band or the sender's tier, granted names included. The bands apply at registration only. The deposit still moves with the name: chargeTransferFee becomes a non-payable rebindPosition(tokenId, to). PopRules.transferFloor, DotnsRegistrar.quoteTransferFee and their helpers are removed, and so are _creditRefund and RefundCredited, which only transfer overpayments used. Existing refund entries stay claimable.

Transfers are no longer payable. The registrar's transfer overrides only existed to forward a fee. They are removed, so the registrar uses OpenZeppelin's non-payable functions, and a transfer that sends value fails. That made the OpenZeppelin payable patches unnecessary: patches/, scripts/shell/apply-oz-patches.sh, its setup.bash call and the CI steps that ran it are removed. So is the gas-report step that copied the PR head's patches to build master.

Root can withdraw protocol fees. withdrawProtocolFees(address to, uint256 amount) moves part or all of protocolFees to an address governance chooses. It checks SystemUtils.originIsRoot(), like the other Root gates. It can spend only the fee balance: deposits, pending withdrawals and refund entries stay out of reach.

Type

  • Bug fix
  • Feature
  • Breaking change
  • Documentation
  • Chore
  • Refactor
  • Security

Scope

  • Registration
  • Resolver
  • Store
  • Proof of Personhood
  • Deployment scripts
  • Tests

Related Issues

#337

Fixes

Closes #337 and #336

Checklist

Code

  • Follows project style
  • forge build passes
  • forge test passes
  • No new compiler warnings

Testing

  • New tests added for changed behavior
  • Fuzz tests added where applicable
  • Invariant tests verified

Security

  • No new selfdestruct or delegatecall
  • Access control reviewed
  • No storage layout conflicts (for upgradeable contracts)

Documentation

  • NatSpec updated on changed interfaces
  • README updated if needed

Breaking Changes

  • No breaking changes
  • Breaking changes documented below

Breaking changes:

  • Removed: IDotnsRegistrar.quoteTransferFee, TransferFeeRequired, IPopRules.transferFloor, IDotnsNameEscrow.chargeTransferFee, ChargeTransferFeeParams, depositProtocolFee, ProtocolFeeDepositParams, CrossTierFeePaid, RefundCredited and InsufficientValue.
  • Added: IDotnsNameEscrow.rebindPosition, withdrawProtocolFees, ProtocolFeesWithdrawn, NotRoot, ProtocolFeesExceeded and ProtocolFeeTransferFailed.
  • transferFrom and both safeTransferFrom overloads are no longer payable.
  • A cross-payer registration now leaves a funded position (amount equal to the price) for the owner.

How to test

forge test --mt "withdrawProtocolFees|cross_payer|transfer_below_band_is_free|band_gated_downgrade|transfer_reverts_with_attached_value"
forge test --mc DotnsNameEscrowInvariant

Notes

Upgrade the DotnsRegistrar, DotnsNameEscrow, PopRules and DotnsRegistrarController proxies together, in one atomic Utility.batch_all from the owner account. The current registrar calls chargeTransferFee and transferFloor, and the new one calls rebindPosition, so upgrading any of the first three alone makes transfers revert. Storage layout is unchanged and no initializer runs. Then re-declare each key's codehash and the protocol version, as DEPLOYMENT_CHECKLIST.md describes.

After the upgrade, a Root referendum can call withdrawProtocolFees to move out the existing balance (30 DOT on Polkadot Asset Hub, 20 PAS on Paseo). dotns-sdk needs a follow-up to stop quoting fees and attaching value to transfers.

@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

CI Summary

Check Result
4naly3er Analysis Found 36 issues: 4 medium, 7 low, 13 gas, 12 informational - View Report
Slither Analysis Found 178 issues: 4 high, 39 medium, 74 low, 60 informational - View Report
Contract Tests (Unit + Fuzz) All tests passed (720 total) - View Report
Contract Tests (Invariant) All tests passed (59 total) - View Report
Gas Report 9 contracts analyzed - View Report
Coverage Failed - Tests failed, cannot compute coverage
Documentation Passed - 67 pages generated - View Docs
Format & Lint Passed - Code formatted correctly
File Validation Passed - All tracked files valid
Deploy Contracts Reproduces the expected address set; resume verified
PR Title PR Title Valid
Labels Unknown
Secret Scan Passed - No secrets detected

@re-gius re-gius changed the title feat(escrow): lock cross-payer registrations as deposits and make open-name transfers free feat(escrow): make every transfer free, fund cross-payer deposits, and let Root withdraw protocol fees Oct 13, 2026
@re-gius
re-gius marked this pull request as ready for review October 13, 2026 14:50
@re-gius
re-gius requested a review from a team as a code owner October 13, 2026 14:50
# Conflicts:
#	README.md
#	contracts/escrow/DotnsNameEscrow.sol
#	contracts/registrars/DotnsRegistrarController.sol

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants