polkamarkets-js 1.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 -422
@@ -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;