@rev-net/core-v6 0.0.24 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,110 +1,74 @@
1
1
  # Revnet Core
2
2
 
3
- Deploy and operate Revnets: unowned Juicebox projects that run autonomously according to predefined stages, with built-in token-collateralized loans.
3
+ `@rev-net/core-v6` deploys and operates Revnets: autonomous Juicebox projects with staged economics, optional tiered NFTs, cross-chain support, buyback integration, and token-collateralized loans.
4
4
 
5
- [Docs](https://docs.juicebox.money) | [Discord](https://discord.gg/nT3XqbzNEr)
5
+ Docs: <https://docs.juicebox.money>
6
+ Architecture: [ARCHITECTURE.md](./ARCHITECTURE.md)
6
7
 
7
- ## What is a Revnet?
8
+ ## Overview
8
9
 
9
- A Revnet is a treasury-backed token that runs itself. No owners, no governors, no multisigs. Once deployed, a revnet follows its predefined stages forever, backed by the Juicebox and Uniswap protocols.
10
+ A Revnet is meant to run without a human owner after launch. Its economics are encoded up front as a sequence of stages, and the runtime hook plus loan system enforce those rules over time.
10
11
 
11
- ## Conceptual Overview
12
+ This package provides:
12
13
 
13
- Revnets are autonomous Juicebox projects with predetermined economic stages. Each stage defines issuance rates, decay schedules, cash-out taxes, reserved splits, and auto-issuance allocations. Once deployed, these parameters cannot be changed -- the revnet operates on its own forever.
14
+ - a deployer that launches Revnets and stores their long-lived configuration
15
+ - a runtime hook that mediates pay, cash-out, mint-permission, and delayed-cash-out behavior
16
+ - an ERC-721 loan system that burns token collateral on borrow and remints on repayment
14
17
 
15
- ### Stage-Based Lifecycle
18
+ It also composes with the 721 hook stack, buyback hook, router terminal, Croptop, and suckers where needed.
16
19
 
17
- ```
18
- 1. Deploy revnet with stage configurations
19
- → REVDeployer.deployFor(revnetId=0, config, terminals, suckerConfig)
20
- → Creates Juicebox project owned by REVDeployer (permanently), dataHook = REVOwner
21
- → Deploys ERC-20 token, initializes buyback pools at 1:1 price, deploys suckers
22
- |
23
- 2. Stage 1 begins (startsAtOrAfter or block.timestamp)
24
- → Tokens issued at initialIssuance rate per unit of base currency
25
- → Issuance decays by issuanceCutPercent every issuanceCutFrequency
26
- → splitPercent of new tokens go to reserved splits
27
- → Cash outs taxed at cashOutTaxRate (2.5% fee to fee revnet)
28
- |
29
- 3. Stage transitions happen automatically
30
- → When startsAtOrAfter timestamp is reached for next stage
31
- → New issuance rate, tax rate, splits, etc. take effect
32
- → No governance, no votes, no owner action required
33
- |
34
- 4. Participants can borrow against their tokens
35
- → REVLoans.borrowFrom(revnetId, source, collateral, ...)
36
- → Collateral tokens are burned, funds pulled from treasury
37
- → Loan is an ERC-721 NFT, liquidates after 10 years
38
- |
39
- 5. Ongoing operations (permissionless or split operator)
40
- → Auto-issuance claims (permissionless)
41
- → Buyback pool configuration (split operator)
42
- → Sucker deployment (split operator, if ruleset allows)
43
- → Split group updates (split operator)
44
- ```
20
+ Use this repo when the product is an autonomous treasury-backed network with encoded stage transitions. Do not use it when governance, mutable operator control, or simple project deployment is the goal.
45
21
 
46
- ### Token-Collateralized Loans
47
-
48
- `REVLoans` lets participants borrow against their revnet tokens. Unlike traditional lending:
49
-
50
- - **Collateral is burned, not held.** Tokens are destroyed on borrow and re-minted on repay. This keeps the token supply accurate -- collateral tokens don't exist during the loan. Callers must first grant `BURN_TOKENS` permission to the loans contract via `JBPermissions.setPermissionsFor()`.
51
- - **Borrowable amount = cash-out value.** The bonding curve determines how much you can borrow for a given amount of collateral.
52
- - **Prepaid fee model.** Borrowers choose a prepaid fee (2.5%-50%) that buys an interest-free window. After that window, a time-proportional source fee accrues.
53
- - **Each loan is an ERC-721 NFT.** Loans can be transferred, and expired loans (10 years) can be liquidated by anyone.
54
-
55
- #### Loan Flow
56
-
57
- ```mermaid
58
- sequenceDiagram
59
- participant Borrower
60
- participant REVLoans
61
- participant JBController
62
- participant JBMultiTerminal
63
- participant Beneficiary
64
-
65
- Note over Borrower,Beneficiary: Borrow
66
- Borrower->>REVLoans: borrowFrom(revnetId, source, collateral, ...)
67
- REVLoans->>JBController: burnTokensOf(borrower, collateral)
68
- REVLoans->>JBMultiTerminal: useAllowanceOf(revnetId, borrowAmount)
69
- JBMultiTerminal-->>REVLoans: net funds (minus protocol fee)
70
- REVLoans-->>Beneficiary: borrowed funds (minus prepaid fee)
71
- REVLoans-->>Borrower: mint loan ERC-721 NFT
72
-
73
- Note over Borrower,Beneficiary: Repay
74
- Borrower->>REVLoans: repayLoan(loanId, collateralToReturn, ...)
75
- REVLoans->>REVLoans: burn loan ERC-721 NFT
76
- REVLoans->>JBMultiTerminal: addToBalanceOf(revnetId, repayAmount)
77
- REVLoans->>JBController: mintTokensOf(beneficiary, collateral)
78
- Note right of Beneficiary: Collateral tokens re-minted
79
- ```
22
+ The key point is that a Revnet is not just "a Juicebox project with presets." It is a project shape whose admin surface is intentionally collapsed into deployment-time configuration plus constrained runtime operators.
23
+
24
+ ## Key Contracts
25
+
26
+ | Contract | Role |
27
+ | --- | --- |
28
+ | `REVDeployer` | Launches and configures Revnets, stages, split operators, and optional auxiliary features. |
29
+ | `REVOwner` | Runtime data-hook and cash-out-hook surface used by active Revnets. |
30
+ | `REVLoans` | Loan surface that lets users borrow against Revnet tokens with burned collateral and NFT loan positions. |
31
+
32
+ ## Mental Model
80
33
 
81
- ### Deployer Variants
34
+ Read the package in two halves:
82
35
 
83
- Every revnet gets a tiered ERC-721 hook deployed automatically even if no tiers are configured at launch. This lets the split operator add and sell NFTs later without migration.
36
+ 1. deployment-time shape: `REVDeployer` decides what the network will be allowed to do
37
+ 2. runtime enforcement: `REVOwner` and `REVLoans` decide how that shape behaves over time
84
38
 
85
- - **Basic revnet** -- `deployFor` with stage configurations mapped to Juicebox rulesets and an empty 721 hook. Choose this when the revnet only needs fungible token issuance and the split operator may optionally add NFT tiers later.
86
- - **Tiered 721 revnet** -- `deployFor` adds a tiered 721 pay hook with pre-configured tiers that mint NFTs as people pay. Choose this when the revnet should sell specific NFT tiers from day one, such as membership passes or limited editions.
87
- - **Croptop revnet** -- A tiered 721 revnet with Croptop posting criteria, allowing the public to post content. Choose this when the revnet should function as an open publishing platform where anyone can submit content that gets minted as NFTs according to the configured posting rules.
39
+ That split matters because most mistakes are one of these:
88
40
 
89
- ## Architecture
41
+ - assuming a deploy-time parameter can be changed later
42
+ - assuming a runtime hook is only advisory rather than economically binding
90
43
 
91
- | Contract | Description |
92
- |----------|-------------|
93
- | `REVDeployer` | Deploys revnets as Juicebox projects owned by the deployer contract itself (no human owner). Translates stage configurations into Juicebox rulesets, manages buyback hooks, suckers, split operators, auto-issuance, and configuration state storage. Handles deployment, configuration, and split operator management. Calls DEPLOYER-restricted setters on REVOwner during deployment to store `cashOutDelayOf` and `tiered721HookOf`. |
94
- | `REVOwner` | Runtime hook contract for all revnets. Implements `IJBRulesetDataHook` and `IJBCashOutHook`. Set as the `dataHook` in each revnet's ruleset metadata. Handles `beforePayRecordedWith`, `beforeCashOutRecordedWith`, `afterCashOutRecordedWith`, `hasMintPermissionFor`, and sucker verification. When 721 tier splits are active, adjusts the payment weight so the terminal only mints tokens proportional to the amount entering the project treasury (the split portion is forwarded separately). Stores `cashOutDelayOf` and `tiered721HookOf` mappings (set by REVDeployer via DEPLOYER-restricted setters `setCashOutDelayOf()` and `setTiered721HookOf()`). |
95
- | `REVLoans` | Lets participants borrow against their revnet tokens. Collateral tokens are burned on borrow and re-minted on repayment. Each loan is an ERC-721 NFT. Charges a prepaid fee (2.5% min, 50% max) that determines the interest-free duration; after that window, a time-proportional source fee accrues. Loans liquidate after 10 years. |
44
+ The shortest useful reading order is:
96
45
 
97
- ### How They Relate
46
+ 1. `REVDeployer`
47
+ 2. `REVOwner`
48
+ 3. `REVLoans`
49
+ 4. any integrated hook or bridge repo the deployment enables
98
50
 
99
- `REVDeployer` owns every revnet's Juicebox project NFT and holds all administrative permissions. `REVOwner` is set as the `dataHook` for every revnet's rulesets, handling all runtime hook behavior (pay hooks, cash-out hooks, mint permissions) and storing `cashOutDelayOf` and `tiered721HookOf` per revnet (set by REVDeployer via DEPLOYER-restricted setters during deployment). Deploy order: REVOwner first, then REVDeployer(owner=REVOwner) -- the constructor calls `REVOwner.setDeployer()` atomically. Both contracts share immutables: `BUYBACK_HOOK`, `DIRECTORY`, `FEE_REVNET_ID`, `SUCKER_REGISTRY`, `LOANS`. During deployment, REVDeployer grants `REVLoans` the `USE_ALLOWANCE` permission so loans can pull funds from the revnet's terminal. `REVLoans` imports `IREVOwner` (not `IREVDeployer`) for `cashOutDelayOf` calls and verifies that a revnet was deployed by its expected `REVDeployer` before issuing any loan.
51
+ ## Read These Files First
100
52
 
101
- ### Interfaces
53
+ 1. `src/REVDeployer.sol`
54
+ 2. `src/REVOwner.sol`
55
+ 3. `src/REVLoans.sol`
56
+ 4. the integrated hook or bridge repo used by the deployment
102
57
 
103
- | Interface | Description |
104
- |-----------|-------------|
105
- | `IREVDeployer` | Deployment, auto-issuance, split operator management, sucker deployment, configuration state storage, `OWNER()` view, plus events. |
106
- | `IREVOwner` | Exposes `cashOutDelayOf` view. Used by REVLoans to read cash-out delay. |
107
- | `IREVLoans` | Borrow, repay, refinance, liquidate, views, plus events. |
58
+ ## Integration Traps
59
+
60
+ - the deployer holding the project NFT is not an implementation detail; it is part of the ownership model
61
+ - split operators are constrained, not equivalent to general protocol governance
62
+ - the loan system depends on live revnet economics, so it should be reviewed together with the runtime hook and treasury assumptions
63
+ - optional integrations like buybacks, 721 hooks, and suckers are compositional, but they materially change the resulting network
64
+
65
+ ## Where State Lives
66
+
67
+ - deployment-time configuration and operator envelope live in `REVDeployer`
68
+ - runtime pay and cash-out behavior live in `REVOwner`
69
+ - loan positions and loan-specific state live in `REVLoans`
70
+
71
+ Do not audit those contracts in isolation if the deployment enables cross-package features; the composed network is the real product.
108
72
 
109
73
  ## Install
110
74
 
@@ -112,109 +76,46 @@ Every revnet gets a tiered ERC-721 hook deployed automatically — even if no ti
112
76
  npm install @rev-net/core-v6
113
77
  ```
114
78
 
115
- If using Forge directly:
79
+ ## Development
116
80
 
117
81
  ```bash
118
- npm install && forge install
82
+ npm install
83
+ forge build
84
+ forge test
119
85
  ```
120
86
 
121
- If `forge install` has issues, try `git submodule update --init --recursive`.
87
+ Useful scripts:
88
+
89
+ - `npm run deploy:mainnets`
90
+ - `npm run deploy:testnets`
91
+ - `npm run deploy:mainnets:1_1`
92
+ - `npm run deploy:testnets:1_1`
122
93
 
123
- ## Develop
94
+ ## Deployment Notes
124
95
 
125
- | Command | Description |
126
- |---------|-------------|
127
- | `forge build` | Compile contracts |
128
- | `forge test` | Run tests (55 test files covering deployment, lifecycle, loans, attacks, invariants, fork tests, regressions) |
129
- | `forge test -vvvv` | Run tests with full traces |
96
+ Revnet deployment assumes the core protocol, 721 hook, buyback hook, router terminal, suckers, and Croptop packages are available. Every Revnet is intentionally unowned after deployment in the human sense; the deployer contract itself retains the project NFT.
130
97
 
131
98
  ## Repository Layout
132
99
 
133
- ```
100
+ ```text
134
101
  src/
135
- REVDeployer.sol # Revnet deployer + configuration + state storage
136
- REVOwner.sol # Runtime data hook + cash-out hook (~310 lines)
137
- REVLoans.sol # Token-collateralized lending (~1,391 lines)
102
+ REVDeployer.sol
103
+ REVOwner.sol
104
+ REVLoans.sol
138
105
  interfaces/
139
- IREVDeployer.sol # Deployer interface + events
140
- IREVOwner.sol # Owner interface (cashOutDelayOf view)
141
- IREVLoans.sol # Loans interface + events
142
106
  structs/
143
- REVConfig.sol # Top-level deployment config
144
- REVDescription.sol # ERC-20 metadata (name, ticker, uri, salt)
145
- REVStageConfig.sol # Economic stage parameters
146
- REVAutoIssuance.sol # Per-stage cross-chain premint
147
- REVLoan.sol # Loan state
148
- REVLoanSource.sol # Terminal + token pair for loans
149
- REVBaseline721HookConfig.sol # 721 hook config (omits issueTokensForSplits)
150
- REV721TiersHookFlags.sol # 721 hook flags for revnets (no issueTokensForSplits)
151
- REVDeploy721TiersHookConfig.sol # 721 hook deployment config wrapper
152
- REVCroptopAllowedPost.sol # Croptop posting criteria
153
- REVSuckerDeploymentConfig.sol # Cross-chain sucker deployment
154
107
  test/
155
- REV.integrations.t.sol # Deployment, payments, cash-outs
156
- REVLifecycle.t.sol # Stage transitions, weight decay
157
- REVAutoIssuanceFuzz.t.sol # Auto-issuance fuzz tests
158
- REVInvincibility.t.sol # Economic property fuzzing
159
- REVInvincibilityHandler.sol # Fuzz handler
160
- REVDeployerRegressions.t.sol # Deployer regressions
161
- REVLoansSourced.t.sol # Multi-source loan tests
162
- REVLoansUnSourced.t.sol # Loan error cases
163
- REVLoansFeeRecovery.t.sol # Fee calculation tests
164
- REVLoansAttacks.t.sol # Flash loan, reentrancy scenarios
165
- REVLoans.invariants.t.sol # Loan fuzzing invariants
166
- REVLoansRegressions.t.sol # Loan regressions
167
- helpers/
168
- MaliciousContracts.sol # Attack contract mocks
169
- mock/
170
- MockBuybackDataHook.sol # Mock for buyback hook tests
108
+ lifecycle, deployment, loan, fork, invariant, audit, and regression coverage
171
109
  script/
172
- Deploy.s.sol # Sphinx multi-chain deployment
110
+ Deploy.s.sol
173
111
  helpers/
174
- RevnetCoreDeploymentLib.sol # Deployment artifact reader
175
112
  ```
176
113
 
177
- ## Permissions
178
-
179
- ### Split Operator (per-revnet)
180
-
181
- The split operator has these default permissions:
182
-
183
- | Permission | Purpose |
184
- |------------|---------|
185
- | `SET_SPLIT_GROUPS` | Change reserved token splits |
186
- | `SET_BUYBACK_POOL` | Configure Uniswap buyback pool |
187
- | `SET_BUYBACK_TWAP` | Adjust TWAP window for buyback |
188
- | `SET_PROJECT_URI` | Update project metadata |
189
- | `ADD_PRICE_FEED` | Add price oracle |
190
- | `SUCKER_SAFETY` | Emergency sucker functions |
191
- | `SET_BUYBACK_HOOK` | Swap buyback hook |
192
- | `SET_ROUTER_TERMINAL` | Swap terminal |
193
- | `SET_TOKEN_METADATA` | Update token name and symbol |
194
-
195
- Plus optional from 721 hook config: `ADJUST_721_TIERS`, `SET_721_METADATA`, `MINT_721`, `SET_721_DISCOUNT_PERCENT`.
196
-
197
- ### Global Permissions
198
-
199
- | Grantee | Permission | Scope |
200
- |---------|------------|-------|
201
- | `SUCKER_REGISTRY` | `MAP_SUCKER_TOKEN` | All revnets (wildcard projectId=0) |
202
- | `REVLoans` | `USE_ALLOWANCE` | All revnets (wildcard projectId=0) |
203
-
204
- ### Permissionless Operations
205
-
206
- - `autoIssueFor` -- claim auto-issuance tokens (anyone)
207
- - `burnHeldTokensOf` -- burn reserved tokens held by deployer (anyone)
114
+ ## Risks And Notes
208
115
 
209
- ## Risks
116
+ - Revnets are intentionally hard to change after launch, so bad stage design is expensive
117
+ - `REVLoans` relies on live treasury conditions and is therefore sensitive to surplus and pricing assumptions
118
+ - the deployer and runtime hook have a tight relationship that should be treated as one design, not two independent contracts
119
+ - burned-collateral lending is operationally different from escrowed-collateral lending and needs clear integrator expectations
210
120
 
211
- - **No human owner.** `REVDeployer` permanently holds the project NFT. There is no function to release it. This is by design -- revnets are ownerless. But it means bugs in stage configurations cannot be fixed after deployment.
212
- - **REVOwner circular dependency.** REVOwner and REVDeployer have a circular dependency broken by `setDeployer()`, called atomically from REVDeployer's constructor. `REVOwner.DEPLOYER` is a storage variable (not immutable). `setDeployer()` sets `msg.sender` as `DEPLOYER` and reverts if already set. If `setDeployer()` is never called, the DEPLOYER-restricted setters (`setCashOutDelayOf`, `setTiered721HookOf`) cannot be called correctly, and all runtime hook behavior breaks.
213
- - **Loan flash-loan exposure.** `borrowableAmountFrom` reads live surplus, which can be inflated via flash loans. A borrower could temporarily inflate the treasury to borrow more than the sustained value would support.
214
- - **uint112 truncation.** `REVLoan.amount` and `REVLoan.collateral` are `uint112` -- values above ~5.19e33 truncate silently.
215
- - **Cash-out fee stacking.** Cash outs incur both the Juicebox terminal fee (2.5%) and the revnet cash-out fee (2.5% to fee revnet). These compound.
216
- - **Auto-issuance stage IDs.** Stage IDs are `block.timestamp + i` during deployment. These match the Juicebox ruleset IDs because `JBRulesets` assigns IDs the same way (`latestId >= block.timestamp ? latestId + 1 : block.timestamp`), producing identical sequential IDs when all stages are queued in a single `deployFor()` call.
217
- - **NATIVE_TOKEN on non-ETH chains.** Using `JBConstants.NATIVE_TOKEN` on Celo or Polygon means CELO/MATIC, not ETH. Use ERC-20 WETH instead. The matching hash does NOT catch this -- it covers economic parameters but NOT terminal configurations.
218
- - **30-day cash-out delay.** When deploying an existing revnet to a new chain where the first stage has already started, a 30-day delay is imposed before cash outs are allowed, preventing cross-chain liquidity arbitrage.
219
- - **Loan source array growth.** `_loanSourcesOf[revnetId]` is unbounded. If an attacker creates loans from many different terminals/tokens, the array grows without limit.
220
- - **10-year loan liquidation.** Expired loans (10+ years) can be liquidated by anyone. The burned collateral is permanently lost -- it was destroyed at borrow time.
121
+ The usual review failure mode is to focus on the loans or the stages in isolation. The real system is the combination of stage economics, runtime hook behavior, and who is still allowed to act after deployment.
package/RISKS.md CHANGED
@@ -1,10 +1,22 @@
1
- # revnet-core-v6 -- Active Risk Vectors
1
+ # Revnet Core Risk Register
2
2
 
3
- Forward-looking risk assessment for auditors. Covers trust assumptions, economic risks, loan system risks, data hook proxy concerns, access control, DoS vectors, and invariants.
3
+ This file focuses on the risks created by autonomous treasury-backed projects with staged economics, composable hooks, cross-chain wiring, and token-collateralized loans.
4
4
 
5
5
  Read [ARCHITECTURE.md](./ARCHITECTURE.md) and [SKILLS.md](./SKILLS.md) for protocol context first.
6
6
 
7
- ---
7
+ ## How to use this file
8
+
9
+ - Read `Priority risks` first; they capture the highest-impact ways a revnet can misprice, misroute, or mis-govern itself.
10
+ - Use the detailed sections for economics, loans, data-hook proxying, and liveness reasoning.
11
+ - Treat `Accepted Behaviors` and `Invariants to Verify` as the operating contract for revnet deployments.
12
+
13
+ ## Priority risks
14
+
15
+ | Priority | Risk | Why it matters | Primary controls |
16
+ |----------|------|----------------|------------------|
17
+ | P0 | Loan mispricing from bad surplus or configuration | `REVLoans` depends on correct surplus, fee, and deployer-owned configuration; bad inputs can enable over-borrowing. | Surplus and price checks, deployer verification, and loan-specific invariant coverage. |
18
+ | P0 | Deployer or data-hook proxy blast radius | `REVDeployer` sits in the pay and cash-out path for all revnets it launched. A bug here affects every attached project. | High-scrutiny review, composition testing, and cautious shared-deployer usage. |
19
+ | P1 | Stage or split misconfiguration becomes permanent | Revnets are intentionally autonomous and hard to govern after launch; bad initial economics are difficult or impossible to fix. | Strong pre-launch review, deployment runbooks, and config simulation before production. |
8
20
 
9
21
  ## 1. Trust Assumptions
10
22
 
@@ -40,7 +52,7 @@ Read [ARCHITECTURE.md](./ARCHITECTURE.md) and [SKILLS.md](./SKILLS.md) for proto
40
52
 
41
53
  - **`cashOutTaxRate` increase destroys loan health.** Active loans use the CURRENT stage's `cashOutTaxRate`. When a stage transition increases this rate, existing loans become under-collateralized -- the collateral's cash-out value drops but the loan amount remains unchanged. No forced repayment or margin call mechanism exists. Over 10 years with multiple stage transitions, this compounds.
42
54
  - **`cashOutTaxRate` decrease creates refinancing opportunity.** When a new stage lowers the tax rate, existing collateral becomes worth more. Borrowers can `reallocateCollateralFromLoan` to extract the surplus value. This creates a predictable, front-runnable event at every stage boundary.
43
- - **Weight decay approaching zero over long periods.** With `issuanceCutPercent > 0` and `issuanceCutFrequency > 0`, issuance weight decays exponentially. After 10+ years, new payments mint negligibly few tokens, meaning the token supply effectively freezes. This concentrates cash-out value among existing holders and makes the bonding curve increasingly sensitive to individual cash-outs. Verify the weight cache mechanism (`updateRulesetWeightCache`) handles the 20,000-iteration threshold correctly when many cycles have elapsed.
55
+ - **Weight decay approaching zero over long periods.** With `issuanceCutPercent > 0` and `issuanceCutFrequency > 0`, issuance weight decays exponentially through successive rulesets. After long enough, new payments mint negligibly few tokens, meaning the token supply effectively freezes. This concentrates cash-out value among existing holders and makes the bonding curve increasingly sensitive to individual cash-outs. The current repo models decay through ruleset duration and `weightCutPercent`, so validation should focus on long-horizon ruleset progression and issuance-decay tests rather than any separate weight-cache updater.
44
56
  - **Duration=0 stages never auto-expire.** A stage with `duration=0` (no issuance cut frequency) persists until explicitly replaced by a subsequent stage's `startsAtOrAfter`. If the next stage's `startsAtOrAfter` is far in the future, the current stage runs indefinitely at its configured parameters.
45
57
 
46
58
  ### Cross-currency reclaim calculations