polkamarkets-js 1.0.2 → 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.
Files changed (163) 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/help.txt +8 -0
  113. package/index.js +3 -0
  114. package/migrations/10_deploy_weth.js +5 -0
  115. package/migrations/11_deploy_full_flow.js +99 -0
  116. package/migrations/12_deploy_pm_v3_querier.js +7 -0
  117. package/migrations/13_deploy_pm_v3_factory.js +14 -0
  118. package/migrations/1_initial_migration.js +5 -0
  119. package/migrations/2_deploy_erc20.js +10 -0
  120. package/migrations/3_deploy_realitio.js +11 -0
  121. package/migrations/4_deploy_pm.js +20 -0
  122. package/migrations/5_seed_markets.js +51 -0
  123. package/migrations/6_deploy_achievements.js +5 -0
  124. package/migrations/7_deploy_voting.js +14 -0
  125. package/migrations/8_deploy_pm_v2.js +20 -0
  126. package/migrations/9_seed_markets_v2.js +68 -0
  127. package/package.json +106 -13
  128. package/src/Application.js +421 -0
  129. package/src/interfaces/index.js +19 -0
  130. package/src/models/AchievementsContract.js +217 -0
  131. package/src/models/ArbitrationContract.js +69 -0
  132. package/src/models/ArbitrationProxyContract.js +32 -0
  133. package/src/models/ERC20Contract.js +156 -0
  134. package/src/models/FantasyERC20Contract.js +92 -0
  135. package/src/models/IContract.js +1002 -0
  136. package/src/models/PolkamarketsSmartAccount.js +100 -0
  137. package/src/models/PredictionMarketContract.js +562 -0
  138. package/src/models/PredictionMarketV2Contract.js +830 -0
  139. package/src/models/PredictionMarketV3Contract.js +233 -0
  140. package/src/models/PredictionMarketV3ControllerContract.js +102 -0
  141. package/src/models/PredictionMarketV3FactoryContract.js +96 -0
  142. package/src/models/PredictionMarketV3ManagerContract.js +111 -0
  143. package/src/models/PredictionMarketV3QuerierContract.js +24 -0
  144. package/src/models/RealitioERC20Contract.js +286 -0
  145. package/src/models/VotingContract.js +182 -0
  146. package/src/models/WETH9Contract.js +92 -0
  147. package/src/models/index.js +33 -0
  148. package/src/utils/Account.js +40 -0
  149. package/src/utils/Contract.js +120 -0
  150. package/src/utils/Numbers.js +94 -0
  151. package/tests/fantasyERC20Contract.js +225 -0
  152. package/tests/index.js +10 -0
  153. package/tests/predictionMarketContract.js +466 -0
  154. package/tests/predictionMarketV2Contract.js +1042 -0
  155. package/tests/predictionMarketV3Contract.js +1079 -0
  156. package/tests/predictionMarketV3ControllerContract.js +613 -0
  157. package/tests/predictionMarketV3FactoryContract.js +469 -0
  158. package/tests/predictionMarketV3ManagerContract.js +610 -0
  159. package/tests/utils.js +16 -0
  160. package/tests/votingContract.js +490 -0
  161. package/tooling/docs/jsdoc.json +6 -0
  162. package/truffle-config.js +134 -0
  163. package/polkamarkets.js +0 -436
