polkamarkets-js 3.2.0 → 3.3.1

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.
Files changed (149) hide show
  1. package/abis/AddAdminToLand.json +1 -0
  2. package/abis/ClaimMerkleRoot.json +1 -0
  3. package/abis/CreateLand.json +1 -0
  4. package/abis/CreateMarkets.json +1 -0
  5. package/abis/DeployContracts.json +1 -0
  6. package/abis/DeployMerkleRewardsDistributor.json +1 -0
  7. package/abis/DeployToken.json +1 -0
  8. package/abis/DeployUSDT.json +1 -0
  9. package/abis/MintTokens.json +1 -0
  10. package/abis/PredictionMarketV3_3.json +1 -0
  11. package/abis/PublishMerkleRoot.json +1 -0
  12. package/abis/ResolveMarket.json +1 -0
  13. package/abis/TradeMarket.json +1 -0
  14. package/abis/USDT.json +1 -0
  15. package/package.json +1 -1
  16. package/script/UpdateMarket.s.sol +56 -0
  17. package/scripts/AddAdminToLand.s.sol +29 -0
  18. package/scripts/ClaimMerkleRoot.s.sol +34 -0
  19. package/scripts/CreateLand.s.sol +28 -0
  20. package/scripts/CreateMarkets.s.sol +71 -0
  21. package/scripts/DeployContracts.s.sol +94 -0
  22. package/scripts/DeployMerkleRewardsDistributor.s.sol +27 -0
  23. package/scripts/DeployToken.s.sol +17 -0
  24. package/scripts/DeployUSDT.s.sol +24 -0
  25. package/scripts/MintTokens.s.sol +21 -0
  26. package/scripts/PublishMerkleRoot.s.sol +50 -0
  27. package/scripts/ResolveMarket.s.sol +23 -0
  28. package/scripts/TradeMarket.s.sol +28 -0
  29. package/scripts/UpdateMarket.s.sol +55 -0
  30. package/src/Application.js +2 -1
  31. package/src/interfaces/index.js +2 -0
  32. package/src/models/PredictionMarketV3Contract.js +5 -1
  33. package/src/models/PredictionMarketV3PlusContract.js +39 -2
  34. package/test/UpdateTest.t.sol +55 -0
  35. package/test/WhaleTest.t.sol +188 -0
  36. package/contracts/PredictionMarketV3_4Bad.sol +0 -1487
  37. package/contracts/PredictionMarketV3_4Good.sol +0 -1508
  38. package/dist/Application.d.ts +0 -201
  39. package/dist/Application.d.ts.map +0 -1
  40. package/dist/Application.js +0 -411
  41. package/dist/Application.js.map +0 -1
  42. package/dist/index.d.ts +0 -7
  43. package/dist/index.d.ts.map +0 -1
  44. package/dist/index.js +0 -16
  45. package/dist/index.js.map +0 -1
  46. package/dist/interfaces/index.d.ts +0 -4
  47. package/dist/interfaces/index.d.ts.map +0 -1
  48. package/dist/interfaces/index.js +0 -22
  49. package/dist/interfaces/index.js.map +0 -1
  50. package/dist/models/AchievementsContract.d.ts +0 -43
  51. package/dist/models/AchievementsContract.d.ts.map +0 -1
  52. package/dist/models/AchievementsContract.js +0 -177
  53. package/dist/models/AchievementsContract.js.map +0 -1
  54. package/dist/models/ArbitrationContract.d.ts +0 -23
  55. package/dist/models/ArbitrationContract.d.ts.map +0 -1
  56. package/dist/models/ArbitrationContract.js +0 -47
  57. package/dist/models/ArbitrationContract.js.map +0 -1
  58. package/dist/models/ArbitrationProxyContract.d.ts +0 -14
  59. package/dist/models/ArbitrationProxyContract.d.ts.map +0 -1
  60. package/dist/models/ArbitrationProxyContract.js +0 -26
  61. package/dist/models/ArbitrationProxyContract.js.map +0 -1
  62. package/dist/models/ERC20Contract.d.ts +0 -50
  63. package/dist/models/ERC20Contract.d.ts.map +0 -1
  64. package/dist/models/ERC20Contract.js +0 -99
  65. package/dist/models/ERC20Contract.js.map +0 -1
  66. package/dist/models/FantasyERC20Contract.d.ts +0 -13
  67. package/dist/models/FantasyERC20Contract.d.ts.map +0 -1
  68. package/dist/models/FantasyERC20Contract.js +0 -43
  69. package/dist/models/FantasyERC20Contract.js.map +0 -1
  70. package/dist/models/IContract.d.ts +0 -57
  71. package/dist/models/IContract.d.ts.map +0 -1
  72. package/dist/models/IContract.js +0 -515
  73. package/dist/models/IContract.js.map +0 -1
  74. package/dist/models/PolkamarketsSmartAccount.d.ts +0 -26
  75. package/dist/models/PolkamarketsSmartAccount.d.ts.map +0 -1
  76. package/dist/models/PolkamarketsSmartAccount.js +0 -100
  77. package/dist/models/PolkamarketsSmartAccount.js.map +0 -1
  78. package/dist/models/PredictionMarketContract.d.ts +0 -113
  79. package/dist/models/PredictionMarketContract.d.ts.map +0 -1
  80. package/dist/models/PredictionMarketContract.js +0 -298
  81. package/dist/models/PredictionMarketContract.js.map +0 -1
  82. package/dist/models/PredictionMarketV2Contract.d.ts +0 -157
  83. package/dist/models/PredictionMarketV2Contract.d.ts.map +0 -1
  84. package/dist/models/PredictionMarketV2Contract.js +0 -431
  85. package/dist/models/PredictionMarketV2Contract.js.map +0 -1
  86. package/dist/models/PredictionMarketV3Contract.d.ts +0 -42
  87. package/dist/models/PredictionMarketV3Contract.d.ts.map +0 -1
  88. package/dist/models/PredictionMarketV3Contract.js +0 -277
  89. package/dist/models/PredictionMarketV3Contract.js.map +0 -1
  90. package/dist/models/PredictionMarketV3ControllerContract.d.ts +0 -128
  91. package/dist/models/PredictionMarketV3ControllerContract.d.ts.map +0 -1
  92. package/dist/models/PredictionMarketV3ControllerContract.js +0 -174
  93. package/dist/models/PredictionMarketV3ControllerContract.js.map +0 -1
  94. package/dist/models/PredictionMarketV3FactoryContract.d.ts +0 -31
  95. package/dist/models/PredictionMarketV3FactoryContract.d.ts.map +0 -1
  96. package/dist/models/PredictionMarketV3FactoryContract.js +0 -81
  97. package/dist/models/PredictionMarketV3FactoryContract.js.map +0 -1
  98. package/dist/models/PredictionMarketV3ManagerContract.d.ts +0 -67
  99. package/dist/models/PredictionMarketV3ManagerContract.d.ts.map +0 -1
  100. package/dist/models/PredictionMarketV3ManagerContract.js +0 -97
  101. package/dist/models/PredictionMarketV3ManagerContract.js.map +0 -1
  102. package/dist/models/PredictionMarketV3QuerierContract.d.ts +0 -33
  103. package/dist/models/PredictionMarketV3QuerierContract.d.ts.map +0 -1
  104. package/dist/models/PredictionMarketV3QuerierContract.js +0 -61
  105. package/dist/models/PredictionMarketV3QuerierContract.js.map +0 -1
  106. package/dist/models/PredictionMarketV3_2Contract.d.ts +0 -32
  107. package/dist/models/PredictionMarketV3_2Contract.d.ts.map +0 -1
  108. package/dist/models/PredictionMarketV3_2Contract.js +0 -169
  109. package/dist/models/PredictionMarketV3_2Contract.js.map +0 -1
  110. package/dist/models/RealitioERC20Contract.d.ts +0 -16
  111. package/dist/models/RealitioERC20Contract.d.ts.map +0 -1
  112. package/dist/models/RealitioERC20Contract.js +0 -18
  113. package/dist/models/RealitioERC20Contract.js.map +0 -1
  114. package/dist/models/VotingContract.d.ts +0 -38
  115. package/dist/models/VotingContract.d.ts.map +0 -1
  116. package/dist/models/VotingContract.js +0 -85
  117. package/dist/models/VotingContract.js.map +0 -1
  118. package/dist/models/WETH9Contract.d.ts +0 -29
  119. package/dist/models/WETH9Contract.d.ts.map +0 -1
  120. package/dist/models/WETH9Contract.js +0 -44
  121. package/dist/models/WETH9Contract.js.map +0 -1
  122. package/dist/models/index.d.ts +0 -18
  123. package/dist/models/index.d.ts.map +0 -1
  124. package/dist/models/index.js +0 -37
  125. package/dist/models/index.js.map +0 -1
  126. package/dist/types/contracts.d.ts +0 -46
  127. package/dist/types/contracts.d.ts.map +0 -1
  128. package/dist/types/contracts.js +0 -3
  129. package/dist/types/contracts.js.map +0 -1
  130. package/dist/types/index.d.ts +0 -1
  131. package/dist/types/index.d.ts.map +0 -1
  132. package/dist/types/index.js +0 -3
  133. package/dist/types/index.js.map +0 -1
  134. package/dist/utils/Account.d.ts +0 -34
  135. package/dist/utils/Account.d.ts.map +0 -1
  136. package/dist/utils/Account.js +0 -38
  137. package/dist/utils/Account.js.map +0 -1
  138. package/dist/utils/Contract.d.ts +0 -31
  139. package/dist/utils/Contract.d.ts.map +0 -1
  140. package/dist/utils/Contract.js +0 -123
  141. package/dist/utils/Contract.js.map +0 -1
  142. package/dist/utils/Numbers.d.ts +0 -27
  143. package/dist/utils/Numbers.d.ts.map +0 -1
  144. package/dist/utils/Numbers.js +0 -87
  145. package/dist/utils/Numbers.js.map +0 -1
  146. package/script/CreateMarketLib.sol +0 -1873
  147. package/script/DeployProxy.s.sol +0 -27
  148. package/script/DeployUpgradeablePM.s.sol +0 -47
  149. package/script/PredictionMarketV3_3Flow.s.sol +0 -132
