@bananapus/distributor-v6 0.0.36 → 0.0.38
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
|
@@ -30,7 +30,7 @@ Use this repo when the problem is "how do we distribute already-owned assets ove
|
|
|
30
30
|
|
|
31
31
|
If the issue is "where did the project's value come from?" start in `nana-core-v6`, `nana-721-hook-v6`, or the upstream repo that minted or received the assets first.
|
|
32
32
|
|
|
33
|
-
## Key
|
|
33
|
+
## Key contracts
|
|
34
34
|
|
|
35
35
|
| Contract | Role |
|
|
36
36
|
| --- | --- |
|
|
@@ -38,7 +38,7 @@ If the issue is "where did the project's value come from?" start in `nana-core-v
|
|
|
38
38
|
| `JBTokenDistributor` | ERC-20 distributor keyed to `IVotes` checkpointed voting power. |
|
|
39
39
|
| `JB721Distributor` | NFT-aware distributor keyed to checkpointed voting power from the hook's `CHECKPOINTS()` module. Only NFTs held at the funded round's snapshot block are eligible. |
|
|
40
40
|
|
|
41
|
-
## Mental
|
|
41
|
+
## Mental model
|
|
42
42
|
|
|
43
43
|
1. a project funds the distributor, often through a payout split
|
|
44
44
|
2. accepted funding is assigned to the current reward round for the chosen token or 721 stake source
|
|
@@ -51,14 +51,14 @@ If the issue is "where did the project's value come from?" start in `nana-core-v
|
|
|
51
51
|
|
|
52
52
|
This repo does not explain why an allocation exists. It only defines how funded inventory is handed out.
|
|
53
53
|
|
|
54
|
-
## Read
|
|
54
|
+
## Read these files first
|
|
55
55
|
|
|
56
56
|
1. `src/interfaces/IJBDistributor.sol`
|
|
57
57
|
2. `src/JBDistributor.sol`
|
|
58
58
|
3. `src/JBTokenDistributor.sol`
|
|
59
59
|
4. `src/JB721Distributor.sol`
|
|
60
60
|
|
|
61
|
-
## Integration
|
|
61
|
+
## Integration traps
|
|
62
62
|
|
|
63
63
|
- distribution correctness depends on the distributor actually holding the assets it is expected to vest
|
|
64
64
|
- ERC-20 and ERC-721 distributions share historical reward-round accounting, but claim authority differs:
|
|
@@ -87,14 +87,14 @@ This repo does not explain why an allocation exists. It only defines how funded
|
|
|
87
87
|
- snapshot timing is part of the trusted surface
|
|
88
88
|
- this repo settles distributions, but it does not prove the upstream entitlement math was correct
|
|
89
89
|
|
|
90
|
-
## Where
|
|
90
|
+
## Where state lives
|
|
91
91
|
|
|
92
92
|
- round and vesting state: `JBDistributor`
|
|
93
93
|
- historical reward-round inputs: `JBRewardRoundData`
|
|
94
94
|
- vesting schedule state: `JBVestingData`
|
|
95
95
|
- asset-specific claim behavior: the concrete distributor
|
|
96
96
|
|
|
97
|
-
## High-
|
|
97
|
+
## High-signal tests
|
|
98
98
|
|
|
99
99
|
1. `test/JBTokenDistributor.t.sol`
|
|
100
100
|
2. `test/JB721Distributor.t.sol`
|
|
@@ -121,7 +121,7 @@ Useful scripts:
|
|
|
121
121
|
- `npm run deploy:mainnets`
|
|
122
122
|
- `npm run deploy:testnets`
|
|
123
123
|
|
|
124
|
-
## Repository
|
|
124
|
+
## Repository layout
|
|
125
125
|
|
|
126
126
|
```text
|
|
127
127
|
src/
|
|
@@ -136,7 +136,7 @@ script/
|
|
|
136
136
|
Deploy.s.sol
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
## Risks
|
|
139
|
+
## Risks and notes
|
|
140
140
|
|
|
141
141
|
- distributors are only as trustworthy as the vesting parameters and funding they receive
|
|
142
142
|
- operational mistakes often come from funding the wrong asset or underfunding the distributor
|
|
@@ -144,7 +144,7 @@ script/
|
|
|
144
144
|
- deployers that set a nonzero claim duration should choose a window long enough for expected claimants, because
|
|
145
145
|
expired unclaimed rewards can be recycled by anyone
|
|
146
146
|
|
|
147
|
-
## For AI
|
|
147
|
+
## For AI agents
|
|
148
148
|
|
|
149
149
|
- Treat this repo as distribution plumbing, not as the source of upstream entitlement math.
|
|
150
150
|
- Read both the ERC-20 and ERC-721 tests before claiming the flows are equivalent.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bananapus/distributor-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.38",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
"deploy:testnets": "source ./.env && npx sphinx propose ./script/Deploy.s.sol --networks testnets"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@bananapus/721-hook-v6": "^0.0.
|
|
28
|
-
"@bananapus/core-v6": "^0.0.
|
|
29
|
-
"@bananapus/permission-ids-v6": "^0.0.
|
|
27
|
+
"@bananapus/721-hook-v6": "^0.0.65",
|
|
28
|
+
"@bananapus/core-v6": "^0.0.78",
|
|
29
|
+
"@bananapus/permission-ids-v6": "^0.0.28",
|
|
30
30
|
"@openzeppelin/contracts": "5.6.1",
|
|
31
31
|
"@prb/math": "4.1.1",
|
|
32
|
-
"@rev-net/core-v6": "^0.0.
|
|
32
|
+
"@rev-net/core-v6": "^0.0.84"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@sphinx-labs/plugins": "0.33.3"
|
package/references/operations.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
| 721 reward shares look diluted | Burned supply was not excluded correctly or token-to-tier mapping is wrong |
|
|
21
21
|
| Split-hook funding credits the wrong amount | The caller did not grant a sufficient ERC-20 allowance before calling `processSplitWith` |
|
|
22
22
|
|
|
23
|
-
## Read
|
|
23
|
+
## Read next
|
|
24
24
|
|
|
25
25
|
- [`script/Deploy.s.sol`](../script/Deploy.s.sol) when the failure might be deployment config rather than distributor math.
|
|
26
26
|
- [`test/invariant/JB721DistributorInvariant.t.sol`](../test/invariant/JB721DistributorInvariant.t.sol) when a local patch looks safe but may have broken a longer-lived accounting invariant.
|
package/src/JBDistributor.sol
CHANGED
|
@@ -163,6 +163,7 @@ abstract contract JBDistributor is IJBDistributor {
|
|
|
163
163
|
|
|
164
164
|
/// @notice The block number recorded as the snapshot point for each round.
|
|
165
165
|
/// @dev Set to `block.number - 1` on first interaction in a round, so that `IVotes.getPastVotes` works.
|
|
166
|
+
/// @custom:param round The round whose snapshot block is being recorded.
|
|
166
167
|
mapping(uint256 round => uint256) public override roundSnapshotBlock;
|
|
167
168
|
|
|
168
169
|
/// @notice Reward data assigned to each funding round.
|
|
@@ -296,7 +297,7 @@ abstract contract JBDistributor is IJBDistributor {
|
|
|
296
297
|
}
|
|
297
298
|
|
|
298
299
|
/// @notice Recycle unclaimed rewards from expired reward rounds into the current reward round.
|
|
299
|
-
/// @dev
|
|
300
|
+
/// @dev Recycling is permissionless; any keeper or frontend can sweep an expired round.
|
|
300
301
|
/// @param hook The hook whose expired rewards should be recycled.
|
|
301
302
|
/// @param token The reward token to recycle.
|
|
302
303
|
/// @param rounds The reward rounds to recycle.
|
|
@@ -633,7 +634,7 @@ abstract contract JBDistributor is IJBDistributor {
|
|
|
633
634
|
// Before collecting, bring the token IDs current by starting vesting for any past reward rounds.
|
|
634
635
|
_claimPastRewards({hook: hook, groupId: groupId, tokenIds: tokenIds, tokens: tokens});
|
|
635
636
|
|
|
636
|
-
// Release whatever portion of
|
|
637
|
+
// Release whatever portion of vesting entries has unlocked by this round.
|
|
637
638
|
_unlockRewards({
|
|
638
639
|
hook: hook, groupId: groupId, tokenIds: tokenIds, tokens: tokens, beneficiary: beneficiary, ownerClaim: true
|
|
639
640
|
});
|
|
@@ -911,7 +912,7 @@ abstract contract JBDistributor is IJBDistributor {
|
|
|
911
912
|
revert JBDistributor_UnexpectedNativeValue({msgValue: msg.value, token: loan.sourceToken});
|
|
912
913
|
}
|
|
913
914
|
|
|
914
|
-
// Pull the exact current payoff from the caller.
|
|
915
|
+
// Pull the exact current payoff from the caller. Distributor inventory must not cover a shortfall.
|
|
915
916
|
IERC20 sourceToken = IERC20(loan.sourceToken);
|
|
916
917
|
uint256 sourceBalanceBefore = sourceToken.balanceOf(address(this));
|
|
917
918
|
sourceToken.safeTransferFrom({from: msg.sender, to: address(this), value: repayBorrowAmount});
|
|
@@ -1263,7 +1264,7 @@ abstract contract JBDistributor is IJBDistributor {
|
|
|
1263
1264
|
/// @param round The reward round.
|
|
1264
1265
|
/// @return claimDeadline The deadline timestamp. Zero means no expiration.
|
|
1265
1266
|
function _claimDeadlineFor(uint256 round) internal view returns (uint48 claimDeadline) {
|
|
1266
|
-
//
|
|
1267
|
+
// A zero claim duration means the round never expires.
|
|
1267
1268
|
if (CLAIM_DURATION == 0) return 0;
|
|
1268
1269
|
|
|
1269
1270
|
// Start the window at the next round boundary, when the funded round first becomes claimable.
|
|
@@ -6,7 +6,8 @@ import {mulDiv} from "@prb/math/src/Common.sol";
|
|
|
6
6
|
/// @notice Pure helpers for the distributor's linear vesting arithmetic.
|
|
7
7
|
library JBVestingMath {
|
|
8
8
|
/// @notice The share still locked for a vesting entry at `currentRound`.
|
|
9
|
-
/// @dev
|
|
9
|
+
/// @dev Linear release: the locked share shrinks one `maxShare/vestingRounds` step per round. Callers maintain
|
|
10
|
+
/// the invariant that
|
|
10
11
|
/// `releaseRound - currentRound <= vestingRounds` whenever `releaseRound > currentRound`.
|
|
11
12
|
/// @param releaseRound The round when the entry is fully unlocked.
|
|
12
13
|
/// @param currentRound The current distributor round.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
+
/// @notice Parameters describing one lazy claim of completed reward rounds into a fresh vesting entry.
|
|
4
5
|
/// @custom:member hook The stake source whose historical rewards are being claimed.
|
|
5
6
|
/// @custom:member groupId The reward group being claimed (0 = the default group).
|
|
6
7
|
/// @custom:member tierIds The tier set defining the group (empty for the default group); used to filter eligible
|
|
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
5
5
|
|
|
6
|
+
/// @notice Parameters describing one round's reward allocation while vesting begins.
|
|
6
7
|
/// @custom:member hook The stake source whose rewards are being vested.
|
|
7
8
|
/// @custom:member groupId The reward group being claimed (0 = the default group).
|
|
8
9
|
/// @custom:member tierIds The tier set defining the group (empty for the default group); used to filter eligible
|