[V136] REVSHARE: pay affiliates a share of their swap liquidity fees

Summary

Port THORNode's affiliate revenue share (REVSHARE, thornode b346a00207) to MAYAChain. From 1.136.0, governance can give a MAYAName a share of the swap liquidity fees its swaps generate, paid by the protocol on top of the affiliate fee the user pays.

Stacked on !892 (POL Reserve). Target branch: feat/v136-pol-reserve. Retarget to develop once !892 merges.

How it works

  • Attribution: the 1.136.0 swapper adds each swap's liquidity fee (CACAO) to a per-block accumulator (affiliate_liquidity_fee/) under the first memo affiliate. This only happens when that affiliate is an existing MAYAName with a positive REVSHARE-<mayaname> mimir. MAYA pool swaps are skipped: their fee goes to the auto buyer, not to system income.
  • Payout, off the top: at the start of UpdateNetwork the Reserve pays each entry REVSHARE bps × attributed fee / 10000 (capped at 5000 bps) to the affiliate collector module, credited to the MAYAName's collector. The pools return that amount to the Reserve together with the other shares. The 75/10/5/1/4/5 split then works on the fees left after REVSHARE, so every share shrinks proportionally.
  • Delivery: NetworkMgr.EndBlock runs the usual preferred asset check for each collector in the accumulator. Without a preferred asset the CACAO is released to the BASEChain alias or owner in the same block; otherwise it is swapped once it passes the threshold, like any other affiliate fee. It then clears the accumulator.
  • Event: rev_share with mayaname, owner, accrued_fee, bps, payout. One per attributed MAYAName per block. A name that expired since attribution gets an empty owner and a zero payout.

Example

A 1,000 CACAO swap with liquidity fee 80 CACAO, first affiliate dog, REVSHARE-dog=5000:

Destination Without REVSHARE With REVSHARE
dog (REVSHARE) — 40
Bond / LPs (75%) 60 30
MayaFund (10%) 8 4
CACAOPool (5%) 4 2
pol_reserve (5%) 4 2
MayaAutoBuyer (1%) 0.8 0.4
Reserve (4%) 3.2 1.6

Mimir

REVSHARE-<mayaname> (basis points, 0 to 5000) is an operational mimir, like THORNode.

  • A value of 0 or more needs an existing MAYAName; above 5000 is rejected.
  • A negative value deletes the key or withdraws a node vote, also after the MAYAName has expired.
  • MAYANames that contain + cannot be used: mimir keys allow only letters, digits, - and _.

Not attributed

  • Affiliate fee conversions: internal swaps that convert an affiliate cut to CACAO. They go to the affiliate collector module or to the MAYAName's BASEChain alias or owner, and their fee was already attributed on the user swap. A user swap to CACAO that pays out to the affiliate's own alias or owner is skipped the same way.
  • Affiliates that are not first: only the first memo affiliate counts.

Differences from THORNode

  • Only opted-in names accrue. THORNode writes an accumulator entry and emits an event for every swap whose first affiliate is a THORName, even with no REVSHARE mimir. Here the swapper checks the mimir first, so other affiliates add no state writes or events. The payout still reads the mimir again at the end of the block.
  • UpdateNetwork keeps its signature. THORNode changed it to take the manager, which here would touch every frozen network manager. Instead, the payout (keeper only) runs in UpdateNetwork, and the preferred asset check (needs the manager) runs in NetworkMgr.EndBlock, which follows it every block.
  • MAYAName collectors. Payouts credit the 1.135 named affiliate collectors, keyed by lower-cased MAYAName.
  • No SWAPKIT alias. THORNode's hard-coded alias for one integrator is not ported.

Versioning

  • SwapperV135 is a verbatim frozen copy (first commit). scripts/lint-versions.bash shows no body changes in versioned functions.
  • Changed for 1.136.0:
    • SwapperVCUR, now gated at 1.136.0
    • NetworkMgrVCUR (already 1.136.0 in !892)
    • new MimirHandler.validateV136 and isOperationalMimirV136
  • New constants: RevShareMaxBps (5000) and MimirTemplateRevShareMAYAName.
  • No store migration and no genesis field: the accumulator is empty at the end of every block.

Tests

  • Unit:
    • swap_revshare_test.go: attribution rules (first affiliate only, unknown or expired names, zero fee, zero mimir, conversions to the collector, alias or owner, user swaps to CACAO), an end-to-end VCUR swap, and no attribution in V135
    • manager_network_revshare_test.go: the split at 0, 5000 and capped bps, the pool returning the payout, collector credit, the rev_share event, release to the alias in EndBlock, and unpayable entries (missing name, empty Reserve) with the accumulator still cleared
    • keeper_affiliate_liquidity_fee_test.go: accumulation, ordering, case, overflow, delete
    • TestValidateRevShare, and TestIsOperationalMimir for 1.136.0
  • Regression: new suites/affiliates/revshare.yaml covers:
    • mimir validation (unknown name, value above the cap)
    • no attribution without the mimir
    • the rev_share event, Reserve → affiliate collector → dog, and pol_reserve getting 5% of the fees left after REVSHARE
    • no attribution without an affiliate or with dog second
    • deleting the mimir
  • Full regression: 143/143 with EXPORT=1. Other suites are unchanged, since none sets a REVSHARE mimir.

Merge request reports

Loading
Loading