@@ -0,0 +1,100 @@
1
+ const { SmartAccount } = require('@particle-network/aa');
2
+ const ethers = require('ethers').ethers;
3
+
4
+ const { ENTRYPOINT_ADDRESS_V06, providerToSmartAccountSigner } = require('permissionless');
5
+ const { createPublicClient, http } = require('viem');
6
+ const { signerToSimpleSmartAccount } = require('permissionless/accounts');
7
+
8
+ class PolkamarketsSmartAccount {
9
+
10
+ static PIMLICO_FACTORY_ADDRESS = '0x9406Cc6185a346906296840746125a0E44976454';
11
+ static THIRDWEB_FACTORY_ADDRESS = '0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00';
12
+
13
+ static singleton = (() => {
14
+ let smartAccount;
15
+
16
+ function createInstance(provider, networkConfig, isConnectedWallet) {
17
+ const options = {
18
+ projectId: networkConfig.particleProjectId,
19
+ clientKey: networkConfig.particleClientKey,
20
+ appId: networkConfig.particleAppId,
21
+ aaOptions: {
22
+ accountContracts: {
23
+ SIMPLE: [{
24
+ version: '1.0.0',
25
+ chainIds: [networkConfig.chainId],
26
+ }],
27
+ }
28
+ },
29
+ };
30
+
31
+ const instance = new PolkamarketsSmartAccount();
32
+ instance.networkConfig = networkConfig;
33
+ instance.provider = provider
34
+ instance.isConnectedWallet = isConnectedWallet
35
+ if (!networkConfig.usePimlico && !networkConfig.useThirdWeb) {
36
+ instance.smartAccount = new SmartAccount(provider, options);
37
+ instance.smartAccount.setSmartAccountContract({ name: 'SIMPLE', version: '1.0.0' })
38
+ }
39
+ return instance;
40
+ }
41
+
42
+ return {
43
+ getInstance: (provider, networkConfig, isConnectedWallet) => {
44
+ if (!smartAccount) {
45
+ smartAccount = createInstance(provider, networkConfig, isConnectedWallet);
46
+ }
47
+ return smartAccount;
48
+ },
49
+ getInstanceIfExists: () => smartAccount,
50
+ clearInstance: () => {
51
+ smartAccount = null;
52
+ }
53
+ };
54
+ })();
55
+
56
+ async providerIsConnectedWallet() {
57
+ if (this.isConnectedWallet) {
58
+ const web3Provider = new ethers.providers.Web3Provider(this.provider)
59
+ const signer = web3Provider.getSigner()
60
+ const address = await signer.getAddress();
61
+
62
+ return { isConnectedWallet: true, address, signer };
63
+ }
64
+
65
+ return { isConnectedWallet: false, address: null, signer: null };
66
+ }
67
+
68
+ async getAddress() {
69
+ const { isConnectedWallet, address } = await this.providerIsConnectedWallet();
70
+ if (isConnectedWallet) {
71
+ return address;
72
+ }
73
+
74
+ if (this.networkConfig.useThirdWeb && this.provider.adminAccount) {
75
+ // if exists adminAccount it means it's using thirdwebauth
76
+ return this.provider.smartAccount.address;
77
+ }
78
+
79
+ if (this.networkConfig.usePimlico || this.networkConfig.useThirdWeb) {
80
+ const publicClient = createPublicClient({
81
+ chain: this.networkConfig.viemChain,
82
+ transport: http(this.networkConfig.rpcUrl)
83
+ });
84
+
85
+ const smartAccountSigner = await providerToSmartAccountSigner(this.provider);
86
+
87
+ const smartAccount = await signerToSimpleSmartAccount(publicClient, {
88
+ signer: smartAccountSigner,
89
+ factoryAddress: PolkamarketsSmartAccount.PIMLICO_FACTORY_ADDRESS,
90
+ entryPoint: ENTRYPOINT_ADDRESS_V06,
91
+ })
92
+
93
+ return smartAccount.address;
94
+ }
95
+
96
+ return this.smartAccount.getAddress();
97
+ }
98
+ }
99
+
100
+ module.exports = PolkamarketsSmartAccount;
@@ -0,0 +1,562 @@
1
+ const _ = require("lodash");
2
+ const moment = require("moment");
3
+
4
+ const prediction = require("../interfaces").prediction;
5
+
6
+ const Numbers = require("../utils/Numbers");
7
+ const IContract = require('./IContract');
8
+
9
+ const realitioLib = require('@reality.eth/reality-eth-lib/formatters/question');
10
+
11
+ const actions = {
12
+ 0: 'Buy',
13
+ 1: 'Sell',
14
+ 2: 'Add Liquidity',
15
+ 3: 'Remove Liquidity',
16
+ 4: 'Claim Winnings',
17
+ 5: 'Claim Liquidity',
18
+ 6: 'Claim Fees',
19
+ 7: 'Claim Voided',
20
+ }
21
+
22
+ /**
23
+ * PredictionMarket Contract Object
24
+ * @constructor PredictionMarketContract
25
+ * @param {Web3} web3
26
+ * @param {Integer} decimals
27
+ * @param {Address} contractAddress
28
+ */
29
+
30
+ class PredictionMarketContract extends IContract {
31
+ constructor(params) {
32
+ super({ abi: prediction, ...params });
33
+ this.contractName = 'predictionMarket';
34
+ }
35
+
36
+ /* Get Functions */
37
+ /**
38
+ * @function getMinimumRequiredBalance
39
+ * @description Returns minimum required ERC20 balance to create markets
40
+ * @returns {Integer} requiredBalance
41
+ */
42
+ async getMinimumRequiredBalance() {
43
+ const requiredBalance = await this.params.contract
44
+ .getContract()
45
+ .methods
46
+ .requiredBalance()
47
+ .call();
48
+
49
+ return Numbers.fromDecimalsNumber(requiredBalance, 18)
50
+ }
51
+
52
+ /* Get Functions */
53
+ /**
54
+ * @function getFee
55
+ * @description Returns fee taken from every transaction to liquidity providers
56
+ * @returns {Integer} fee
57
+ */
58
+ async getFee() {
59
+ const fee = await this.params.contract
60
+ .getContract()
61
+ .methods
62
+ .fee()
63
+ .call();
64
+
65
+ return Numbers.fromDecimalsNumber(fee, 18)
66
+ }
67
+
68
+ /* Get Functions */
69
+ /**
70
+ * @function getMarkets
71
+ * @description Get Markets
72
+ * @returns {Integer | Array} Get Market Ids
73
+ */
74
+ async getMarkets() {
75
+ let res = await this.params.contract
76
+ .getContract()
77
+ .methods
78
+ .getMarkets()
79
+ .call();
80
+ return res.map((marketId) => Number(Numbers.fromHex(marketId)));
81
+ }
82
+
83
+ /**
84
+ * @function getMarketData
85
+ * @description Get getMarketData
86
+ * @param {Integer} marketId
87
+ * @returns {String} Market Name
88
+ * @returns {Integer} closeDateTime
89
+ * @returns {Integer} state
90
+ * @returns {Address} Oracle Address
91
+ * @returns {Integer} liquidity
92
+ * @returns {Array} outcomeIds
93
+ */
94
+ async getMarketData({ marketId }) {
95
+ const marketData = await this.params.contract.getContract().methods.getMarketData(marketId).call();
96
+ const outcomeIds = await this.__sendTx(this.getContract().methods.getMarketOutcomeIds(marketId), true);
97
+
98
+ return {
99
+ name: '', // TODO: remove; deprecated
100
+ closeDateTime: moment.unix(marketData[1]).format("YYYY-MM-DD HH:mm"),
101
+ state: parseInt(marketData[0]),
102
+ oracleAddress: '0x0000000000000000000000000000000000000000',
103
+ liquidity: Numbers.fromDecimalsNumber(marketData[2], 18),
104
+ outcomeIds: outcomeIds.map((outcomeId) => Numbers.fromBigNumberToInteger(outcomeId, 18))
105
+ };
106
+ }
107
+
108
+ /**
109
+ * @function getOutcomeData
110
+ * @description Get Market Outcome Data
111
+ * @param {Integer} marketId
112
+ * @param {Integer} outcomeId
113
+ * @returns {String} name
114
+ * @returns {Integer} price
115
+ * @returns {Integer} sahres
116
+ */
117
+ async getOutcomeData({ marketId, outcomeId }) {
118
+ const outcomeData = await this.params.contract.getContract().methods.getMarketOutcomeData(marketId, outcomeId).call();
119
+
120
+ return {
121
+ name: '', // TODO: remove; deprecated
122
+ price: Numbers.fromDecimalsNumber(outcomeData[0], 18),
123
+ shares: Numbers.fromDecimalsNumber(outcomeData[1], 18),
124
+ };
125
+ }
126
+
127
+ /**
128
+ * @function getMarketDetails
129
+ * @description getMarketDetails
130
+ * @param {Integer} marketId
131
+ * @returns {String} name
132
+ * @returns {String} category
133
+ * @returns {String} subcategory
134
+ * @returns {String} image
135
+ * @returns {Array} outcomes
136
+ */
137
+ async getMarketDetails({ marketId }) {
138
+ const marketData = await this.params.contract.getContract().methods.getMarketData(marketId).call();
139
+ const outcomeIds = await this.__sendTx(this.getContract().methods.getMarketOutcomeIds(marketId), true);
140
+
141
+ const events = await this.getEvents('MarketCreated', { marketId });
142
+
143
+ if (events.length === 0) {
144
+ // legacy record, returning empty data
145
+ return { name: '', category: '', subcategory: '', image: '', outcomes: [] };
146
+ }
147
+
148
+ // parsing question with realitio standard
149
+ const question = realitioLib.populatedJSONForTemplate(
150
+ '{"title": "%s", "type": "single-select", "outcomes": [%s], "category": "%s", "lang": "%s"}',
151
+ events[0].returnValues.question
152
+ );
153
+
154
+ return {
155
+ name: question.title,
156
+ category: question.category.split(';')[0],
157
+ subcategory: question.category.split(';')[1],
158
+ outcomes: question.outcomes,
159
+ image: events[0].returnValues.image
160
+ };
161
+ }
162
+
163
+ async getMarketIdsFromQuestions({ questions }) {
164
+ const events = await this.getEvents('MarketCreated');
165
+
166
+ return events.filter((event) => {
167
+ return questions.includes(event.returnValues.question);
168
+ }).map((event) => event.returnValues.marketId);
169
+ }
170
+
171
+ /**
172
+ * @function getMarketQuestionId
173
+ * @description getMarketQuestionId
174
+ * @param {Integer} marketId
175
+ * @returns {Bytes32} questionId
176
+ */
177
+ async getMarketQuestionId({ marketId }) {
178
+ const marketAltData = await this.params.contract.getContract().methods.getMarketAltData(marketId).call();
179
+
180
+ return marketAltData[1];
181
+ }
182
+
183
+ /**
184
+ * @function getAverageOutcomeBuyPrice
185
+ * @description Calculates average buy price of market outcome based on user events
186
+ * @param {Array} events
187
+ * @param {Integer} marketId
188
+ * @param {Integer} outcomeId
189
+ * @returns {Integer} price
190
+ */
191
+ getAverageOutcomeBuyPrice({ events, marketId, outcomeId }) {
192
+ // filtering by marketId + outcomeId + buy action
193
+ events = events.filter(event => {
194
+ return (
195
+ event.action === 'Buy' &&
196
+ event.marketId === marketId &&
197
+ event.outcomeId === outcomeId
198
+ );
199
+ });
200
+
201
+ if (events.length === 0) return 0;
202
+
203
+ const totalShares = events.map(item => item.shares).reduce((prev, next) => prev + next);
204
+ const totalAmount = events.map(item => item.value).reduce((prev, next) => prev + next);
205
+
206
+ return totalAmount / totalShares;
207
+ }
208
+
209
+ /**
210
+ * @function getAverageAddLiquidityPrice
211
+ * @description Calculates average add liquidity of market outcome based on user events
212
+ * @param {Array} events
213
+ * @param {Integer} marketId
214
+ * @returns {Integer} price
215
+ */
216
+ getAverageAddLiquidityPrice({ events, marketId }) {
217
+ // filtering by marketId + add liquidity action
218
+ events = events.filter(event => {
219
+ return (
220
+ event.action === 'Add Liquidity' &&
221
+ event.marketId === marketId
222
+ );
223
+ });
224
+
225
+ if (events.length === 0) return 0;
226
+
227
+ const totalShares = events.map(item => item.shares).reduce((prev, next) => prev + next);
228
+ const totalAmount = events.map(item => item.value).reduce((prev, next) => prev + next);
229
+
230
+ return totalAmount / totalShares;
231
+ }
232
+
233
+ /**
234
+ * @function getMyPortfolio
235
+ * @description Get My Porfolio
236
+ * @returns {Array} Outcome Shares
237
+ */
238
+ async getMyPortfolio() {
239
+ const account = await this.getMyAccount();
240
+ if (!account) return [];
241
+
242
+ return this.getPortfolio({ user: account });
243
+ }
244
+
245
+ /**
246
+ * @function getPortfolio
247
+ * @description Get My Porfolio
248
+ * @param {Address} user
249
+ * @returns {Array} Outcome Shares
250
+ */
251
+ async getPortfolio({ user }) {
252
+ const events = await this.getActions({ user });
253
+ const allMarketIds = await this.getMarkets();
254
+ const userMarketIds = events.map(e => e.marketId).filter((x, i, a) => a.indexOf(x) == i);
255
+
256
+ return await allMarketIds.reduce(async (obj, marketId) => {
257
+ let portfolio;
258
+ if (!userMarketIds.includes(marketId)) {
259
+ // user did not interact with market, no need to fetch holdings
260
+ portfolio = {
261
+ liquidity: { shares: 0, price: 0 },
262
+ outcomes: {
263
+ 0: { shares: 0, price: 0 },
264
+ 1: { shares: 0, price: 0 },
265
+ },
266
+ claimStatus: {
267
+ winningsToClaim: false,
268
+ winningsClaimed: false,
269
+ liquidityToClaim: false,
270
+ liquidityClaimed: false,
271
+ liquidityFees: 0
272
+ }
273
+ };
274
+ } else {
275
+ const marketShares = await this.getContract().methods.getUserMarketShares(marketId, user).call();
276
+ let claimStatus;
277
+ try {
278
+ claimStatus = await this.getContract().methods.getUserClaimStatus(marketId, user).call();
279
+ } catch (err) {
280
+ // SafeMath subtraction overflow error from Moonriver deployment
281
+ if (err.message.includes('SafeMath: subtraction overflow')) {
282
+ claimStatus = [false, false, false, false, 0];
283
+
284
+ const marketData = await this.params.contract.getContract().methods.getMarketData(marketId).call();
285
+ if (parseInt(marketData[0]) === 2) {
286
+ // market resolved, computing if user has winnings to claim
287
+ claimStatus[0] = marketShares[parseInt(marketData[5]) + 1] > 0;
288
+ if (claimStatus[0]) {
289
+ const events = await this.getEvents('MarketActionTx', { marketId, user, action: 4 });
290
+ claimStatus[1] = events.length > 0;
291
+ }
292
+ claimStatus[2] = marketShares[0] > 0;
293
+ claimStatus[3] = claimStatus[2];
294
+ }
295
+ } else {
296
+ throw err;
297
+ }
298
+ }
299
+
300
+ portfolio = {
301
+ liquidity: {
302
+ shares: Numbers.fromDecimalsNumber(marketShares[0], 18),
303
+ price: this.getAverageAddLiquidityPrice({ events, marketId }),
304
+ },
305
+ outcomes: {
306
+ 0: {
307
+ shares: Numbers.fromDecimalsNumber(marketShares[1], 18),
308
+ price: this.getAverageOutcomeBuyPrice({ events, marketId, outcomeId: 0 }),
309
+ },
310
+ 1: {
311
+ shares: Numbers.fromDecimalsNumber(marketShares[2], 18),
312
+ price: this.getAverageOutcomeBuyPrice({ events, marketId, outcomeId: 1 }),
313
+ },
314
+ },
315
+ claimStatus: {
316
+ winningsToClaim: claimStatus[0],
317
+ winningsClaimed: claimStatus[1],
318
+ liquidityToClaim: claimStatus[2],
319
+ liquidityClaimed: claimStatus[3],
320
+ liquidityFees: Numbers.fromDecimalsNumber(claimStatus[4], 18)
321
+ }
322
+ };
323
+ }
324
+
325
+ return await {
326
+ ...(await obj),
327
+ [marketId]: portfolio,
328
+ };
329
+ }, {});
330
+ }
331
+
332
+ /**
333
+ * @function getMyMarketShares
334
+ * @description Get My Market Shares
335
+ * @param {Integer} marketId
336
+ * @returns {Integer} Liquidity Shares
337
+ * @returns {Array} Outcome Shares
338
+ */
339
+ async getMyMarketShares({ marketId }) {
340
+ const account = await this.getMyAccount();
341
+ if (!account) return [];
342
+
343
+ const marketShares = await this.getContract().methods.getUserMarketShares(marketId, account).call();
344
+
345
+ return {
346
+ liquidityShares: Numbers.fromDecimalsNumber(marketShares[0], 18),
347
+ outcomeShares: {
348
+ 0: Numbers.fromDecimalsNumber(marketShares[1], 18),
349
+ 1: Numbers.fromDecimalsNumber(marketShares[2], 18),
350
+ }
351
+ };
352
+ }
353
+
354
+ async getMyActions() {
355
+ const account = await this.getMyAccount();
356
+ if (!account) return [];
357
+
358
+ return this.getActions({ user: account });
359
+ }
360
+
361
+ async getActions({ user }) {
362
+ const events = await this.getEvents('MarketActionTx', { user });
363
+
364
+ // filtering by address
365
+ return events.map(event => {
366
+ return {
367
+ action: actions[Numbers.fromBigNumberToInteger(event.returnValues.action, 18)],
368
+ marketId: Numbers.fromBigNumberToInteger(event.returnValues.marketId, 18),
369
+ outcomeId: Numbers.fromBigNumberToInteger(event.returnValues.outcomeId, 18),
370
+ shares: Numbers.fromDecimalsNumber(event.returnValues.shares, 18),
371
+ value: Numbers.fromDecimalsNumber(event.returnValues.value, 18),
372
+ timestamp: Numbers.fromBigNumberToInteger(event.returnValues.timestamp, 18),
373
+ transactionHash: event.transactionHash,
374
+ }
375
+ });
376
+ }
377
+
378
+ /**
379
+ * @function getMarketOutcomePrice
380
+ * @description Get Market Price
381
+ * @param {Integer} marketId
382
+ * @param {Integer} outcomeId
383
+ * @return {Integer} price
384
+ */
385
+ async getMarketOutcomePrice({ marketId, outcomeId }) {
386
+ return Numbers.fromDecimals(
387
+ await this.__sendTx(
388
+ this.getContract().methods.getMarketOutcomePrice(marketId, outcomeId),
389
+ true
390
+ ),
391
+ 18
392
+ );
393
+ }
394
+
395
+ /**
396
+ * @function getMarketPrices
397
+ * @description Get Market Price
398
+ * @param {Integer} marketId
399
+ * @return {Object} prices
400
+ */
401
+ async getMarketPrices({ marketId }) {
402
+ const marketPrices = await this.getContract().methods.getMarketPrices(marketId).call();
403
+
404
+ return {
405
+ liquidity: Numbers.fromDecimalsNumber(marketPrices[0], 18),
406
+ outcomes: {
407
+ 0: Numbers.fromDecimalsNumber(marketPrices[1], 18),
408
+ 1: Numbers.fromDecimalsNumber(marketPrices[2], 18)
409
+ }
410
+ };
411
+ }
412
+
413
+ /* POST User Functions */
414
+
415
+ /**
416
+ * @function createMarket
417
+ * @description Create a µarket
418
+ * @param {String} name
419
+ * @param {Integer} duration
420
+ * @param {Address} oracleAddress
421
+ * @param {String} outcome1Name
422
+ * @param {String} outcome2Name
423
+ * @param {Integer} ethAmount
424
+ */
425
+ async createMarket({ name, image, duration, oracleAddress, outcomes, category, ethAmount }) {
426
+ let ethToWei = Numbers.toSmartContractDecimals(ethAmount, 18);
427
+ const question = realitioLib.encodeText('single-select', name, outcomes, category);
428
+
429
+ return await this.__sendTx(
430
+ this.getContract().methods.createMarket(
431
+ question,
432
+ image,
433
+ duration,
434
+ oracleAddress,
435
+ outcomes.length
436
+ ),
437
+ false,
438
+ ethToWei
439
+ );
440
+ };
441
+
442
+ /**
443
+ * @function addLiquidity
444
+ * @description Add Liquidity from Market
445
+ * @param {Integer} marketId
446
+ * @param {Integer} ethAmount
447
+ */
448
+ async addLiquidity({ marketId, ethAmount }) {
449
+ let ethToWei = Numbers.toSmartContractDecimals(ethAmount, 18);
450
+ return await this.__sendTx(
451
+ this.getContract().methods.addLiquidity(marketId),
452
+ false,
453
+ ethToWei
454
+ );
455
+ };
456
+
457
+ /**
458
+ * @function removeLiquidity
459
+ * @description Remove Liquidity from Market
460
+ * @param {Integer} marketId
461
+ * @param {Integer} shares
462
+ */
463
+ async removeLiquidity({ marketId, shares }) {
464
+ shares = Numbers.toSmartContractDecimals(shares, 18);
465
+ return await this.__sendTx(
466
+ this.getContract().methods.removeLiquidity(marketId, shares)
467
+ );
468
+ };
469
+
470
+
471
+ /**
472
+ * @function buy
473
+ * @description Buy Shares of a Market Outcome
474
+ * @param {Integer} marketId
475
+ * @param {Integer} outcomeId
476
+ * @param {Integer} ethAmount
477
+ */
478
+ async buy({ marketId, outcomeId, ethAmount, minOutcomeSharesToBuy }) {
479
+ let ethToWei = Numbers.toSmartContractDecimals(ethAmount, 18);
480
+ minOutcomeSharesToBuy = Numbers.toSmartContractDecimals(minOutcomeSharesToBuy, 18);
481
+
482
+ return await this.__sendTx(
483
+ this.getContract().methods.buy(marketId, outcomeId, minOutcomeSharesToBuy),
484
+ false,
485
+ ethToWei
486
+ );
487
+ };
488
+
489
+ /**
490
+ * @function sell
491
+ * @description Sell Shares of a Market Outcome
492
+ * @param {Integer} marketId
493
+ * @param {Integer} outcomeId
494
+ * @param {Integer} shares
495
+ */
496
+ async sell({ marketId, outcomeId, ethAmount, maxOutcomeSharesToSell }) {
497
+ ethAmount = Numbers.toSmartContractDecimals(ethAmount, 18);
498
+ maxOutcomeSharesToSell = Numbers.toSmartContractDecimals(maxOutcomeSharesToSell, 18);
499
+ return await this.__sendTx(
500
+ this.getContract().methods.sell(marketId, outcomeId, ethAmount, maxOutcomeSharesToSell),
501
+ false,
502
+ );
503
+ };
504
+
505
+ async resolveMarketOutcome({ marketId }) {
506
+ return await this.__sendTx(
507
+ this.getContract().methods.resolveMarketOutcome(marketId),
508
+ false,
509
+ );
510
+ };
511
+
512
+ async claimWinnings({ marketId }) {
513
+ return await this.__sendTx(
514
+ this.getContract().methods.claimWinnings(marketId),
515
+ false,
516
+ );
517
+ };
518
+
519
+ async claimVoidedOutcomeShares({ marketId, outcomeId }) {
520
+ return await this.__sendTx(
521
+ this.getContract().methods.claimVoidedOutcomeShares(marketId, outcomeId),
522
+ false,
523
+ );
524
+ };
525
+
526
+ async claimLiquidity({ marketId }) {
527
+ return await this.__sendTx(
528
+ this.getContract().methods.claimLiquidity(marketId),
529
+ false,
530
+ );
531
+ };
532
+
533
+ async calcBuyAmount({ marketId, outcomeId, ethAmount }) {
534
+ ethAmount = Numbers.toSmartContractDecimals(ethAmount, 18);
535
+
536
+ const amount = await this.getContract()
537
+ .methods.calcBuyAmount(
538
+ ethAmount,
539
+ marketId,
540
+ outcomeId
541
+ )
542
+ .call();
543
+
544
+ return Numbers.fromDecimalsNumber(amount, 18);
545
+ }
546
+
547
+ async calcSellAmount({ marketId, outcomeId, ethAmount }) {
548
+ ethAmount = Numbers.toSmartContractDecimals(ethAmount, 18);
549
+
550
+ const amount = await this.getContract()
551
+ .methods.calcSellAmount(
552
+ ethAmount,
553
+ marketId,
554
+ outcomeId
555
+ )
556
+ .call();
557
+
558
+ return Numbers.fromDecimalsNumber(amount, 18);
559
+ }
560
+ }
561
+
562
+ module.exports = PredictionMarketContract;