@@ -1,1487 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.26;
3
-
4
- // openzeppelin upgradeable imports
5
- import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
6
- import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
7
- import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
8
- import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
9
-
10
- // openzeppelin non-upgradeable imports (for interfaces)
11
- import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
12
- import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
13
-
14
- // local imports
15
- import "./IFantasyERC20.sol";
16
- import "./IRealityETH_ERC20.sol";
17
- import "./IPredictionMarketV3Manager.sol";
18
- import "./IWETH.sol";
19
-
20
- library CeilDivBad {
21
- // calculates ceil(x/y)
22
- function ceildiv(uint256 x, uint256 y) internal pure returns (uint256) {
23
- if (x > 0) return ((x - 1) / y) + 1;
24
- return 0;
25
- }
26
- }
27
-
28
- /// @title Market Contract Factory
29
- contract PredictionMarketV3_4Bad is Initializable, ReentrancyGuardUpgradeable, OwnableUpgradeable, UUPSUpgradeable {
30
- using SafeERC20 for IERC20;
31
- using CeilDivBad for uint256;
32
-
33
- // ------ Events ------
34
-
35
- event MarketCreated(
36
- address indexed user,
37
- uint256 indexed marketId,
38
- uint256 outcomes,
39
- string question,
40
- string image,
41
- IERC20 token
42
- );
43
-
44
- event MarketActionTx(
45
- address indexed user,
46
- MarketAction indexed action,
47
- uint256 indexed marketId,
48
- uint256 outcomeId,
49
- uint256 shares,
50
- uint256 value,
51
- uint256 timestamp
52
- );
53
-
54
- event Referral(
55
- address indexed user,
56
- uint256 indexed marketId,
57
- string code,
58
- MarketAction action,
59
- uint256 outcomeId,
60
- uint256 value,
61
- uint256 timestamp
62
- );
63
-
64
- event MarketOutcomeShares(uint256 indexed marketId, uint256 timestamp, uint256[] outcomeShares, uint256 liquidity);
65
-
66
- event MarketOutcomePrice(uint256 indexed marketId, uint256 indexed outcomeId, uint256 value, uint256 timestamp);
67
-
68
- event MarketLiquidity(
69
- uint256 indexed marketId,
70
- uint256 value, // total liquidity
71
- uint256 price, // value of one liquidity share; max: 1 (even odds situation)
72
- uint256 timestamp
73
- );
74
-
75
- event MarketResolved(
76
- address indexed user,
77
- uint256 indexed marketId,
78
- uint256 outcomeId,
79
- uint256 timestamp,
80
- bool admin
81
- );
82
-
83
- event MarketPaused(address indexed user, uint256 indexed marketId, bool paused, uint256 timestamp);
84
-
85
- event MarketCloseDateEdited(
86
- address indexed user,
87
- uint256 indexed marketId,
88
- uint256 closesAtTimestamp,
89
- uint256 timestamp
90
- );
91
-
92
- event AllowedManagerSet(address indexed manager, bool allowed);
93
-
94
- event Paused(bool paused, address indexed user);
95
-
96
- // ------ Events End ------
97
-
98
- uint256 private constant MAX_UINT_256 = type(uint256).max;
99
-
100
- uint256 private constant ONE = 10**18;
101
-
102
- uint256 public constant MAX_OUTCOMES = 2**5;
103
-
104
- uint256 public constant MAX_FEE = 5 * 10**16; // 5%
105
-
106
- uint256 public constant MINIMUM_REALITIO_TIMEOUT = 3600; // 1 hour
107
-
108
- enum MarketState {
109
- open,
110
- closed,
111
- resolved
112
- }
113
- enum MarketAction {
114
- buy,
115
- sell,
116
- addLiquidity,
117
- removeLiquidity,
118
- claimWinnings,
119
- claimLiquidity,
120
- claimFees,
121
- claimVoided
122
- }
123
-
124
- struct Market {
125
- // market details
126
- uint256 closesAtTimestamp;
127
- uint256 balance; // total stake
128
- uint256 liquidity; // stake held
129
- uint256 sharesAvailable; // shares held (all outcomes)
130
- mapping(address user => uint256 shares) liquidityShares;
131
- mapping(address user => bool claimed) liquidityClaims; // wether user has claimed liquidity earnings
132
- MarketState state; // resolution variables
133
- MarketResolution resolution; // fees
134
- MarketFees fees;
135
- // market outcomes
136
- uint256 outcomeCount;
137
- mapping(uint256 outcomeId => MarketOutcome outcome) outcomes;
138
- IERC20 token; // ERC20 token market will use for trading
139
- IPredictionMarketV3Manager manager; // manager contract
140
- address creator; // market creator
141
- bool paused; // market paused, no trading allowed
142
- }
143
-
144
- struct Fees {
145
- uint256 fee; // fee % taken from every transaction
146
- uint256 treasuryFee; // fee % taken from every transaction to a treasury address
147
- uint256 distributorFee; // fee % taken from every transaction to a distributor address
148
- }
149
-
150
- struct MarketFees {
151
- uint256 poolWeight; // internal var used to ensure pro-rate fee distribution
152
- mapping(address user => uint256 claimed) claimed;
153
- address treasury; // address to send treasury fees to
154
- address distributor; // fee % taken from every transaction to a treasury address
155
- Fees buyFees; // fees for buy transactions
156
- Fees sellFees; // fees for sell transactions
157
- }
158
-
159
- struct MarketResolution {
160
- bool resolved;
161
- IRealityETH_ERC20 realitio;
162
- uint256 outcomeId;
163
- bytes32 questionId; // realitio questionId
164
- // realitio
165
- uint256 realitioTimeout;
166
- }
167
-
168
- struct MarketOutcome {
169
- uint256 marketId;
170
- uint256 id;
171
- Shares shares;
172
- }
173
-
174
- struct Shares {
175
- uint256 total; // number of shares
176
- uint256 available; // available shares
177
- mapping(address user => uint256 shares) holders;
178
- mapping(address user => bool winningsClaimed) claims; // wether user has claimed winnings
179
- mapping(address user => bool voidedClaimed) voidedClaims; // wether user has claimed voided market shares
180
- }
181
-
182
- struct CreateMarketDescription {
183
- uint256 value;
184
- uint32 closesAt;
185
- uint256 outcomes;
186
- IERC20 token;
187
- uint256[] distribution;
188
- string question;
189
- string image;
190
- address arbitrator;
191
- Fees buyFees;
192
- Fees sellFees;
193
- address treasury;
194
- address distributor;
195
- uint32 realitioTimeout;
196
- IPredictionMarketV3Manager manager;
197
- }
198
-
199
- uint256 public testVarInTheBeginning;
200
- uint256[] public testVarInTheBeginningArray;
201
-
202
- uint256[] marketIds;
203
- mapping(uint256 marketId => Market market) markets;
204
- uint256 public marketIndex;
205
- mapping(address manager => bool allowed) allowedManagers;
206
-
207
- // weth configs
208
- IWETH public WETH;
209
-
210
- bool public paused;
211
-
212
- // ------ Modifiers ------
213
-
214
- modifier isMarket(uint256 marketId) {
215
- require(marketId < marketIndex, "!m");
216
- _;
217
- }
218
-
219
- modifier timeTransitions(uint256 marketId) {
220
- if (block.timestamp > markets[marketId].closesAtTimestamp && markets[marketId].state == MarketState.open) {
221
- _nextState(marketId);
222
- }
223
- _;
224
- }
225
-
226
- modifier atState(uint256 marketId, MarketState state) {
227
- require(markets[marketId].state == state, "!ms");
228
- _;
229
- }
230
-
231
- modifier notAtState(uint256 marketId, MarketState state) {
232
- require(markets[marketId].state != state, "!ms");
233
- _;
234
- }
235
-
236
- modifier whenNotPaused() {
237
- require(!paused, "!p");
238
- _;
239
- }
240
-
241
- modifier whenPaused() {
242
- require(paused, "!p");
243
- _;
244
- }
245
-
246
- modifier marketNotPaused(uint256 marketId) {
247
- require(!paused, "p");
248
- require(!markets[marketId].paused, "mp");
249
- _;
250
- }
251
-
252
- modifier marketPaused(uint256 marketId) {
253
- require(markets[marketId].paused, "!mp");
254
- _;
255
- }
256
-
257
- modifier transitionNext(uint256 marketId) {
258
- _;
259
- _nextState(marketId);
260
- }
261
-
262
- modifier transitionLast(uint256 marketId) {
263
- _;
264
- _lastState(marketId);
265
- }
266
-
267
- modifier isWETHMarket(uint256 marketId) {
268
- require(address(WETH) != address(0), "w0");
269
- require(address(markets[marketId].token) == address(WETH), "!w");
270
- _;
271
- }
272
-
273
- // ------ Modifiers End ------
274
-
275
- /// @custom:oz-upgrades-unsafe-allow constructor
276
- constructor() {
277
- _disableInitializers();
278
- }
279
-
280
- /// @dev Initialize the contract - replaces constructor for upgradeable contracts
281
- function initialize(IWETH _WETH, address initialOwner) public initializer {
282
- __ReentrancyGuard_init();
283
- __Ownable_init(initialOwner);
284
- __UUPSUpgradeable_init();
285
-
286
- WETH = _WETH;
287
- }
288
-
289
- receive() external payable {
290
- assert(msg.sender == address(WETH)); // only accept ETH via fallback from the WETH contract
291
- }
292
-
293
- // ------ Core Functions ------
294
-
295
- /// @dev for internal use only, validates the market fees and throws if they are not valid
296
- function _validateFees(Fees memory fees) private pure {
297
- require(fees.fee <= MAX_FEE, "f>5");
298
- require(fees.treasuryFee <= MAX_FEE, "tf>5");
299
- require(fees.distributorFee <= MAX_FEE, "df>5");
300
- }
301
-
302
- /// @dev Creates a market, initializes the outcome shares pool and submits a question in Realitio
303
- function _createMarket(CreateMarketDescription memory desc) private returns (uint256 marketId) {
304
- marketId = marketIndex;
305
- marketIds.push(marketId);
306
-
307
- Market storage market = markets[marketId];
308
-
309
- IRealityETH_ERC20 realitio = IRealityETH_ERC20(desc.manager.getERC20RealitioAddress(desc.token));
310
-
311
- require(desc.value > 0, "v0");
312
- require(desc.closesAt > block.timestamp, "c<n");
313
- require(desc.arbitrator != address(0), "a0");
314
- require(desc.outcomes > 0 && desc.outcomes <= MAX_OUTCOMES, "!oc");
315
- require(address(realitio) != address(0), "r0");
316
- require(desc.realitioTimeout >= MINIMUM_REALITIO_TIMEOUT, "rt<1h");
317
- require(allowedManagers[address(desc.manager)], "!am");
318
- require(desc.manager.isAllowedToCreateMarket(desc.token, msg.sender), "m!=a");
319
-
320
- market.token = desc.token;
321
- market.closesAtTimestamp = desc.closesAt;
322
- market.state = MarketState.open;
323
-
324
- // setting up fees
325
- _validateFees(desc.buyFees);
326
- market.fees.buyFees = desc.buyFees;
327
- _validateFees(desc.sellFees);
328
- market.fees.sellFees = desc.sellFees;
329
-
330
- market.fees.treasury = desc.treasury;
331
- market.fees.distributor = desc.distributor;
332
- // setting intial value to an integer that does not map to any outcomeId
333
- market.resolution.outcomeId = MAX_UINT_256;
334
- market.outcomeCount = desc.outcomes;
335
-
336
- // creating question in realitio
337
- market.resolution.questionId = realitio.askQuestionERC20(
338
- 2,
339
- desc.question,
340
- desc.arbitrator,
341
- desc.realitioTimeout,
342
- desc.closesAt,
343
- 0,
344
- 0
345
- );
346
- market.resolution.realitio = realitio;
347
- market.resolution.realitioTimeout = desc.realitioTimeout;
348
- market.manager = desc.manager;
349
- market.creator = msg.sender;
350
-
351
- _addLiquidity(marketId, desc.value, desc.distribution);
352
-
353
- // emiting initial price events
354
- _emitMarketActionEvents(marketId);
355
- emit MarketCreated(msg.sender, marketId, desc.outcomes, desc.question, desc.image, desc.token);
356
-
357
- // incrementing market array index
358
- marketIndex += 1;
359
- }
360
-
361
- function createMarket(CreateMarketDescription calldata desc) external nonReentrant returns (uint256 marketId) {
362
- marketId = _createMarket(
363
- CreateMarketDescription({
364
- value: desc.value,
365
- closesAt: desc.closesAt,
366
- outcomes: desc.outcomes,
367
- token: desc.token,
368
- distribution: desc.distribution,
369
- question: desc.question,
370
- image: desc.image,
371
- arbitrator: desc.arbitrator,
372
- buyFees: desc.buyFees,
373
- sellFees: desc.sellFees,
374
- treasury: desc.treasury,
375
- distributor: desc.distributor,
376
- realitioTimeout: desc.realitioTimeout,
377
- manager: desc.manager
378
- })
379
- );
380
- // transferring funds
381
- desc.token.safeTransferFrom(msg.sender, address(this), desc.value);
382
- }
383
-
384
- function mintAndCreateMarket(CreateMarketDescription calldata desc) external nonReentrant returns (uint256 marketId) {
385
- // mint the amount of tokens to the user
386
- IFantasyERC20(address(desc.token)).mint(msg.sender, desc.value);
387
-
388
- marketId = _createMarket(desc);
389
- // transferring funds
390
- desc.token.safeTransferFrom(msg.sender, address(this), desc.value);
391
-
392
- return marketId;
393
- }
394
-
395
- /// @dev Calculates the number of shares bought with "amount" balance
396
- function calcBuyAmount(
397
- uint256 amount,
398
- uint256 marketId,
399
- uint256 outcomeId
400
- ) public view returns (uint256) {
401
- Market storage market = markets[marketId];
402
- require(outcomeId < market.outcomeCount, "!o");
403
-
404
- uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
405
- uint256 fee = getMarketFee(marketId);
406
- uint256 amountMinusFees = amount - ((amount * fee) / ONE);
407
- uint256 buyTokenPoolBalance = outcomesShares[outcomeId];
408
- uint256 endingOutcomeBalance = buyTokenPoolBalance * ONE;
409
- for (uint256 i; i < market.outcomeCount; ++i) {
410
- if (i != outcomeId) {
411
- uint256 outcomeShares = outcomesShares[i];
412
- endingOutcomeBalance = (endingOutcomeBalance * outcomeShares).ceildiv(outcomeShares + amountMinusFees);
413
- }
414
- }
415
- require(endingOutcomeBalance > 0, "b0");
416
-
417
- return buyTokenPoolBalance + amountMinusFees - (endingOutcomeBalance.ceildiv(ONE));
418
- }
419
-
420
- /// @dev Calculates the number of shares needed to be sold in order to receive "amount" in balance
421
- function calcSellAmount(
422
- uint256 amount,
423
- uint256 marketId,
424
- uint256 outcomeId
425
- ) public view returns (uint256) {
426
- Market storage market = markets[marketId];
427
- require(outcomeId < market.outcomeCount, "!o");
428
-
429
- uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
430
- uint256 fee = getMarketSellFee(marketId);
431
- uint256 amountPlusFees = (amount * ONE) / (ONE - fee);
432
- uint256 sellTokenPoolBalance = outcomesShares[outcomeId];
433
- uint256 endingOutcomeBalance = sellTokenPoolBalance * ONE;
434
- for (uint256 i; i < market.outcomeCount; ++i) {
435
- if (i != outcomeId) {
436
- uint256 outcomeShares = outcomesShares[i];
437
- endingOutcomeBalance = (endingOutcomeBalance * outcomeShares).ceildiv(outcomeShares - amountPlusFees);
438
- }
439
- }
440
- require(endingOutcomeBalance > 0, "b0");
441
-
442
- return amountPlusFees + endingOutcomeBalance.ceildiv(ONE) - sellTokenPoolBalance;
443
- }
444
-
445
- /// @dev Buy shares of a market outcome - returns gross amount of transaction (amount + fee)
446
- function _buy(
447
- uint256 marketId,
448
- uint256 outcomeId,
449
- uint256 minOutcomeSharesToBuy,
450
- uint256 value
451
- ) private timeTransitions(marketId) atState(marketId, MarketState.open) marketNotPaused(marketId) returns (uint256) {
452
- Market storage market = markets[marketId];
453
-
454
- uint256 shares = calcBuyAmount(value, marketId, outcomeId);
455
- require(shares >= minOutcomeSharesToBuy, "s<m");
456
- require(shares > 0, "s0");
457
-
458
- // subtracting fee from transaction value
459
- uint256 feeAmount = (value * market.fees.buyFees.fee) / ONE;
460
- market.fees.poolWeight += feeAmount;
461
- uint256 valueMinusFees = value - feeAmount;
462
-
463
- uint256 treasuryFeeAmount = (value * market.fees.buyFees.treasuryFee) / ONE;
464
- uint256 distributorFeeAmount = (value * market.fees.buyFees.distributorFee) / ONE;
465
- valueMinusFees -= treasuryFeeAmount + distributorFeeAmount;
466
-
467
- MarketOutcome storage outcome = market.outcomes[outcomeId];
468
-
469
- // Funding market shares with received funds
470
- _addSharesToMarket(marketId, valueMinusFees);
471
-
472
- require(outcome.shares.available >= shares, "s<sp");
473
-
474
- _transferOutcomeSharesfromPool(msg.sender, marketId, outcomeId, shares);
475
-
476
- // value emmited in event includes fee (gross amount)
477
- emit MarketActionTx(msg.sender, MarketAction.buy, marketId, outcomeId, shares, value, block.timestamp);
478
- _emitMarketActionEvents(marketId);
479
-
480
- // transfering treasury/distributor fees
481
- if (treasuryFeeAmount > 0) {
482
- market.token.safeTransfer(market.fees.treasury, treasuryFeeAmount);
483
- }
484
- if (distributorFeeAmount > 0) {
485
- market.token.safeTransfer(market.fees.distributor, distributorFeeAmount);
486
- }
487
-
488
- return value;
489
- }
490
-
491
- /// @dev Buy shares of a market outcome
492
- function buy(
493
- uint256 marketId,
494
- uint256 outcomeId,
495
- uint256 minOutcomeSharesToBuy,
496
- uint256 value
497
- ) external nonReentrant {
498
- Market storage market = markets[marketId];
499
- market.token.safeTransferFrom(msg.sender, address(this), value);
500
- _buy(marketId, outcomeId, minOutcomeSharesToBuy, value);
501
- }
502
-
503
- function buyWithETH(
504
- uint256 marketId,
505
- uint256 outcomeId,
506
- uint256 minOutcomeSharesToBuy
507
- ) external payable isWETHMarket(marketId) nonReentrant {
508
- uint256 value = msg.value;
509
- // wrapping and depositing funds
510
- IWETH(WETH).deposit{value: value}();
511
- _buy(marketId, outcomeId, minOutcomeSharesToBuy, value);
512
- }
513
-
514
- function referralBuy(
515
- uint256 marketId,
516
- uint256 outcomeId,
517
- uint256 minOutcomeSharesToBuy,
518
- uint256 value,
519
- string memory code
520
- ) public nonReentrant {
521
- Market storage market = markets[marketId];
522
- market.token.safeTransferFrom(msg.sender, address(this), value);
523
- _buy(marketId, outcomeId, minOutcomeSharesToBuy, value);
524
-
525
- emit Referral(msg.sender, marketId, code, MarketAction.buy, outcomeId, value, block.timestamp);
526
- }
527
-
528
- /// @dev Sell shares of a market outcome - returns gross amount of transaction (amount + fee)
529
- function _sell(
530
- uint256 marketId,
531
- uint256 outcomeId,
532
- uint256 value,
533
- uint256 maxOutcomeSharesToSell
534
- ) private timeTransitions(marketId) atState(marketId, MarketState.open) marketNotPaused(marketId) returns (uint256) {
535
- Market storage market = markets[marketId];
536
- MarketOutcome storage outcome = market.outcomes[outcomeId];
537
-
538
- uint256 shares = calcSellAmount(value, marketId, outcomeId);
539
-
540
- require(shares <= maxOutcomeSharesToSell, "s>m");
541
- require(shares > 0, "s0");
542
- require(outcome.shares.holders[msg.sender] >= shares, "s>h");
543
-
544
- _transferOutcomeSharesToPool(msg.sender, marketId, outcomeId, shares);
545
-
546
- // adding fees to transaction value
547
- uint256 fee = getMarketSellFee(marketId);
548
- uint256 oneMinusFee = ONE - fee;
549
- {
550
- uint256 feeAmount = (value * market.fees.sellFees.fee) / oneMinusFee;
551
- market.fees.poolWeight += feeAmount;
552
- }
553
- uint256 valuePlusFees = value + (value * fee) / oneMinusFee;
554
-
555
- require(market.balance >= valuePlusFees, "b<v");
556
-
557
- // Rebalancing market shares
558
- _removeSharesFromMarket(marketId, valuePlusFees);
559
-
560
- // value emmited in event includes fee (gross amount)
561
- emit MarketActionTx(msg.sender, MarketAction.sell, marketId, outcomeId, shares, valuePlusFees, block.timestamp);
562
- _emitMarketActionEvents(marketId);
563
-
564
- {
565
- uint256 treasuryFeeAmount = (value * market.fees.sellFees.treasuryFee) / oneMinusFee;
566
- uint256 distributorFeeAmount = (value * market.fees.sellFees.distributorFee) / oneMinusFee;
567
- // transfering treasury/distributor fees
568
- if (treasuryFeeAmount > 0) {
569
- market.token.safeTransfer(market.fees.treasury, treasuryFeeAmount);
570
- }
571
- if (distributorFeeAmount > 0) {
572
- market.token.safeTransfer(market.fees.distributor, distributorFeeAmount);
573
- }
574
- }
575
-
576
- return valuePlusFees;
577
- }
578
-
579
- function sell(
580
- uint256 marketId,
581
- uint256 outcomeId,
582
- uint256 value,
583
- uint256 maxOutcomeSharesToSell
584
- ) external nonReentrant {
585
- _sell(marketId, outcomeId, value, maxOutcomeSharesToSell);
586
- // Transferring funds to user
587
- Market storage market = markets[marketId];
588
- market.token.safeTransfer(msg.sender, value);
589
- }
590
-
591
- function sellToETH(
592
- uint256 marketId,
593
- uint256 outcomeId,
594
- uint256 value,
595
- uint256 maxOutcomeSharesToSell
596
- ) external isWETHMarket(marketId) nonReentrant {
597
- _sell(marketId, outcomeId, value, maxOutcomeSharesToSell);
598
-
599
- IWETH(WETH).withdraw(value);
600
- (bool sent, ) = payable(msg.sender).call{value: value}("");
601
- require(sent, "!s");
602
- }
603
-
604
- function referralSell(
605
- uint256 marketId,
606
- uint256 outcomeId,
607
- uint256 value,
608
- uint256 maxOutcomeSharesToSell,
609
- string memory code
610
- ) external nonReentrant {
611
- uint256 valuePlusFees = _sell(marketId, outcomeId, value, maxOutcomeSharesToSell);
612
- // Transferring funds to user
613
- Market storage market = markets[marketId];
614
- market.token.safeTransfer(msg.sender, value);
615
-
616
- emit Referral(msg.sender, marketId, code, MarketAction.sell, outcomeId, valuePlusFees, block.timestamp);
617
- }
618
-
619
- /// @dev Adds liquidity to a market - external
620
- function _addLiquidity(
621
- uint256 marketId,
622
- uint256 value,
623
- uint256[] memory distribution
624
- ) private timeTransitions(marketId) atState(marketId, MarketState.open) marketNotPaused(marketId) {
625
- Market storage market = markets[marketId];
626
-
627
- require(value > 0, "v0");
628
-
629
- uint256 liquidityAmount;
630
-
631
- uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
632
- uint256[] memory sendBackAmounts = new uint256[](market.outcomeCount);
633
- uint256 poolWeight = 0;
634
-
635
- if (market.liquidity > 0) {
636
- require(distribution.length == 0, "!d");
637
-
638
- // part of the liquidity is exchanged for outcome shares if market is not balanced
639
- for (uint256 i; i < market.outcomeCount; ++i) {
640
- uint256 outcomeShares = outcomesShares[i];
641
- if (poolWeight < outcomeShares) poolWeight = outcomeShares;
642
- }
643
-
644
- for (uint256 i; i < market.outcomeCount; ++i) {
645
- uint256 remaining = (value * outcomesShares[i]) / poolWeight;
646
- sendBackAmounts[i] = value - remaining;
647
- }
648
-
649
- liquidityAmount = (value * market.liquidity) / poolWeight;
650
-
651
- // re-balancing fees pool
652
- _rebalanceFeesPool(marketId, liquidityAmount, MarketAction.addLiquidity);
653
- } else {
654
- uint256 distributionLength = distribution.length;
655
- // funding market with no liquidity
656
- if (distributionLength > 0) {
657
- require(distributionLength == market.outcomeCount, "d!=oc");
658
-
659
- uint256 maxHint = 0;
660
- for (uint256 i; i < distributionLength; ++i) {
661
- uint256 hint = distribution[i];
662
- if (maxHint < hint) maxHint = hint;
663
- }
664
-
665
- for (uint256 i; i < distributionLength; ++i) {
666
- uint256 remaining = (value * distribution[i]) / maxHint;
667
- require(remaining > 0, "!d");
668
- sendBackAmounts[i] = value - remaining;
669
- }
670
- }
671
-
672
- // funding market with total liquidity amount
673
- liquidityAmount = value;
674
- }
675
-
676
- // funding market
677
- market.liquidity = market.liquidity + liquidityAmount;
678
- market.liquidityShares[msg.sender] = market.liquidityShares[msg.sender] + liquidityAmount;
679
-
680
- _addSharesToMarket(marketId, value);
681
-
682
- {
683
- // transform sendBackAmounts to array of amounts added
684
- for (uint256 i; i < market.outcomeCount; ++i) {
685
- if (sendBackAmounts[i] > 0) {
686
- _transferOutcomeSharesfromPool(msg.sender, marketId, i, sendBackAmounts[i]);
687
- }
688
- }
689
-
690
- // emitting events, using outcome 0 for price reference
691
- uint256 referencePrice = getMarketOutcomePrice(marketId, 0);
692
-
693
- for (uint256 i; i < market.outcomeCount; ++i) {
694
- if (sendBackAmounts[i] > 0) {
695
- // outcome price = outcome shares / reference outcome shares * reference outcome price
696
- uint256 outcomePrice = (referencePrice * market.outcomes[0].shares.available) /
697
- market.outcomes[i].shares.available;
698
-
699
- emit MarketActionTx(
700
- msg.sender,
701
- MarketAction.buy,
702
- marketId,
703
- i,
704
- sendBackAmounts[i],
705
- (sendBackAmounts[i] * outcomePrice) / ONE, // price * shares
706
- block.timestamp
707
- );
708
- }
709
- }
710
- }
711
-
712
- uint256 liquidityPrice = getMarketLiquidityPrice(marketId);
713
- uint256 liquidityValue = (liquidityPrice * liquidityAmount) / ONE;
714
-
715
- emit MarketActionTx(
716
- msg.sender,
717
- MarketAction.addLiquidity,
718
- marketId,
719
- 0,
720
- liquidityAmount,
721
- liquidityValue,
722
- block.timestamp
723
- );
724
- emit MarketLiquidity(marketId, market.liquidity, liquidityPrice, block.timestamp);
725
- }
726
-
727
- function addLiquidity(uint256 marketId, uint256 value) external nonReentrant {
728
- uint256[] memory distribution = new uint256[](0);
729
- _addLiquidity(marketId, value, distribution);
730
-
731
- Market storage market = markets[marketId];
732
- market.token.safeTransferFrom(msg.sender, address(this), value);
733
- }
734
-
735
- /// @dev Removes liquidity to a market - external
736
- function _removeLiquidity(uint256 marketId, uint256 shares)
737
- private
738
- timeTransitions(marketId)
739
- atState(marketId, MarketState.open)
740
- marketNotPaused(marketId)
741
- returns (uint256)
742
- {
743
- Market storage market = markets[marketId];
744
-
745
- // removing 100% of the liquidity is not allowed
746
- require(shares < market.liquidity, "s>l");
747
- require(market.liquidityShares[msg.sender] >= shares, "s>h");
748
-
749
- // re-balancing fees pool
750
- _rebalanceFeesPool(marketId, shares, MarketAction.removeLiquidity);
751
-
752
- uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
753
- uint256[] memory sendAmounts = new uint256[](market.outcomeCount);
754
- uint256 poolWeight = MAX_UINT_256;
755
-
756
- // part of the liquidity is exchanged for outcome shares if market is not balanced
757
- for (uint256 i; i < market.outcomeCount; ++i) {
758
- uint256 outcomeShares = outcomesShares[i];
759
- if (poolWeight > outcomeShares) poolWeight = outcomeShares;
760
- }
761
-
762
- uint256 liquidityAmount = (shares * poolWeight) / market.liquidity;
763
-
764
- for (uint256 i; i < market.outcomeCount; ++i) {
765
- sendAmounts[i] = (outcomesShares[i] * shares) / market.liquidity;
766
- sendAmounts[i] = sendAmounts[i] - liquidityAmount;
767
- }
768
-
769
- // removing liquidity from market
770
- _removeSharesFromMarket(marketId, liquidityAmount);
771
- market.liquidity = market.liquidity - shares;
772
- // removing liquidity tokens from market creator
773
- market.liquidityShares[msg.sender] = market.liquidityShares[msg.sender] - shares;
774
-
775
- for (uint256 i; i < market.outcomeCount; ++i) {
776
- if (sendAmounts[i] > 0) {
777
- _transferOutcomeSharesfromPool(msg.sender, marketId, i, sendAmounts[i]);
778
- }
779
- }
780
-
781
- // emitting events, using outcome 0 for price reference
782
- uint256 referencePrice = getMarketOutcomePrice(marketId, 0);
783
-
784
- for (uint256 i; i < market.outcomeCount; ++i) {
785
- if (sendAmounts[i] > 0) {
786
- // outcome price = outcome shares / reference outcome shares * reference outcome price
787
- uint256 outcomePrice = (referencePrice * market.outcomes[0].shares.available) /
788
- market.outcomes[i].shares.available;
789
-
790
- emit MarketActionTx(
791
- msg.sender,
792
- MarketAction.buy,
793
- marketId,
794
- i,
795
- sendAmounts[i],
796
- (sendAmounts[i] * outcomePrice) / ONE, // price * shares
797
- block.timestamp
798
- );
799
- }
800
- }
801
-
802
- emit MarketActionTx(
803
- msg.sender,
804
- MarketAction.removeLiquidity,
805
- marketId,
806
- 0,
807
- shares,
808
- liquidityAmount,
809
- block.timestamp
810
- );
811
- emit MarketLiquidity(marketId, market.liquidity, getMarketLiquidityPrice(marketId), block.timestamp);
812
-
813
- return liquidityAmount;
814
- }
815
-
816
- function removeLiquidity(uint256 marketId, uint256 shares) external nonReentrant {
817
- uint256 value = _removeLiquidity(marketId, shares);
818
- // transferring user funds from liquidity removed
819
- Market storage market = markets[marketId];
820
- market.token.safeTransfer(msg.sender, value);
821
- }
822
-
823
- /// @dev Fetches winning outcome from Realitio and resolves the market
824
- function resolveMarketOutcome(uint256 marketId)
825
- external
826
- timeTransitions(marketId)
827
- atState(marketId, MarketState.closed)
828
- transitionNext(marketId)
829
- returns (uint256 outcomeId)
830
- {
831
- Market storage market = markets[marketId];
832
-
833
- // will fail if question is not finalized
834
- outcomeId = uint256(market.resolution.realitio.resultFor(market.resolution.questionId));
835
-
836
- market.resolution.outcomeId = outcomeId;
837
-
838
- emit MarketResolved(msg.sender, marketId, outcomeId, block.timestamp, false);
839
- _emitMarketActionEvents(marketId);
840
- }
841
-
842
- /// @dev overrides market resolution, instead of using realitio
843
- function adminResolveMarketOutcome(uint256 marketId, uint256 outcomeId)
844
- external
845
- notAtState(marketId, MarketState.resolved)
846
- transitionLast(marketId)
847
- returns (uint256)
848
- {
849
- Market storage market = markets[marketId];
850
-
851
- require(market.manager.isAllowedToEditMarket(market.token, msg.sender), "not allowed to resolve market");
852
-
853
- market.resolution.outcomeId = outcomeId;
854
-
855
- emit MarketResolved(msg.sender, marketId, outcomeId, block.timestamp, true);
856
- _emitMarketActionEvents(marketId);
857
-
858
- return market.resolution.outcomeId;
859
- }
860
-
861
- /// @dev pauses a market, no trading allowed
862
- function adminPauseMarket(uint256 marketId) external isMarket(marketId) marketNotPaused(marketId) nonReentrant {
863
- Market storage market = markets[marketId];
864
- require(market.manager.isAllowedToEditMarket(market.token, msg.sender), "not allowed to pause market");
865
-
866
- market.paused = true;
867
- emit MarketPaused(msg.sender, marketId, true, block.timestamp);
868
- }
869
-
870
- /// @dev unpauses a market, trading allowed
871
- function adminUnpauseMarket(uint256 marketId) external isMarket(marketId) marketPaused(marketId) nonReentrant {
872
- Market storage market = markets[marketId];
873
- require(market.manager.isAllowedToEditMarket(market.token, msg.sender), "not allowed to unpause market");
874
-
875
- market.paused = false;
876
- emit MarketPaused(msg.sender, marketId, false, block.timestamp);
877
- }
878
-
879
- /// @dev overrides market close date
880
- function adminSetMarketCloseDate(uint256 marketId, uint256 closesAt)
881
- external
882
- isMarket(marketId)
883
- notAtState(marketId, MarketState.resolved)
884
- {
885
- Market storage market = markets[marketId];
886
- require(market.manager.isAllowedToEditMarket(market.token, msg.sender), "not allowed to set close date");
887
-
888
- require(closesAt > block.timestamp, "resolution before current date");
889
- market.closesAtTimestamp = closesAt;
890
- emit MarketCloseDateEdited(msg.sender, marketId, closesAt, block.timestamp);
891
- }
892
-
893
- /// @dev Allows holders of resolved outcome shares to claim earnings.
894
- function _claimWinnings(uint256 marketId)
895
- private
896
- atState(marketId, MarketState.resolved)
897
- marketNotPaused(marketId)
898
- returns (uint256 value)
899
- {
900
- Market storage market = markets[marketId];
901
- MarketOutcome storage resolvedOutcome = market.outcomes[market.resolution.outcomeId];
902
-
903
- require(!isMarketVoided(marketId), "mv");
904
- require(resolvedOutcome.shares.holders[msg.sender] > 0, "!h");
905
- require(!resolvedOutcome.shares.claims[msg.sender], "!c");
906
-
907
- // 1 share => price = 1
908
- value = resolvedOutcome.shares.holders[msg.sender];
909
-
910
- // assuring market has enough funds
911
- require(market.balance >= value, "b<v");
912
-
913
- market.balance = market.balance - value;
914
- resolvedOutcome.shares.claims[msg.sender] = true;
915
-
916
- emit MarketActionTx(
917
- msg.sender,
918
- MarketAction.claimWinnings,
919
- marketId,
920
- market.resolution.outcomeId,
921
- resolvedOutcome.shares.holders[msg.sender],
922
- value,
923
- block.timestamp
924
- );
925
- }
926
-
927
- function claimWinnings(uint256 marketId) external nonReentrant {
928
- uint256 value = _claimWinnings(marketId);
929
- // transferring user funds from winnings claimed
930
- Market storage market = markets[marketId];
931
- market.token.safeTransfer(msg.sender, value);
932
- }
933
-
934
- /// @dev Allows holders of voided outcome shares to claim balance back.
935
- function _claimVoidedOutcomeShares(uint256 marketId, uint256 outcomeId)
936
- private
937
- atState(marketId, MarketState.resolved)
938
- marketNotPaused(marketId)
939
- returns (uint256 value)
940
- {
941
- Market storage market = markets[marketId];
942
- MarketOutcome storage outcome = market.outcomes[outcomeId];
943
-
944
- require(isMarketVoided(marketId), "!mv");
945
- require(outcome.shares.holders[msg.sender] > 0, "!h");
946
- require(!outcome.shares.voidedClaims[msg.sender], "!c");
947
-
948
- // voided market - shares are valued at last market price
949
- uint256 price = getMarketOutcomePrice(marketId, outcomeId);
950
- value = (price * outcome.shares.holders[msg.sender]) / ONE;
951
-
952
- // assuring market has enough funds
953
- require(market.balance >= value, "b<v");
954
-
955
- market.balance = market.balance - value;
956
- outcome.shares.voidedClaims[msg.sender] = true;
957
-
958
- emit MarketActionTx(
959
- msg.sender,
960
- MarketAction.claimVoided,
961
- marketId,
962
- outcomeId,
963
- outcome.shares.holders[msg.sender],
964
- value,
965
- block.timestamp
966
- );
967
-
968
- return value;
969
- }
970
-
971
- function claimVoidedOutcomeShares(uint256 marketId, uint256 outcomeId) external nonReentrant {
972
- uint256 value = _claimVoidedOutcomeShares(marketId, outcomeId);
973
- // transferring user funds from voided outcome shares claimed
974
- Market storage market = markets[marketId];
975
- market.token.safeTransfer(msg.sender, value);
976
- }
977
-
978
- /// @dev Allows liquidity providers to claim earnings from liquidity providing.
979
- function _claimLiquidity(uint256 marketId)
980
- private
981
- atState(marketId, MarketState.resolved)
982
- marketNotPaused(marketId)
983
- returns (uint256 value)
984
- {
985
- Market storage market = markets[marketId];
986
-
987
- require(market.liquidityShares[msg.sender] > 0, "!h");
988
- require(!market.liquidityClaims[msg.sender], "!c");
989
-
990
- // value = total resolved outcome pool shares * pool share (%)
991
- uint256 liquidityPrice = getMarketLiquidityPrice(marketId);
992
- value = (liquidityPrice * market.liquidityShares[msg.sender]) / ONE;
993
-
994
- // assuring market has enough funds
995
- require(market.balance >= value, "b<v");
996
-
997
- market.balance = market.balance - value;
998
- market.liquidityClaims[msg.sender] = true;
999
-
1000
- emit MarketActionTx(
1001
- msg.sender,
1002
- MarketAction.claimLiquidity,
1003
- marketId,
1004
- 0,
1005
- market.liquidityShares[msg.sender],
1006
- value,
1007
- block.timestamp
1008
- );
1009
- }
1010
-
1011
- function claimLiquidity(uint256 marketId) external nonReentrant {
1012
- uint256 value = _claimLiquidity(marketId);
1013
- // transferring user funds from liquidity claimed
1014
- Market storage market = markets[marketId];
1015
- market.token.safeTransfer(msg.sender, value);
1016
-
1017
- // claiming any pending fees
1018
- uint256 feesValue = _claimFees(marketId);
1019
- if (feesValue > 0) {
1020
- market.token.safeTransfer(msg.sender, feesValue);
1021
- }
1022
- }
1023
-
1024
- /// @dev Allows liquidity providers to claim their fees share from fees pool
1025
- function _claimFees(uint256 marketId) private marketNotPaused(marketId) returns (uint256 value) {
1026
- Market storage market = markets[marketId];
1027
-
1028
- value = getUserClaimableFees(marketId, msg.sender);
1029
-
1030
- if (value > 0) {
1031
- market.fees.claimed[msg.sender] = market.fees.claimed[msg.sender] + value;
1032
- }
1033
-
1034
- emit MarketActionTx(
1035
- msg.sender,
1036
- MarketAction.claimFees,
1037
- marketId,
1038
- 0,
1039
- market.liquidityShares[msg.sender],
1040
- value,
1041
- block.timestamp
1042
- );
1043
- }
1044
-
1045
- function claimFees(uint256 marketId) public nonReentrant {
1046
- uint256 value = _claimFees(marketId);
1047
- // transferring user funds from fees claimed
1048
- Market storage market = markets[marketId];
1049
- market.token.safeTransfer(msg.sender, value);
1050
- }
1051
-
1052
- /// @dev Rebalances the fees pool. Needed in every AddLiquidity / RemoveLiquidity call
1053
- function _rebalanceFeesPool(
1054
- uint256 marketId,
1055
- uint256 liquidityShares,
1056
- MarketAction action
1057
- ) private {
1058
- Market storage market = markets[marketId];
1059
-
1060
- uint256 poolWeight = (liquidityShares * market.fees.poolWeight) / market.liquidity;
1061
-
1062
- if (action == MarketAction.addLiquidity) {
1063
- market.fees.poolWeight += poolWeight;
1064
- market.fees.claimed[msg.sender] += poolWeight;
1065
- } else {
1066
- market.fees.poolWeight -= poolWeight;
1067
- market.fees.claimed[msg.sender] = market.fees.claimed[msg.sender] - poolWeight;
1068
- }
1069
- }
1070
-
1071
- /// @dev Transitions market to next state
1072
- function _nextState(uint256 marketId) private {
1073
- Market storage market = markets[marketId];
1074
- market.state = MarketState(uint256(market.state) + 1);
1075
- }
1076
-
1077
- /// @dev Transitions market to last state
1078
- function _lastState(uint256 marketId) private {
1079
- Market storage market = markets[marketId];
1080
- market.state = MarketState.resolved;
1081
- }
1082
-
1083
- /// @dev Emits a outcome price event for every outcome
1084
- function _emitMarketActionEvents(uint256 marketId) private {
1085
- Market storage market = markets[marketId];
1086
- uint256[] memory outcomeShares = new uint256[](market.outcomeCount);
1087
-
1088
- for (uint256 i; i < market.outcomeCount; ++i) {
1089
- outcomeShares[i] = market.outcomes[i].shares.available;
1090
- }
1091
-
1092
- emit MarketOutcomeShares(marketId, block.timestamp, outcomeShares, market.liquidity);
1093
- }
1094
-
1095
- /// @dev Adds outcome shares to shares pool
1096
- function _addSharesToMarket(uint256 marketId, uint256 shares) private {
1097
- Market storage market = markets[marketId];
1098
-
1099
- for (uint256 i; i < market.outcomeCount; ++i) {
1100
- MarketOutcome storage outcome = market.outcomes[i];
1101
-
1102
- outcome.shares.available = outcome.shares.available + shares;
1103
- outcome.shares.total = outcome.shares.total + shares;
1104
-
1105
- // only adding to market total shares, the available remains
1106
- market.sharesAvailable = market.sharesAvailable + shares;
1107
- }
1108
-
1109
- market.balance = market.balance + shares;
1110
- }
1111
-
1112
- /// @dev Removes outcome shares from shares pool
1113
- function _removeSharesFromMarket(uint256 marketId, uint256 shares) private {
1114
- Market storage market = markets[marketId];
1115
-
1116
- for (uint256 i; i < market.outcomeCount; ++i) {
1117
- MarketOutcome storage outcome = market.outcomes[i];
1118
-
1119
- outcome.shares.available = outcome.shares.available - shares;
1120
- outcome.shares.total = outcome.shares.total - shares;
1121
-
1122
- // only subtracting from market total shares, the available remains
1123
- market.sharesAvailable = market.sharesAvailable - shares;
1124
- }
1125
-
1126
- market.balance = market.balance - shares;
1127
- }
1128
-
1129
- /// @dev Transfer outcome shares from pool to user balance
1130
- function _transferOutcomeSharesfromPool(
1131
- address user,
1132
- uint256 marketId,
1133
- uint256 outcomeId,
1134
- uint256 shares
1135
- ) private {
1136
- Market storage market = markets[marketId];
1137
- MarketOutcome storage outcome = market.outcomes[outcomeId];
1138
-
1139
- // transfering shares from shares pool to user
1140
- outcome.shares.holders[user] = outcome.shares.holders[user] + shares;
1141
- outcome.shares.available = outcome.shares.available - shares;
1142
- market.sharesAvailable = market.sharesAvailable - shares;
1143
- }
1144
-
1145
- /// @dev Transfer outcome shares from user balance back to pool
1146
- function _transferOutcomeSharesToPool(
1147
- address user,
1148
- uint256 marketId,
1149
- uint256 outcomeId,
1150
- uint256 shares
1151
- ) private {
1152
- Market storage market = markets[marketId];
1153
- MarketOutcome storage outcome = market.outcomes[outcomeId];
1154
-
1155
- // adding shares back to pool
1156
- outcome.shares.holders[user] = outcome.shares.holders[user] - shares;
1157
- outcome.shares.available = outcome.shares.available + shares;
1158
- market.sharesAvailable = market.sharesAvailable + shares;
1159
- }
1160
-
1161
- // ------ Core Functions End ------
1162
-
1163
- // ------ Getters ------
1164
-
1165
- function getUserMarketShares(uint256 marketId, address user)
1166
- external
1167
- view
1168
- returns (uint256 liquidity, uint256[] memory outcomes)
1169
- {
1170
- Market storage market = markets[marketId];
1171
- uint256[] memory outcomeShares = new uint256[](market.outcomeCount);
1172
-
1173
- for (uint256 i; i < market.outcomeCount; ++i) {
1174
- outcomeShares[i] = market.outcomes[i].shares.holders[user];
1175
- }
1176
-
1177
- return (market.liquidityShares[user], outcomeShares);
1178
- }
1179
-
1180
- function getUserClaimStatus(uint256 marketId, address user)
1181
- external
1182
- view
1183
- returns (
1184
- bool winningsToClaim,
1185
- bool winningsClaimed,
1186
- bool liquidityToClaim,
1187
- bool liquidityClaimed,
1188
- uint256 claimableFees
1189
- )
1190
- {
1191
- Market storage market = markets[marketId];
1192
-
1193
- // market still not resolved
1194
- if (market.state != MarketState.resolved) {
1195
- return (false, false, false, false, getUserClaimableFees(marketId, user));
1196
- }
1197
-
1198
- MarketOutcome storage outcome = market.outcomes[market.resolution.outcomeId];
1199
-
1200
- return (
1201
- outcome.shares.holders[user] > 0,
1202
- outcome.shares.claims[user],
1203
- market.liquidityShares[user] > 0,
1204
- market.liquidityClaims[user],
1205
- getUserClaimableFees(marketId, user)
1206
- );
1207
- }
1208
-
1209
- function getUserLiquidityPoolShare(uint256 marketId, address user) external view returns (uint256) {
1210
- Market storage market = markets[marketId];
1211
-
1212
- return (market.liquidityShares[user] * ONE) / market.liquidity;
1213
- }
1214
-
1215
- function getUserClaimableFees(uint256 marketId, address user) public view returns (uint256) {
1216
- Market storage market = markets[marketId];
1217
-
1218
- uint256 rawAmount = (market.fees.poolWeight * market.liquidityShares[user]) / market.liquidity;
1219
-
1220
- // No fees left to claim
1221
- if (market.fees.claimed[user] > rawAmount) return 0;
1222
-
1223
- return rawAmount - market.fees.claimed[user];
1224
- }
1225
-
1226
- function getMarkets() external view returns (uint256[] memory) {
1227
- return marketIds;
1228
- }
1229
-
1230
- function getMarketData(uint256 marketId)
1231
- external
1232
- view
1233
- returns (
1234
- MarketState state,
1235
- uint256 closesAt,
1236
- uint256 liquidity,
1237
- uint256 balance,
1238
- uint256 sharesAvailable,
1239
- int256 resolvedOutcomeId
1240
- )
1241
- {
1242
- Market storage market = markets[marketId];
1243
-
1244
- return (
1245
- market.state,
1246
- market.closesAtTimestamp,
1247
- market.liquidity,
1248
- market.balance,
1249
- market.sharesAvailable,
1250
- getMarketResolvedOutcome(marketId)
1251
- );
1252
- }
1253
-
1254
- function getMarketAltData(uint256 marketId)
1255
- external
1256
- view
1257
- returns (
1258
- uint256 buyFee,
1259
- bytes32 questionId,
1260
- uint256 questionIdUint,
1261
- IERC20 token,
1262
- uint256 buyTreasuryFee,
1263
- address treasury,
1264
- IRealityETH_ERC20 realitio,
1265
- uint256 realitioTimeout,
1266
- IPredictionMarketV3Manager manager
1267
- )
1268
- {
1269
- Market storage market = markets[marketId];
1270
-
1271
- return (
1272
- market.fees.buyFees.fee,
1273
- market.resolution.questionId,
1274
- uint256(market.resolution.questionId),
1275
- market.token,
1276
- market.fees.buyFees.treasuryFee,
1277
- market.fees.treasury,
1278
- market.resolution.realitio,
1279
- market.resolution.realitioTimeout,
1280
- market.manager
1281
- );
1282
- }
1283
-
1284
- function getMarketCreator(uint256 marketId) external view returns (address) {
1285
- Market storage market = markets[marketId];
1286
-
1287
- return market.creator;
1288
- }
1289
-
1290
- function getMarketQuestion(uint256 marketId) external view returns (bytes32) {
1291
- Market storage market = markets[marketId];
1292
-
1293
- return (market.resolution.questionId);
1294
- }
1295
-
1296
- function getMarketPrices(uint256 marketId) external view returns (uint256 liquidity, uint256[] memory outcomes) {
1297
- Market storage market = markets[marketId];
1298
- uint256[] memory prices = new uint256[](market.outcomeCount);
1299
-
1300
- for (uint256 i; i < market.outcomeCount; ++i) {
1301
- prices[i] = getMarketOutcomePrice(marketId, i);
1302
- }
1303
-
1304
- return (getMarketLiquidityPrice(marketId), prices);
1305
- }
1306
-
1307
- function getMarketShares(uint256 marketId) external view returns (uint256 liquidity, uint256[] memory outcomes) {
1308
- Market storage market = markets[marketId];
1309
- uint256[] memory outcomeShares = new uint256[](market.outcomeCount);
1310
-
1311
- for (uint256 i; i < market.outcomeCount; ++i) {
1312
- outcomeShares[i] = market.outcomes[i].shares.available;
1313
- }
1314
-
1315
- return (market.liquidity, outcomeShares);
1316
- }
1317
-
1318
- function getMarketLiquidityPrice(uint256 marketId) public view returns (uint256) {
1319
- Market storage market = markets[marketId];
1320
-
1321
- if (market.state == MarketState.resolved && !isMarketVoided(marketId)) {
1322
- // resolved market, outcome prices are either 0 or 1
1323
- // final liquidity price = outcome shares / liquidity shares
1324
- return (market.outcomes[market.resolution.outcomeId].shares.available * ONE) / market.liquidity;
1325
- }
1326
-
1327
- // liquidity price = # outcomes / (liquidity * sum (1 / every outcome shares)
1328
- uint256 marketSharesSum = 0;
1329
-
1330
- for (uint256 i; i < market.outcomeCount; ++i) {
1331
- MarketOutcome storage outcome = market.outcomes[i];
1332
-
1333
- marketSharesSum = marketSharesSum + (ONE * ONE) / outcome.shares.available;
1334
- }
1335
-
1336
- return (market.outcomeCount * ONE * ONE * ONE) / market.liquidity / marketSharesSum;
1337
- }
1338
-
1339
- function getMarketResolvedOutcome(uint256 marketId) public view returns (int256) {
1340
- Market storage market = markets[marketId];
1341
-
1342
- // returning -1 if market still not resolved
1343
- if (market.state != MarketState.resolved) {
1344
- return -1;
1345
- }
1346
-
1347
- return int256(market.resolution.outcomeId);
1348
- }
1349
-
1350
- function isMarketVoided(uint256 marketId) public view returns (bool) {
1351
- Market storage market = markets[marketId];
1352
-
1353
- // market still not resolved, still in valid state
1354
- if (market.state != MarketState.resolved) {
1355
- return false;
1356
- }
1357
-
1358
- // resolved market id does not match any of the market ids
1359
- return market.resolution.outcomeId >= market.outcomeCount;
1360
- }
1361
-
1362
- function getMarketBuyFee(uint256 marketId) public view returns (uint256) {
1363
- Market storage market = markets[marketId];
1364
-
1365
- return market.fees.buyFees.fee + market.fees.buyFees.treasuryFee + market.fees.buyFees.distributorFee;
1366
- }
1367
-
1368
- function getMarketSellFee(uint256 marketId) public view returns (uint256) {
1369
- Market storage market = markets[marketId];
1370
-
1371
- return market.fees.sellFees.fee + market.fees.sellFees.treasuryFee + market.fees.sellFees.distributorFee;
1372
- }
1373
-
1374
- // alias of getMarketBuyFee, used for compatibility
1375
- function getMarketFee(uint256 marketId) public view returns (uint256) {
1376
- return getMarketBuyFee(marketId);
1377
- }
1378
-
1379
- function getMarketFees(uint256 marketId)
1380
- external
1381
- view
1382
- returns (
1383
- Fees memory buyFees,
1384
- Fees memory sellFees,
1385
- address treasury,
1386
- address distributor
1387
- )
1388
- {
1389
- Market storage market = markets[marketId];
1390
-
1391
- return (market.fees.buyFees, market.fees.sellFees, market.fees.treasury, market.fees.distributor);
1392
- }
1393
-
1394
- // ------ Outcome Getters ------
1395
-
1396
- function getMarketOutcomeIds(uint256 marketId) external view returns (uint256[] memory outcomeIds) {
1397
- Market storage market = markets[marketId];
1398
- outcomeIds = new uint256[](market.outcomeCount);
1399
-
1400
- for (uint256 i; i < market.outcomeCount; ++i) {
1401
- outcomeIds[i] = i;
1402
- }
1403
- }
1404
-
1405
- function getMarketOutcomePrice(uint256 marketId, uint256 outcomeId) public view returns (uint256) {
1406
- Market storage market = markets[marketId];
1407
-
1408
- if (market.state == MarketState.resolved && !isMarketVoided(marketId)) {
1409
- // resolved market, price is either 0 or 1
1410
- return outcomeId == market.resolution.outcomeId ? ONE : 0;
1411
- }
1412
-
1413
- // outcome price = 1 / (1 + sum(outcome shares / every outcome shares))
1414
- uint256 div = ONE;
1415
- for (uint256 i; i < market.outcomeCount; ++i) {
1416
- if (i == outcomeId) continue;
1417
-
1418
- div = div + (market.outcomes[outcomeId].shares.available * ONE) / market.outcomes[i].shares.available;
1419
- }
1420
-
1421
- return (ONE * ONE) / div;
1422
- }
1423
-
1424
- function getMarketOutcomeData(uint256 marketId, uint256 outcomeId)
1425
- external
1426
- view
1427
- returns (
1428
- uint256 price,
1429
- uint256 availableShares,
1430
- uint256 totalShares
1431
- )
1432
- {
1433
- Market storage market = markets[marketId];
1434
- MarketOutcome storage outcome = market.outcomes[outcomeId];
1435
-
1436
- return (getMarketOutcomePrice(marketId, outcomeId), outcome.shares.available, outcome.shares.total);
1437
- }
1438
-
1439
- function getMarketOutcomesShares(uint256 marketId) public view returns (uint256[] memory shares) {
1440
- Market storage market = markets[marketId];
1441
-
1442
- shares = new uint256[](market.outcomeCount);
1443
- for (uint256 i; i < market.outcomeCount; ++i) {
1444
- shares[i] = market.outcomes[i].shares.available;
1445
- }
1446
- }
1447
-
1448
- function getMarketPaused(uint256 marketId) external view returns (bool) {
1449
- Market storage market = markets[marketId];
1450
-
1451
- return market.paused;
1452
- }
1453
-
1454
- // ------ Ownable Setters ------
1455
-
1456
- function setAllowedManager(address manager, bool allowed) external onlyOwner {
1457
- allowedManagers[manager] = allowed;
1458
- emit AllowedManagerSet(manager, allowed);
1459
- }
1460
-
1461
- function withdraw(address token, uint256 amount) external onlyOwner {
1462
- IERC20(token).safeTransfer(msg.sender, amount);
1463
- }
1464
-
1465
- function pause() external onlyOwner whenNotPaused {
1466
- paused = true;
1467
- emit Paused(true, msg.sender);
1468
- }
1469
-
1470
- function unpause() external onlyOwner whenPaused {
1471
- paused = false;
1472
- emit Paused(false, msg.sender);
1473
- }
1474
-
1475
- function setTestVarInTheBeginning(uint256 _testVarInTheBeginning) external {
1476
- testVarInTheBeginning = _testVarInTheBeginning;
1477
- }
1478
-
1479
- function setTestVarInTheBeginningArray(uint256[] memory _testVarInTheBeginningArray) external {
1480
- testVarInTheBeginningArray = _testVarInTheBeginningArray;
1481
- }
1482
-
1483
- // ------ Upgrade Authorization ------
1484
-
1485
- /// @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract
1486
- function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
1487
- }