polkamarkets-js 1.0.2 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/hardhat.config.js +4 -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 +256 -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 -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;
|