polkamarkets-js 1.0.1 → 3.1.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/.openzeppelin/unknown-1337.json +2056 -0
- package/CONTRIBUTING.md +36 -0
- package/README.md +24 -25
- package/_book/README.md +590 -0
- package/_book/core.md +50 -0
- package/_book/gitbook/fonts/fontawesome/FontAwesome.otf +0 -0
- package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.eot +0 -0
- package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.svg +685 -0
- package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.ttf +0 -0
- package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff +0 -0
- package/_book/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 +0 -0
- package/_book/gitbook/gitbook-plugin-fontsettings/fontsettings.js +240 -0
- package/_book/gitbook/gitbook-plugin-fontsettings/website.css +291 -0
- package/_book/gitbook/gitbook-plugin-highlight/ebook.css +135 -0
- package/_book/gitbook/gitbook-plugin-highlight/website.css +434 -0
- package/_book/gitbook/gitbook-plugin-lunr/lunr.min.js +7 -0
- package/_book/gitbook/gitbook-plugin-lunr/search-lunr.js +59 -0
- package/_book/gitbook/gitbook-plugin-search/lunr.min.js +7 -0
- package/_book/gitbook/gitbook-plugin-search/search-engine.js +50 -0
- package/_book/gitbook/gitbook-plugin-search/search.css +35 -0
- package/_book/gitbook/gitbook-plugin-search/search.js +213 -0
- package/_book/gitbook/gitbook-plugin-sharing/buttons.js +90 -0
- package/_book/gitbook/gitbook.js +4 -0
- package/_book/gitbook/images/apple-touch-icon-precomposed-152.png +0 -0
- package/_book/gitbook/images/favicon.ico +0 -0
- package/_book/gitbook/style.css +9 -0
- package/_book/gitbook/theme.js +4 -0
- package/_book/index.html +705 -0
- package/_book/intro.md +32 -0
- package/_book/search_index.json +1 -0
- package/book.json +8 -0
- package/build/contracts/AccessControl.json +1 -0
- package/build/contracts/AccessControlEnumerable.json +1 -0
- package/build/contracts/Achievements.json +1 -0
- package/build/contracts/Address.json +1 -0
- package/build/contracts/BalanceHolder.json +1 -0
- package/build/contracts/BalanceHolder_ERC20.json +1 -0
- package/build/contracts/CeilDiv.json +1 -0
- package/build/contracts/Clones.json +1 -0
- package/build/contracts/Context.json +1 -0
- package/build/contracts/Counters.json +1 -0
- package/build/contracts/ERC165.json +1 -0
- package/build/contracts/ERC20.json +1 -0
- package/build/contracts/ERC20Burnable.json +1 -0
- package/build/contracts/ERC20Pausable.json +1 -0
- package/build/contracts/ERC20PresetMinterPauser.json +1 -0
- package/build/contracts/ERC721.json +1 -0
- package/build/contracts/EnumerableMap.json +1 -0
- package/build/contracts/EnumerableSet.json +1 -0
- package/build/contracts/FantasyERC20.json +1 -0
- package/build/contracts/IAccessControl.json +1 -0
- package/build/contracts/IAccessControlEnumerable.json +1 -0
- package/build/contracts/IBalanceHolder_ERC20.json +1 -0
- package/build/contracts/IERC165.json +1 -0
- package/build/contracts/IERC20.json +1 -0
- package/build/contracts/IERC20Metadata.json +1 -0
- package/build/contracts/IERC20Permit.json +1 -0
- package/build/contracts/IERC721.json +1 -0
- package/build/contracts/IERC721Enumerable.json +1 -0
- package/build/contracts/IERC721Metadata.json +1 -0
- package/build/contracts/IERC721Receiver.json +1 -0
- package/build/contracts/IFantasyERC20.json +1 -0
- package/build/contracts/IPredictionMarketV3.json +1 -0
- package/build/contracts/IPredictionMarketV3Factory.json +1 -0
- package/build/contracts/IPredictionMarketV3Manager.json +1 -0
- package/build/contracts/IRealityETH_ERC20.json +1 -0
- package/build/contracts/IRealityETH_IERC20.json +1 -0
- package/build/contracts/IWETH.json +1 -0
- package/build/contracts/LandFactory.json +1 -0
- package/build/contracts/Math.json +1 -0
- package/build/contracts/Migrations.json +1 -0
- package/build/contracts/Ownable.json +1 -0
- package/build/contracts/Pausable.json +1 -0
- package/build/contracts/PredictionMarket.json +1 -0
- package/build/contracts/PredictionMarketV2.json +1 -0
- package/build/contracts/PredictionMarketV3.json +1 -0
- package/build/contracts/PredictionMarketV3Controller.json +1 -0
- package/build/contracts/PredictionMarketV3Factory.json +1 -0
- package/build/contracts/PredictionMarketV3Manager.json +1 -0
- package/build/contracts/PredictionMarketV3Querier.json +1 -0
- package/build/contracts/RealitioERC20.json +1 -0
- package/build/contracts/RealitioForeignArbitrationProxyWithAppeals.json +1 -0
- package/build/contracts/RealitioHomeArbitrationProxy.json +1 -0
- package/build/contracts/RealitioSafeMath256.json +1 -0
- package/build/contracts/RealitioSafeMath32.json +1 -0
- package/build/contracts/RealityETH_ERC20_Factory.json +1 -0
- package/build/contracts/RealityETH_ERC20_v3_0.json +1 -0
- package/build/contracts/ReentrancyGuard.json +1 -0
- package/build/contracts/SafeERC20.json +1 -0
- package/build/contracts/SafeMath.json +1 -0
- package/build/contracts/Strings.json +1 -0
- package/build/contracts/Voting.json +1 -0
- package/build/contracts/WETH9.json +1 -0
- package/build/contracts/test.json +1 -0
- package/cleanContracts.js +22 -0
- package/contracts/FantasyERC20.sol +81 -0
- package/contracts/IFantasyERC20.sol +20 -0
- package/contracts/IPredictionMarketV3.sol +207 -0
- package/contracts/IPredictionMarketV3Factory.sol +10 -0
- package/contracts/IPredictionMarketV3Manager.sol +12 -0
- package/contracts/IRealityETH_ERC20.sol +64 -0
- package/contracts/LandFactory.sol +248 -0
- package/contracts/Migrations.sol +24 -0
- package/contracts/PredictionMarketV3.sol +1332 -0
- package/contracts/PredictionMarketV3Controller.sol +87 -0
- package/contracts/PredictionMarketV3Factory.sol +205 -0
- package/contracts/PredictionMarketV3Manager.sol +45 -0
- package/contracts/PredictionMarketV3Querier.sol +79 -0
- package/contracts/RealityETH_ERC20_Factory.sol +54 -0
- package/contracts/Voting.sol +153 -0
- package/contracts/WETH9.sol +62 -0
- package/help.txt +8 -0
- package/index.js +3 -0
- package/migrations/10_deploy_weth.js +5 -0
- package/migrations/11_deploy_full_flow.js +99 -0
- package/migrations/12_deploy_pm_v3_querier.js +7 -0
- package/migrations/13_deploy_pm_v3_factory.js +14 -0
- package/migrations/1_initial_migration.js +5 -0
- package/migrations/2_deploy_erc20.js +10 -0
- package/migrations/3_deploy_realitio.js +11 -0
- package/migrations/4_deploy_pm.js +20 -0
- package/migrations/5_seed_markets.js +51 -0
- package/migrations/6_deploy_achievements.js +5 -0
- package/migrations/7_deploy_voting.js +14 -0
- package/migrations/8_deploy_pm_v2.js +20 -0
- package/migrations/9_seed_markets_v2.js +68 -0
- package/package.json +106 -13
- package/src/Application.js +421 -0
- package/src/interfaces/index.js +19 -0
- package/src/models/AchievementsContract.js +217 -0
- package/src/models/ArbitrationContract.js +69 -0
- package/src/models/ArbitrationProxyContract.js +32 -0
- package/src/models/ERC20Contract.js +156 -0
- package/src/models/FantasyERC20Contract.js +92 -0
- package/src/models/IContract.js +1002 -0
- package/src/models/PolkamarketsSmartAccount.js +100 -0
- package/src/models/PredictionMarketContract.js +562 -0
- package/src/models/PredictionMarketV2Contract.js +830 -0
- package/src/models/PredictionMarketV3Contract.js +233 -0
- package/src/models/PredictionMarketV3ControllerContract.js +102 -0
- package/src/models/PredictionMarketV3FactoryContract.js +96 -0
- package/src/models/PredictionMarketV3ManagerContract.js +111 -0
- package/src/models/PredictionMarketV3QuerierContract.js +24 -0
- package/src/models/RealitioERC20Contract.js +286 -0
- package/src/models/VotingContract.js +182 -0
- package/src/models/WETH9Contract.js +92 -0
- package/src/models/index.js +33 -0
- package/src/utils/Account.js +40 -0
- package/src/utils/Contract.js +120 -0
- package/src/utils/Numbers.js +94 -0
- package/tests/fantasyERC20Contract.js +225 -0
- package/tests/index.js +10 -0
- package/tests/predictionMarketContract.js +466 -0
- package/tests/predictionMarketV2Contract.js +1042 -0
- package/tests/predictionMarketV3Contract.js +1079 -0
- package/tests/predictionMarketV3ControllerContract.js +613 -0
- package/tests/predictionMarketV3FactoryContract.js +469 -0
- package/tests/predictionMarketV3ManagerContract.js +610 -0
- package/tests/utils.js +16 -0
- package/tests/votingContract.js +490 -0
- package/tooling/docs/jsdoc.json +6 -0
- package/truffle-config.js +134 -0
- package/polkamarkets.js +0 -422
|
@@ -0,0 +1,1079 @@
|
|
|
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', async () => {
|
|
10
|
+
require('dotenv').config();
|
|
11
|
+
|
|
12
|
+
let app;
|
|
13
|
+
let accountAddress;
|
|
14
|
+
let predictionMarketContract;
|
|
15
|
+
let predictionMarketManagerContract;
|
|
16
|
+
let realitioERC20Contract
|
|
17
|
+
let requiredBalanceERC20Contract;
|
|
18
|
+
let tokenERC20Contract;
|
|
19
|
+
let WETH9Contract;
|
|
20
|
+
|
|
21
|
+
// market / outcome ids we'll make unit tests with
|
|
22
|
+
let outcomeIds = [0, 1];
|
|
23
|
+
const value = 0.01;
|
|
24
|
+
|
|
25
|
+
context('Contract Deployment', async () => {
|
|
26
|
+
it('should start the Application', mochaAsync(async () => {
|
|
27
|
+
app = new Application({
|
|
28
|
+
web3Provider: process.env.WEB3_PROVIDER,
|
|
29
|
+
web3PrivateKey: process.env.WEB3_PRIVATE_KEY
|
|
30
|
+
});
|
|
31
|
+
expect(app).to.not.equal(null);
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
it('should deploy Prediction Market Contract', mochaAsync(async () => {
|
|
35
|
+
accountAddress = await app.getAddress();
|
|
36
|
+
|
|
37
|
+
// Create Contract
|
|
38
|
+
predictionMarketContract = app.getPredictionMarketV3Contract({});
|
|
39
|
+
predictionMarketManagerContract = app.getPredictionMarketV3ManagerContract({});
|
|
40
|
+
realitioERC20Contract = app.getRealitioERC20Contract({});
|
|
41
|
+
requiredBalanceERC20Contract = app.getERC20Contract({});
|
|
42
|
+
WETH9Contract = app.getWETH9Contract({});
|
|
43
|
+
|
|
44
|
+
// Deploy
|
|
45
|
+
await requiredBalanceERC20Contract.deploy({params: ['Polkamarkets', 'POLK']});
|
|
46
|
+
const requiredBalanceERC20ContractAddress = requiredBalanceERC20Contract.getAddress();
|
|
47
|
+
|
|
48
|
+
await realitioERC20Contract.deploy({});
|
|
49
|
+
let realitioContractAddress = realitioERC20Contract.getAddress();
|
|
50
|
+
|
|
51
|
+
await WETH9Contract.deploy({});
|
|
52
|
+
const WETH9ContractAddress = WETH9Contract.getAddress();
|
|
53
|
+
|
|
54
|
+
await predictionMarketContract.deploy({
|
|
55
|
+
params: [
|
|
56
|
+
WETH9ContractAddress
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
const predictionMarketContractAddress = predictionMarketContract.getAddress();
|
|
60
|
+
|
|
61
|
+
await predictionMarketManagerContract.deploy({
|
|
62
|
+
params: [
|
|
63
|
+
predictionMarketContractAddress,
|
|
64
|
+
requiredBalanceERC20ContractAddress,
|
|
65
|
+
'1000000000000000000',
|
|
66
|
+
realitioContractAddress
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
const predictionMarketManagerContractAddress = predictionMarketManagerContract.getAddress();
|
|
70
|
+
// minting and approving requiredBalanceERC20Contract to spend tokens
|
|
71
|
+
await requiredBalanceERC20Contract.mint({
|
|
72
|
+
address: accountAddress,
|
|
73
|
+
amount: '1000'
|
|
74
|
+
});
|
|
75
|
+
await requiredBalanceERC20Contract.approve({
|
|
76
|
+
address: predictionMarketManagerContractAddress,
|
|
77
|
+
amount: '1000000'
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// creating land
|
|
81
|
+
await predictionMarketManagerContract.createLand({
|
|
82
|
+
name: 'Token',
|
|
83
|
+
symbol: 'TOKEN',
|
|
84
|
+
tokenAmountToClaim: '1000',
|
|
85
|
+
tokenToAnswer: requiredBalanceERC20ContractAddress,
|
|
86
|
+
});
|
|
87
|
+
const land = await predictionMarketManagerContract.getLandById({ id: 0 });
|
|
88
|
+
// switching realitioERC20 contract addresses
|
|
89
|
+
realitioERC20Contract = app.getRealitioERC20Contract({ contractAddress: land.realitio });
|
|
90
|
+
realitioContractAddress = realitioERC20Contract.getAddress();
|
|
91
|
+
|
|
92
|
+
tokenERC20Contract = app.getFantasyERC20Contract({ contractAddress: land.token });
|
|
93
|
+
const tokenERC20ContractAddress = tokenERC20Contract.getAddress();
|
|
94
|
+
// minting and approving tokenERC20Contract to spend tokens
|
|
95
|
+
await tokenERC20Contract.claimAndApproveTokens();
|
|
96
|
+
|
|
97
|
+
expect(predictionMarketContractAddress).to.not.equal(null);
|
|
98
|
+
expect(predictionMarketManagerContractAddress).to.not.equal(null);
|
|
99
|
+
expect(realitioContractAddress).to.not.equal(null);
|
|
100
|
+
expect(requiredBalanceERC20ContractAddress).to.not.equal(null);
|
|
101
|
+
expect(tokenERC20ContractAddress).to.not.equal(null);
|
|
102
|
+
}));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
context('Market Creation', async () => {
|
|
106
|
+
let marketId;
|
|
107
|
+
|
|
108
|
+
it('should create a Market', mochaAsync(async () => {
|
|
109
|
+
try {
|
|
110
|
+
const res = await predictionMarketContract.mintAndCreateMarket({
|
|
111
|
+
value,
|
|
112
|
+
name: 'Will BTC price close above 100k$ on May 1st 2024',
|
|
113
|
+
description: 'This is a description',
|
|
114
|
+
image: 'foo-bar',
|
|
115
|
+
category: 'Foo;Bar',
|
|
116
|
+
oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
117
|
+
duration: moment(moment().add(1, 'month').format('YYYY-MM-DD')).unix(),
|
|
118
|
+
outcomes: ['Yes', 'No'],
|
|
119
|
+
token: tokenERC20Contract.getAddress(),
|
|
120
|
+
realitioAddress: realitioERC20Contract.getAddress(),
|
|
121
|
+
realitioTimeout: 300,
|
|
122
|
+
PM3ManagerAddress: predictionMarketManagerContract.getAddress()
|
|
123
|
+
});
|
|
124
|
+
expect(res.status).to.equal(true);
|
|
125
|
+
} catch(e) {
|
|
126
|
+
console.log(e);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const marketIds = await predictionMarketContract.getMarkets();
|
|
130
|
+
marketId = marketIds[marketIds.length - 1];
|
|
131
|
+
expect(marketIds.length).to.equal(1);
|
|
132
|
+
expect(marketIds[marketIds.length - 1]).to.equal(marketId);
|
|
133
|
+
}));
|
|
134
|
+
|
|
135
|
+
it('should create another Market', mochaAsync(async () => {
|
|
136
|
+
const res = await predictionMarketContract.mintAndCreateMarket({
|
|
137
|
+
name: 'Will ETH price close above 10k$ on May 1st 2024',
|
|
138
|
+
image: 'foo-bar',
|
|
139
|
+
category: 'Foo;Bar',
|
|
140
|
+
oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
141
|
+
duration: moment(moment().add(1, 'month').format('YYYY-MM-DD')).unix(),
|
|
142
|
+
outcomes: ['Yes', 'No'],
|
|
143
|
+
value: 0.001,
|
|
144
|
+
token: tokenERC20Contract.getAddress(),
|
|
145
|
+
realitioAddress: realitioERC20Contract.getAddress(),
|
|
146
|
+
realitioTimeout: 300,
|
|
147
|
+
PM3ManagerAddress: predictionMarketManagerContract.getAddress()
|
|
148
|
+
});
|
|
149
|
+
expect(res.status).to.equal(true);
|
|
150
|
+
|
|
151
|
+
const marketIds = await predictionMarketContract.getMarkets();
|
|
152
|
+
expect(marketIds.length).to.equal(2);
|
|
153
|
+
}));
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
context('Market Data', async () => {
|
|
157
|
+
let marketId = 0;
|
|
158
|
+
it('should get Market data', mochaAsync(async () => {
|
|
159
|
+
const res = await predictionMarketContract.getMarketData({marketId});
|
|
160
|
+
expect(res).to.eql({
|
|
161
|
+
closeDateTime: moment().add(1, 'month').format('YYYY-MM-DD 00:00'),
|
|
162
|
+
state: 0,
|
|
163
|
+
oracleAddress: '0x0000000000000000000000000000000000000000',
|
|
164
|
+
liquidity: 0.01,
|
|
165
|
+
outcomeIds: [0, 1],
|
|
166
|
+
resolvedOutcomeId: -1,
|
|
167
|
+
voided: false
|
|
168
|
+
});
|
|
169
|
+
}));
|
|
170
|
+
|
|
171
|
+
it('should get Market details', mochaAsync(async () => {
|
|
172
|
+
const res = await predictionMarketContract.getMarketDetails({marketId});
|
|
173
|
+
expect(res).to.eql({
|
|
174
|
+
name: 'Will BTC price close above 100k$ on May 1st 2024',
|
|
175
|
+
description: 'This is a description',
|
|
176
|
+
category: 'Foo',
|
|
177
|
+
subcategory: 'Bar',
|
|
178
|
+
outcomes: ['Yes', 'No'],
|
|
179
|
+
image: 'foo-bar'
|
|
180
|
+
});
|
|
181
|
+
}));
|
|
182
|
+
|
|
183
|
+
it('should get Market Outcomes data', mochaAsync(async () => {
|
|
184
|
+
const outcome1Data = await predictionMarketContract.getOutcomeData({marketId, outcomeId: outcomeIds[0]});
|
|
185
|
+
expect(outcome1Data).to.include({
|
|
186
|
+
price: 0.5,
|
|
187
|
+
shares: 0.01
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const outcome2Data = await predictionMarketContract.getOutcomeData({marketId, outcomeId: outcomeIds[1]});
|
|
191
|
+
expect(outcome2Data).to.include({
|
|
192
|
+
price: 0.5,
|
|
193
|
+
shares: 0.01
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// outcomes share prices should sum to 1
|
|
197
|
+
expect(outcome1Data.price + outcome2Data.price).to.equal(1);
|
|
198
|
+
// outcomes number of shares should dum to value * 2
|
|
199
|
+
expect(outcome1Data.shares + outcome2Data.shares).to.equal(value * 2);
|
|
200
|
+
}));
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// context('Market Interaction - WETH Market', async () => {
|
|
204
|
+
// let marketId;
|
|
205
|
+
// const wrapped = true;
|
|
206
|
+
|
|
207
|
+
// before(mochaAsync(async () => {
|
|
208
|
+
// try {
|
|
209
|
+
// const res = await predictionMarketContract.createMarketWithETH({
|
|
210
|
+
// value,
|
|
211
|
+
// name: 'WETH Market',
|
|
212
|
+
// image: 'foo-bar',
|
|
213
|
+
// category: 'Foo;Bar',
|
|
214
|
+
// oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
215
|
+
// duration: moment('2024-05-01').unix(),
|
|
216
|
+
// outcomes: ['A', 'B']
|
|
217
|
+
// });
|
|
218
|
+
// expect(res.status).to.equal(true);
|
|
219
|
+
// } catch(e) {
|
|
220
|
+
// console.log(e);
|
|
221
|
+
// }
|
|
222
|
+
|
|
223
|
+
// const marketIds = await predictionMarketContract.getMarkets();
|
|
224
|
+
// marketId = marketIds[marketIds.length - 1];
|
|
225
|
+
// }));
|
|
226
|
+
|
|
227
|
+
// it('should match WETH supply', mochaAsync(async () => {
|
|
228
|
+
// const ETHBalance = Number(await WETH9Contract.getBalance());
|
|
229
|
+
// expect(Number(ETHBalance)).to.equal(value);
|
|
230
|
+
|
|
231
|
+
// const WETHSupply = await WETH9Contract.totalSupply();
|
|
232
|
+
// expect(Number(WETHSupply)).to.equal(value);
|
|
233
|
+
// }));
|
|
234
|
+
|
|
235
|
+
// it('should match market WETH balance', mochaAsync(async () => {
|
|
236
|
+
// const contractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
237
|
+
// expect(contractBalance).to.equal(value);
|
|
238
|
+
// }));
|
|
239
|
+
|
|
240
|
+
// it('should add liquidity', mochaAsync(async () => {
|
|
241
|
+
// const contractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
242
|
+
// const WETHBalance = Number(await WETH9Contract.getBalance());
|
|
243
|
+
|
|
244
|
+
// try {
|
|
245
|
+
// const res = await predictionMarketContract.addLiquidity({marketId, value, wrapped})
|
|
246
|
+
// expect(res.status).to.equal(true);
|
|
247
|
+
// } catch(e) {
|
|
248
|
+
// console.log(e);
|
|
249
|
+
// }
|
|
250
|
+
|
|
251
|
+
// const newContractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
252
|
+
// const NewWETHBalance = Number(await WETH9Contract.getBalance());
|
|
253
|
+
// const amountTransferred = Number((newContractBalance - contractBalance).toFixed(5));
|
|
254
|
+
|
|
255
|
+
// expect(amountTransferred).to.equal(value);
|
|
256
|
+
// expect(NewWETHBalance).to.equal(WETHBalance + value);
|
|
257
|
+
// }));
|
|
258
|
+
|
|
259
|
+
// it('should remove liquidity', mochaAsync(async () => {
|
|
260
|
+
// const contractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
261
|
+
// const WETHBalance = Number(await WETH9Contract.getBalance());
|
|
262
|
+
|
|
263
|
+
// try {
|
|
264
|
+
// const res = await predictionMarketContract.removeLiquidity({marketId, shares: value, wrapped})
|
|
265
|
+
// expect(res.status).to.equal(true);
|
|
266
|
+
// } catch(e) {
|
|
267
|
+
// console.log(e);
|
|
268
|
+
// }
|
|
269
|
+
|
|
270
|
+
// const newContractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
271
|
+
// const NewWETHBalance = Number(await WETH9Contract.getBalance());
|
|
272
|
+
// const amountTransferred = Number((contractBalance - newContractBalance).toFixed(5));
|
|
273
|
+
|
|
274
|
+
// expect(amountTransferred).to.equal(value);
|
|
275
|
+
// expect(NewWETHBalance).to.equal(WETHBalance - value);
|
|
276
|
+
// }));
|
|
277
|
+
|
|
278
|
+
// it('should buy outcome shares', mochaAsync(async () => {
|
|
279
|
+
// const outcomeId = 0;
|
|
280
|
+
// const minOutcomeSharesToBuy = 0.015;
|
|
281
|
+
|
|
282
|
+
// const contractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
283
|
+
// const WETHBalance = Number(await WETH9Contract.getBalance());
|
|
284
|
+
|
|
285
|
+
// try {
|
|
286
|
+
// const res = await predictionMarketContract.buy({marketId, outcomeId, value, minOutcomeSharesToBuy, wrapped});
|
|
287
|
+
// expect(res.status).to.equal(true);
|
|
288
|
+
// } catch(e) {
|
|
289
|
+
// console.log(e);
|
|
290
|
+
// }
|
|
291
|
+
|
|
292
|
+
// const newContractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
293
|
+
// const NewWETHBalance = Number(await WETH9Contract.getBalance());
|
|
294
|
+
// const amountTransferred = Number((newContractBalance - contractBalance).toFixed(5));
|
|
295
|
+
|
|
296
|
+
// expect(amountTransferred).to.equal(value);
|
|
297
|
+
// expect(NewWETHBalance).to.equal(WETHBalance + value);
|
|
298
|
+
// }));
|
|
299
|
+
|
|
300
|
+
// it('should sell outcome shares', mochaAsync(async () => {
|
|
301
|
+
// const outcomeId = 0;
|
|
302
|
+
// const maxOutcomeSharesToSell = 0.015;
|
|
303
|
+
|
|
304
|
+
// const contractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
305
|
+
// const WETHBalance = Number(await WETH9Contract.getBalance());
|
|
306
|
+
|
|
307
|
+
// try {
|
|
308
|
+
// const res = await predictionMarketContract.sell({marketId, outcomeId, value, maxOutcomeSharesToSell, wrapped});
|
|
309
|
+
// expect(res.status).to.equal(true);
|
|
310
|
+
// } catch(e) {
|
|
311
|
+
// console.log(e);
|
|
312
|
+
// }
|
|
313
|
+
|
|
314
|
+
// const newContractBalance = await WETH9Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
315
|
+
// const NewWETHBalance = Number(await WETH9Contract.getBalance());
|
|
316
|
+
// const amountTransferred = Number((contractBalance - newContractBalance).toFixed(5));
|
|
317
|
+
|
|
318
|
+
// expect(amountTransferred).to.equal(value);
|
|
319
|
+
// expect(NewWETHBalance).to.equal(WETHBalance - value);
|
|
320
|
+
// }));
|
|
321
|
+
// });
|
|
322
|
+
|
|
323
|
+
context('Market Interaction - Balanced Market (Same Outcome Odds)', async () => {
|
|
324
|
+
let marketId = 0;
|
|
325
|
+
it('should add liquidity without changing shares balance', mochaAsync(async () => {
|
|
326
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
327
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
328
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
329
|
+
|
|
330
|
+
// balanced market - same price in all outcomoes
|
|
331
|
+
expect(outcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[1]);
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
const res = await predictionMarketContract.addLiquidity({marketId, value})
|
|
335
|
+
expect(res.status).to.equal(true);
|
|
336
|
+
} catch(e) {
|
|
337
|
+
console.log(e);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const myNewShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
341
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
342
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
343
|
+
|
|
344
|
+
expect(newMarketData.liquidity).to.above(marketData.liquidity);
|
|
345
|
+
expect(newMarketData.liquidity).to.equal(marketData.liquidity + value);
|
|
346
|
+
|
|
347
|
+
// Outcome prices shoud remain the same after providing liquidity
|
|
348
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[0]);
|
|
349
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(outcomePrices.outcomes[1]);
|
|
350
|
+
|
|
351
|
+
// Price balances are 0.5-0.5, liquidity will be added solely through liquidity shares
|
|
352
|
+
expect(myNewShares.liquidityShares).to.above(myShares.liquidityShares);
|
|
353
|
+
expect(myNewShares.liquidityShares).to.equal(myShares.liquidityShares + value);
|
|
354
|
+
// shares balance remains the same
|
|
355
|
+
expect(myNewShares.outcomeShares[0]).to.equal(myShares.outcomeShares[0]);
|
|
356
|
+
expect(myNewShares.outcomeShares[1]).to.equal(myShares.outcomeShares[1]);
|
|
357
|
+
}));
|
|
358
|
+
|
|
359
|
+
it('should remove liquidity without changing shares balance', mochaAsync(async () => {
|
|
360
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
361
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
362
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
363
|
+
const contractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
364
|
+
|
|
365
|
+
// balanced market - same price in all outcomoes
|
|
366
|
+
expect(outcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[1]);
|
|
367
|
+
|
|
368
|
+
try {
|
|
369
|
+
const res = await predictionMarketContract.removeLiquidity({marketId, shares: value})
|
|
370
|
+
expect(res.status).to.equal(true);
|
|
371
|
+
} catch(e) {
|
|
372
|
+
console.log(e);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const myNewShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
376
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
377
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
378
|
+
const newContractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
379
|
+
|
|
380
|
+
expect(newMarketData.liquidity).to.below(marketData.liquidity);
|
|
381
|
+
expect(newMarketData.liquidity).to.equal(marketData.liquidity - value);
|
|
382
|
+
|
|
383
|
+
// Outcome prices shoud remain the same after providing liquidity
|
|
384
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[0]);
|
|
385
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(outcomePrices.outcomes[1]);
|
|
386
|
+
|
|
387
|
+
// Price balances are 0.5-0.5, liquidity will be added solely through liquidity shares
|
|
388
|
+
expect(myNewShares.liquidityShares).to.below(myShares.liquidityShares);
|
|
389
|
+
expect(myNewShares.liquidityShares).to.equal(myShares.liquidityShares - value);
|
|
390
|
+
// shares balance remains the same
|
|
391
|
+
expect(myNewShares.outcomeShares[0]).to.equal(myShares.outcomeShares[0]);
|
|
392
|
+
expect(myNewShares.outcomeShares[1]).to.equal(myShares.outcomeShares[1]);
|
|
393
|
+
|
|
394
|
+
// User gets liquidity tokens back in ETH
|
|
395
|
+
expect(newContractBalance).to.below(contractBalance);
|
|
396
|
+
const amountTransferred = Number((contractBalance - newContractBalance).toFixed(5));
|
|
397
|
+
expect(amountTransferred).to.equal(value);
|
|
398
|
+
}));
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
context('Market Interaction - Unbalanced Market (Different Outcome Odds)', async () => {
|
|
402
|
+
let marketId = 0;
|
|
403
|
+
it('should display my shares', mochaAsync(async () => {
|
|
404
|
+
const res = await predictionMarketContract.getMyMarketShares({marketId});
|
|
405
|
+
// currently holding liquidity tokens from market creation
|
|
406
|
+
expect(res).to.eql({
|
|
407
|
+
liquidityShares: 0.01,
|
|
408
|
+
outcomeShares: {
|
|
409
|
+
0: 0.00,
|
|
410
|
+
1: 0.00,
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
}));
|
|
414
|
+
|
|
415
|
+
it('should buy outcome shares', mochaAsync(async () => {
|
|
416
|
+
const outcomeId = 0;
|
|
417
|
+
const minOutcomeSharesToBuy = 0.015;
|
|
418
|
+
|
|
419
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
420
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
421
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
422
|
+
const contractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
const res = await predictionMarketContract.buy({marketId, outcomeId, value, minOutcomeSharesToBuy});
|
|
426
|
+
expect(res.status).to.equal(true);
|
|
427
|
+
} catch(e) {
|
|
428
|
+
console.log(e);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
432
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
433
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
434
|
+
const newContractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
435
|
+
|
|
436
|
+
// outcome price should increase
|
|
437
|
+
expect(newOutcomePrices.outcomes[0]).to.above(outcomePrices.outcomes[0]);
|
|
438
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(0.8);
|
|
439
|
+
// opposite outcome price should decrease
|
|
440
|
+
expect(newOutcomePrices.outcomes[1]).to.below(outcomePrices.outcomes[1]);
|
|
441
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(0.2);
|
|
442
|
+
// Prices sum = 1
|
|
443
|
+
// 0.5 + 0.5 = 1
|
|
444
|
+
expect(newOutcomePrices.outcomes[0] + newOutcomePrices.outcomes[1]).to.equal(1);
|
|
445
|
+
|
|
446
|
+
// Liquidity value remains the same
|
|
447
|
+
expect(newMarketData.liquidity).to.equal(marketData.liquidity);
|
|
448
|
+
|
|
449
|
+
// outcome shares should decrease
|
|
450
|
+
expect(newOutcomeShares.outcomes[0]).to.below(outcomeShares.outcomes[0]);
|
|
451
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.005);
|
|
452
|
+
// opposite outcome shares should increase
|
|
453
|
+
expect(newOutcomeShares.outcomes[1]).to.above(outcomeShares.outcomes[1]);
|
|
454
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.02);
|
|
455
|
+
// # Shares Product = Liquidity^2
|
|
456
|
+
// 0.005 * 0.02 = 0.01^2
|
|
457
|
+
expect(outcomeShares.outcomes[0] * outcomeShares.outcomes[1]).to.equal(newMarketData.liquidity**2);
|
|
458
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1]).to.equal(newMarketData.liquidity**2);
|
|
459
|
+
|
|
460
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
461
|
+
expect(myShares).to.eql({
|
|
462
|
+
liquidityShares: 0.01,
|
|
463
|
+
outcomeShares: {
|
|
464
|
+
0: 0.015,
|
|
465
|
+
1: 0.00,
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// Contract adds value to balance
|
|
470
|
+
expect(newContractBalance).to.above(contractBalance);
|
|
471
|
+
// TODO: check amountReceived from internal transactions
|
|
472
|
+
const amountReceived = Number((newContractBalance - contractBalance).toFixed(5));
|
|
473
|
+
expect(amountReceived).to.equal(value);
|
|
474
|
+
}));
|
|
475
|
+
|
|
476
|
+
it('should add liquidity', mochaAsync(async () => {
|
|
477
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
478
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
479
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
480
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
481
|
+
|
|
482
|
+
try {
|
|
483
|
+
const res = await predictionMarketContract.addLiquidity({marketId, value})
|
|
484
|
+
expect(res.status).to.equal(true);
|
|
485
|
+
} catch(e) {
|
|
486
|
+
console.log(e);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const myNewShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
490
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
491
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
492
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
493
|
+
|
|
494
|
+
// Outcome prices shoud remain the same after providing liquidity
|
|
495
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[0]);
|
|
496
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(outcomePrices.outcomes[1]);
|
|
497
|
+
|
|
498
|
+
// # Shares Product = Liquidity^2
|
|
499
|
+
// 0.0075 * 0.03 = 0.015^2
|
|
500
|
+
expect(newMarketData.liquidity).to.above(marketData.liquidity);
|
|
501
|
+
expect(newMarketData.liquidity).to.equal(0.015);
|
|
502
|
+
expect(newOutcomeShares.outcomes[0]).to.above(outcomeShares.outcomes[0]);
|
|
503
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.0075);
|
|
504
|
+
expect(newOutcomeShares.outcomes[1]).to.above(outcomeShares.outcomes[1]);
|
|
505
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.03);
|
|
506
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1]).to.equal(newMarketData.liquidity**2);
|
|
507
|
+
|
|
508
|
+
// Price balances are not 0.5-0.5, liquidity will be added through shares + liquidity
|
|
509
|
+
expect(myNewShares.liquidityShares).to.above(myShares.liquidityShares);
|
|
510
|
+
expect(myNewShares.liquidityShares).to.equal(0.015);
|
|
511
|
+
// shares balance of higher odd outcome increases
|
|
512
|
+
expect(myNewShares.outcomeShares[0]).to.above(myShares.outcomeShares[0]);
|
|
513
|
+
expect(myNewShares.outcomeShares[0]).to.equal(0.0225);
|
|
514
|
+
// shares balance of lower odd outcome remains
|
|
515
|
+
expect(myNewShares.outcomeShares[1]).to.equal(myShares.outcomeShares[1]);
|
|
516
|
+
expect(myNewShares.outcomeShares[1]).to.equal(0);
|
|
517
|
+
}));
|
|
518
|
+
|
|
519
|
+
it('should remove liquidity', mochaAsync(async () => {
|
|
520
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
521
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
522
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
523
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
524
|
+
const contractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
525
|
+
const liquiditySharesToRemove = 0.005;
|
|
526
|
+
|
|
527
|
+
try {
|
|
528
|
+
const res = await predictionMarketContract.removeLiquidity({marketId, shares: liquiditySharesToRemove});
|
|
529
|
+
expect(res.status).to.equal(true);
|
|
530
|
+
} catch(e) {
|
|
531
|
+
console.log(e);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const myNewShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
535
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
536
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
537
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
538
|
+
const newContractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
539
|
+
|
|
540
|
+
// Outcome prices shoud remain the same after removing liquidity
|
|
541
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[0]);
|
|
542
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(outcomePrices.outcomes[1]);
|
|
543
|
+
|
|
544
|
+
// # Shares Product = Liquidity^2
|
|
545
|
+
// 0.005 * 0.02 = 0.01^2
|
|
546
|
+
expect(newMarketData.liquidity).to.below(marketData.liquidity);
|
|
547
|
+
expect(newMarketData.liquidity).to.equal(0.01);
|
|
548
|
+
expect(newOutcomeShares.outcomes[0]).to.below(outcomeShares.outcomes[0]);
|
|
549
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.005);
|
|
550
|
+
expect(newOutcomeShares.outcomes[1]).to.below(outcomeShares.outcomes[1]);
|
|
551
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.02);
|
|
552
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1]).to.equal(newMarketData.liquidity**2);
|
|
553
|
+
|
|
554
|
+
// Price balances are not 0.5-0.5, liquidity will be added through shares + liquidity
|
|
555
|
+
expect(myNewShares.liquidityShares).to.below(myShares.liquidityShares);
|
|
556
|
+
expect(myNewShares.liquidityShares).to.equal(0.01);
|
|
557
|
+
// shares balance of higher odd outcome remains
|
|
558
|
+
expect(myNewShares.outcomeShares[0]).to.equal(myShares.outcomeShares[0]);
|
|
559
|
+
expect(myNewShares.outcomeShares[0]).to.equal(0.0225);
|
|
560
|
+
// shares balance of lower odd outcome increases
|
|
561
|
+
expect(myNewShares.outcomeShares[1]).to.above(myShares.outcomeShares[1]);
|
|
562
|
+
expect(myNewShares.outcomeShares[1]).to.equal(0.0075);
|
|
563
|
+
|
|
564
|
+
// User gets part of the liquidity tokens back in ETH
|
|
565
|
+
expect(newContractBalance).to.below(contractBalance);
|
|
566
|
+
const amountTransferred = Number((contractBalance - newContractBalance).toFixed(5));
|
|
567
|
+
expect(amountTransferred).to.equal(0.0025);
|
|
568
|
+
}));
|
|
569
|
+
|
|
570
|
+
it('should sell outcome shares', mochaAsync(async () => {
|
|
571
|
+
const outcomeId = 0;
|
|
572
|
+
const maxOutcomeSharesToSell = 0.015;
|
|
573
|
+
|
|
574
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
575
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
576
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
577
|
+
const contractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
578
|
+
|
|
579
|
+
try {
|
|
580
|
+
const res = await predictionMarketContract.sell({marketId, outcomeId, value, maxOutcomeSharesToSell});
|
|
581
|
+
expect(res.status).to.equal(true);
|
|
582
|
+
} catch(e) {
|
|
583
|
+
console.log(e);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
587
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
588
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
589
|
+
const newContractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
590
|
+
|
|
591
|
+
// outcome price should decrease
|
|
592
|
+
expect(newOutcomePrices.outcomes[0]).to.below(outcomePrices.outcomes[0]);
|
|
593
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(0.5);
|
|
594
|
+
// opposite outcome price should increase
|
|
595
|
+
expect(newOutcomePrices.outcomes[1]).to.above(outcomePrices.outcomes[1]);
|
|
596
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(0.5);
|
|
597
|
+
// Prices sum = 1
|
|
598
|
+
// 0.5 + 0.5 = 1
|
|
599
|
+
expect(newOutcomePrices.outcomes[0] + newOutcomePrices.outcomes[1]).to.equal(1);
|
|
600
|
+
|
|
601
|
+
// Liquidity value remains the same
|
|
602
|
+
expect(newMarketData.liquidity).to.equal(marketData.liquidity);
|
|
603
|
+
|
|
604
|
+
// outcome shares should increase
|
|
605
|
+
expect(newOutcomeShares.outcomes[0]).to.above(outcomeShares.outcomes[0]);
|
|
606
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.01);
|
|
607
|
+
// opposite outcome shares should increase
|
|
608
|
+
expect(newOutcomeShares.outcomes[1]).to.below(outcomeShares.outcomes[1]);
|
|
609
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.01);
|
|
610
|
+
// # Shares Product = Liquidity^2
|
|
611
|
+
// 0.01 * 0.01 = 0.01^2
|
|
612
|
+
expect(outcomeShares.outcomes[0] * outcomeShares.outcomes[1]).to.equal(newMarketData.liquidity**2);
|
|
613
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1]).to.equal(newMarketData.liquidity**2);
|
|
614
|
+
|
|
615
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
616
|
+
expect(myShares).to.eql({
|
|
617
|
+
liquidityShares: 0.01,
|
|
618
|
+
outcomeShares: {
|
|
619
|
+
0: 0.0075,
|
|
620
|
+
1: 0.0075,
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
// User gets shares value back in ETH
|
|
625
|
+
expect(newContractBalance).to.below(contractBalance);
|
|
626
|
+
const amountTransferred = Number((contractBalance - newContractBalance).toFixed(5));
|
|
627
|
+
expect(amountTransferred).to.equal(0.01);
|
|
628
|
+
}));
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
context('Multiple Outcomes', async () => {
|
|
632
|
+
let marketId = 0;
|
|
633
|
+
context('Market Creation', async () => {
|
|
634
|
+
it('should create a Market with 3 outcomes', mochaAsync(async () => {
|
|
635
|
+
try {
|
|
636
|
+
const res = await predictionMarketContract.mintAndCreateMarket({
|
|
637
|
+
value,
|
|
638
|
+
name: 'Market with 3 outcomes',
|
|
639
|
+
image: 'foo-bar',
|
|
640
|
+
category: 'Foo;Bar',
|
|
641
|
+
oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
642
|
+
duration: moment(moment().add(1, 'month').format('YYYY-MM-DD')).unix(),
|
|
643
|
+
outcomes: ['A', 'B', 'C'],
|
|
644
|
+
token: tokenERC20Contract.getAddress(),
|
|
645
|
+
realitioAddress: realitioERC20Contract.getAddress(),
|
|
646
|
+
realitioTimeout: 300,
|
|
647
|
+
PM3ManagerAddress: predictionMarketManagerContract.getAddress()
|
|
648
|
+
});
|
|
649
|
+
expect(res.status).to.equal(true);
|
|
650
|
+
} catch(e) {
|
|
651
|
+
console.log(e);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const marketIds = await predictionMarketContract.getMarkets();
|
|
655
|
+
marketId = marketIds[marketIds.length - 1];
|
|
656
|
+
|
|
657
|
+
const res = await predictionMarketContract.getMarketData({marketId});
|
|
658
|
+
expect(res.outcomeIds.length).to.eql(3);
|
|
659
|
+
expect(res.outcomeIds).to.eql([0, 1, 2]);
|
|
660
|
+
}));
|
|
661
|
+
|
|
662
|
+
it('should create a Market with 32 outcomes', mochaAsync(async () => {
|
|
663
|
+
// Array with outcomes with outcome id as name
|
|
664
|
+
// TODO: improve gas optimization for markets with 10+ outcomes
|
|
665
|
+
const outcomeCount = 32;
|
|
666
|
+
const outcomes = Array.from(Array(outcomeCount).keys());
|
|
667
|
+
|
|
668
|
+
try {
|
|
669
|
+
const res = await predictionMarketContract.mintAndCreateMarket({
|
|
670
|
+
value,
|
|
671
|
+
name: `Market with ${outcomeCount} outcomes`,
|
|
672
|
+
image: 'foo-bar',
|
|
673
|
+
category: 'Foo;Bar',
|
|
674
|
+
oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
675
|
+
duration: moment(moment().add(1, 'month').format('YYYY-MM-DD')).unix(),
|
|
676
|
+
outcomes,
|
|
677
|
+
token: tokenERC20Contract.getAddress(),
|
|
678
|
+
realitioAddress: realitioERC20Contract.getAddress(),
|
|
679
|
+
realitioTimeout: 300,
|
|
680
|
+
PM3ManagerAddress: predictionMarketManagerContract.getAddress()
|
|
681
|
+
});
|
|
682
|
+
expect(res.status).to.equal(true);
|
|
683
|
+
} catch(e) {
|
|
684
|
+
console.log(e);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const marketIds = await predictionMarketContract.getMarkets();
|
|
688
|
+
marketId = marketIds[marketIds.length - 1];
|
|
689
|
+
|
|
690
|
+
const res = await predictionMarketContract.getMarketData({marketId});
|
|
691
|
+
expect(res.outcomeIds.length).to.eql(outcomeCount);
|
|
692
|
+
expect(res.outcomeIds).to.eql(outcomes);
|
|
693
|
+
}));
|
|
694
|
+
|
|
695
|
+
it('should not create a Market with more than 32 outcomes', mochaAsync(async () => {
|
|
696
|
+
const oldMarketIds = await predictionMarketContract.getMarkets();
|
|
697
|
+
try {
|
|
698
|
+
const outcomes = Array.from(Array(33).keys());
|
|
699
|
+
|
|
700
|
+
const res = await predictionMarketContract.mintAndCreateMarket({
|
|
701
|
+
value,
|
|
702
|
+
name: 'Market with 257 outcomes',
|
|
703
|
+
image: 'foo-bar',
|
|
704
|
+
category: 'Foo;Bar',
|
|
705
|
+
oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
706
|
+
duration: moment(moment().add(1, 'month').format('YYYY-MM-DD')).unix(),
|
|
707
|
+
outcomes,
|
|
708
|
+
token: tokenERC20Contract.getAddress(),
|
|
709
|
+
realitioAddress: realitioERC20Contract.getAddress(),
|
|
710
|
+
realitioTimeout: 300,
|
|
711
|
+
PM3ManagerAddress: predictionMarketManagerContract.getAddress()
|
|
712
|
+
});
|
|
713
|
+
expect(res.status).to.equal(true);
|
|
714
|
+
} catch(e) {
|
|
715
|
+
// not logging error, as tx is expected to fail
|
|
716
|
+
// console.log(e);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const currentMarketIds = await predictionMarketContract.getMarkets();
|
|
720
|
+
|
|
721
|
+
expect(currentMarketIds.length).to.eql(oldMarketIds.length);
|
|
722
|
+
}));
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
context('Market Interaction', async () => {
|
|
726
|
+
let marketId;
|
|
727
|
+
let outcomeIds = [0, 1, 2];
|
|
728
|
+
|
|
729
|
+
before(mochaAsync(async () => {
|
|
730
|
+
try {
|
|
731
|
+
const res = await predictionMarketContract.mintAndCreateMarket({
|
|
732
|
+
value,
|
|
733
|
+
name: 'Market with 3 outcomes',
|
|
734
|
+
image: 'foo-bar',
|
|
735
|
+
category: 'Foo;Bar',
|
|
736
|
+
oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
737
|
+
duration: moment(moment().add(1, 'month').format('YYYY-MM-DD')).unix(),
|
|
738
|
+
outcomes: ['D', 'E', 'F'],
|
|
739
|
+
token: tokenERC20Contract.getAddress(),
|
|
740
|
+
realitioAddress: realitioERC20Contract.getAddress(),
|
|
741
|
+
realitioTimeout: 300,
|
|
742
|
+
PM3ManagerAddress: predictionMarketManagerContract.getAddress()
|
|
743
|
+
});
|
|
744
|
+
expect(res.status).to.equal(true);
|
|
745
|
+
} catch(e) {
|
|
746
|
+
console.log(e);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const marketIds = await predictionMarketContract.getMarkets();
|
|
750
|
+
marketId = marketIds[marketIds.length - 1];
|
|
751
|
+
}));
|
|
752
|
+
|
|
753
|
+
it('should buy outcome shares', mochaAsync(async () => {
|
|
754
|
+
const outcomeId = 0;
|
|
755
|
+
const minOutcomeSharesToBuy = 0.015;
|
|
756
|
+
|
|
757
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
758
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
759
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
760
|
+
const contractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
761
|
+
|
|
762
|
+
try {
|
|
763
|
+
const res = await predictionMarketContract.buy({marketId, outcomeId, value, minOutcomeSharesToBuy});
|
|
764
|
+
expect(res.status).to.equal(true);
|
|
765
|
+
} catch(e) {
|
|
766
|
+
console.log(e);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
770
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
771
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
772
|
+
const newContractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
773
|
+
|
|
774
|
+
// outcome price should increase
|
|
775
|
+
expect(newOutcomePrices.outcomes[0]).to.above(outcomePrices.outcomes[0]);
|
|
776
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(0.8);
|
|
777
|
+
// opposite outcome price should decrease
|
|
778
|
+
expect(newOutcomePrices.outcomes[1]).to.below(outcomePrices.outcomes[1]);
|
|
779
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(0.1);
|
|
780
|
+
expect(newOutcomePrices.outcomes[2]).to.below(outcomePrices.outcomes[2]);
|
|
781
|
+
expect(newOutcomePrices.outcomes[2]).to.equal(0.1);
|
|
782
|
+
// Prices sum = 1
|
|
783
|
+
// 0.1 + 0.1 + 0.8 = 1
|
|
784
|
+
expect(newOutcomePrices.outcomes[0] + newOutcomePrices.outcomes[1] + newOutcomePrices.outcomes[2]).to.equal(1);
|
|
785
|
+
|
|
786
|
+
// Liquidity value remains the same
|
|
787
|
+
expect(newMarketData.liquidity).to.equal(marketData.liquidity);
|
|
788
|
+
|
|
789
|
+
// outcome shares should decrease
|
|
790
|
+
expect(newOutcomeShares.outcomes[0]).to.below(outcomeShares.outcomes[0]);
|
|
791
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.0025);
|
|
792
|
+
// opposite outcome shares should increase
|
|
793
|
+
expect(newOutcomeShares.outcomes[1]).to.above(outcomeShares.outcomes[1]);
|
|
794
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.02);
|
|
795
|
+
expect(newOutcomeShares.outcomes[2]).to.above(outcomeShares.outcomes[2]);
|
|
796
|
+
expect(newOutcomeShares.outcomes[2]).to.equal(0.02);
|
|
797
|
+
// # Shares Product = Liquidity^2
|
|
798
|
+
// 0.0025 * 0.02 * 0.02 = 0.01^3
|
|
799
|
+
expect(outcomeShares.outcomes[0] * outcomeShares.outcomes[1] * outcomeShares.outcomes[2]).to.equal(newMarketData.liquidity ** 3);
|
|
800
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1] * newOutcomeShares.outcomes[2]).to.equal(newMarketData.liquidity ** 3);
|
|
801
|
+
|
|
802
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
803
|
+
expect(myShares).to.eql({
|
|
804
|
+
liquidityShares: 0.01,
|
|
805
|
+
outcomeShares: {
|
|
806
|
+
0: 0.0175,
|
|
807
|
+
1: 0.00,
|
|
808
|
+
2: 0.00,
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// Contract adds value to balance
|
|
813
|
+
expect(newContractBalance).to.above(contractBalance);
|
|
814
|
+
// TODO: check amountReceived from internal transactions
|
|
815
|
+
const amountReceived = Number((newContractBalance - contractBalance).toFixed(5));
|
|
816
|
+
expect(amountReceived).to.equal(value);
|
|
817
|
+
}));
|
|
818
|
+
|
|
819
|
+
it('should add liquidity', mochaAsync(async () => {
|
|
820
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
821
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
822
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
823
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
824
|
+
|
|
825
|
+
try {
|
|
826
|
+
const res = await predictionMarketContract.addLiquidity({marketId, value})
|
|
827
|
+
expect(res.status).to.equal(true);
|
|
828
|
+
} catch(e) {
|
|
829
|
+
console.log(e);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
const myNewShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
833
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
834
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
835
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
836
|
+
|
|
837
|
+
// Outcome prices shoud remain the same after providing liquidity
|
|
838
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[0]);
|
|
839
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(outcomePrices.outcomes[1]);
|
|
840
|
+
expect(newOutcomePrices.outcomes[2]).to.equal(outcomePrices.outcomes[2]);
|
|
841
|
+
|
|
842
|
+
// # Shares Product = Liquidity^2
|
|
843
|
+
// 0.00375 * 0.03 * 0.03 = 0.015^3
|
|
844
|
+
expect(newMarketData.liquidity).to.above(marketData.liquidity);
|
|
845
|
+
expect(newMarketData.liquidity).to.equal(0.015);
|
|
846
|
+
expect(newOutcomeShares.outcomes[0]).to.above(outcomeShares.outcomes[0]);
|
|
847
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.00375);
|
|
848
|
+
expect(newOutcomeShares.outcomes[1]).to.above(outcomeShares.outcomes[1]);
|
|
849
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.03);
|
|
850
|
+
expect(newOutcomeShares.outcomes[2]).to.above(outcomeShares.outcomes[2]);
|
|
851
|
+
expect(newOutcomeShares.outcomes[2]).to.equal(0.03);
|
|
852
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1] * newOutcomeShares.outcomes[2]).to.be.closeTo(newMarketData.liquidity ** 3, 0.00000001);
|
|
853
|
+
|
|
854
|
+
// Price balances are not 0.5-0.5, liquidity will be added through shares + liquidity
|
|
855
|
+
expect(myNewShares.liquidityShares).to.above(myShares.liquidityShares);
|
|
856
|
+
expect(myNewShares.liquidityShares).to.equal(0.015);
|
|
857
|
+
// shares balance of higher odd outcome increases
|
|
858
|
+
expect(myNewShares.outcomeShares[0]).to.above(myShares.outcomeShares[0]);
|
|
859
|
+
expect(myNewShares.outcomeShares[0]).to.equal(0.02625);
|
|
860
|
+
// shares balance of lower odd outcome remains
|
|
861
|
+
expect(myNewShares.outcomeShares[1]).to.equal(myShares.outcomeShares[1]);
|
|
862
|
+
expect(myNewShares.outcomeShares[1]).to.equal(0);
|
|
863
|
+
expect(myNewShares.outcomeShares[2]).to.equal(myShares.outcomeShares[2]);
|
|
864
|
+
expect(myNewShares.outcomeShares[2]).to.equal(0);
|
|
865
|
+
}));
|
|
866
|
+
|
|
867
|
+
it('should remove liquidity', mochaAsync(async () => {
|
|
868
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
869
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
870
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
871
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
872
|
+
const contractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
873
|
+
const liquiditySharesToRemove = 0.005;
|
|
874
|
+
|
|
875
|
+
try {
|
|
876
|
+
const res = await predictionMarketContract.removeLiquidity({marketId, shares: liquiditySharesToRemove});
|
|
877
|
+
expect(res.status).to.equal(true);
|
|
878
|
+
} catch(e) {
|
|
879
|
+
console.log(e);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const myNewShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
883
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
884
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
885
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
886
|
+
const newContractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
887
|
+
|
|
888
|
+
// Outcome prices shoud remain the same after removing liquidity
|
|
889
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(outcomePrices.outcomes[0]);
|
|
890
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(outcomePrices.outcomes[1]);
|
|
891
|
+
expect(newOutcomePrices.outcomes[2]).to.equal(outcomePrices.outcomes[2]);
|
|
892
|
+
|
|
893
|
+
// # Shares Product = Liquidity^3
|
|
894
|
+
// 0.0025 * 0.02 * 0.02 = 0.01^3
|
|
895
|
+
expect(newMarketData.liquidity).to.below(marketData.liquidity);
|
|
896
|
+
expect(newMarketData.liquidity).to.equal(0.01);
|
|
897
|
+
expect(newOutcomeShares.outcomes[0]).to.below(outcomeShares.outcomes[0]);
|
|
898
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.0025);
|
|
899
|
+
expect(newOutcomeShares.outcomes[1]).to.below(outcomeShares.outcomes[1]);
|
|
900
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.02);
|
|
901
|
+
expect(newOutcomeShares.outcomes[2]).to.below(outcomeShares.outcomes[2]);
|
|
902
|
+
expect(newOutcomeShares.outcomes[2]).to.equal(0.02);
|
|
903
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1] * newOutcomeShares.outcomes[2]).to.equal(newMarketData.liquidity ** 3);
|
|
904
|
+
|
|
905
|
+
// Price balances are not 0.5-0.5, liquidity will be added through shares + liquidity
|
|
906
|
+
expect(myNewShares.liquidityShares).to.below(myShares.liquidityShares);
|
|
907
|
+
expect(myNewShares.liquidityShares).to.equal(0.01);
|
|
908
|
+
// shares balance of higher odd outcome remains
|
|
909
|
+
expect(myNewShares.outcomeShares[0]).to.equal(myShares.outcomeShares[0]);
|
|
910
|
+
expect(myNewShares.outcomeShares[0]).to.equal(0.02625);
|
|
911
|
+
// shares balance of lower odd outcome increases
|
|
912
|
+
expect(myNewShares.outcomeShares[1]).to.above(myShares.outcomeShares[1]);
|
|
913
|
+
expect(myNewShares.outcomeShares[1]).to.equal(0.00875);
|
|
914
|
+
expect(myNewShares.outcomeShares[2]).to.above(myShares.outcomeShares[2]);
|
|
915
|
+
expect(myNewShares.outcomeShares[2]).to.equal(0.00875);
|
|
916
|
+
|
|
917
|
+
// User gets part of the liquidity tokens back in ETH
|
|
918
|
+
expect(newContractBalance).to.below(contractBalance);
|
|
919
|
+
const amountTransferred = Number((contractBalance - newContractBalance).toFixed(5));
|
|
920
|
+
expect(amountTransferred).to.equal(0.00125);
|
|
921
|
+
}));
|
|
922
|
+
|
|
923
|
+
it('should sell outcome shares', mochaAsync(async () => {
|
|
924
|
+
const outcomeId = 0;
|
|
925
|
+
const maxOutcomeSharesToSell = 0.0175;
|
|
926
|
+
|
|
927
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
928
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
929
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
930
|
+
const contractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
931
|
+
|
|
932
|
+
try {
|
|
933
|
+
const res = await predictionMarketContract.sell({marketId, outcomeId, value, maxOutcomeSharesToSell});
|
|
934
|
+
expect(res.status).to.equal(true);
|
|
935
|
+
} catch(e) {
|
|
936
|
+
console.log(e);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const newMarketData = await predictionMarketContract.getMarketData({marketId});
|
|
940
|
+
const newOutcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
941
|
+
const newOutcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
942
|
+
const newContractBalance = await tokenERC20Contract.balanceOf({address: predictionMarketContract.getAddress()});
|
|
943
|
+
|
|
944
|
+
// outcome price should decrease
|
|
945
|
+
expect(newOutcomePrices.outcomes[0]).to.below(outcomePrices.outcomes[0]);
|
|
946
|
+
expect(newOutcomePrices.outcomes[0]).to.equal(1/3);
|
|
947
|
+
// opposite outcome price should increase
|
|
948
|
+
expect(newOutcomePrices.outcomes[1]).to.above(outcomePrices.outcomes[1]);
|
|
949
|
+
expect(newOutcomePrices.outcomes[1]).to.equal(1/3);
|
|
950
|
+
expect(newOutcomePrices.outcomes[2]).to.above(outcomePrices.outcomes[2]);
|
|
951
|
+
expect(newOutcomePrices.outcomes[2]).to.equal(1/3);
|
|
952
|
+
// Prices sum = 1
|
|
953
|
+
// 0.333 + 0.333 + 0.333 = 1
|
|
954
|
+
expect(newOutcomePrices.outcomes[0] + newOutcomePrices.outcomes[1] + newOutcomePrices.outcomes[2]).to.equal(1);
|
|
955
|
+
|
|
956
|
+
// Liquidity value remains the same
|
|
957
|
+
expect(newMarketData.liquidity).to.equal(marketData.liquidity);
|
|
958
|
+
|
|
959
|
+
// outcome shares should increase
|
|
960
|
+
expect(newOutcomeShares.outcomes[0]).to.above(outcomeShares.outcomes[0]);
|
|
961
|
+
expect(newOutcomeShares.outcomes[0]).to.equal(0.01);
|
|
962
|
+
// opposite outcome shares should increase
|
|
963
|
+
expect(newOutcomeShares.outcomes[1]).to.below(outcomeShares.outcomes[1]);
|
|
964
|
+
expect(newOutcomeShares.outcomes[1]).to.equal(0.01);
|
|
965
|
+
expect(newOutcomeShares.outcomes[2]).to.below(outcomeShares.outcomes[2]);
|
|
966
|
+
expect(newOutcomeShares.outcomes[2]).to.equal(0.01);
|
|
967
|
+
// # Shares Product = Liquidity^2
|
|
968
|
+
// 0.01 * 0.01 = 0.01^2
|
|
969
|
+
expect(outcomeShares.outcomes[0] * outcomeShares.outcomes[1] * outcomeShares.outcomes[2]).to.equal(newMarketData.liquidity ** 3);
|
|
970
|
+
expect(newOutcomeShares.outcomes[0] * newOutcomeShares.outcomes[1] * newOutcomeShares.outcomes[2]).to.equal(newMarketData.liquidity ** 3);
|
|
971
|
+
|
|
972
|
+
const myShares = await predictionMarketContract.getMyMarketShares({marketId});
|
|
973
|
+
expect(myShares).to.eql({
|
|
974
|
+
liquidityShares: 0.01,
|
|
975
|
+
outcomeShares: {
|
|
976
|
+
0: 0.00875,
|
|
977
|
+
1: 0.00875,
|
|
978
|
+
2: 0.00875,
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
// User gets shares value back in ETH
|
|
983
|
+
expect(newContractBalance).to.below(contractBalance);
|
|
984
|
+
const amountTransferred = Number((contractBalance - newContractBalance).toFixed(5));
|
|
985
|
+
expect(amountTransferred).to.equal(0.01);
|
|
986
|
+
}));
|
|
987
|
+
});
|
|
988
|
+
context('Distributed probabilites', async () => {
|
|
989
|
+
let marketId;
|
|
990
|
+
let outcomeIds = [0, 1, 2];
|
|
991
|
+
|
|
992
|
+
const initialOdds = [
|
|
993
|
+
[
|
|
994
|
+
[50, 50],
|
|
995
|
+
['50000000', '50000000']
|
|
996
|
+
],
|
|
997
|
+
[
|
|
998
|
+
[40, 60],
|
|
999
|
+
['60000000', '40000000']
|
|
1000
|
+
],
|
|
1001
|
+
[
|
|
1002
|
+
[15, 20, 65],
|
|
1003
|
+
['1300000000', '975000000', '300000000']
|
|
1004
|
+
],
|
|
1005
|
+
[
|
|
1006
|
+
[65, 15, 20],
|
|
1007
|
+
['300000000', '1300000000', '975000000']
|
|
1008
|
+
],
|
|
1009
|
+
[
|
|
1010
|
+
[10, 20, 30, 40],
|
|
1011
|
+
['24000000000', '12000000000', '8000000000', '6000000000']
|
|
1012
|
+
]
|
|
1013
|
+
];
|
|
1014
|
+
|
|
1015
|
+
for (const [odds, expectedDistribution] of initialOdds) {
|
|
1016
|
+
context(`Odds: ${odds}`, async () => {
|
|
1017
|
+
before(mochaAsync(async () => {
|
|
1018
|
+
const distribution = await predictionMarketContract.calcDistribution({odds});
|
|
1019
|
+
|
|
1020
|
+
expect(distribution).to.eql(expectedDistribution);
|
|
1021
|
+
|
|
1022
|
+
try {
|
|
1023
|
+
const res = await predictionMarketContract.mintAndCreateMarket({
|
|
1024
|
+
value,
|
|
1025
|
+
name: `Market with ${odds} odds`,
|
|
1026
|
+
image: 'foo-bar',
|
|
1027
|
+
category: 'Foo;Bar',
|
|
1028
|
+
oracleAddress: '0x0000000000000000000000000000000000000001', // TODO
|
|
1029
|
+
duration: moment(moment().add(1, 'month').format('YYYY-MM-DD')).unix(),
|
|
1030
|
+
outcomes: ['A', 'B', 'C', 'D', 'E'].slice(0, odds.length),
|
|
1031
|
+
token: tokenERC20Contract.getAddress(),
|
|
1032
|
+
odds,
|
|
1033
|
+
realitioAddress: realitioERC20Contract.getAddress(),
|
|
1034
|
+
realitioTimeout: 300,
|
|
1035
|
+
PM3ManagerAddress: predictionMarketManagerContract.getAddress()
|
|
1036
|
+
});
|
|
1037
|
+
expect(res.status).to.equal(true);
|
|
1038
|
+
} catch(e) {
|
|
1039
|
+
console.log(e);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
const marketIds = await predictionMarketContract.getMarkets();
|
|
1043
|
+
marketId = marketIds[marketIds.length - 1];
|
|
1044
|
+
}));
|
|
1045
|
+
|
|
1046
|
+
it('market prices should match odds', mochaAsync(async () => {
|
|
1047
|
+
const outcomePrices = await predictionMarketContract.getMarketPrices({marketId});
|
|
1048
|
+
|
|
1049
|
+
for (let i = 0; i < odds.length; i++) {
|
|
1050
|
+
const price = outcomePrices.outcomes[i];
|
|
1051
|
+
const expectedPrice = odds[i] / 100;
|
|
1052
|
+
|
|
1053
|
+
expect(price).to.closeTo(expectedPrice, 0.00000001);
|
|
1054
|
+
}
|
|
1055
|
+
}));
|
|
1056
|
+
|
|
1057
|
+
it('market shares should match shares', mochaAsync(async () => {
|
|
1058
|
+
const outcomeShares = await predictionMarketContract.getMarketShares({marketId});
|
|
1059
|
+
|
|
1060
|
+
for (let i = 0; i < odds.length; i++) {
|
|
1061
|
+
const shares = outcomeShares.outcomes[i];
|
|
1062
|
+
const minOdds = Math.min(...odds);
|
|
1063
|
+
const expectedShares = value * minOdds / odds[i];
|
|
1064
|
+
|
|
1065
|
+
expect(shares).to.closeTo(expectedShares, 0.00000001);
|
|
1066
|
+
}
|
|
1067
|
+
}));
|
|
1068
|
+
|
|
1069
|
+
it('market liquidity should match liquidity', mochaAsync(async () => {
|
|
1070
|
+
const marketData = await predictionMarketContract.getMarketData({marketId});
|
|
1071
|
+
const expectedLiquidity = value;
|
|
1072
|
+
|
|
1073
|
+
expect(marketData.liquidity).to.equal(expectedLiquidity);
|
|
1074
|
+
}));
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
});
|
|
1079
|
+
});
|