polkamarkets-js 1.0.2 → 3.1.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 (164) hide show
  1. package/.openzeppelin/unknown-1337.json +2056 -0
  2. package/CONTRIBUTING.md +36 -0
  3. package/README.md +24 -25
  4. package/_book/README.md +590 -0
  5. package/_book/core.md +50 -0
  6. package/_book/gitbook/fonts/fontawesome/FontAwesome.otf +0 -0
  7. package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.eot +0 -0
  8. package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.svg +685 -0
  9. package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.ttf +0 -0
  10. package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff +0 -0
  11. package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 +0 -0
  12. package/_book/gitbook/gitbook-plugin-fontsettings/fontsettings.js +240 -0
  13. package/_book/gitbook/gitbook-plugin-fontsettings/website.css +291 -0
  14. package/_book/gitbook/gitbook-plugin-highlight/ebook.css +135 -0
  15. package/_book/gitbook/gitbook-plugin-highlight/website.css +434 -0
  16. package/_book/gitbook/gitbook-plugin-lunr/lunr.min.js +7 -0
  17. package/_book/gitbook/gitbook-plugin-lunr/search-lunr.js +59 -0
  18. package/_book/gitbook/gitbook-plugin-search/lunr.min.js +7 -0
  19. package/_book/gitbook/gitbook-plugin-search/search-engine.js +50 -0
  20. package/_book/gitbook/gitbook-plugin-search/search.css +35 -0
  21. package/_book/gitbook/gitbook-plugin-search/search.js +213 -0
  22. package/_book/gitbook/gitbook-plugin-sharing/buttons.js +90 -0
  23. package/_book/gitbook/gitbook.js +4 -0
  24. package/_book/gitbook/images/apple-touch-icon-precomposed-152.png +0 -0
  25. package/_book/gitbook/images/favicon.ico +0 -0
  26. package/_book/gitbook/style.css +9 -0
  27. package/_book/gitbook/theme.js +4 -0
  28. package/_book/index.html +705 -0
  29. package/_book/intro.md +32 -0
  30. package/_book/search_index.json +1 -0
  31. package/book.json +8 -0
  32. package/build/contracts/AccessControl.json +1 -0
  33. package/build/contracts/AccessControlEnumerable.json +1 -0
  34. package/build/contracts/Achievements.json +1 -0
  35. package/build/contracts/Address.json +1 -0
  36. package/build/contracts/BalanceHolder.json +1 -0
  37. package/build/contracts/BalanceHolder_ERC20.json +1 -0
  38. package/build/contracts/CeilDiv.json +1 -0
  39. package/build/contracts/Clones.json +1 -0
  40. package/build/contracts/Context.json +1 -0
  41. package/build/contracts/Counters.json +1 -0
  42. package/build/contracts/ERC165.json +1 -0
  43. package/build/contracts/ERC20.json +1 -0
  44. package/build/contracts/ERC20Burnable.json +1 -0
  45. package/build/contracts/ERC20Pausable.json +1 -0
  46. package/build/contracts/ERC20PresetMinterPauser.json +1 -0
  47. package/build/contracts/ERC721.json +1 -0
  48. package/build/contracts/EnumerableMap.json +1 -0
  49. package/build/contracts/EnumerableSet.json +1 -0
  50. package/build/contracts/FantasyERC20.json +1 -0
  51. package/build/contracts/IAccessControl.json +1 -0
  52. package/build/contracts/IAccessControlEnumerable.json +1 -0
  53. package/build/contracts/IBalanceHolder_ERC20.json +1 -0
  54. package/build/contracts/IERC165.json +1 -0
  55. package/build/contracts/IERC20.json +1 -0
  56. package/build/contracts/IERC20Metadata.json +1 -0
  57. package/build/contracts/IERC20Permit.json +1 -0
  58. package/build/contracts/IERC721.json +1 -0
  59. package/build/contracts/IERC721Enumerable.json +1 -0
  60. package/build/contracts/IERC721Metadata.json +1 -0
  61. package/build/contracts/IERC721Receiver.json +1 -0
  62. package/build/contracts/IFantasyERC20.json +1 -0
  63. package/build/contracts/IPredictionMarketV3.json +1 -0
  64. package/build/contracts/IPredictionMarketV3Factory.json +1 -0
  65. package/build/contracts/IPredictionMarketV3Manager.json +1 -0
  66. package/build/contracts/IRealityETH_ERC20.json +1 -0
  67. package/build/contracts/IRealityETH_IERC20.json +1 -0
  68. package/build/contracts/IWETH.json +1 -0
  69. package/build/contracts/LandFactory.json +1 -0
  70. package/build/contracts/Math.json +1 -0
  71. package/build/contracts/Migrations.json +1 -0
  72. package/build/contracts/Ownable.json +1 -0
  73. package/build/contracts/Pausable.json +1 -0
  74. package/build/contracts/PredictionMarket.json +1 -0
  75. package/build/contracts/PredictionMarketV2.json +1 -0
  76. package/build/contracts/PredictionMarketV3.json +1 -0
  77. package/build/contracts/PredictionMarketV3Controller.json +1 -0
  78. package/build/contracts/PredictionMarketV3Factory.json +1 -0
  79. package/build/contracts/PredictionMarketV3Manager.json +1 -0
  80. package/build/contracts/PredictionMarketV3Querier.json +1 -0
  81. package/build/contracts/RealitioERC20.json +1 -0
  82. package/build/contracts/RealitioForeignArbitrationProxyWithAppeals.json +1 -0
  83. package/build/contracts/RealitioHomeArbitrationProxy.json +1 -0
  84. package/build/contracts/RealitioSafeMath256.json +1 -0
  85. package/build/contracts/RealitioSafeMath32.json +1 -0
  86. package/build/contracts/RealityETH_ERC20_Factory.json +1 -0
  87. package/build/contracts/RealityETH_ERC20_v3_0.json +1 -0
  88. package/build/contracts/ReentrancyGuard.json +1 -0
  89. package/build/contracts/SafeERC20.json +1 -0
  90. package/build/contracts/SafeMath.json +1 -0
  91. package/build/contracts/Strings.json +1 -0
  92. package/build/contracts/Voting.json +1 -0
  93. package/build/contracts/WETH9.json +1 -0
  94. package/build/contracts/test.json +1 -0
  95. package/cleanContracts.js +22 -0
  96. package/contracts/FantasyERC20.sol +81 -0
  97. package/contracts/IFantasyERC20.sol +20 -0
  98. package/contracts/IPredictionMarketV3.sol +207 -0
  99. package/contracts/IPredictionMarketV3Factory.sol +10 -0
  100. package/contracts/IPredictionMarketV3Manager.sol +12 -0
  101. package/contracts/IRealityETH_ERC20.sol +64 -0
  102. package/contracts/LandFactory.sol +248 -0
  103. package/contracts/Migrations.sol +24 -0
  104. package/contracts/PredictionMarketV3.sol +1332 -0
  105. package/contracts/PredictionMarketV3Controller.sol +87 -0
  106. package/contracts/PredictionMarketV3Factory.sol +205 -0
  107. package/contracts/PredictionMarketV3Manager.sol +45 -0
  108. package/contracts/PredictionMarketV3Querier.sol +79 -0
  109. package/contracts/RealityETH_ERC20_Factory.sol +54 -0
  110. package/contracts/Voting.sol +153 -0
  111. package/contracts/WETH9.sol +62 -0
  112. package/hardhat.config.js +4 -0
  113. package/help.txt +8 -0
  114. package/index.js +3 -0
  115. package/migrations/10_deploy_weth.js +5 -0
  116. package/migrations/11_deploy_full_flow.js +99 -0
  117. package/migrations/12_deploy_pm_v3_querier.js +7 -0
  118. package/migrations/13_deploy_pm_v3_factory.js +14 -0
  119. package/migrations/1_initial_migration.js +5 -0
  120. package/migrations/2_deploy_erc20.js +10 -0
  121. package/migrations/3_deploy_realitio.js +11 -0
  122. package/migrations/4_deploy_pm.js +20 -0
  123. package/migrations/5_seed_markets.js +51 -0
  124. package/migrations/6_deploy_achievements.js +5 -0
  125. package/migrations/7_deploy_voting.js +14 -0
  126. package/migrations/8_deploy_pm_v2.js +20 -0
  127. package/migrations/9_seed_markets_v2.js +68 -0
  128. package/package.json +106 -13
  129. package/src/Application.js +421 -0
  130. package/src/interfaces/index.js +19 -0
  131. package/src/models/AchievementsContract.js +217 -0
  132. package/src/models/ArbitrationContract.js +69 -0
  133. package/src/models/ArbitrationProxyContract.js +32 -0
  134. package/src/models/ERC20Contract.js +156 -0
  135. package/src/models/FantasyERC20Contract.js +92 -0
  136. package/src/models/IContract.js +1002 -0
  137. package/src/models/PolkamarketsSmartAccount.js +100 -0
  138. package/src/models/PredictionMarketContract.js +562 -0
  139. package/src/models/PredictionMarketV2Contract.js +830 -0
  140. package/src/models/PredictionMarketV3Contract.js +256 -0
  141. package/src/models/PredictionMarketV3ControllerContract.js +102 -0
  142. package/src/models/PredictionMarketV3FactoryContract.js +96 -0
  143. package/src/models/PredictionMarketV3ManagerContract.js +111 -0
  144. package/src/models/PredictionMarketV3QuerierContract.js +24 -0
  145. package/src/models/RealitioERC20Contract.js +286 -0
  146. package/src/models/VotingContract.js +182 -0
  147. package/src/models/WETH9Contract.js +92 -0
  148. package/src/models/index.js +33 -0
  149. package/src/utils/Account.js +40 -0
  150. package/src/utils/Contract.js +120 -0
  151. package/src/utils/Numbers.js +94 -0
  152. package/tests/fantasyERC20Contract.js +225 -0
  153. package/tests/index.js +10 -0
  154. package/tests/predictionMarketContract.js +466 -0
  155. package/tests/predictionMarketV2Contract.js +1042 -0
  156. package/tests/predictionMarketV3Contract.js +1079 -0
  157. package/tests/predictionMarketV3ControllerContract.js +613 -0
  158. package/tests/predictionMarketV3FactoryContract.js +469 -0
  159. package/tests/predictionMarketV3ManagerContract.js +610 -0
  160. package/tests/utils.js +16 -0
  161. package/tests/votingContract.js +490 -0
  162. package/tooling/docs/jsdoc.json +6 -0
  163. package/truffle-config.js +134 -0
  164. package/polkamarkets.js +0 -436
