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