@ballkidz/defifa 0.0.6 → 0.0.8
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/AUDIT_INSTRUCTIONS.md +422 -0
- package/CRYPTO_ECON.md +5 -5
- package/RISKS.md +38 -335
- package/SKILLS.md +1 -1
- package/STYLE_GUIDE.md +14 -1
- package/USER_JOURNEYS.md +691 -0
- package/package.json +7 -5
- package/script/Deploy.s.sol +26 -13
- package/script/helpers/DefifaDeploymentLib.sol +30 -14
- package/src/DefifaDeployer.sol +225 -187
- package/src/DefifaGovernor.sol +291 -281
- package/src/DefifaHook.sol +81 -42
- package/src/DefifaProjectOwner.sol +27 -4
- package/src/DefifaTokenUriResolver.sol +137 -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 +68 -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 +37 -11
- package/test/DefifaHookRegressions.t.sol +14 -12
- package/test/DefifaMintCostInvariant.t.sol +31 -12
- package/test/DefifaNoContest.t.sol +33 -13
- package/test/DefifaSecurity.t.sol +45 -25
- package/test/DefifaUSDC.t.sol +44 -34
- package/test/Fork.t.sol +42 -40
- 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
|
@@ -1,98 +1,99 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity 0.8.26;
|
|
3
3
|
|
|
4
|
-
import {Base64} from "lib/base64/base64.sol";
|
|
5
|
-
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
6
|
-
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
|
7
4
|
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {IDefifaTokenUriResolver} from "./interfaces/IDefifaTokenUriResolver.sol";
|
|
11
|
-
import {DefifaFontImporter} from "./libraries/DefifaFontImporter.sol";
|
|
12
|
-
import {DefifaGamePhase} from "./enums/DefifaGamePhase.sol";
|
|
5
|
+
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
|
6
|
+
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
13
7
|
|
|
14
|
-
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
15
|
-
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
16
8
|
import {ERC721} from "@bananapus/721-hook-v6/src/abstract/ERC721.sol";
|
|
9
|
+
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
17
10
|
import {JB721Tier} from "@bananapus/721-hook-v6/src/structs/JB721Tier.sol";
|
|
18
11
|
import {JBIpfsDecoder} from "@bananapus/721-hook-v6/src/libraries/JBIpfsDecoder.sol";
|
|
12
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
13
|
+
|
|
14
|
+
import {Base64} from "lib/base64/base64.sol";
|
|
15
|
+
import {ITypeface} from "lib/typeface/contracts/interfaces/ITypeface.sol";
|
|
16
|
+
|
|
17
|
+
import {DefifaFontImporter} from "./libraries/DefifaFontImporter.sol";
|
|
18
|
+
import {DefifaGamePhase} from "./enums/DefifaGamePhase.sol";
|
|
19
|
+
import {IDefifaHook} from "./interfaces/IDefifaHook.sol";
|
|
20
|
+
import {IDefifaTokenUriResolver} from "./interfaces/IDefifaTokenUriResolver.sol";
|
|
19
21
|
|
|
20
|
-
/// @title DefifaTokenUriResolver
|
|
21
22
|
/// @notice Standard Token URIs for Defifa games.
|
|
22
23
|
contract DefifaTokenUriResolver is IDefifaTokenUriResolver, IJB721TokenUriResolver {
|
|
23
24
|
using Strings for uint256;
|
|
24
25
|
|
|
25
26
|
//*********************************************************************//
|
|
26
|
-
//
|
|
27
|
+
// ----------------------- internal constants ------------------------ //
|
|
27
28
|
//*********************************************************************//
|
|
28
29
|
|
|
29
30
|
/// @notice The fidelity of the decimal returned in the NFT image.
|
|
30
|
-
uint256
|
|
31
|
+
uint256 internal constant _IMG_DECIMAL_FIDELITY = 5;
|
|
31
32
|
|
|
32
33
|
//*********************************************************************//
|
|
33
34
|
// --------------- public immutable stored properties ---------------- //
|
|
34
35
|
//*********************************************************************//
|
|
35
36
|
|
|
36
37
|
/// @notice The typeface of the SVGs.
|
|
37
|
-
ITypeface public immutable override
|
|
38
|
+
ITypeface public immutable override TYPEFACE;
|
|
38
39
|
|
|
39
40
|
//*********************************************************************//
|
|
40
41
|
// -------------------------- constructor ---------------------------- //
|
|
41
42
|
//*********************************************************************//
|
|
42
43
|
|
|
43
|
-
constructor(ITypeface
|
|
44
|
-
|
|
44
|
+
constructor(ITypeface typeface) {
|
|
45
|
+
TYPEFACE = typeface;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
//*********************************************************************//
|
|
48
|
-
//
|
|
49
|
+
// ----------------------- external views ---------------------------- //
|
|
49
50
|
//*********************************************************************//
|
|
50
51
|
|
|
51
52
|
/// @notice The metadata URI of the provided token ID.
|
|
52
53
|
/// @dev Defer to the token's tier IPFS URI if set.
|
|
53
|
-
/// @param
|
|
54
|
-
/// @param
|
|
54
|
+
/// @param nft The address of the nft the token URI should be oriented to.
|
|
55
|
+
/// @param tokenId The ID of the token to get the tier URI for.
|
|
55
56
|
/// @return The token URI corresponding with the tier.
|
|
56
|
-
function tokenUriOf(address
|
|
57
|
+
function tokenUriOf(address nft, uint256 tokenId) external view override returns (string memory) {
|
|
57
58
|
// Keep a reference to the hook.
|
|
58
|
-
IDefifaHook
|
|
59
|
+
IDefifaHook hook = IDefifaHook(nft);
|
|
59
60
|
|
|
60
61
|
// Get the game ID.
|
|
61
|
-
uint256
|
|
62
|
+
uint256 gameId = hook.PROJECT_ID();
|
|
62
63
|
|
|
63
64
|
// Keep a reference to the game phase text.
|
|
64
|
-
string memory
|
|
65
|
+
string memory gamePhaseText;
|
|
65
66
|
|
|
66
67
|
// Keep a reference to the rarity text;
|
|
67
|
-
string memory
|
|
68
|
+
string memory rarityText;
|
|
68
69
|
|
|
69
70
|
// Keep a reference to the rarity text;
|
|
70
|
-
string memory
|
|
71
|
+
string memory valueText;
|
|
71
72
|
|
|
72
73
|
// Keep a reference to the game's name.
|
|
73
74
|
// TODO: Somehow make the `IDefifaHook` have the `name` function.
|
|
74
|
-
string memory
|
|
75
|
+
string memory title = ERC721(address(hook)).name();
|
|
75
76
|
|
|
76
77
|
// Keep a reference to the tier's name.
|
|
77
|
-
string memory
|
|
78
|
+
string memory team;
|
|
78
79
|
|
|
79
80
|
// Keep a reference to the SVG parts.
|
|
80
81
|
string[] memory parts = new string[](4);
|
|
81
82
|
|
|
82
83
|
// Keep a reference to the pot.
|
|
83
|
-
string memory
|
|
84
|
+
string memory potText;
|
|
84
85
|
|
|
85
86
|
{
|
|
86
87
|
// Get a reference to the tier.
|
|
87
|
-
JB721Tier memory
|
|
88
|
-
|
|
88
|
+
JB721Tier memory tier =
|
|
89
|
+
hook.store().tierOfTokenId({hook: address(hook), tokenId: tokenId, includeResolvedUri: false});
|
|
89
90
|
|
|
90
91
|
// Set the tier's name.
|
|
91
|
-
|
|
92
|
+
team = hook.tierNameOf(tier.id);
|
|
92
93
|
|
|
93
94
|
// Check to see if the tier has a URI. Return it if it does.
|
|
94
|
-
if (
|
|
95
|
-
return JBIpfsDecoder.decode({baseUri:
|
|
95
|
+
if (tier.encodedIPFSUri != bytes32(0)) {
|
|
96
|
+
return JBIpfsDecoder.decode({baseUri: hook.baseURI(), hexString: tier.encodedIPFSUri});
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
parts[0] = string("data:application/json;base64,");
|
|
@@ -100,82 +101,80 @@ contract DefifaTokenUriResolver is IDefifaTokenUriResolver, IJB721TokenUriResolv
|
|
|
100
101
|
parts[1] = string(
|
|
101
102
|
abi.encodePacked(
|
|
102
103
|
'{"name":"',
|
|
103
|
-
|
|
104
|
+
team,
|
|
104
105
|
'", "id": "',
|
|
105
|
-
uint256(
|
|
106
|
+
uint256(tier.id).toString(),
|
|
106
107
|
'","description":"Team: ',
|
|
107
|
-
|
|
108
|
+
team,
|
|
108
109
|
", ID: ",
|
|
109
|
-
uint256(
|
|
110
|
+
uint256(tier.id).toString(),
|
|
110
111
|
'.","image":"data:image/svg+xml;base64,'
|
|
111
112
|
)
|
|
112
113
|
);
|
|
113
114
|
|
|
114
115
|
{
|
|
115
116
|
// Get a reference to the game phase.
|
|
116
|
-
DefifaGamePhase
|
|
117
|
+
DefifaGamePhase gamePhase = hook.gamePhaseReporter().currentGamePhaseOf(gameId);
|
|
117
118
|
|
|
118
119
|
// Keep a reference to the game pot.
|
|
119
|
-
(uint256
|
|
120
|
-
|
|
120
|
+
(uint256 gamePot, address gamePotToken, uint256 gamePotDecimals) =
|
|
121
|
+
hook.gamePotReporter().currentGamePotOf({gameId: gameId, includeCommitments: false});
|
|
121
122
|
|
|
122
123
|
// Include the amount redeemed.
|
|
123
|
-
|
|
124
|
+
gamePot = gamePot + hook.amountRedeemed();
|
|
124
125
|
|
|
125
126
|
// Set the pot text.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
_token: _gamePotToken,
|
|
129
|
-
_decimals: _gamePotDecimals,
|
|
130
|
-
_fidelity: _IMG_DECIMAL_FIDELITY
|
|
127
|
+
potText = _formatBalance({
|
|
128
|
+
amount: gamePot, token: gamePotToken, decimals: gamePotDecimals, fidelity: _IMG_DECIMAL_FIDELITY
|
|
131
129
|
});
|
|
132
130
|
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
} else if (
|
|
136
|
-
|
|
137
|
-
} else if (
|
|
138
|
-
|
|
139
|
-
} else if (
|
|
140
|
-
|
|
141
|
-
} else if (
|
|
142
|
-
|
|
143
|
-
} else if (
|
|
144
|
-
|
|
131
|
+
if (gamePhase == DefifaGamePhase.COUNTDOWN) {
|
|
132
|
+
gamePhaseText = "Minting starts soon.";
|
|
133
|
+
} else if (gamePhase == DefifaGamePhase.MINT) {
|
|
134
|
+
gamePhaseText = "Minting and refunds are open.";
|
|
135
|
+
} else if (gamePhase == DefifaGamePhase.REFUND) {
|
|
136
|
+
gamePhaseText = "Minting is over. Refunds are ending.";
|
|
137
|
+
} else if (gamePhase == DefifaGamePhase.SCORING) {
|
|
138
|
+
gamePhaseText = "Awaiting scorecard approval.";
|
|
139
|
+
} else if (gamePhase == DefifaGamePhase.COMPLETE) {
|
|
140
|
+
gamePhaseText = "Scorecard locked in. Burn to claim reward.";
|
|
141
|
+
} else if (gamePhase == DefifaGamePhase.NO_CONTEST) {
|
|
142
|
+
gamePhaseText = "No contest. Refunds open.";
|
|
145
143
|
}
|
|
146
144
|
|
|
147
145
|
// Keep a reference to the number of tokens outstanding from this tier.
|
|
148
|
-
uint256
|
|
146
|
+
uint256 totalMinted = hook.currentSupplyOfTier(tier.id);
|
|
149
147
|
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
abi.encodePacked(
|
|
148
|
+
if (gamePhase == DefifaGamePhase.MINT) {
|
|
149
|
+
rarityText = string(
|
|
150
|
+
abi.encodePacked(totalMinted.toString(), totalMinted == 1 ? " card so far" : " cards so far")
|
|
153
151
|
);
|
|
154
152
|
} else {
|
|
155
|
-
|
|
153
|
+
rarityText = string(
|
|
156
154
|
abi.encodePacked(
|
|
157
|
-
|
|
155
|
+
totalMinted.toString(), totalMinted == 1 ? " card in existence" : " cards in existence"
|
|
158
156
|
)
|
|
159
157
|
);
|
|
160
158
|
}
|
|
161
159
|
|
|
162
|
-
if (
|
|
163
|
-
uint256
|
|
164
|
-
|
|
165
|
-
|
|
160
|
+
if (gamePhase == DefifaGamePhase.SCORING || gamePhase == DefifaGamePhase.COMPLETE) {
|
|
161
|
+
uint256 potPortion = mulDiv({
|
|
162
|
+
x: gamePot, y: hook.cashOutWeightOf(tokenId), denominator: hook.TOTAL_CASHOUT_WEIGHT()
|
|
163
|
+
});
|
|
164
|
+
valueText = !hook.cashOutWeightIsSet()
|
|
166
165
|
? "Awaiting scorecard..."
|
|
167
166
|
: _formatBalance({
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
amount: potPortion,
|
|
168
|
+
token: gamePotToken,
|
|
169
|
+
decimals: gamePotDecimals,
|
|
170
|
+
fidelity: _IMG_DECIMAL_FIDELITY
|
|
172
171
|
});
|
|
173
172
|
} else {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
173
|
+
valueText = _formatBalance({
|
|
174
|
+
amount: tier.price,
|
|
175
|
+
token: gamePotToken,
|
|
176
|
+
decimals: gamePotDecimals,
|
|
177
|
+
fidelity: _IMG_DECIMAL_FIDELITY
|
|
179
178
|
});
|
|
180
179
|
}
|
|
181
180
|
}
|
|
@@ -184,54 +183,54 @@ contract DefifaTokenUriResolver is IDefifaTokenUriResolver, IJB721TokenUriResolv
|
|
|
184
183
|
abi.encodePacked(
|
|
185
184
|
'<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">',
|
|
186
185
|
'<style>@font-face{font-family:"Capsules-500";src:url(data:font/truetype;charset=utf-8;base64,',
|
|
187
|
-
DefifaFontImporter.getSkinnyFontSource(
|
|
186
|
+
DefifaFontImporter.getSkinnyFontSource(TYPEFACE),
|
|
188
187
|
');format("opentype");}',
|
|
189
188
|
'@font-face{font-family:"Capsules-700";src:url(data:font/truetype;charset=utf-8;base64,',
|
|
190
|
-
DefifaFontImporter.getBeefyFontSource(
|
|
189
|
+
DefifaFontImporter.getBeefyFontSource(TYPEFACE),
|
|
191
190
|
');format("opentype");}',
|
|
192
191
|
"text{white-space:pre-wrap; width:100%; }</style>",
|
|
193
192
|
'<rect width="100%" height="100%" fill="#181424"/>',
|
|
194
193
|
'<text x="10" y="30" style="font-size:16px; font-family: Capsules-500; font-weight:500; fill: #c0b3f1;">GAME: ',
|
|
195
|
-
|
|
194
|
+
gameId.toString(),
|
|
196
195
|
" | POT: ",
|
|
197
|
-
|
|
196
|
+
potText,
|
|
198
197
|
" | CARDS: ",
|
|
199
|
-
|
|
198
|
+
hook.store().totalSupplyOf(address(hook)).toString(),
|
|
200
199
|
"</text>",
|
|
201
200
|
'<text x="10" y="50" style="font-size:16px; font-family: Capsules-500; font-weight:500; fill: #ed017c;">',
|
|
202
|
-
|
|
201
|
+
gamePhaseText,
|
|
203
202
|
"</text>",
|
|
204
203
|
'<text x="10" y="85" style="font-size:26px; font-family: Capsules-500; font-weight:500; fill: #c0b3f1;">',
|
|
205
|
-
_getSubstring(
|
|
204
|
+
_getSubstring(title, 0, 30),
|
|
206
205
|
"</text>",
|
|
207
206
|
'<text x="10" y="120" style="font-size:26px; font-family: Capsules-500; font-weight:500; fill: #c0b3f1;">',
|
|
208
|
-
_getSubstring(
|
|
207
|
+
_getSubstring(title, 30, 60),
|
|
209
208
|
"</text>",
|
|
210
209
|
'<text x="10" y="205" style="font-size:80px; font-family: Capsules-700; font-weight:700; fill: #fea282;">',
|
|
211
|
-
bytes(_getSubstring(
|
|
212
|
-
? _getSubstring(
|
|
210
|
+
bytes(_getSubstring(team, 20, 30)).length != 0 && bytes(_getSubstring(team, 10, 20)).length != 0
|
|
211
|
+
? _getSubstring(team, 0, 10)
|
|
213
212
|
: "",
|
|
214
213
|
"</text>",
|
|
215
214
|
'<text x="10" y="295" style="font-size:80px; font-family: Capsules-700; font-weight:700; fill: #fea282;">',
|
|
216
|
-
bytes(_getSubstring(
|
|
217
|
-
? _getSubstring(
|
|
218
|
-
: bytes(_getSubstring(
|
|
215
|
+
bytes(_getSubstring(team, 20, 30)).length != 0
|
|
216
|
+
? _getSubstring(team, 10, 20)
|
|
217
|
+
: bytes(_getSubstring(team, 10, 20)).length != 0 ? _getSubstring(team, 0, 10) : "",
|
|
219
218
|
"</text>",
|
|
220
219
|
'<text x="10" y="385" style="font-size:80px; font-family: Capsules-700; font-weight:700; fill: #fea282;">',
|
|
221
|
-
bytes(_getSubstring(
|
|
222
|
-
? _getSubstring(
|
|
223
|
-
: bytes(_getSubstring(
|
|
224
|
-
? _getSubstring(
|
|
225
|
-
: _getSubstring(
|
|
220
|
+
bytes(_getSubstring(team, 20, 30)).length != 0
|
|
221
|
+
? _getSubstring(team, 20, 30)
|
|
222
|
+
: bytes(_getSubstring(team, 10, 20)).length != 0
|
|
223
|
+
? _getSubstring(team, 10, 20)
|
|
224
|
+
: _getSubstring(team, 0, 10),
|
|
226
225
|
"</text>",
|
|
227
226
|
'<text x="10" y="430" style="font-size:16px; font-family: Capsules-500; font-weight:500; fill: #c0b3f1;">TOKEN ID: ',
|
|
228
|
-
|
|
227
|
+
tokenId.toString(),
|
|
229
228
|
"</text>",
|
|
230
229
|
'<text x="10" y="455" style="font-size:16px; font-family: Capsules-500; font-weight:500; fill: #c0b3f1;">RARITY: ',
|
|
231
|
-
|
|
230
|
+
rarityText,
|
|
232
231
|
"</text>",
|
|
233
232
|
'<text x="10" y="480" style="font-size:16px; font-family: Capsules-500; font-weight:500; fill: #c0b3f1;">BACKED BY: ',
|
|
234
|
-
|
|
233
|
+
valueText,
|
|
235
234
|
"</text>",
|
|
236
235
|
"</svg>"
|
|
237
236
|
)
|
|
@@ -241,72 +240,76 @@ contract DefifaTokenUriResolver is IDefifaTokenUriResolver, IJB721TokenUriResolv
|
|
|
241
240
|
return string.concat(parts[0], Base64.encode(abi.encodePacked(parts[1], parts[2], parts[3])));
|
|
242
241
|
}
|
|
243
242
|
|
|
243
|
+
//*********************************************************************//
|
|
244
|
+
// ----------------------- internal views ---------------------------- //
|
|
245
|
+
//*********************************************************************//
|
|
246
|
+
|
|
244
247
|
/// @notice Formats a balance from a fixed point number to a string.
|
|
245
|
-
/// @param
|
|
246
|
-
/// @param
|
|
247
|
-
/// @param
|
|
248
|
-
/// @param
|
|
248
|
+
/// @param amount The fixed point amount.
|
|
249
|
+
/// @param token The token the amount is in.
|
|
250
|
+
/// @param decimals The number of decimals in the fixed point amount.
|
|
251
|
+
/// @param fidelity The number of decimals that should be returned in the formatted string.
|
|
249
252
|
/// @return The formatted balance.
|
|
250
253
|
function _formatBalance(
|
|
251
|
-
uint256
|
|
252
|
-
address
|
|
253
|
-
uint256
|
|
254
|
-
uint256
|
|
254
|
+
uint256 amount,
|
|
255
|
+
address token,
|
|
256
|
+
uint256 decimals,
|
|
257
|
+
uint256 fidelity
|
|
255
258
|
)
|
|
256
259
|
internal
|
|
257
260
|
view
|
|
258
261
|
returns (string memory)
|
|
259
262
|
{
|
|
260
|
-
bool
|
|
263
|
+
bool isEth = token == JBConstants.NATIVE_TOKEN;
|
|
261
264
|
|
|
262
|
-
uint256
|
|
265
|
+
uint256 fixedPoint = 10 ** decimals;
|
|
263
266
|
|
|
264
267
|
// Convert amount to a decimal format
|
|
265
|
-
string memory
|
|
268
|
+
string memory integerPart = (amount / fixedPoint).toString();
|
|
266
269
|
|
|
267
|
-
uint256
|
|
268
|
-
uint256
|
|
269
|
-
uint256
|
|
270
|
+
uint256 remainder = amount % fixedPoint;
|
|
271
|
+
uint256 scaledRemainder = remainder * (10 ** fidelity);
|
|
272
|
+
uint256 decimalPart = scaledRemainder / fixedPoint;
|
|
270
273
|
|
|
271
274
|
// Pad with zeros if necessary
|
|
272
|
-
string memory
|
|
273
|
-
while (bytes(
|
|
274
|
-
|
|
275
|
+
string memory decimalPartStr = decimalPart.toString();
|
|
276
|
+
while (bytes(decimalPartStr).length < fidelity) {
|
|
277
|
+
decimalPartStr = string(abi.encodePacked("0", decimalPartStr));
|
|
275
278
|
}
|
|
276
279
|
|
|
277
280
|
// Concatenate the strings
|
|
278
|
-
return
|
|
279
|
-
? string(abi.encodePacked("\u039E",
|
|
280
|
-
: string(abi.encodePacked(
|
|
281
|
+
return isEth
|
|
282
|
+
? string(abi.encodePacked("\u039E", integerPart, ".", decimalPartStr))
|
|
283
|
+
: string(abi.encodePacked(integerPart, ".", decimalPartStr, " ", IERC20Metadata(token).symbol()));
|
|
281
284
|
}
|
|
282
285
|
|
|
283
286
|
/// @notice Gets a substring.
|
|
284
287
|
/// @dev If the first character is a space, it is not included.
|
|
285
|
-
/// @param
|
|
286
|
-
/// @param
|
|
287
|
-
/// @param
|
|
288
|
+
/// @param str The string to get a substring of.
|
|
289
|
+
/// @param startIndex The first index of the substring from within the string.
|
|
290
|
+
/// @param endIndex The last index of the string from within the string.
|
|
288
291
|
/// @return substring The substring.
|
|
289
292
|
function _getSubstring(
|
|
290
|
-
string memory
|
|
291
|
-
uint256
|
|
292
|
-
uint256
|
|
293
|
+
string memory str,
|
|
294
|
+
uint256 startIndex,
|
|
295
|
+
uint256 endIndex
|
|
293
296
|
)
|
|
294
297
|
internal
|
|
295
298
|
pure
|
|
296
299
|
returns (string memory substring)
|
|
297
300
|
{
|
|
298
|
-
bytes memory
|
|
299
|
-
if (
|
|
300
|
-
if (
|
|
301
|
-
|
|
302
|
-
if (
|
|
303
|
-
bytes memory
|
|
304
|
-
for (uint256
|
|
305
|
-
|
|
301
|
+
bytes memory strBytes = bytes(str);
|
|
302
|
+
if (startIndex >= strBytes.length) return "";
|
|
303
|
+
if (endIndex > strBytes.length) endIndex = strBytes.length;
|
|
304
|
+
startIndex = strBytes[startIndex] == bytes1(0x20) ? startIndex + 1 : startIndex;
|
|
305
|
+
if (startIndex >= endIndex) return "";
|
|
306
|
+
bytes memory result = new bytes(endIndex - startIndex);
|
|
307
|
+
for (uint256 i = startIndex; i < endIndex;) {
|
|
308
|
+
result[i - startIndex] = strBytes[i];
|
|
306
309
|
unchecked {
|
|
307
|
-
++
|
|
310
|
+
++i;
|
|
308
311
|
}
|
|
309
312
|
}
|
|
310
|
-
return string(
|
|
313
|
+
return string(result);
|
|
311
314
|
}
|
|
312
315
|
}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity 0.8.
|
|
3
|
-
|
|
4
|
-
import {DefifaLaunchProjectData} from "../structs/DefifaLaunchProjectData.sol";
|
|
5
|
-
import {IDefifaHook} from "./IDefifaHook.sol";
|
|
6
|
-
import {IDefifaGovernor} from "./IDefifaGovernor.sol";
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
7
3
|
|
|
8
4
|
import {IJB721TokenUriResolver} from "@bananapus/721-hook-v6/src/interfaces/IJB721TokenUriResolver.sol";
|
|
9
|
-
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
10
|
-
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
11
5
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
6
|
+
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
7
|
+
import {JBSplit} from "@bananapus/core-v6/src/structs/JBSplit.sol";
|
|
8
|
+
|
|
9
|
+
import {DefifaLaunchProjectData} from "../structs/DefifaLaunchProjectData.sol";
|
|
10
|
+
import {IDefifaGovernor} from "./IDefifaGovernor.sol";
|
|
11
|
+
import {IDefifaHook} from "./IDefifaHook.sol";
|
|
12
12
|
|
|
13
13
|
/// @notice Deploys and manages Defifa prediction games, including lifecycle phase transitions
|
|
14
14
|
/// and commitment fulfillment.
|
|
15
15
|
interface IDefifaDeployer {
|
|
16
|
+
event CommitmentPayoutFailed(uint256 indexed gameId, uint256 amount, bytes reason);
|
|
17
|
+
|
|
18
|
+
event DistributeToSplit(JBSplit split, uint256 amount, address caller);
|
|
19
|
+
|
|
20
|
+
event FulfilledCommitments(uint256 indexed gameId, uint256 pot, address caller);
|
|
21
|
+
|
|
16
22
|
event LaunchGame(
|
|
17
23
|
uint256 indexed gameId,
|
|
18
24
|
IDefifaHook indexed hook,
|
|
@@ -21,55 +27,62 @@ interface IDefifaDeployer {
|
|
|
21
27
|
address caller
|
|
22
28
|
);
|
|
23
29
|
|
|
30
|
+
event QueuedNoContest(uint256 indexed gameId, address caller);
|
|
31
|
+
|
|
24
32
|
event QueuedRefundPhase(uint256 indexed gameId, address caller);
|
|
25
33
|
|
|
26
34
|
event QueuedScoringPhase(uint256 indexed gameId, address caller);
|
|
27
35
|
|
|
28
|
-
|
|
36
|
+
/// @notice The fee divisor for base protocol fees (100 / fee percent).
|
|
37
|
+
/// @return The fee divisor.
|
|
38
|
+
function BASE_PROTOCOL_FEE_DIVISOR() external view returns (uint256);
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
/// @notice The Juicebox project ID of the base protocol project.
|
|
41
|
+
/// @return The project ID.
|
|
42
|
+
function BASE_PROTOCOL_PROJECT_ID() external view returns (uint256);
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
/// @notice The Juicebox controller used to manage projects.
|
|
45
|
+
/// @return The controller contract.
|
|
46
|
+
function CONTROLLER() external view returns (IJBController);
|
|
33
47
|
|
|
34
|
-
/// @notice The
|
|
35
|
-
/// @return The
|
|
36
|
-
function
|
|
48
|
+
/// @notice The fee divisor for Defifa fees (100 / fee percent).
|
|
49
|
+
/// @return The fee divisor.
|
|
50
|
+
function DEFIFA_FEE_DIVISOR() external view returns (uint256);
|
|
37
51
|
|
|
38
52
|
/// @notice The Juicebox project ID of the Defifa project.
|
|
39
53
|
/// @return The project ID.
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
/// @notice The Juicebox project ID of the base protocol project.
|
|
43
|
-
/// @return The project ID.
|
|
44
|
-
function baseProtocolProjectId() external view returns (uint256);
|
|
45
|
-
|
|
46
|
-
/// @notice The code origin address used as an implementation for hook clones.
|
|
47
|
-
/// @return The code origin address.
|
|
48
|
-
function hookCodeOrigin() external view returns (address);
|
|
49
|
-
|
|
50
|
-
/// @notice The token URI resolver used for game NFT metadata.
|
|
51
|
-
/// @return The token URI resolver contract.
|
|
52
|
-
function tokenUriResolver() external view returns (IJB721TokenUriResolver);
|
|
54
|
+
function DEFIFA_PROJECT_ID() external view returns (uint256);
|
|
53
55
|
|
|
54
56
|
/// @notice The governor contract used for scorecard governance.
|
|
55
57
|
/// @return The governor contract.
|
|
56
|
-
function
|
|
58
|
+
function GOVERNOR() external view returns (IDefifaGovernor);
|
|
57
59
|
|
|
58
|
-
/// @notice The
|
|
59
|
-
/// @return The
|
|
60
|
-
function
|
|
60
|
+
/// @notice The code origin address used as an implementation for hook clones.
|
|
61
|
+
/// @return The code origin address.
|
|
62
|
+
function HOOK_CODE_ORIGIN() external view returns (address);
|
|
61
63
|
|
|
62
64
|
/// @notice The address registry used for content-addressable deployment lookups.
|
|
63
65
|
/// @return The address registry contract.
|
|
64
|
-
function
|
|
66
|
+
function REGISTRY() external view returns (IJBAddressRegistry);
|
|
65
67
|
|
|
66
|
-
/// @notice The
|
|
67
|
-
/// @return The
|
|
68
|
-
function
|
|
68
|
+
/// @notice The split group ID used for distributing game pot funds.
|
|
69
|
+
/// @return The split group.
|
|
70
|
+
function SPLIT_GROUP() external view returns (uint256);
|
|
69
71
|
|
|
70
|
-
/// @notice The
|
|
71
|
-
/// @return The
|
|
72
|
-
function
|
|
72
|
+
/// @notice The token URI resolver used for game NFT metadata.
|
|
73
|
+
/// @return The token URI resolver contract.
|
|
74
|
+
function TOKEN_URI_RESOLVER() external view returns (IJB721TokenUriResolver);
|
|
75
|
+
|
|
76
|
+
/// @notice Whether the next game phase needs to be queued.
|
|
77
|
+
/// @param gameId The ID of the game.
|
|
78
|
+
/// @return True if the next phase needs queueing.
|
|
79
|
+
function nextPhaseNeedsQueueing(uint256 gameId) external view returns (bool);
|
|
80
|
+
|
|
81
|
+
/// @notice The safety parameters for a game.
|
|
82
|
+
/// @param gameId The ID of the game.
|
|
83
|
+
/// @return minParticipation The minimum participation threshold.
|
|
84
|
+
/// @return scorecardTimeout The scorecard timeout duration.
|
|
85
|
+
function safetyParamsOf(uint256 gameId) external view returns (uint256 minParticipation, uint32 scorecardTimeout);
|
|
73
86
|
|
|
74
87
|
/// @notice The timing parameters for a game.
|
|
75
88
|
/// @param gameId The ID of the game.
|
|
@@ -81,26 +94,15 @@ interface IDefifaDeployer {
|
|
|
81
94
|
/// @return The token address.
|
|
82
95
|
function tokenOf(uint256 gameId) external view returns (address);
|
|
83
96
|
|
|
84
|
-
/// @notice
|
|
85
|
-
/// @param gameId The ID of the game.
|
|
86
|
-
/// @return minParticipation The minimum participation threshold.
|
|
87
|
-
/// @return scorecardTimeout The scorecard timeout duration.
|
|
88
|
-
function safetyParamsOf(uint256 gameId) external view returns (uint256 minParticipation, uint32 scorecardTimeout);
|
|
89
|
-
|
|
90
|
-
/// @notice Whether the next game phase needs to be queued.
|
|
97
|
+
/// @notice Fulfill the commitments of a game by distributing the pot.
|
|
91
98
|
/// @param gameId The ID of the game.
|
|
92
|
-
|
|
93
|
-
function nextPhaseNeedsQueueing(uint256 gameId) external view returns (bool);
|
|
99
|
+
function fulfillCommitmentsOf(uint256 gameId) external;
|
|
94
100
|
|
|
95
101
|
/// @notice Launch a new Defifa game.
|
|
96
102
|
/// @param launchProjectData The configuration for launching the game.
|
|
97
103
|
/// @return gameId The ID of the newly launched game.
|
|
98
104
|
function launchGameWith(DefifaLaunchProjectData calldata launchProjectData) external returns (uint256 gameId);
|
|
99
105
|
|
|
100
|
-
/// @notice Fulfill the commitments of a game by distributing the pot.
|
|
101
|
-
/// @param gameId The ID of the game.
|
|
102
|
-
function fulfillCommitmentsOf(uint256 gameId) external;
|
|
103
|
-
|
|
104
106
|
/// @notice Trigger a no-contest outcome for a game.
|
|
105
107
|
/// @param gameId The ID of the game.
|
|
106
108
|
function triggerNoContestFor(uint256 gameId) external;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity 0.8.
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
-
import {DefifaGamePhase} from "
|
|
4
|
+
import {DefifaGamePhase} from "../enums/DefifaGamePhase.sol";
|
|
5
5
|
|
|
6
6
|
interface IDefifaGamePhaseReporter {
|
|
7
7
|
function currentGamePhaseOf(uint256 gameId) external view returns (DefifaGamePhase);
|