@ballkidz/defifa 0.0.7 → 0.0.9
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/ADMINISTRATION.md +3 -3
- package/ARCHITECTURE.md +2 -0
- package/AUDIT_INSTRUCTIONS.md +422 -0
- package/CRYPTO_ECON.md +5 -5
- package/README.md +1 -1
- package/RISKS.md +38 -335
- package/SKILLS.md +1 -1
- package/USER_JOURNEYS.md +691 -0
- package/package.json +7 -7
- package/script/Deploy.s.sol +14 -3
- package/script/helpers/DefifaDeploymentLib.sol +13 -15
- package/src/DefifaDeployer.sol +221 -192
- package/src/DefifaGovernor.sol +286 -276
- package/src/DefifaHook.sol +68 -34
- package/src/DefifaProjectOwner.sol +27 -4
- package/src/DefifaTokenUriResolver.sol +136 -134
- package/src/enums/DefifaGamePhase.sol +1 -1
- package/src/enums/DefifaScorecardState.sol +1 -1
- package/src/interfaces/IDefifaDeployer.sol +52 -50
- package/src/interfaces/IDefifaGamePhaseReporter.sol +2 -2
- package/src/interfaces/IDefifaGamePotReporter.sol +1 -1
- package/src/interfaces/IDefifaGovernor.sol +53 -54
- package/src/interfaces/IDefifaHook.sol +104 -103
- package/src/interfaces/IDefifaTokenUriResolver.sol +2 -2
- package/src/libraries/DefifaFontImporter.sol +11 -9
- package/src/libraries/DefifaHookLib.sol +66 -53
- package/src/structs/DefifaAttestations.sol +1 -1
- package/src/structs/DefifaDelegation.sol +1 -1
- package/src/structs/DefifaLaunchProjectData.sol +4 -4
- package/src/structs/DefifaOpsData.sol +1 -1
- package/src/structs/DefifaScorecard.sol +1 -1
- package/src/structs/DefifaTierCashOutWeight.sol +1 -1
- package/src/structs/DefifaTierParams.sol +2 -1
- package/test/DefifaAdversarialQuorum.t.sol +602 -0
- package/test/DefifaAuditLowGuards.t.sol +304 -0
- package/test/DefifaFeeAccounting.t.sol +37 -16
- package/test/DefifaGovernor.t.sol +43 -19
- package/test/DefifaHookRegressions.t.sol +14 -12
- package/test/DefifaMintCostInvariant.t.sol +31 -12
- package/test/DefifaNoContest.t.sol +34 -16
- package/test/DefifaSecurity.t.sol +46 -28
- package/test/DefifaUSDC.t.sol +45 -36
- package/test/Fork.t.sol +43 -43
- package/test/SVG.t.sol +2 -2
- package/test/TestAuditGaps.sol +982 -0
- package/test/TestQALastMile.t.sol +511 -0
- package/test/regression/FulfillmentBlocksRatification.t.sol +36 -30
- package/test/regression/GracePeriodBypass.t.sol +15 -10
package/src/DefifaHook.sol
CHANGED
|
@@ -36,7 +36,6 @@ import {DefifaTierCashOutWeight} from "./structs/DefifaTierCashOutWeight.sol";
|
|
|
36
36
|
import {DefifaGamePhase} from "./enums/DefifaGamePhase.sol";
|
|
37
37
|
import {DefifaHookLib} from "./libraries/DefifaHookLib.sol";
|
|
38
38
|
|
|
39
|
-
/// @title DefifaHook
|
|
40
39
|
/// @notice A hook that transforms Juicebox treasury interactions into a Defifa game.
|
|
41
40
|
contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
42
41
|
using Checkpoints for Checkpoints.Trace208;
|
|
@@ -106,17 +105,17 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
106
105
|
//*********************************************************************//
|
|
107
106
|
|
|
108
107
|
/// @notice The $DEFIFA token that is expected to be issued from paying fees.
|
|
109
|
-
IERC20 public immutable override
|
|
108
|
+
IERC20 public immutable override DEFIFA_TOKEN;
|
|
110
109
|
|
|
111
110
|
/// @notice The $BASE_PROTOCOL token that is expected to be issued from paying fees.
|
|
112
|
-
IERC20 public immutable override
|
|
111
|
+
IERC20 public immutable override BASE_PROTOCOL_TOKEN;
|
|
113
112
|
|
|
114
113
|
//*********************************************************************//
|
|
115
114
|
// --------------------- public stored properties -------------------- //
|
|
116
115
|
//*********************************************************************//
|
|
117
116
|
|
|
118
117
|
/// @notice The address of the origin 'DefifaHook', used to check in the init if the contract is the original or not
|
|
119
|
-
address public immutable override
|
|
118
|
+
address public immutable override CODE_ORIGIN;
|
|
120
119
|
|
|
121
120
|
/// @notice The contract that stores and manages the NFT's data.
|
|
122
121
|
IJB721TiersHookStore public override store;
|
|
@@ -267,7 +266,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
267
266
|
|
|
268
267
|
// Fetch the cash out hook metadata using the corresponding metadata ID.
|
|
269
268
|
(bool metadataExists, bytes memory metadata) = JBMetadataResolver.getDataFor({
|
|
270
|
-
id: JBMetadataResolver.getId({purpose: "cashOut", target:
|
|
269
|
+
id: JBMetadataResolver.getId({purpose: "cashOut", target: CODE_ORIGIN}), metadata: context.metadata
|
|
271
270
|
});
|
|
272
271
|
|
|
273
272
|
uint256[] memory decodedTokenIds;
|
|
@@ -279,20 +278,22 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
279
278
|
DefifaGamePhase _gamePhase = gamePhaseReporter.currentGamePhaseOf(context.projectId);
|
|
280
279
|
|
|
281
280
|
// Calculate the amount paid to mint the tokens that are being burned.
|
|
282
|
-
uint256 _cumulativeMintPrice =
|
|
283
|
-
|
|
281
|
+
uint256 _cumulativeMintPrice = DefifaHookLib.computeCumulativeMintPrice({
|
|
282
|
+
tokenIds: decodedTokenIds, hookStore: store, hook: address(this)
|
|
283
|
+
});
|
|
284
284
|
|
|
285
285
|
// Use this contract as the only cash out hook.
|
|
286
286
|
hookSpecifications = new JBCashOutHookSpecification[](1);
|
|
287
|
-
hookSpecifications[0] =
|
|
288
|
-
|
|
287
|
+
hookSpecifications[0] = JBCashOutHookSpecification({
|
|
288
|
+
hook: this, noop: false, amount: 0, metadata: abi.encode(_cumulativeMintPrice)
|
|
289
|
+
});
|
|
289
290
|
|
|
290
291
|
// Compute the cash out count based on the game phase.
|
|
291
292
|
cashOutCount = DefifaHookLib.computeCashOutCount({
|
|
292
293
|
gamePhase: _gamePhase,
|
|
293
294
|
cumulativeMintPrice: _cumulativeMintPrice,
|
|
294
295
|
surplusValue: context.surplus.value,
|
|
295
|
-
|
|
296
|
+
totalAmountRedeemed: amountRedeemed,
|
|
296
297
|
cumulativeCashOutWeight: cashOutWeightOf(decodedTokenIds)
|
|
297
298
|
});
|
|
298
299
|
|
|
@@ -315,7 +316,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
315
316
|
{
|
|
316
317
|
cumulativeWeight = DefifaHookLib.computeCashOutWeightBatch({
|
|
317
318
|
tokenIds: tokenIds,
|
|
318
|
-
|
|
319
|
+
hookStore: store,
|
|
319
320
|
hook: address(this),
|
|
320
321
|
tierCashOutWeights: _tierCashOutWeights,
|
|
321
322
|
tokensRedeemedFrom: tokensRedeemedFrom
|
|
@@ -328,7 +329,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
328
329
|
function cashOutWeightOf(uint256 tokenId) public view override returns (uint256) {
|
|
329
330
|
return DefifaHookLib.computeCashOutWeight({
|
|
330
331
|
tokenId: tokenId,
|
|
331
|
-
|
|
332
|
+
hookStore: store,
|
|
332
333
|
hook: address(this),
|
|
333
334
|
tierCashOutWeights: _tierCashOutWeights,
|
|
334
335
|
tokensRedeemedFrom: tokensRedeemedFrom
|
|
@@ -338,7 +339,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
338
339
|
/// @notice The amount of tokens of a tier that are currently in circulation.
|
|
339
340
|
/// @param tierId The ID of the tier to get the current supply of.
|
|
340
341
|
function currentSupplyOfTier(uint256 tierId) public view returns (uint256) {
|
|
341
|
-
return DefifaHookLib.computeCurrentSupply({
|
|
342
|
+
return DefifaHookLib.computeCurrentSupply({hookStore: store, hook: address(this), tierId: tierId});
|
|
342
343
|
}
|
|
343
344
|
|
|
344
345
|
/// @notice Indicates if this contract adheres to the specified interface.
|
|
@@ -356,8 +357,8 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
356
357
|
view
|
|
357
358
|
returns (uint256 defifaTokenAllocation, uint256 baseProtocolTokenAllocation)
|
|
358
359
|
{
|
|
359
|
-
defifaTokenAllocation =
|
|
360
|
-
baseProtocolTokenAllocation =
|
|
360
|
+
defifaTokenAllocation = DEFIFA_TOKEN.balanceOf(address(this));
|
|
361
|
+
baseProtocolTokenAllocation = BASE_PROTOCOL_TOKEN.balanceOf(address(this));
|
|
361
362
|
}
|
|
362
363
|
|
|
363
364
|
/// @notice The metadata URI of the provided token ID.
|
|
@@ -384,11 +385,11 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
384
385
|
// slither-disable-next-line unused-return
|
|
385
386
|
return DefifaHookLib.computeTokensClaim({
|
|
386
387
|
tokenIds: tokenIds,
|
|
387
|
-
|
|
388
|
+
hookStore: store,
|
|
388
389
|
hook: address(this),
|
|
389
390
|
totalMintCost: _totalMintCost,
|
|
390
|
-
defifaBalance:
|
|
391
|
-
baseProtocolBalance:
|
|
391
|
+
defifaBalance: DEFIFA_TOKEN.balanceOf(address(this)),
|
|
392
|
+
baseProtocolBalance: BASE_PROTOCOL_TOKEN.balanceOf(address(this))
|
|
392
393
|
});
|
|
393
394
|
}
|
|
394
395
|
|
|
@@ -412,9 +413,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
412
413
|
JB721Hook(_directory)
|
|
413
414
|
Ownable(msg.sender)
|
|
414
415
|
{
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
416
|
+
CODE_ORIGIN = address(this);
|
|
417
|
+
DEFIFA_TOKEN = _defifaToken;
|
|
418
|
+
BASE_PROTOCOL_TOKEN = _baseProtocolToken;
|
|
418
419
|
}
|
|
419
420
|
|
|
420
421
|
//*********************************************************************//
|
|
@@ -483,7 +484,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
483
484
|
override
|
|
484
485
|
{
|
|
485
486
|
// Make the original un-initializable.
|
|
486
|
-
if (address(this) ==
|
|
487
|
+
if (address(this) == CODE_ORIGIN) revert();
|
|
487
488
|
|
|
488
489
|
// Stop re-initialization.
|
|
489
490
|
if (address(store) != address(0)) revert();
|
|
@@ -568,6 +569,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
568
569
|
JB721Tier memory _tier = store.tierOf({hook: address(this), id: tierId, includeResolvedUri: false});
|
|
569
570
|
|
|
570
571
|
// Increment _totalMintCost so reserved recipients can claim their share of fee tokens ($DEFIFA/$NANA).
|
|
572
|
+
// Note: reserved mints dilute existing fee token claimants because they increase the total mint cost
|
|
573
|
+
// denominator without contributing new funds to the fee token balances. This is the intended design —
|
|
574
|
+
// reserved recipients receive a proportional claim on fee tokens as if they had paid to mint.
|
|
571
575
|
_totalMintCost += _tier.price * count;
|
|
572
576
|
|
|
573
577
|
for (uint256 _i; _i < count;) {
|
|
@@ -676,6 +680,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
676
680
|
}
|
|
677
681
|
|
|
678
682
|
// If there's nothing being claimed and we did not distribute fee tokens, revert to prevent burning for nothing.
|
|
683
|
+
// Tokens in 0-weight tiers (losing teams) cannot burn to reclaim fees if no fee tokens were
|
|
684
|
+
// distributed. This is correct behavior — 0-weight means the tier has no claim on the pot. Burning would
|
|
685
|
+
// return 0 value regardless.
|
|
679
686
|
if (context.reclaimedAmount.value == 0 && !_beneficiaryReceivedTokens) revert DefifaHook_NothingToClaim();
|
|
680
687
|
|
|
681
688
|
// Decrement the paid mint cost by the cumulative mint price of the tokens being burned.
|
|
@@ -718,7 +725,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
718
725
|
|
|
719
726
|
// Validate weights and build the array. Reverts on invalid input.
|
|
720
727
|
_tierCashOutWeights =
|
|
721
|
-
DefifaHookLib.validateAndBuildWeights({tierWeights: tierWeights,
|
|
728
|
+
DefifaHookLib.validateAndBuildWeights({tierWeights: tierWeights, hookStore: store, hook: address(this)});
|
|
722
729
|
|
|
723
730
|
// Mark the cashOut weight as set.
|
|
724
731
|
cashOutWeightIsSet = true;
|
|
@@ -730,6 +737,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
730
737
|
/// @param delegatee The account to delegate tier attestation units to.
|
|
731
738
|
/// @param tierId The ID of the tier to delegate attestation units for.
|
|
732
739
|
function setTierDelegateTo(address delegatee, uint256 tierId) public virtual override {
|
|
740
|
+
// Make sure a delegate is specified.
|
|
741
|
+
if (delegatee == address(0)) revert DefifaHook_DelegateAddressZero();
|
|
742
|
+
|
|
733
743
|
// Make sure the current game phase is the minting phase.
|
|
734
744
|
if (gamePhaseReporter.currentGamePhaseOf(PROJECT_ID) != DefifaGamePhase.MINT) {
|
|
735
745
|
revert DefifaHook_DelegateChangesUnavailableInThisPhase();
|
|
@@ -785,11 +795,11 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
785
795
|
returns (bool beneficiaryReceivedTokens)
|
|
786
796
|
{
|
|
787
797
|
return DefifaHookLib.claimTokensFor({
|
|
788
|
-
|
|
798
|
+
beneficiary: _beneficiary,
|
|
789
799
|
shareToBeneficiary: shareToBeneficiary,
|
|
790
800
|
outOfTotal: outOfTotal,
|
|
791
|
-
|
|
792
|
-
|
|
801
|
+
defifaToken: DEFIFA_TOKEN,
|
|
802
|
+
baseProtocolToken: BASE_PROTOCOL_TOKEN
|
|
793
803
|
});
|
|
794
804
|
}
|
|
795
805
|
|
|
@@ -847,6 +857,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
847
857
|
uint256[] memory _tokenIds;
|
|
848
858
|
|
|
849
859
|
// Record the mint. The returned token IDs correspond to the tiers passed in.
|
|
860
|
+
// slither-disable-next-line reentrancy-benign
|
|
850
861
|
(_tokenIds, leftoverAmount) = store.recordMint({
|
|
851
862
|
amount: _amount,
|
|
852
863
|
tierIds: _mintTierIds,
|
|
@@ -892,8 +903,14 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
892
903
|
// Get the current amount for the sending delegate.
|
|
893
904
|
uint208 _current = _delegateTierCheckpoints[_from][_tierId].latest();
|
|
894
905
|
// Set the new amount for the sending delegate.
|
|
906
|
+
// uint208 is sufficient for attestation values: each tier's attestation units are bounded by the NFT
|
|
907
|
+
// supply (max ~999_999_999 per tier * 128 tiers), well within uint208's ~4.1e62 range.
|
|
908
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
895
909
|
(uint256 _oldValue, uint256 _newValue) = _delegateTierCheckpoints[_from][_tierId].push({
|
|
896
|
-
|
|
910
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
911
|
+
key: uint48(block.timestamp),
|
|
912
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
913
|
+
value: _current - uint208(_amount)
|
|
897
914
|
});
|
|
898
915
|
emit TierDelegateAttestationsChanged(_from, _tierId, _oldValue, _newValue, msg.sender);
|
|
899
916
|
}
|
|
@@ -903,8 +920,12 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
903
920
|
// Get the current amount for the receiving delegate.
|
|
904
921
|
uint208 _current = _delegateTierCheckpoints[_to][_tierId].latest();
|
|
905
922
|
// Set the new amount for the receiving delegate.
|
|
923
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
906
924
|
(uint256 _oldValue, uint256 _newValue) = _delegateTierCheckpoints[_to][_tierId].push({
|
|
907
|
-
|
|
925
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
926
|
+
key: uint48(block.timestamp),
|
|
927
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
928
|
+
value: _current + uint208(_amount)
|
|
908
929
|
});
|
|
909
930
|
emit TierDelegateAttestationsChanged(_to, _tierId, _oldValue, _newValue, msg.sender);
|
|
910
931
|
}
|
|
@@ -918,7 +939,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
918
939
|
|
|
919
940
|
// Resolve the metadata.
|
|
920
941
|
(bool found, bytes memory metadata) = JBMetadataResolver.getDataFor({
|
|
921
|
-
id: JBMetadataResolver.getId({purpose: "pay", target:
|
|
942
|
+
id: JBMetadataResolver.getId({purpose: "pay", target: CODE_ORIGIN}), metadata: context.payerMetadata
|
|
922
943
|
});
|
|
923
944
|
|
|
924
945
|
if (!found) revert DefifaHook_NothingToMint();
|
|
@@ -935,8 +956,9 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
935
956
|
if (_tierIdsToMint.length == 0) revert DefifaHook_NothingToMint();
|
|
936
957
|
|
|
937
958
|
// Compute attestation units per unique tier (validates ascending order, reverts on bad order).
|
|
938
|
-
(uint256[] memory _tierIds, uint256[] memory _attestationAmounts, uint256 _uniqueTierCount) =
|
|
939
|
-
|
|
959
|
+
(uint256[] memory _tierIds, uint256[] memory _attestationAmounts, uint256 _uniqueTierCount) = DefifaHookLib.computeAttestationUnits({
|
|
960
|
+
tierIdsToMint: _tierIdsToMint, hookStore: store, hook: address(this)
|
|
961
|
+
});
|
|
940
962
|
|
|
941
963
|
// Apply attestation units for each unique tier.
|
|
942
964
|
for (uint256 _i; _i < _uniqueTierCount;) {
|
|
@@ -992,19 +1014,31 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
992
1014
|
|
|
993
1015
|
// If minting, add to the total tier checkpoints.
|
|
994
1016
|
if (_from == address(0)) {
|
|
1017
|
+
// Casting to uint208/uint48 is safe because attestation unit amounts are bounded by NFT supply counts.
|
|
1018
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1019
|
+
uint208 newValue = _current + uint208(_amount);
|
|
1020
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
995
1021
|
// slither-disable-next-line unused-return
|
|
996
|
-
_totalTierCheckpoints[_tierId].push({key: uint48(block.timestamp), value:
|
|
1022
|
+
_totalTierCheckpoints[_tierId].push({key: uint48(block.timestamp), value: newValue});
|
|
997
1023
|
}
|
|
998
1024
|
|
|
999
1025
|
// If burning, subtract from the total tier checkpoints.
|
|
1000
1026
|
if (_to == address(0)) {
|
|
1027
|
+
// Casting to uint208/uint48 is safe because attestation unit amounts are bounded by NFT supply counts.
|
|
1028
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1029
|
+
uint208 newValue = _current - uint208(_amount);
|
|
1030
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
1001
1031
|
// slither-disable-next-line unused-return
|
|
1002
|
-
_totalTierCheckpoints[_tierId].push({key: uint48(block.timestamp), value:
|
|
1032
|
+
_totalTierCheckpoints[_tierId].push({key: uint48(block.timestamp), value: newValue});
|
|
1003
1033
|
}
|
|
1004
1034
|
}
|
|
1005
1035
|
|
|
1006
1036
|
// Resolve the recipient's delegate. If the recipient has no delegate set, auto-delegate to themselves to
|
|
1007
1037
|
// prevent attestation units from being permanently lost.
|
|
1038
|
+
// Note: delegation persists after token transfers. If Alice delegates to Bob, then transfers her token
|
|
1039
|
+
// to Carol, Carol's attestation units auto-delegate to Carol (not Bob). However, Alice's delegation
|
|
1040
|
+
// to Bob persists — if Alice later receives another token, her units still go to Bob. This matches
|
|
1041
|
+
// ERC5805Votes behavior where delegation is an account-level setting, not a token-level one.
|
|
1008
1042
|
address _toDelegate = _tierDelegation[_to][_tierId];
|
|
1009
1043
|
if (_toDelegate == address(0) && _to != address(0)) {
|
|
1010
1044
|
_toDelegate = _to;
|
|
@@ -1051,7 +1085,7 @@ contract DefifaHook is JB721Hook, Ownable, IDefifaHook {
|
|
|
1051
1085
|
}
|
|
1052
1086
|
|
|
1053
1087
|
// Record the transfer.
|
|
1054
|
-
// slither-disable-next-line
|
|
1088
|
+
// slither-disable-next-line reentrancy-events,calls-loop
|
|
1055
1089
|
store.recordTransferForTier({tierId: tier.id, from: from, to: to});
|
|
1056
1090
|
|
|
1057
1091
|
// Dont transfer on mint since the delegation will be transferred more efficiently in _processPayment.
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
-
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
|
|
5
|
-
import {DefifaDeployer} from "./DefifaDeployer.sol";
|
|
6
4
|
import {IJBPermissions, JBPermissionsData} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
7
5
|
import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
|
|
8
6
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
7
|
+
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
|
|
8
|
+
|
|
9
|
+
import {DefifaDeployer} from "./DefifaDeployer.sol";
|
|
9
10
|
|
|
10
11
|
/// @notice A contract that can be sent a project to be burned, while still allowing defifa permissions.
|
|
11
12
|
/// @dev Once the project NFT is transferred here, it cannot be recovered. This contract permanently
|
|
12
13
|
/// holds the project NFT and grants SET_SPLIT_GROUPS permission to the Defifa deployer.
|
|
13
14
|
contract DefifaProjectOwner is IERC721Receiver {
|
|
15
|
+
//*********************************************************************//
|
|
16
|
+
// --------------------------- custom errors ------------------------- //
|
|
17
|
+
//*********************************************************************//
|
|
18
|
+
|
|
19
|
+
error DefifaProjectOwner_InvalidSender();
|
|
20
|
+
|
|
21
|
+
//*********************************************************************//
|
|
22
|
+
// --------------- public immutable stored properties ---------------- //
|
|
23
|
+
//*********************************************************************//
|
|
24
|
+
|
|
14
25
|
/// @notice The contract where operator permissions are stored.
|
|
15
26
|
IJBPermissions public immutable PERMISSIONS;
|
|
16
27
|
|
|
@@ -20,6 +31,10 @@ contract DefifaProjectOwner is IERC721Receiver {
|
|
|
20
31
|
/// @notice The Defifa deployer.
|
|
21
32
|
DefifaDeployer public immutable DEPLOYER;
|
|
22
33
|
|
|
34
|
+
//*********************************************************************//
|
|
35
|
+
// -------------------------- constructor ---------------------------- //
|
|
36
|
+
//*********************************************************************//
|
|
37
|
+
|
|
23
38
|
/// @param permissions The contract where operator permissions are stored.
|
|
24
39
|
/// @param projects The contract from which projects are minted.
|
|
25
40
|
/// @param deployer The Defifa deployer which will receive permissions to set splits.
|
|
@@ -29,6 +44,10 @@ contract DefifaProjectOwner is IERC721Receiver {
|
|
|
29
44
|
DEPLOYER = deployer;
|
|
30
45
|
}
|
|
31
46
|
|
|
47
|
+
//*********************************************************************//
|
|
48
|
+
// ---------------------- external transactions ---------------------- //
|
|
49
|
+
//*********************************************************************//
|
|
50
|
+
|
|
32
51
|
/// @notice Give the defifa deployer permission to set splits on this contract's behalf.
|
|
33
52
|
function onERC721Received(
|
|
34
53
|
address operator,
|
|
@@ -44,7 +63,7 @@ contract DefifaProjectOwner is IERC721Receiver {
|
|
|
44
63
|
operator;
|
|
45
64
|
|
|
46
65
|
// Make sure the 721 received is the JBProjects contract.
|
|
47
|
-
if (msg.sender != address(PROJECTS)) revert();
|
|
66
|
+
if (msg.sender != address(PROJECTS)) revert DefifaProjectOwner_InvalidSender();
|
|
48
67
|
|
|
49
68
|
// Set the correct permission.
|
|
50
69
|
uint8[] memory permissionIds = new uint8[](1);
|
|
@@ -54,7 +73,11 @@ contract DefifaProjectOwner is IERC721Receiver {
|
|
|
54
73
|
PERMISSIONS.setPermissionsFor({
|
|
55
74
|
account: address(this),
|
|
56
75
|
permissionsData: JBPermissionsData({
|
|
57
|
-
|
|
76
|
+
// Casting to uint64 is safe because Juicebox project IDs are sequential and will not exceed uint64.
|
|
77
|
+
operator: address(DEPLOYER),
|
|
78
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
79
|
+
projectId: uint64(tokenId),
|
|
80
|
+
permissionIds: permissionIds
|
|
58
81
|
})
|
|
59
82
|
});
|
|
60
83
|
|