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.
- 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 -436
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
const Contract = require("../utils/Contract");
|
|
2
|
+
const _ = require("lodash");
|
|
3
|
+
const axios = require('axios');
|
|
4
|
+
const PolkamarketsSmartAccount = require('./PolkamarketsSmartAccount');
|
|
5
|
+
const ethers = require('ethers').ethers;
|
|
6
|
+
|
|
7
|
+
const { ENTRYPOINT_ADDRESS_V06, bundlerActions, providerToSmartAccountSigner, getAccountNonce } = require('permissionless');
|
|
8
|
+
const { pimlicoBundlerActions, pimlicoPaymasterActions } = require('permissionless/actions/pimlico');
|
|
9
|
+
const { createClient, createPublicClient, http } = require('viem');
|
|
10
|
+
const { signerToSimpleSmartAccount } = require('permissionless/accounts');
|
|
11
|
+
|
|
12
|
+
const { getPaymasterAndData, estimateUserOpGas, bundleUserOp, signUserOp, waitForUserOpReceipt, getUserOpGasFees, createUnsignedUserOp } = require('thirdweb/wallets/smart');
|
|
13
|
+
const { createThirdwebClient, getContract, prepareContractCall } = require('thirdweb');
|
|
14
|
+
const { defineChain } = require('thirdweb/chains');
|
|
15
|
+
/**
|
|
16
|
+
* Contract Object Interface
|
|
17
|
+
* @constructor IContract
|
|
18
|
+
* @param {Web3} web3
|
|
19
|
+
* @param {Address} contractAddress ? (opt)
|
|
20
|
+
* @param {ABI} abi
|
|
21
|
+
* @param {Account} acc ? (opt)
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class IContract {
|
|
26
|
+
constructor({
|
|
27
|
+
web3,
|
|
28
|
+
contractAddress = null /* If not deployed */,
|
|
29
|
+
abi,
|
|
30
|
+
acc,
|
|
31
|
+
web3EventsProvider,
|
|
32
|
+
gasPrice,
|
|
33
|
+
isSocialLogin = false,
|
|
34
|
+
startBlock
|
|
35
|
+
}) {
|
|
36
|
+
try {
|
|
37
|
+
if (!abi) {
|
|
38
|
+
throw new Error("No ABI Interface provided");
|
|
39
|
+
}
|
|
40
|
+
if (!web3) {
|
|
41
|
+
throw new Error("Please provide a valid web3 provider");
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
this.web3 = web3;
|
|
45
|
+
|
|
46
|
+
if (acc) {
|
|
47
|
+
this.acc = acc;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.params = {
|
|
51
|
+
web3,
|
|
52
|
+
abi,
|
|
53
|
+
contractAddress,
|
|
54
|
+
web3EventsProvider,
|
|
55
|
+
gasPrice,
|
|
56
|
+
contract: new Contract(web3, abi, contractAddress),
|
|
57
|
+
isSocialLogin,
|
|
58
|
+
startBlock,
|
|
59
|
+
};
|
|
60
|
+
} catch (err) {
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async __init__() {
|
|
66
|
+
try {
|
|
67
|
+
if (!this.getAddress()) {
|
|
68
|
+
throw new Error("Please add a Contract Address");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await this.__assert();
|
|
72
|
+
} catch (err) {
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
async __metamaskCall({ f, acc, value, callback = () => { } }) {
|
|
78
|
+
return f.send({
|
|
79
|
+
from: acc,
|
|
80
|
+
value: value,
|
|
81
|
+
gasPrice: this.params.gasPrice,
|
|
82
|
+
maxPriorityFeePerGas: null,
|
|
83
|
+
maxFeePerGas: null
|
|
84
|
+
})
|
|
85
|
+
.on("confirmation", (confirmationNumber, receipt) => {
|
|
86
|
+
callback(confirmationNumber)
|
|
87
|
+
if (confirmationNumber > 0) {
|
|
88
|
+
resolve(receipt);
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
.on("error", (err) => {
|
|
92
|
+
throw err;
|
|
93
|
+
// reject(err);
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
waitForTransactionHashToBeGenerated(userOpHash, networkConfig) {
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
const interval = setInterval(async () => {
|
|
100
|
+
const userOperation = await axios.post(`${networkConfig.bundlerRPC}/rpc?chainId=${networkConfig.chainId}`,
|
|
101
|
+
{
|
|
102
|
+
"method": "eth_getUserOperationByHash",
|
|
103
|
+
"params": [
|
|
104
|
+
userOpHash
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (userOperation.data.result && userOperation.data.result.transactionHash) {
|
|
110
|
+
clearInterval(interval);
|
|
111
|
+
resolve(userOperation.data.result.transactionHash);
|
|
112
|
+
} else if (networkConfig.bundlerAPI) {
|
|
113
|
+
let userOperationData;
|
|
114
|
+
try {
|
|
115
|
+
userOperationData = await axios.get(`${networkConfig.bundlerAPI}/user_operations/${userOpHash}`);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
// fetch should be non-blocking
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (userOperationData && userOperationData.data && userOperationData.data.status === 'failed') {
|
|
121
|
+
clearInterval(interval);
|
|
122
|
+
reject(new Error('User operation failed'));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}, 1000);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
operationDataFromCall(f) {
|
|
130
|
+
return {
|
|
131
|
+
contract: this.params.abi.contractName,
|
|
132
|
+
method: f._method.name,
|
|
133
|
+
arguments: f.arguments,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
getUserOpHash(chainId, userOp, entryPoint) {
|
|
138
|
+
const abiCoder = new ethers.utils.AbiCoder();
|
|
139
|
+
|
|
140
|
+
const userOpHash = ethers.utils.keccak256(this.packUserOp(userOp, true));
|
|
141
|
+
const enc = abiCoder.encode(['bytes32', 'address', 'uint256'], [userOpHash, entryPoint, chainId]);
|
|
142
|
+
return ethers.utils.keccak256(enc);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
packUserOp(userOp, forSignature = true) {
|
|
146
|
+
const abiCoder = new ethers.utils.AbiCoder();
|
|
147
|
+
if (forSignature) {
|
|
148
|
+
return abiCoder.encode(
|
|
149
|
+
['address', 'uint256', 'bytes32', 'bytes32', 'uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes32'],
|
|
150
|
+
[
|
|
151
|
+
userOp.sender,
|
|
152
|
+
userOp.nonce,
|
|
153
|
+
ethers.utils.keccak256(userOp.initCode),
|
|
154
|
+
ethers.utils.keccak256(userOp.callData),
|
|
155
|
+
userOp.callGasLimit,
|
|
156
|
+
userOp.verificationGasLimit,
|
|
157
|
+
userOp.preVerificationGas,
|
|
158
|
+
userOp.maxFeePerGas,
|
|
159
|
+
userOp.maxPriorityFeePerGas,
|
|
160
|
+
ethers.utils.keccak256(userOp.paymasterAndData),
|
|
161
|
+
],
|
|
162
|
+
);
|
|
163
|
+
} else {
|
|
164
|
+
// for the purpose of calculating gas cost encode also signature (and no keccak of bytes)
|
|
165
|
+
return abiCoder.encode(
|
|
166
|
+
['address', 'uint256', 'bytes', 'bytes', 'uint256', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes', 'bytes'],
|
|
167
|
+
[
|
|
168
|
+
userOp.sender,
|
|
169
|
+
userOp.nonce,
|
|
170
|
+
userOp.initCode,
|
|
171
|
+
userOp.callData,
|
|
172
|
+
userOp.callGasLimit,
|
|
173
|
+
userOp.verificationGasLimit,
|
|
174
|
+
userOp.preVerificationGas,
|
|
175
|
+
userOp.maxFeePerGas,
|
|
176
|
+
userOp.maxPriorityFeePerGas,
|
|
177
|
+
userOp.paymasterAndData,
|
|
178
|
+
userOp.signature,
|
|
179
|
+
],
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
waitForTransactionHashToBeGeneratedPimlico(userOpHash, pimlicoBundlerClient) {
|
|
185
|
+
return new Promise((resolve, reject) => {
|
|
186
|
+
const interval = setInterval(async () => {
|
|
187
|
+
const getStatusResult = await pimlicoBundlerClient.getUserOperationStatus({
|
|
188
|
+
hash: userOpHash,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
if (getStatusResult.transactionHash) {
|
|
192
|
+
clearInterval(interval);
|
|
193
|
+
resolve(getStatusResult.transactionHash);
|
|
194
|
+
}
|
|
195
|
+
}, 1000);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async usePimlicoForGaslessTransactions(f, tx, methodCallData, networkConfig, provider) {
|
|
200
|
+
const accountABI = ["function execute(address to, uint256 value, bytes data)"];
|
|
201
|
+
const account = new ethers.utils.Interface(accountABI);
|
|
202
|
+
const callData = account.encodeFunctionData("execute", [
|
|
203
|
+
tx.to,
|
|
204
|
+
ethers.constants.Zero,
|
|
205
|
+
methodCallData,
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
const publicClient = createPublicClient({
|
|
209
|
+
chain: networkConfig.viemChain,
|
|
210
|
+
transport: http(networkConfig.rpcUrl)
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const bundlerClient = createClient({
|
|
214
|
+
transport: http(`${networkConfig.pimlicoUrl}/${networkConfig.chainId}/rpc?apikey=${networkConfig.pimlicoApiKey}`),
|
|
215
|
+
chain: networkConfig.viemChain,
|
|
216
|
+
})
|
|
217
|
+
.extend(bundlerActions(ENTRYPOINT_ADDRESS_V06))
|
|
218
|
+
.extend(pimlicoBundlerActions(ENTRYPOINT_ADDRESS_V06))
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
const paymasterClient = createClient({
|
|
222
|
+
transport: http(`${networkConfig.pimlicoUrl}/${networkConfig.chainId}/rpc?apikey=${networkConfig.pimlicoApiKey}`),
|
|
223
|
+
chain: networkConfig.viemChain,
|
|
224
|
+
}).extend(pimlicoPaymasterActions(ENTRYPOINT_ADDRESS_V06))
|
|
225
|
+
|
|
226
|
+
const smartAccountSigner = await providerToSmartAccountSigner(provider);
|
|
227
|
+
|
|
228
|
+
const smartAccount = await signerToSimpleSmartAccount(publicClient, {
|
|
229
|
+
signer: smartAccountSigner,
|
|
230
|
+
factoryAddress: PolkamarketsSmartAccount.PIMLICO_FACTORY_ADDRESS,
|
|
231
|
+
entryPoint: ENTRYPOINT_ADDRESS_V06,
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
const initCode = await smartAccount.getInitCode();
|
|
235
|
+
const senderAddress = smartAccount.address;
|
|
236
|
+
|
|
237
|
+
const gasPrice = await bundlerClient.getUserOperationGasPrice()
|
|
238
|
+
|
|
239
|
+
const key = BigInt(Math.floor(Math.random() * 6277101735386680763835789423207666416102355444464034512895));
|
|
240
|
+
|
|
241
|
+
const nonce = await getAccountNonce(publicClient, {
|
|
242
|
+
sender: senderAddress,
|
|
243
|
+
entryPoint: ENTRYPOINT_ADDRESS_V06,
|
|
244
|
+
key
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
const userOperation = {
|
|
248
|
+
sender: senderAddress,
|
|
249
|
+
nonce,
|
|
250
|
+
initCode: initCode,
|
|
251
|
+
callData: callData,
|
|
252
|
+
maxFeePerGas: Number(gasPrice.fast.maxFeePerGas),
|
|
253
|
+
maxPriorityFeePerGas: Number(gasPrice.fast.maxPriorityFeePerGas),
|
|
254
|
+
signature: await smartAccount.getDummySignature(),
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const sponsorUserOperationResult = await paymasterClient.sponsorUserOperation({
|
|
258
|
+
userOperation,
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
const sponsoredUserOperation = {
|
|
262
|
+
...userOperation,
|
|
263
|
+
...sponsorUserOperationResult,
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const signature = await smartAccount.signUserOperation(sponsoredUserOperation);
|
|
267
|
+
|
|
268
|
+
sponsoredUserOperation.signature = signature;
|
|
269
|
+
|
|
270
|
+
let userOpHash = this.getUserOpHash(networkConfig.chainId, sponsoredUserOperation, ENTRYPOINT_ADDRESS_V06);
|
|
271
|
+
|
|
272
|
+
if (networkConfig.bundlerAPI) {
|
|
273
|
+
sponsoredUserOperation.nonce = ethers.BigNumber.from(sponsoredUserOperation.nonce).toHexString();
|
|
274
|
+
sponsoredUserOperation.maxFeePerGas = ethers.BigNumber.from(sponsoredUserOperation.maxFeePerGas).toHexString();
|
|
275
|
+
sponsoredUserOperation.maxPriorityFeePerGas = ethers.BigNumber.from(sponsoredUserOperation.maxPriorityFeePerGas).toHexString();
|
|
276
|
+
sponsoredUserOperation.preVerificationGas = ethers.BigNumber.from(sponsoredUserOperation.preVerificationGas).toHexString();
|
|
277
|
+
sponsoredUserOperation.verificationGasLimit = ethers.BigNumber.from(sponsoredUserOperation.verificationGasLimit).toHexString();
|
|
278
|
+
sponsoredUserOperation.callGasLimit = ethers.BigNumber.from(sponsoredUserOperation.callGasLimit).toHexString();
|
|
279
|
+
|
|
280
|
+
const txResponse = await axios.post(`${networkConfig.bundlerAPI}/user_operations`,
|
|
281
|
+
{
|
|
282
|
+
user_operation: {
|
|
283
|
+
user_operation: sponsoredUserOperation,
|
|
284
|
+
user_operation_hash: userOpHash,
|
|
285
|
+
user_operation_data: [this.operationDataFromCall(f)],
|
|
286
|
+
network_id: networkConfig.chainId,
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
if (txResponse.data.error) {
|
|
292
|
+
throw new Error(txResponse.data.error.message);
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
userOpHash = await bundlerClient.sendUserOperation({
|
|
296
|
+
userOperation: sponsoredUserOperation,
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const transactionHash = await this.waitForTransactionHashToBeGeneratedPimlico(userOpHash, bundlerClient);
|
|
301
|
+
|
|
302
|
+
const receipt = await publicClient.waitForTransactionReceipt(
|
|
303
|
+
{ hash: transactionHash }
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
return receipt;
|
|
307
|
+
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async useThirdWebForGaslessTransactions(f, tx, methodCallData, networkConfig, provider) {
|
|
311
|
+
const accountABI = ["function execute(address to, uint256 value, bytes data)"];
|
|
312
|
+
const account = new ethers.utils.Interface(accountABI);
|
|
313
|
+
const callData = account.encodeFunctionData("execute", [
|
|
314
|
+
tx.to,
|
|
315
|
+
ethers.constants.Zero,
|
|
316
|
+
methodCallData,
|
|
317
|
+
]);
|
|
318
|
+
|
|
319
|
+
const publicClient = createPublicClient({
|
|
320
|
+
chain: networkConfig.viemChain,
|
|
321
|
+
transport: http(networkConfig.rpcUrl)
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const smartAccountSigner = await providerToSmartAccountSigner(provider);
|
|
325
|
+
|
|
326
|
+
const smartAccount = await signerToSimpleSmartAccount(publicClient, {
|
|
327
|
+
signer: smartAccountSigner,
|
|
328
|
+
factoryAddress: PolkamarketsSmartAccount.PIMLICO_FACTORY_ADDRESS,
|
|
329
|
+
entryPoint: ENTRYPOINT_ADDRESS_V06,
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
const initCode = await smartAccount.getInitCode();
|
|
333
|
+
const senderAddress = smartAccount.address;
|
|
334
|
+
|
|
335
|
+
const client = createThirdwebClient({ clientId: networkConfig.thirdWebClientId });
|
|
336
|
+
|
|
337
|
+
const chain = defineChain(networkConfig.chainId);
|
|
338
|
+
|
|
339
|
+
const gasPrice = await getUserOpGasFees(
|
|
340
|
+
{
|
|
341
|
+
options: {
|
|
342
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_V06,
|
|
343
|
+
chain,
|
|
344
|
+
client,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
const key = BigInt(Math.floor(Math.random() * 6277101735386680763835789423207666416102355444464034512895));
|
|
350
|
+
|
|
351
|
+
const nonce = await getAccountNonce(publicClient, {
|
|
352
|
+
sender: senderAddress,
|
|
353
|
+
entryPoint: ENTRYPOINT_ADDRESS_V06,
|
|
354
|
+
key
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
const userOperation = {
|
|
358
|
+
sender: senderAddress,
|
|
359
|
+
nonce,
|
|
360
|
+
initCode: initCode,
|
|
361
|
+
callData: callData,
|
|
362
|
+
maxFeePerGas: Number(gasPrice.maxFeePerGas),
|
|
363
|
+
maxPriorityFeePerGas: Number(gasPrice.maxPriorityFeePerGas),
|
|
364
|
+
signature: await smartAccount.getDummySignature(),
|
|
365
|
+
paymasterAndData: '0x',
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const gasFees = await estimateUserOpGas({
|
|
369
|
+
userOp: userOperation,
|
|
370
|
+
options: {
|
|
371
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_V06,
|
|
372
|
+
chain,
|
|
373
|
+
client,
|
|
374
|
+
}
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
userOperation.verificationGasLimit = gasFees.verificationGasLimit;
|
|
378
|
+
userOperation.preVerificationGas = gasFees.preVerificationGas;
|
|
379
|
+
userOperation.callGasLimit = gasFees.callGasLimit;
|
|
380
|
+
|
|
381
|
+
const sponsorUserOperationResult = await getPaymasterAndData(
|
|
382
|
+
{
|
|
383
|
+
userOp: userOperation,
|
|
384
|
+
client,
|
|
385
|
+
chain,
|
|
386
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_V06,
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
userOperation.paymasterAndData = sponsorUserOperationResult.paymasterAndData;
|
|
391
|
+
|
|
392
|
+
if (
|
|
393
|
+
sponsorUserOperationResult.callGasLimit &&
|
|
394
|
+
sponsorUserOperationResult.verificationGasLimit &&
|
|
395
|
+
sponsorUserOperationResult.preVerificationGas
|
|
396
|
+
) {
|
|
397
|
+
userOperation.callGasLimit = sponsorUserOperationResult.callGasLimit;
|
|
398
|
+
userOperation.verificationGasLimit = sponsorUserOperationResult.verificationGasLimit;
|
|
399
|
+
userOperation.preVerificationGas = sponsorUserOperationResult.preVerificationGas;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const signedUserOp = await signUserOp({
|
|
403
|
+
userOp: userOperation,
|
|
404
|
+
chain,
|
|
405
|
+
client,
|
|
406
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_V06,
|
|
407
|
+
adminAccount: smartAccountSigner,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
let userOpHash = this.getUserOpHash(networkConfig.chainId, signedUserOp, ENTRYPOINT_ADDRESS_V06);
|
|
411
|
+
|
|
412
|
+
if (networkConfig.bundlerAPI) {
|
|
413
|
+
userOperation.nonce = ethers.BigNumber.from(userOperation.nonce).toHexString();
|
|
414
|
+
userOperation.maxFeePerGas = ethers.BigNumber.from(userOperation.maxFeePerGas).toHexString();
|
|
415
|
+
userOperation.maxPriorityFeePerGas = ethers.BigNumber.from(userOperation.maxPriorityFeePerGas).toHexString();
|
|
416
|
+
userOperation.preVerificationGas = ethers.BigNumber.from(userOperation.preVerificationGas).toHexString();
|
|
417
|
+
userOperation.verificationGasLimit = ethers.BigNumber.from(userOperation.verificationGasLimit).toHexString();
|
|
418
|
+
userOperation.callGasLimit = ethers.BigNumber.from(userOperation.callGasLimit).toHexString();
|
|
419
|
+
userOperation.signature = signedUserOp.signature;
|
|
420
|
+
|
|
421
|
+
// currently txs are not bundled in thirdweb
|
|
422
|
+
axios.post(`${networkConfig.bundlerAPI}/user_operations`,
|
|
423
|
+
{
|
|
424
|
+
user_operation: {
|
|
425
|
+
user_operation: userOperation,
|
|
426
|
+
user_operation_hash: userOpHash,
|
|
427
|
+
user_operation_data: [this.operationDataFromCall(f)],
|
|
428
|
+
network_id: networkConfig.chainId,
|
|
429
|
+
},
|
|
430
|
+
do_not_bundle: true
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
userOpHash = await bundleUserOp({
|
|
436
|
+
userOp: signedUserOp,
|
|
437
|
+
options: {
|
|
438
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_V06,
|
|
439
|
+
chain,
|
|
440
|
+
client,
|
|
441
|
+
}
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
const receipt = await waitForUserOpReceipt({
|
|
445
|
+
chain,
|
|
446
|
+
client,
|
|
447
|
+
userOpHash,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
return receipt;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async useThirdWebForGaslessTransactionsWithThirdWebAuth(f, tx, methodCallData, networkConfig, provider) {
|
|
454
|
+
|
|
455
|
+
const client = createThirdwebClient({ clientId: networkConfig.thirdWebClientId });
|
|
456
|
+
|
|
457
|
+
const chain = defineChain(networkConfig.chainId);
|
|
458
|
+
|
|
459
|
+
const factoryContract = getContract({
|
|
460
|
+
client: client,
|
|
461
|
+
address: PolkamarketsSmartAccount.THIRDWEB_FACTORY_ADDRESS,
|
|
462
|
+
chain: chain,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
const accountContract = getContract({
|
|
466
|
+
client,
|
|
467
|
+
address: provider.smartAccount.address,
|
|
468
|
+
chain,
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
const transaction = prepareContractCall({
|
|
472
|
+
contract: accountContract,
|
|
473
|
+
method: "function execute(address, uint256, bytes)",
|
|
474
|
+
params: [
|
|
475
|
+
tx.to,
|
|
476
|
+
0n,
|
|
477
|
+
tx.data,
|
|
478
|
+
],
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
const userOperation = await createUnsignedUserOp({
|
|
482
|
+
transaction,
|
|
483
|
+
factoryContract,
|
|
484
|
+
accountContract,
|
|
485
|
+
adminAddress: provider.adminAccount.address,
|
|
486
|
+
sponsorGas: true,
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
const signedUserOp = await signUserOp({
|
|
490
|
+
userOp: userOperation,
|
|
491
|
+
chain,
|
|
492
|
+
client,
|
|
493
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_V06,
|
|
494
|
+
adminAccount: provider.adminAccount,
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
let userOpHash = this.getUserOpHash(networkConfig.chainId, signedUserOp, ENTRYPOINT_ADDRESS_V06);
|
|
498
|
+
|
|
499
|
+
if (networkConfig.bundlerAPI) {
|
|
500
|
+
userOperation.nonce = ethers.BigNumber.from(userOperation.nonce).toHexString();
|
|
501
|
+
userOperation.maxFeePerGas = ethers.BigNumber.from(userOperation.maxFeePerGas).toHexString();
|
|
502
|
+
userOperation.maxPriorityFeePerGas = ethers.BigNumber.from(userOperation.maxPriorityFeePerGas).toHexString();
|
|
503
|
+
userOperation.preVerificationGas = ethers.BigNumber.from(userOperation.preVerificationGas).toHexString();
|
|
504
|
+
userOperation.verificationGasLimit = ethers.BigNumber.from(userOperation.verificationGasLimit).toHexString();
|
|
505
|
+
userOperation.callGasLimit = ethers.BigNumber.from(userOperation.callGasLimit).toHexString();
|
|
506
|
+
userOperation.signature = signedUserOp.signature;
|
|
507
|
+
|
|
508
|
+
// currently txs are not bundled in thirdweb
|
|
509
|
+
axios.post(`${networkConfig.bundlerAPI}/user_operations`,
|
|
510
|
+
{
|
|
511
|
+
user_operation: {
|
|
512
|
+
user_operation: userOperation,
|
|
513
|
+
user_operation_hash: userOpHash,
|
|
514
|
+
user_operation_data: [this.operationDataFromCall(f)],
|
|
515
|
+
network_id: networkConfig.chainId,
|
|
516
|
+
},
|
|
517
|
+
do_not_bundle: true
|
|
518
|
+
}
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
userOpHash = await bundleUserOp({
|
|
523
|
+
userOp: signedUserOp,
|
|
524
|
+
options: {
|
|
525
|
+
entrypointAddress: ENTRYPOINT_ADDRESS_V06,
|
|
526
|
+
chain,
|
|
527
|
+
client,
|
|
528
|
+
}
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
const receipt = await waitForUserOpReceipt({
|
|
532
|
+
chain,
|
|
533
|
+
client,
|
|
534
|
+
userOpHash,
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
return receipt;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async sendGaslessTransactions(f) {
|
|
541
|
+
const smartAccount = PolkamarketsSmartAccount.singleton.getInstance();
|
|
542
|
+
const networkConfig = smartAccount.networkConfig;
|
|
543
|
+
|
|
544
|
+
const { isConnectedWallet, signer } = await smartAccount.providerIsConnectedWallet();
|
|
545
|
+
|
|
546
|
+
const methodName = f._method.name;
|
|
547
|
+
|
|
548
|
+
const contractInterface = new ethers.utils.Interface(this.params.abi.abi);
|
|
549
|
+
const methodCallData = contractInterface.encodeFunctionData(methodName, f.arguments);
|
|
550
|
+
|
|
551
|
+
const tx = {
|
|
552
|
+
to: this.params.contractAddress,
|
|
553
|
+
data: methodCallData,
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
let receipt;
|
|
558
|
+
|
|
559
|
+
if (isConnectedWallet) {
|
|
560
|
+
const txResponse = await signer.sendTransaction({ ...tx, gasLimit: 210000 });
|
|
561
|
+
receipt = await txResponse.wait();
|
|
562
|
+
} else {
|
|
563
|
+
|
|
564
|
+
if (networkConfig.usePimlico) {
|
|
565
|
+
receipt = await this.usePimlicoForGaslessTransactions(f, tx, methodCallData, networkConfig, smartAccount.provider);
|
|
566
|
+
} else if (networkConfig.useThirdWeb) {
|
|
567
|
+
if (smartAccount.provider.adminAccount) {
|
|
568
|
+
// if exists adminAccount it means it's using thirdwebauth
|
|
569
|
+
receipt = await this.useThirdWebForGaslessTransactionsWithThirdWebAuth(f, tx, methodCallData, networkConfig, smartAccount.provider);
|
|
570
|
+
} else {
|
|
571
|
+
receipt = await this.useThirdWebForGaslessTransactions(f, tx, methodCallData, networkConfig, smartAccount.provider);
|
|
572
|
+
}
|
|
573
|
+
} else {
|
|
574
|
+
// trying operation 3 times
|
|
575
|
+
const retries = 3;
|
|
576
|
+
let feeQuotesResult;
|
|
577
|
+
for (let i = 0; i < retries; i++) {
|
|
578
|
+
try {
|
|
579
|
+
feeQuotesResult = await smartAccount.smartAccount.getFeeQuotes(tx);
|
|
580
|
+
break;
|
|
581
|
+
} catch (error) {
|
|
582
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
583
|
+
|
|
584
|
+
if (i === retries - 1) {
|
|
585
|
+
throw error;
|
|
586
|
+
} else {
|
|
587
|
+
// 1s interval between retries
|
|
588
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
let userOp = feeQuotesResult.verifyingPaymasterGasless.userOp;
|
|
594
|
+
let userOpHash = feeQuotesResult.verifyingPaymasterGasless.userOpHash;
|
|
595
|
+
|
|
596
|
+
// Get random key
|
|
597
|
+
const key = BigInt(Math.floor(Math.random() * 6277101735386680763835789423207666416102355444464034512895));
|
|
598
|
+
|
|
599
|
+
const entrypointAbi = [
|
|
600
|
+
"function getNonce(address sender, uint192 key) view returns (uint256)",
|
|
601
|
+
];
|
|
602
|
+
|
|
603
|
+
const ethersProvider = new ethers.providers.JsonRpcProvider(this.params.web3.currentProvider.host);
|
|
604
|
+
|
|
605
|
+
const entrypointContract = new ethers.Contract(ENTRYPOINT_ADDRESS_V06, entrypointAbi, ethersProvider);
|
|
606
|
+
|
|
607
|
+
const senderAddress = await smartAccount.getAddress();
|
|
608
|
+
|
|
609
|
+
const nonce = await entrypointContract.getNonce(senderAddress, key);
|
|
610
|
+
|
|
611
|
+
userOp.nonce = nonce.toHexString();
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
const paymasterSponsorData = await axios.post(`https://paymaster.particle.network`,
|
|
615
|
+
{
|
|
616
|
+
|
|
617
|
+
"method": "pm_sponsorUserOperation",
|
|
618
|
+
"params": [
|
|
619
|
+
userOp,
|
|
620
|
+
ENTRYPOINT_ADDRESS_V06,
|
|
621
|
+
]
|
|
622
|
+
}, {
|
|
623
|
+
params: {
|
|
624
|
+
chainId: networkConfig.chainId,
|
|
625
|
+
projectUuid: networkConfig.particleProjectId,
|
|
626
|
+
projectKey: networkConfig.particleClientKey,
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
userOp.paymasterAndData = paymasterSponsorData.data.result.paymasterAndData;
|
|
633
|
+
|
|
634
|
+
userOpHash = this.getUserOpHash(networkConfig.chainId, userOp, ENTRYPOINT_ADDRESS_V06);
|
|
635
|
+
|
|
636
|
+
const signedUserOp = await smartAccount.smartAccount.signUserOperation({ userOpHash, userOp });
|
|
637
|
+
|
|
638
|
+
let txResponse;
|
|
639
|
+
for (let i = 0; i < retries; i++) {
|
|
640
|
+
try {
|
|
641
|
+
if (networkConfig.bundlerAPI) {
|
|
642
|
+
txResponse = await axios.post(`${networkConfig.bundlerAPI}/user_operations`,
|
|
643
|
+
{
|
|
644
|
+
user_operation: {
|
|
645
|
+
user_operation: signedUserOp,
|
|
646
|
+
user_operation_hash: userOpHash,
|
|
647
|
+
user_operation_data: [this.operationDataFromCall(f)],
|
|
648
|
+
network_id: networkConfig.chainId,
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
} else {
|
|
653
|
+
txResponse = await axios.post(`${networkConfig.bundlerRPC}/rpc?chainId=${networkConfig.chainId}`,
|
|
654
|
+
{
|
|
655
|
+
|
|
656
|
+
"method": "eth_sendUserOperation",
|
|
657
|
+
"params": [
|
|
658
|
+
signedUserOp,
|
|
659
|
+
ENTRYPOINT_ADDRESS_V06
|
|
660
|
+
]
|
|
661
|
+
}
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (!txResponse.data.error) break;
|
|
666
|
+
} catch (error) {
|
|
667
|
+
if (i === retries - 1) {
|
|
668
|
+
throw error;
|
|
669
|
+
} else {
|
|
670
|
+
// 1s interval between retries
|
|
671
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (txResponse.data.error) {
|
|
677
|
+
throw new Error(txResponse.data.error.message);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const transactionHash = await this.waitForTransactionHashToBeGenerated(userOpHash, networkConfig);
|
|
681
|
+
|
|
682
|
+
const web3Provider = new ethers.providers.Web3Provider(smartAccount.provider)
|
|
683
|
+
|
|
684
|
+
receipt = await web3Provider.waitForTransaction(transactionHash);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
console.log('receipt:', receipt.status, receipt.transactionHash);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
if (receipt.logs) {
|
|
691
|
+
const events = receipt.logs.map(log => {
|
|
692
|
+
try {
|
|
693
|
+
const event = contractInterface.parseLog(log);
|
|
694
|
+
return event;
|
|
695
|
+
} catch (error) {
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
receipt.events = this.convertEtherEventsToWeb3Events(events);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return receipt;
|
|
703
|
+
} catch (error) {
|
|
704
|
+
console.error(error);
|
|
705
|
+
throw error;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
convertEtherEventsToWeb3Events(events) {
|
|
710
|
+
const transformedEvents = {};
|
|
711
|
+
for (const event of events) {
|
|
712
|
+
if (!event) {
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const { name, args, eventFragment } = event;
|
|
717
|
+
|
|
718
|
+
const returnValues = {};
|
|
719
|
+
|
|
720
|
+
eventFragment.inputs.forEach((input, index) => {
|
|
721
|
+
let value = args[index];
|
|
722
|
+
|
|
723
|
+
// if value is a BigNumber, convert it to a string
|
|
724
|
+
if (ethers.BigNumber.isBigNumber(value)) {
|
|
725
|
+
value = value.toString();
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
returnValues[input.name] = value;
|
|
729
|
+
returnValues[index.toString()] = value;
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
const transformedEvent = {
|
|
733
|
+
event: name,
|
|
734
|
+
returnValues,
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
if (!transformedEvents[name]) {
|
|
738
|
+
transformedEvents[name] = [];
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
transformedEvents[name].push(transformedEvent);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
return transformedEvents;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
async __sendTx(f, call = false, value, callback = () => { }) {
|
|
748
|
+
if (this.params.isSocialLogin && !call) {
|
|
749
|
+
return await this.sendGaslessTransactions(f);
|
|
750
|
+
} else {
|
|
751
|
+
var res;
|
|
752
|
+
if (!this.acc && !call) {
|
|
753
|
+
const accounts = await this.params.web3.eth.getAccounts();
|
|
754
|
+
res = await this.__metamaskCall({ f, acc: accounts[0], value, callback });
|
|
755
|
+
} else if (this.acc && !call) {
|
|
756
|
+
let data = f.encodeABI();
|
|
757
|
+
res = await this.params.contract.send(
|
|
758
|
+
this.acc.getAccount(),
|
|
759
|
+
data,
|
|
760
|
+
value
|
|
761
|
+
).catch(err => { throw err; });
|
|
762
|
+
} else if (this.acc && call) {
|
|
763
|
+
res = await f.call({ from: this.acc.getAddress() }).catch(err => { throw err; });
|
|
764
|
+
} else {
|
|
765
|
+
res = await f.call().catch(err => { throw err; });
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
if (res.logs) {
|
|
769
|
+
const contractInterface = new ethers.utils.Interface(this.params.abi.abi);
|
|
770
|
+
|
|
771
|
+
const events = res.logs.map(log => {
|
|
772
|
+
try {
|
|
773
|
+
const event = contractInterface.parseLog(log);
|
|
774
|
+
return event;
|
|
775
|
+
} catch (error) {
|
|
776
|
+
return null;
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
res.events = this.convertEtherEventsToWeb3Events(events);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
return res;
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
async __deploy(params, callback) {
|
|
788
|
+
return await this.params.contract.deploy(
|
|
789
|
+
this.acc,
|
|
790
|
+
this.params.contract.getABI(),
|
|
791
|
+
this.params.contract.getJSON().bytecode,
|
|
792
|
+
params,
|
|
793
|
+
callback
|
|
794
|
+
);
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
async __assert() {
|
|
798
|
+
if (!this.getAddress()) {
|
|
799
|
+
throw new Error("Contract is not deployed, first deploy it and provide a contract address");
|
|
800
|
+
}
|
|
801
|
+
/* Use ABI */
|
|
802
|
+
this.params.contract.use(this.params.abi, this.getAddress());
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* @function deploy
|
|
807
|
+
* @description Deploy the Contract
|
|
808
|
+
*/
|
|
809
|
+
async deploy({ callback, params = [] }) {
|
|
810
|
+
let res = await this.__deploy(params, callback);
|
|
811
|
+
this.params.contractAddress = res.contractAddress;
|
|
812
|
+
/* Call to Backend API */
|
|
813
|
+
await this.__assert();
|
|
814
|
+
return res;
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* @function setNewOwner
|
|
820
|
+
* @description Set New Owner of the Contract
|
|
821
|
+
* @param {string} address
|
|
822
|
+
*/
|
|
823
|
+
async setNewOwner({ address }) {
|
|
824
|
+
return await this.__sendTx(
|
|
825
|
+
this.params.contract
|
|
826
|
+
.getContract()
|
|
827
|
+
.methods.transferOwnership(address)
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* @function owner
|
|
833
|
+
* @description Get Owner of the Contract
|
|
834
|
+
* @returns {string} address
|
|
835
|
+
*/
|
|
836
|
+
|
|
837
|
+
async owner() {
|
|
838
|
+
return await this.params.contract.getContract().methods.owner().call();
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* @function isPaused
|
|
843
|
+
* @description Get Owner of the Contract
|
|
844
|
+
* @returns {boolean}
|
|
845
|
+
*/
|
|
846
|
+
|
|
847
|
+
async isPaused() {
|
|
848
|
+
return await this.params.contract.getContract().methods.paused().call();
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* @function pauseContract
|
|
853
|
+
* @type admin
|
|
854
|
+
* @description Pause Contract
|
|
855
|
+
*/
|
|
856
|
+
async pauseContract() {
|
|
857
|
+
return await this.__sendTx(
|
|
858
|
+
this.params.contract.getContract().methods.pause()
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* @function unpauseContract
|
|
864
|
+
* @type admin
|
|
865
|
+
* @description Unpause Contract
|
|
866
|
+
*/
|
|
867
|
+
async unpauseContract() {
|
|
868
|
+
return await this.__sendTx(
|
|
869
|
+
this.params.contract.getContract().methods.unpause()
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/* Optional */
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* @function removeOtherERC20Tokens
|
|
877
|
+
* @description Remove Tokens from other ERC20 Address (in case of accident)
|
|
878
|
+
* @param {Address} tokenAddress
|
|
879
|
+
* @param {Address} toAddress
|
|
880
|
+
*/
|
|
881
|
+
async removeOtherERC20Tokens({ tokenAddress, toAddress }) {
|
|
882
|
+
return await this.__sendTx(
|
|
883
|
+
this.params.contract
|
|
884
|
+
.getContract()
|
|
885
|
+
.methods.removeOtherERC20Tokens(tokenAddress, toAddress)
|
|
886
|
+
);
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* @function safeGuardAllTokens
|
|
891
|
+
* @description Remove all tokens for the sake of bug or problem in the smart contract, contract has to be paused first, only Admin
|
|
892
|
+
* @param {Address} toAddress
|
|
893
|
+
*/
|
|
894
|
+
async safeGuardAllTokens({ toAddress }) {
|
|
895
|
+
return await this.__sendTx(
|
|
896
|
+
this.params.contract
|
|
897
|
+
.getContract()
|
|
898
|
+
.methods.safeGuardAllTokens(toAddress)
|
|
899
|
+
);
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* @function changeTokenAddress
|
|
904
|
+
* @description Change Token Address of Application
|
|
905
|
+
* @param {Address} newTokenAddress
|
|
906
|
+
*/
|
|
907
|
+
async changeTokenAddress({ newTokenAddress }) {
|
|
908
|
+
return await this.__sendTx(
|
|
909
|
+
this.params.contract
|
|
910
|
+
.getContract()
|
|
911
|
+
.methods.changeTokenAddress(newTokenAddress)
|
|
912
|
+
);
|
|
913
|
+
};
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* @function getAddress
|
|
917
|
+
* @description Get Balance of Contract
|
|
918
|
+
* @param {Integer} Balance
|
|
919
|
+
*/
|
|
920
|
+
getAddress() {
|
|
921
|
+
return this.params.contractAddress;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* @function getContract
|
|
926
|
+
* @description Gets Contract
|
|
927
|
+
* @return {Contract} Contract
|
|
928
|
+
*/
|
|
929
|
+
getContract() {
|
|
930
|
+
return this.params.contract.getContract();
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* @function getBalance
|
|
935
|
+
* @description Get Balance of Contract
|
|
936
|
+
* @param {Integer} Balance
|
|
937
|
+
*/
|
|
938
|
+
|
|
939
|
+
async getBalance() {
|
|
940
|
+
let wei = await this.web3.eth.getBalance(this.getAddress());
|
|
941
|
+
return this.web3.utils.fromWei(wei, 'ether');
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* @function getMyAccount
|
|
946
|
+
* @description Returns connected wallet account address
|
|
947
|
+
* @returns {String | undefined} address
|
|
948
|
+
*/
|
|
949
|
+
async getMyAccount() {
|
|
950
|
+
if (this.params.isSocialLogin) {
|
|
951
|
+
const smartAccount = PolkamarketsSmartAccount.singleton.getInstance();
|
|
952
|
+
return await smartAccount.getAddress();
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (this.acc) {
|
|
956
|
+
return this.acc.getAddress()
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const accounts = await this.params.web3.eth.getAccounts();
|
|
960
|
+
|
|
961
|
+
return accounts[0];
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* @function getEvents
|
|
966
|
+
* @description Gets contract events
|
|
967
|
+
* @returns {String | undefined} address
|
|
968
|
+
*/
|
|
969
|
+
async getEvents(event, filter, fromBlock = null, toBlock = 'latest') {
|
|
970
|
+
if (!fromBlock) {
|
|
971
|
+
fromBlock = this.params.startBlock || 0;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (!this.params.web3EventsProvider) {
|
|
975
|
+
const events = this.getContract().getPastEvents(event, {
|
|
976
|
+
fromBlock,
|
|
977
|
+
toBlock,
|
|
978
|
+
filter
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
return events;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// getting events via http from web3 events provide
|
|
985
|
+
let uri = `${this.params.web3EventsProvider}/events?contract=${this.contractName}&address=${this.getAddress()}&eventName=${event}`
|
|
986
|
+
if (filter) uri = uri.concat(`&filter=${JSON.stringify(filter)}`);
|
|
987
|
+
|
|
988
|
+
const { data } = await axios.get(uri);
|
|
989
|
+
return data;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* @function getBlock
|
|
994
|
+
* @description Gets block details
|
|
995
|
+
* @returns {Object} block
|
|
996
|
+
*/
|
|
997
|
+
async getBlock(blockNumber) {
|
|
998
|
+
return await this.params.web3.eth.getBlock(blockNumber);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
module.exports = IContract;
|