@@ -0,0 +1,610 @@
1
+
2
+
3
+ import { expect } from 'chai';
4
+ import moment from 'moment';
5
+
6
+ import { mochaAsync } from './utils';
7
+ import { Application } from '..';
8
+
9
+ context('Prediction Market Contract V3 Manager', async () => {
10
+ require('dotenv').config();
11
+
12
+ const TOKEN_AMOUNT_TO_CLAIM = 10;
13
+ const LOCK_AMOUNT = 5;
14
+ const NEW_LOCK_AMOUNT = 1;
15
+
16
+ const USER1_ADDRESS = process.env.TEST_USER1_ADDRESS;
17
+ const USER1_PRIVATE_KEY = process.env.TEST_USER1_PRIVATE_KEY;
18
+ const USER2_ADDRESS = process.env.TEST_USER2_ADDRESS;
19
+ const USER2_PRIVATE_KEY = process.env.TEST_USER2_PRIVATE_KEY;
20
+
21
+ let app;
22
+ let accountAddress;
23
+ let predictionMarketContract;
24
+ let predictionMarketManagerContract;
25
+ let realitioERC20Contract
26
+ let pmmTokenContract;
27
+
28
+ let landId = 0;
29
+
30
+ context('Contract Deployment', async () => {
31
+ it('should start the Application', mochaAsync(async () => {
32
+ app = new Application({
33
+ web3Provider: process.env.WEB3_PROVIDER,
34
+ web3PrivateKey: process.env.WEB3_PRIVATE_KEY
35
+ });
36
+ expect(app).to.not.equal(null);
37
+ }));
38
+
39
+ it('should deploy Prediction Market Contract', mochaAsync(async () => {
40
+ accountAddress = await app.getAddress();
41
+
42
+ // Create Contract
43
+ predictionMarketContract = app.getPredictionMarketV3Contract({});
44
+ predictionMarketManagerContract = app.getPredictionMarketV3ManagerContract({});
45
+ realitioERC20Contract = app.getRealitioERC20Contract({});
46
+ pmmTokenContract = app.getERC20Contract({});
47
+
48
+ // Deploy
49
+ await pmmTokenContract.deploy({params: ['Polkamarkets', 'POLK']});
50
+ const pmmTokenContractAddress = pmmTokenContract.getAddress();
51
+
52
+ await realitioERC20Contract.deploy({});
53
+ let realitioContractAddress = realitioERC20Contract.getAddress();
54
+
55
+ await predictionMarketContract.deploy({
56
+ params: [
57
+ '0x0000000000000000000000000000000000000000'
58
+ ]
59
+ });
60
+ const predictionMarketContractAddress = predictionMarketContract.getAddress();
61
+
62
+ await predictionMarketManagerContract.deploy({
63
+ params: [
64
+ predictionMarketContractAddress,
65
+ pmmTokenContractAddress,
66
+ (LOCK_AMOUNT * 10**18).toString(), // TODO: improve this
67
+ realitioContractAddress
68
+ ]
69
+ });
70
+ const predictionMarketManagerContractAddress = predictionMarketManagerContract.getAddress();
71
+ // minting and approving pmmTokenContract to spend tokens
72
+ await pmmTokenContract.mint({
73
+ address: accountAddress,
74
+ amount: '1000'
75
+ });
76
+ await pmmTokenContract.approve({
77
+ address: predictionMarketManagerContractAddress,
78
+ amount: '1000000'
79
+ });
80
+
81
+ expect(predictionMarketContractAddress).to.not.equal(null);
82
+ expect(predictionMarketManagerContractAddress).to.not.equal(null);
83
+ expect(realitioContractAddress).to.not.equal(null);
84
+ expect(pmmTokenContractAddress).to.not.equal(null);
85
+ }));
86
+ });
87
+
88
+ context('Land Management', async () => {
89
+ context('Land Creation', async () => {
90
+ it('should create a Land', mochaAsync(async () => {
91
+ const currentLandIndex = await predictionMarketManagerContract.getLandTokensLength();
92
+ landId = currentLandIndex;
93
+ const currentPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
94
+
95
+ await predictionMarketManagerContract.createLand({
96
+ name: 'Token',
97
+ symbol: 'TOKEN',
98
+ tokenAmountToClaim: TOKEN_AMOUNT_TO_CLAIM,
99
+ tokenToAnswer: pmmTokenContract.getAddress(),
100
+ });
101
+ const land = await predictionMarketManagerContract.getLandById({ id: currentLandIndex });
102
+ const newLandIndex = await predictionMarketManagerContract.getLandTokensLength();
103
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
104
+
105
+ expect(newPmmTokenBalance).to.equal(currentPmmTokenBalance - LOCK_AMOUNT);
106
+ expect(newLandIndex).to.equal(currentLandIndex + 1);
107
+ expect(land.token).to.not.equal('0x0000000000000000000000000000000000000000');
108
+ expect(land.active).to.equal(true);
109
+ expect(land.lockAmount).to.equal(LOCK_AMOUNT);
110
+ expect(land.lockUser).to.equal(accountAddress);
111
+ expect(land.realitio).to.not.equal('0x0000000000000000000000000000000000000000');
112
+ }));
113
+
114
+ it('should create another Land', mochaAsync(async () => {
115
+ const currentLandIndex = await predictionMarketManagerContract.getLandTokensLength();
116
+ const currentPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
117
+
118
+ await predictionMarketManagerContract.createLand({
119
+ name: 'Token 2',
120
+ symbol: 'TOKEN2',
121
+ tokenAmountToClaim: TOKEN_AMOUNT_TO_CLAIM,
122
+ tokenToAnswer: pmmTokenContract.getAddress(),
123
+ });
124
+ const land = await predictionMarketManagerContract.getLandById({ id: currentLandIndex });
125
+ const newLandIndex = await predictionMarketManagerContract.getLandTokensLength();
126
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
127
+
128
+ expect(newPmmTokenBalance).to.equal(currentPmmTokenBalance - LOCK_AMOUNT);
129
+ expect(newLandIndex).to.equal(currentLandIndex + 1);
130
+ expect(land.token).to.not.equal('0x0000000000000000000000000000000000000000');
131
+ expect(land.active).to.equal(true);
132
+ expect(land.lockAmount).to.equal(LOCK_AMOUNT);
133
+ expect(land.lockUser).to.equal(accountAddress);
134
+ expect(land.realitio).to.not.equal('0x0000000000000000000000000000000000000000');
135
+ }));
136
+ });
137
+
138
+ context('Land Admins', async () => {
139
+ let landId = 0;
140
+ let token;
141
+
142
+ const user1 = USER1_ADDRESS;
143
+ const user2 = USER2_ADDRESS;
144
+
145
+ let user1App;
146
+ let user1PredictionMarketManagerContract;
147
+
148
+ before(mochaAsync(async () => {
149
+ const land = await predictionMarketManagerContract.getLandById({ id: landId });
150
+ token = land.token;
151
+
152
+ user1App = new Application({
153
+ web3Provider: process.env.WEB3_PROVIDER,
154
+ web3PrivateKey: USER1_PRIVATE_KEY
155
+ });
156
+ user1PredictionMarketManagerContract = user1App.getPredictionMarketV3ManagerContract({
157
+ contractAddress: predictionMarketManagerContract.getAddress()
158
+ });
159
+ }));
160
+
161
+ it('should add an admin to a Land', mochaAsync(async () => {
162
+ const currentIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
163
+ await predictionMarketManagerContract.addAdminToLand({
164
+ token,
165
+ user: user2
166
+ });
167
+ const newIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
168
+
169
+ expect(currentIsAdmin).to.equal(false);
170
+ expect(newIsAdmin).to.equal(true);
171
+ }));
172
+
173
+ it('should remove an admin from a Land', mochaAsync(async () => {
174
+ const currentIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
175
+ await predictionMarketManagerContract.removeAdminFromLand({
176
+ token,
177
+ user: user2
178
+ });
179
+ const newIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
180
+
181
+ expect(currentIsAdmin).to.equal(true);
182
+ expect(newIsAdmin).to.equal(false);
183
+ }));
184
+
185
+ it('should not be able to add an admin to a Land if not an admin making the call', mochaAsync(async () => {
186
+ const currentIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
187
+ try {
188
+ await user1PredictionMarketManagerContract.addAdminToLand({
189
+ token,
190
+ user: user2
191
+ });
192
+ } catch(e) {
193
+ // not logging error, as tx is expected to fail
194
+ }
195
+ const newIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
196
+
197
+ expect(currentIsAdmin).to.equal(false);
198
+ expect(newIsAdmin).to.equal(false);
199
+ }));
200
+
201
+ it('should be able to add/remove an admin to a Land after being made admin', mochaAsync(async () => {
202
+ await predictionMarketManagerContract.addAdminToLand({
203
+ token,
204
+ user: user1
205
+ });
206
+
207
+ const currentIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
208
+ await user1PredictionMarketManagerContract.addAdminToLand({
209
+ token,
210
+ user: user2
211
+ });
212
+ const newIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
213
+
214
+ expect(currentIsAdmin).to.equal(false);
215
+ expect(newIsAdmin).to.equal(true);
216
+
217
+ await user1PredictionMarketManagerContract.removeAdminFromLand({
218
+ token,
219
+ user: user2
220
+ });
221
+ const lastNewIsAdmin = await predictionMarketManagerContract.isLandAdmin({ token, user: user2 });
222
+
223
+ expect(lastNewIsAdmin).to.equal(false);
224
+
225
+ // resetting user1 admin status
226
+ await predictionMarketManagerContract.removeAdminFromLand({
227
+ token,
228
+ user: user1
229
+ });
230
+ }));
231
+ });
232
+
233
+ context('Land Disabling + Enabling + Offset', async () => {
234
+ let landId = 0;
235
+ let land;
236
+ let token;
237
+
238
+ let user1App;
239
+ let user1PredictionMarketManagerContract;
240
+
241
+ let landTokenContract;
242
+
243
+ before(mochaAsync(async () => {
244
+ land = await predictionMarketManagerContract.getLandById({ id: landId });
245
+ landTokenContract = app.getFantasyERC20Contract({contractAddress: land.token});
246
+ token = land.token;
247
+
248
+ user1App = new Application({
249
+ web3Provider: process.env.WEB3_PROVIDER,
250
+ web3PrivateKey: USER1_PRIVATE_KEY
251
+ });
252
+ user1PredictionMarketManagerContract = user1App.getPredictionMarketV3ManagerContract({
253
+ contractAddress: predictionMarketManagerContract.getAddress()
254
+ });
255
+ }));
256
+
257
+ it('should not be able to disable a Land if not an admin making the call', mochaAsync(async () => {
258
+ try {
259
+ await user1PredictionMarketManagerContract.disableLand({
260
+ token
261
+ });
262
+ } catch(e) {
263
+ // not logging error, as tx is expected to fail
264
+ }
265
+
266
+ const refreshedLand = await predictionMarketManagerContract.getLandById({ id: landId });
267
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
268
+
269
+ expect(land.active).to.equal(true);
270
+ expect(refreshedLand.active).to.equal(true);
271
+ }));
272
+
273
+ it('should disable a Land', mochaAsync(async () => {
274
+ const currentPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
275
+ const currentPaused = await landTokenContract.paused();
276
+ await predictionMarketManagerContract.disableLand({
277
+ token: land.token
278
+ });
279
+
280
+ const refreshedLand = await predictionMarketManagerContract.getLandById({ id: landId });
281
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
282
+ const newPaused = await landTokenContract.paused();
283
+
284
+ expect(land.active).to.equal(true);
285
+ expect(currentPaused).to.equal(false);
286
+ expect(newPaused).to.equal(true);
287
+ expect(newPmmTokenBalance).to.equal(currentPmmTokenBalance + LOCK_AMOUNT);
288
+ expect(refreshedLand.token).to.equal(land.token);
289
+ expect(refreshedLand.active).to.equal(false);
290
+ expect(refreshedLand.lockAmount).to.equal(0);
291
+ expect(refreshedLand.lockUser).to.equal('0x0000000000000000000000000000000000000000');
292
+ expect(refreshedLand.realitio).to.equal(land.realitio);
293
+ }));
294
+
295
+ it('should not be able to disable a Land if already disabled', mochaAsync(async () => {
296
+ const currentPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
297
+ try {
298
+ await predictionMarketManagerContract.disableLand({
299
+ token
300
+ });
301
+ } catch(e) {
302
+ // not logging error, as tx is expected to fail
303
+ }
304
+
305
+ const refreshedLand = await predictionMarketManagerContract.getLandById({ id: landId });
306
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
307
+
308
+ expect(refreshedLand.active).to.equal(false);
309
+ expect(newPmmTokenBalance).to.equal(currentPmmTokenBalance);
310
+ }));
311
+
312
+ it('should enable a Land', mochaAsync(async () => {
313
+ const currentPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
314
+ const currentPaused = await landTokenContract.paused();
315
+ await predictionMarketManagerContract.enableLand({
316
+ token: land.token
317
+ });
318
+
319
+ const refreshedLand = await predictionMarketManagerContract.getLandById({ id: landId });
320
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
321
+ const newPaused = await landTokenContract.paused();
322
+
323
+ expect(currentPaused).to.equal(true);
324
+ expect(newPaused).to.equal(false);
325
+ expect(newPmmTokenBalance).to.equal(currentPmmTokenBalance - LOCK_AMOUNT);
326
+ expect(refreshedLand.token).to.equal(land.token);
327
+ expect(refreshedLand.active).to.equal(true);
328
+ expect(refreshedLand.lockAmount).to.equal(LOCK_AMOUNT);
329
+ expect(refreshedLand.lockUser).to.equal(accountAddress);
330
+ expect(refreshedLand.realitio).to.equal(land.realitio);
331
+ }));
332
+
333
+ it('should be able to update lock amount if not the contract owner', mochaAsync(async () => {
334
+ const currentLockAmount = await predictionMarketManagerContract.lockAmount();
335
+ expect(currentLockAmount).to.equal(LOCK_AMOUNT);
336
+
337
+ try {
338
+ await user1PredictionMarketManagerContract.updateLockAmount({
339
+ amount: NEW_LOCK_AMOUNT,
340
+ });
341
+ } catch(e) {
342
+ // not logging error, as tx is expected to fail
343
+ }
344
+
345
+ const newLockAmount = await predictionMarketManagerContract.lockAmount();
346
+ expect(newLockAmount).to.equal(LOCK_AMOUNT);
347
+ }));
348
+
349
+ it('should be able to update lock amount', mochaAsync(async () => {
350
+ const currentLockAmount = await predictionMarketManagerContract.lockAmount();
351
+ expect(currentLockAmount).to.equal(LOCK_AMOUNT);
352
+
353
+ await predictionMarketManagerContract.updateLockAmount({
354
+ amount: NEW_LOCK_AMOUNT,
355
+ });
356
+
357
+ const newLockAmount = await predictionMarketManagerContract.lockAmount();
358
+ expect(newLockAmount).to.equal(NEW_LOCK_AMOUNT);
359
+ }));
360
+
361
+ it('should not be able to unlock offset from land if not an admin', mochaAsync(async () => {
362
+ const currentLockAmount = await predictionMarketManagerContract.lockAmount();
363
+ expect(currentLockAmount).to.equal(NEW_LOCK_AMOUNT);
364
+ const currentPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
365
+
366
+ try {
367
+ await user1PredictionMarketManagerContract.unlockOffsetFromLand({
368
+ token: land.token
369
+ });
370
+ } catch(e) {
371
+ // not logging error, as tx is expected to fail
372
+ }
373
+
374
+ const refreshedLand = await predictionMarketManagerContract.getLandById({ id: landId });
375
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
376
+
377
+ expect(newPmmTokenBalance).to.equal(currentPmmTokenBalance);
378
+ expect(refreshedLand.lockAmount).to.equal(LOCK_AMOUNT);
379
+ }));
380
+
381
+ it('should be able to unlock offset from land', mochaAsync(async () => {
382
+ const currentLockAmount = await predictionMarketManagerContract.lockAmount();
383
+ expect(currentLockAmount).to.equal(NEW_LOCK_AMOUNT);
384
+ const currentPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
385
+
386
+ await predictionMarketManagerContract.unlockOffsetFromLand({
387
+ token: land.token
388
+ });
389
+
390
+ const refreshedLand = await predictionMarketManagerContract.getLandById({ id: landId });
391
+ const newPmmTokenBalance = await pmmTokenContract.balanceOf({ address: accountAddress });
392
+
393
+ expect(newPmmTokenBalance).to.equal(currentPmmTokenBalance + LOCK_AMOUNT - NEW_LOCK_AMOUNT);
394
+ expect(refreshedLand.lockAmount).to.equal(NEW_LOCK_AMOUNT);
395
+ }));
396
+ });
397
+ });
398
+
399
+ context('Land Markets', async () => {
400
+ let landId = 0;
401
+ let marketId = 0;
402
+ let outcomeId = 0;
403
+ let value = 0.01;
404
+ let land;
405
+
406
+ let user1;
407
+ let user1App;
408
+ let user1PredictionMarketContract;
409
+
410
+ let landTokenContract;
411
+ let user1LandTokenContract;
412
+
413
+ before(mochaAsync(async () => {
414
+ land = await predictionMarketManagerContract.getLandById({ id: landId });
415
+
416
+ user1 = USER1_ADDRESS;
417
+ user1App = new Application({
418
+ web3Provider: process.env.WEB3_PROVIDER,
419
+ web3PrivateKey: USER1_PRIVATE_KEY
420
+ });
421
+ user1PredictionMarketContract = user1App.getPredictionMarketV3Contract({
422
+ contractAddress: predictionMarketContract.getAddress()
423
+ });
424
+
425
+ landTokenContract = app.getFantasyERC20Contract({contractAddress: land.token});
426
+ user1LandTokenContract = user1App.getFantasyERC20Contract({contractAddress: land.token});
427
+ // approving land token to spend tokens
428
+ await landTokenContract.claimAndApproveTokens();
429
+ await user1LandTokenContract.claimAndApproveTokens();
430
+ }));
431
+
432
+ context('Market Creation', async () => {
433
+ it('should not be able to create a Market if not an admin making the call', mochaAsync(async () => {
434
+ const currentMarketIds = await predictionMarketContract.getMarkets();
435
+ const currentLandTokenBalance = await landTokenContract.balanceOf({ address: user1 });
436
+ expect(currentLandTokenBalance).to.equal(TOKEN_AMOUNT_TO_CLAIM);
437
+
438
+ try {
439
+ await user1PredictionMarketContract.mintAndCreateMarket({
440
+ value,
441
+ name: 'Will BTC price close above 100k$ on May 1st 2025',
442
+ description: 'This is a description',
443
+ image: 'foo-bar',
444
+ category: 'Foo;Bar',
445
+ oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
446
+ duration: moment('2025-05-01').unix(),
447
+ outcomes: ['Yes', 'No'],
448
+ token: landTokenContract.getAddress(),
449
+ realitioAddress: land.realitio,
450
+ realitioTimeout: 300,
451
+ PM3ManagerAddress: predictionMarketManagerContract.getAddress()
452
+ });
453
+ } catch(e) {
454
+ // not logging error, as tx is expected to fail
455
+ }
456
+
457
+ const newMarketIds = await predictionMarketContract.getMarkets();
458
+ expect(newMarketIds.length).to.equal(currentMarketIds.length);
459
+ }));
460
+
461
+ it('should create a Market', mochaAsync(async () => {
462
+ const currentMarketIds = await predictionMarketContract.getMarkets();
463
+ const currentLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
464
+ expect(currentLandTokenBalance).to.equal(TOKEN_AMOUNT_TO_CLAIM);
465
+
466
+ try {
467
+ const res = await predictionMarketContract.mintAndCreateMarket({
468
+ value,
469
+ name: 'Will BTC price close above 100k$ on May 1st 2025',
470
+ description: 'This is a description',
471
+ image: 'foo-bar',
472
+ category: 'Foo;Bar',
473
+ oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
474
+ duration: moment('2025-05-01').unix(),
475
+ outcomes: ['Yes', 'No'],
476
+ token: landTokenContract.getAddress(),
477
+ realitioAddress: land.realitio,
478
+ realitioTimeout: 300,
479
+ PM3ManagerAddress: predictionMarketManagerContract.getAddress()
480
+ });
481
+ expect(res.status).to.equal(true);
482
+ } catch(e) {
483
+ console.log(e);
484
+ }
485
+
486
+ const newLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
487
+ const newMarketIds = await predictionMarketContract.getMarkets();
488
+ expect(newMarketIds.length).to.equal(currentMarketIds.length + 1);
489
+ // balance remains the same since tokens were minted
490
+ expect(newLandTokenBalance).to.equal(currentLandTokenBalance);
491
+ }));
492
+ });
493
+
494
+ context('Market Interaction', async () => {
495
+ it('should be able to buy shares when land enabled', mochaAsync(async () => {
496
+ const minOutcomeSharesToBuy = 0.015;
497
+ const currentLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
498
+
499
+ try {
500
+ const res = await predictionMarketContract.buy({marketId, outcomeId, value, minOutcomeSharesToBuy});
501
+ expect(res.status).to.equal(true);
502
+ } catch(e) {
503
+ console.log(e);
504
+ }
505
+
506
+ const newLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
507
+ const amountTransferred = Number((currentLandTokenBalance - newLandTokenBalance).toFixed(5));
508
+
509
+ expect(amountTransferred).to.equal(value);
510
+ }));
511
+
512
+ it('should sell outcome shares', mochaAsync(async () => {
513
+ const outcomeId = 0;
514
+ const maxOutcomeSharesToSell = 0.015;
515
+
516
+ const currentLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
517
+
518
+ try {
519
+ const res = await predictionMarketContract.sell({marketId, outcomeId, value, maxOutcomeSharesToSell});
520
+ expect(res.status).to.equal(true);
521
+ } catch(e) {
522
+ console.log(e);
523
+ }
524
+
525
+ const newLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
526
+ const amountTransferred = Number((newLandTokenBalance - currentLandTokenBalance).toFixed(5));
527
+
528
+ expect(amountTransferred).to.equal(value);
529
+ }));
530
+
531
+ it('should not be able to buy shares when land disabled', mochaAsync(async () => {
532
+ const minOutcomeSharesToBuy = 0.015;
533
+ const currentLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
534
+
535
+ await predictionMarketManagerContract.disableLand({
536
+ token: land.token
537
+ });
538
+
539
+ try {
540
+ const res = await predictionMarketContract.buy({marketId, outcomeId, value, minOutcomeSharesToBuy});
541
+ expect(res.status).to.equal(true);
542
+ } catch(e) {
543
+ // not logging error, as tx is expected to fail
544
+ }
545
+
546
+ const newLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
547
+ const amountTransferred = currentLandTokenBalance - newLandTokenBalance;
548
+
549
+ expect(amountTransferred).to.equal(0);
550
+ }));
551
+
552
+ it('should be able to buy shares when land enabled again', mochaAsync(async () => {
553
+ const minOutcomeSharesToBuy = 0.015;
554
+ const currentLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
555
+
556
+ await predictionMarketManagerContract.enableLand({
557
+ token: land.token
558
+ });
559
+
560
+ try {
561
+ const res = await predictionMarketContract.buy({marketId, outcomeId, value, minOutcomeSharesToBuy});
562
+ expect(res.status).to.equal(true);
563
+ } catch(e) {
564
+ console.log(e);
565
+ }
566
+
567
+ const newLandTokenBalance = await landTokenContract.balanceOf({ address: accountAddress });
568
+ const amountTransferred = Number((currentLandTokenBalance - newLandTokenBalance).toFixed(5));
569
+
570
+ expect(amountTransferred).to.equal(value);
571
+ }));
572
+ });
573
+
574
+ context('Market Resolution', async () => {
575
+ let outcomeId = 1;
576
+
577
+ it('should not be able to resolve a Market if not an admin making the call', mochaAsync(async () => {
578
+ try {
579
+ await user1PredictionMarketContract.adminResolveMarketOutcome({
580
+ marketId,
581
+ outcomeId
582
+ });
583
+ } catch(e) {
584
+ // not logging error, as tx is expected to fail
585
+ }
586
+
587
+ const market = await predictionMarketContract.getMarketData({ marketId });
588
+ expect(market.state).to.equal(0);
589
+ }));
590
+
591
+ it('should be able to resolve a Market', mochaAsync(async () => {
592
+ try {
593
+ const res = await predictionMarketContract.adminResolveMarketOutcome({
594
+ marketId,
595
+ outcomeId
596
+ });
597
+ expect(res.status).to.equal(true);
598
+ } catch(e) {
599
+ console.log(e);
600
+ }
601
+
602
+ // doing dummy transaction to get the latest block
603
+ await landTokenContract.approve({ address: '0x000000000000000000000000000000000000dead', amount: 0 });
604
+
605
+ const market = await predictionMarketContract.getMarketData({ marketId });
606
+ expect(market.state).to.equal(2);
607
+ }));
608
+ });
609
+ });
610
+ });
package/tests/utils.js ADDED
@@ -0,0 +1,16 @@
1
+ export const mochaAsync = (fn) => {
2
+ return done => {
3
+ fn.call().then(done, err => {
4
+ done(err);
5
+ });
6
+ };
7
+ };
8
+
9
+ export const detectValidationErrors = (res) => {
10
+ if (res.message == 'Validation errors') {
11
+ console.log(res.errors[0]);
12
+ return true;
13
+ } else {
14
+ return false;
15
+ }
16
+ }