@instadapp/interop-x 0.0.0-dev.6ea4ee5 → 0.0.0-dev.73da8c9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. package/bin/interop-x +1 -1
  2. package/dist/package.json +72 -0
  3. package/dist/{abi → src/abi}/erc20.json +0 -0
  4. package/dist/{abi → src/abi}/gnosisSafe.json +0 -0
  5. package/dist/{abi → src/abi}/index.js +0 -0
  6. package/dist/{abi → src/abi}/interopBridgeToken.json +0 -0
  7. package/dist/{abi → src/abi}/interopXGateway.json +0 -0
  8. package/dist/src/api/index.js +33 -0
  9. package/dist/{config → src/config}/index.js +0 -0
  10. package/dist/{constants → src/constants}/addresses.js +0 -8
  11. package/dist/{constants → src/constants}/index.js +1 -0
  12. package/dist/src/constants/itokens.js +13 -0
  13. package/dist/{constants → src/constants}/tokens.js +0 -0
  14. package/dist/{db → src/db}/index.js +0 -0
  15. package/dist/{db → src/db}/models/index.js +0 -0
  16. package/dist/{db → src/db}/models/transaction.js +3 -1
  17. package/dist/{db → src/db}/sequelize.js +1 -1
  18. package/dist/{index.js → src/index.js} +5 -0
  19. package/dist/{logger → src/logger}/index.js +0 -0
  20. package/dist/{net → src/net}/index.js +0 -0
  21. package/dist/{net → src/net}/peer/index.js +6 -2
  22. package/dist/{net → src/net}/pool/index.js +16 -9
  23. package/dist/{net → src/net}/protocol/dial/BaseDialProtocol.js +0 -0
  24. package/dist/{net → src/net}/protocol/dial/SignatureDialProtocol.js +15 -12
  25. package/dist/{net → src/net}/protocol/index.js +0 -0
  26. package/dist/{tasks → src/tasks}/BaseTask.js +1 -1
  27. package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +158 -0
  28. package/dist/{tasks → src/tasks}/InteropXGateway/SyncDepositEvents.js +15 -19
  29. package/dist/{tasks → src/tasks}/index.js +4 -0
  30. package/dist/{typechain → src/typechain}/Erc20.js +0 -0
  31. package/dist/{typechain → src/typechain}/GnosisSafe.js +0 -0
  32. package/dist/{typechain → src/typechain}/InteropBridgeToken.js +0 -0
  33. package/dist/{typechain → src/typechain}/InteropXGateway.js +0 -0
  34. package/dist/{typechain → src/typechain}/common.js +0 -0
  35. package/dist/{typechain → src/typechain}/factories/Erc20__factory.js +0 -0
  36. package/dist/{typechain → src/typechain}/factories/GnosisSafe__factory.js +0 -0
  37. package/dist/{typechain → src/typechain}/factories/InteropBridgeToken__factory.js +0 -0
  38. package/dist/{typechain → src/typechain}/factories/InteropXGateway__factory.js +0 -0
  39. package/dist/{typechain → src/typechain}/factories/index.js +0 -0
  40. package/dist/{typechain → src/typechain}/index.js +0 -0
  41. package/dist/{types.js → src/types.js} +0 -0
  42. package/dist/src/utils/index.js +178 -0
  43. package/package.json +10 -4
  44. package/patches/@ethersproject+properties+5.6.0.patch +13 -0
  45. package/src/api/index.ts +33 -0
  46. package/src/constants/addresses.ts +0 -8
  47. package/src/constants/index.ts +1 -0
  48. package/src/constants/itokens.ts +10 -0
  49. package/src/db/models/transaction.ts +8 -4
  50. package/src/db/sequelize.ts +1 -1
  51. package/src/index.ts +7 -0
  52. package/src/net/peer/index.ts +7 -6
  53. package/src/net/pool/index.ts +20 -10
  54. package/src/net/protocol/dial/SignatureDialProtocol.ts +17 -13
  55. package/src/tasks/BaseTask.ts +1 -1
  56. package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +253 -0
  57. package/src/tasks/InteropXGateway/SyncDepositEvents.ts +22 -10
  58. package/src/tasks/index.ts +7 -2
  59. package/src/utils/index.ts +113 -4
  60. package/dist/utils/index.js +0 -101
@@ -0,0 +1,253 @@
1
+ import { BaseTask } from "../BaseTask";
2
+ import Logger from '@/logger';
3
+ import { BigNumber, ethers } from "ethers";
4
+ import abi from "@/abi";
5
+ import { Transaction } from "@/db";
6
+ import { buildDataForTransaction, buildSignatureBytes, getContract, getRpcProviderUrl, Signature } from "@/utils";
7
+ import { addresses } from "@/constants";
8
+ import { ChainId } from "@/types";
9
+ import config from "@/config";
10
+ import { GnosisSafe, InteropXGateway } from "@/typechain";
11
+ import { Op } from "sequelize";
12
+ import wait from "waait";
13
+ import { peerPool, protocol } from "@/net";
14
+ import { LogDescription } from "ethers/lib/utils";
15
+
16
+ const generateGnosisTransaction = async (transactionData: any, safeContract: GnosisSafe) => {
17
+ console.log(transactionData);
18
+
19
+ let isExecuted = await safeContract.dataHashes(
20
+ await safeContract.getTransactionHash(
21
+ transactionData.to,
22
+ transactionData.value,
23
+ transactionData.data,
24
+ transactionData.operation,
25
+ transactionData.safeTxGas,
26
+ transactionData.baseGas,
27
+ transactionData.gasPrice,
28
+ transactionData.gasToken,
29
+ transactionData.refundReceiver,
30
+ transactionData.nonce
31
+ )
32
+ )
33
+
34
+ while (isExecuted == 1) {
35
+ transactionData.safeTxGas = BigNumber.from(String(transactionData.safeTxGas)).add(1).toString()
36
+
37
+ isExecuted = await safeContract.dataHashes(
38
+ await safeContract.getTransactionHash(
39
+ transactionData.to,
40
+ transactionData.value,
41
+ transactionData.data,
42
+ transactionData.operation,
43
+ transactionData.safeTxGas,
44
+ transactionData.baseGas,
45
+ transactionData.gasPrice,
46
+ transactionData.gasToken,
47
+ transactionData.refundReceiver,
48
+ transactionData.nonce
49
+ )
50
+ )
51
+ }
52
+
53
+ return transactionData
54
+ }
55
+
56
+ class ProcessDepositEvents extends BaseTask {
57
+ contractAddress: string;
58
+ provider: ethers.providers.JsonRpcProvider;
59
+ contract: InteropXGateway;
60
+ chainId: ChainId;
61
+ leadNodeOnly = true
62
+
63
+ constructor({ chainId }: { chainId: ChainId }) {
64
+ super({
65
+ logger: new Logger("InteropXGateway::ProcessDepositEvents"),
66
+ })
67
+ this.chainId = chainId;
68
+ }
69
+
70
+ async pollHandler() {
71
+ const blockNumber = await this.provider.getBlockNumber()
72
+
73
+ const transaction = await Transaction.findOne({
74
+ where: {
75
+ status: 'pending',
76
+ sourceStatus: 'success',
77
+ targetStatus: 'uninitialised',
78
+ action: 'deposit',
79
+ sourceCreatedAt: {
80
+ [Op.gte]: new Date(Date.now() - 12 * 60 * 60 * 1000),
81
+ },
82
+ targetDelayUntil: {
83
+ [Op.or]: {
84
+ [Op.is]: null,
85
+ [Op.lt]: new Date(),
86
+ }
87
+ },
88
+ sourceBlockNumber: {
89
+ [Op.lt]: blockNumber - 12,
90
+ },
91
+ sourceChainId: this.chainId,
92
+ }
93
+ })
94
+
95
+ if (!transaction) {
96
+ return;
97
+ }
98
+
99
+
100
+ transaction.targetStatus = 'pending';
101
+ await transaction.save();
102
+
103
+
104
+ // refresh event data?
105
+
106
+ const targetChainProvider = new ethers.providers.JsonRpcProvider(
107
+ getRpcProviderUrl(transaction.targetChainId as ChainId)
108
+ );
109
+
110
+ const targetWallet = new ethers.Wallet(config.privateKey!, targetChainProvider);
111
+
112
+ const safeAddress = addresses[transaction.targetChainId].gnosisSafe;
113
+
114
+
115
+ const safeContract = getContract<GnosisSafe>(
116
+ safeAddress,
117
+ abi.gnosisSafe,
118
+ targetWallet
119
+ )
120
+
121
+ const ownersThreshold = await safeContract.getThreshold();
122
+ await wait(10000);
123
+
124
+ let gnosisTx = await generateGnosisTransaction({
125
+ baseGas: "0",
126
+ data: await buildDataForTransaction(transaction),
127
+ gasPrice: "0",
128
+ gasToken: "0x0000000000000000000000000000000000000000",
129
+ nonce: '0',
130
+ operation: "1",
131
+ refundReceiver: "0x0000000000000000000000000000000000000000",
132
+ safeAddress: safeAddress,
133
+ safeTxGas: "79668",
134
+ to: addresses[transaction.targetChainId].multisend,
135
+ value: "0",
136
+ }, safeContract);
137
+
138
+ const owners = await safeContract.getOwners().then(owners => owners.map(owner => owner.toLowerCase()));
139
+
140
+ const ownerPeerIds = peerPool.activePeers.filter(peer => owners.includes(peer.publicAddress.toLowerCase())).map(peer => peer.id)
141
+
142
+ console.log(`Collecting signatures for execution ${transaction.transactionHash}`)
143
+
144
+ console.log(ownerPeerIds);
145
+
146
+ const signatures = await protocol.requestSignatures({
147
+ type: 'source',
148
+ transactionHash: transaction.transactionHash,
149
+ safeTxGas: gnosisTx.safeTxGas,
150
+ safeNonce: gnosisTx.nonce
151
+ }, ownerPeerIds)
152
+
153
+
154
+ const validSignatures = signatures.filter(s => !!s.data && s.data !== '0x') as Signature[];
155
+
156
+ console.log({ signatures, validSignatures, ownersThreshold: ownersThreshold.toString() });
157
+
158
+ if (validSignatures.length === 0 || ownersThreshold.gt(validSignatures.length)) {
159
+ await transaction.save();
160
+ transaction.targetDelayUntil = new Date(Date.now() + 30 * 1000);
161
+ transaction.targetStatus = 'uninitialised'
162
+
163
+ await transaction.save();
164
+ const errorMessage = signatures.find(s => !!s.error)?.error;
165
+ throw new Error(`Not enough signatures` + (errorMessage ? `: ${errorMessage}` : ''));
166
+ }
167
+
168
+ const execTransactionParams = [
169
+ gnosisTx.to,
170
+ gnosisTx.value,
171
+ gnosisTx.data,
172
+ gnosisTx.operation,
173
+ gnosisTx.safeTxGas,
174
+ gnosisTx.baseGas,
175
+ gnosisTx.gasPrice,
176
+ gnosisTx.gasToken,
177
+ gnosisTx.refundReceiver,
178
+ buildSignatureBytes(validSignatures),
179
+ ];
180
+
181
+ console.log(`Executing transaction for execution ${transaction.transactionHash}`)
182
+
183
+ console.log({
184
+ execTransactionParams
185
+ })
186
+
187
+ const { data: txData } = await safeContract.populateTransaction.execTransaction(
188
+ gnosisTx.to,
189
+ gnosisTx.value,
190
+ gnosisTx.data,
191
+ gnosisTx.operation,
192
+ gnosisTx.safeTxGas,
193
+ gnosisTx.baseGas,
194
+ gnosisTx.gasPrice,
195
+ gnosisTx.gasToken,
196
+ gnosisTx.refundReceiver,
197
+ buildSignatureBytes(validSignatures)
198
+ );
199
+
200
+ console.log({
201
+ from: targetWallet.address,
202
+ gasPrice: BigNumber.from(120 * 10 ** 9).toString(),
203
+ gasLimit: BigNumber.from(6_000_000).toString(),
204
+ to: safeAddress,
205
+ data: txData,
206
+ })
207
+ return;
208
+
209
+ const txSent = await targetWallet.sendTransaction({
210
+ from: targetWallet.address,
211
+ gasPrice: BigNumber.from(120 * 10 ** 9),
212
+ gasLimit: BigNumber.from(6_000_000),
213
+ to: safeAddress,
214
+ data: txData,
215
+ })
216
+
217
+ const receipt = await txSent.wait();
218
+
219
+ const parsedLogs: LogDescription[] = [];
220
+
221
+ receipt.logs.forEach((log) => {
222
+ try {
223
+ parsedLogs.push(safeContract.interface.parseLog(log));
224
+ } catch (e) { }
225
+ });
226
+
227
+ if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
228
+ console.log('ExecutionSuccess')
229
+ } else {
230
+ console.log('ExecutionFailure')
231
+ }
232
+ }
233
+
234
+ async start(): Promise<void> {
235
+ this.logger.info(`Starting execution watcher on interop chain`);
236
+
237
+ this.contractAddress = addresses[this.chainId].interopXGateway;
238
+
239
+ this.provider = new ethers.providers.JsonRpcProvider(
240
+ getRpcProviderUrl(this.chainId)
241
+ );
242
+
243
+ this.contract = getContract<InteropXGateway>(
244
+ this.contractAddress,
245
+ abi.interopXGateway,
246
+ new ethers.Wallet(config.privateKey!, this.provider)
247
+ );
248
+
249
+ await super.start()
250
+ }
251
+ }
252
+
253
+ export default ProcessDepositEvents;
@@ -3,7 +3,7 @@ import Logger from '@/logger';
3
3
  import { ethers } from "ethers";
4
4
  import abi from "@/abi";
5
5
  import { Transaction } from "@/db";
6
- import { generateInteropTransactionHash, getRpcProviderUrl } from "@/utils";
6
+ import { generateInteropTransactionHash, getContract, getRpcProviderUrl } from "@/utils";
7
7
  import { addresses } from "@/constants";
8
8
  import { ChainId } from "@/types";
9
9
  import config from "@/config";
@@ -43,8 +43,8 @@ class SyncDepositEvents extends BaseTask {
43
43
  const { sourceChainId, targetChainId, user, vnonce, amount, token } = event.args;
44
44
 
45
45
  const uniqueIdentifier = {
46
- type: 'desposit',
47
- sourceTransactionHash: event.transactionHash,
46
+ action: 'deposit',
47
+ submitTransactionHash: event.transactionHash,
48
48
  sourceChainId: sourceChainId.toNumber(),
49
49
  targetChainId: targetChainId.toNumber(),
50
50
  }
@@ -56,17 +56,20 @@ class SyncDepositEvents extends BaseTask {
56
56
  const tx = await event.getTransaction()
57
57
 
58
58
  await Transaction.create({
59
+ ...uniqueIdentifier,
59
60
  transactionHash: generateInteropTransactionHash(uniqueIdentifier),
60
- type: 'deposit',
61
61
  from: tx.from,
62
62
  to: user,
63
63
 
64
- sourceChainId: sourceChainId.toNumber(),
64
+
65
+ submitTransactionHash: event.transactionHash,
66
+ submitBlockNumber: event.blockNumber,
67
+
68
+ // submit & source are the same
65
69
  sourceTransactionHash: event.transactionHash,
66
70
  sourceBlockNumber: event.blockNumber,
67
- sourceStatus: "uninitialised",
71
+ sourceStatus: "success",
68
72
 
69
- targetChainId: targetChainId.toNumber(),
70
73
  targetStatus: "uninitialised",
71
74
 
72
75
  submitEvent: {
@@ -74,7 +77,16 @@ class SyncDepositEvents extends BaseTask {
74
77
  sourceChainId: sourceChainId.toString(),
75
78
  targetChainId: targetChainId.toString(),
76
79
  token: token,
77
- ammout: amount.toString(),
80
+ amount: amount.toString(),
81
+ vnonce: vnonce.toString(),
82
+ },
83
+
84
+ sourceEvent: {
85
+ user,
86
+ sourceChainId: sourceChainId.toString(),
87
+ targetChainId: targetChainId.toString(),
88
+ token: token,
89
+ amount: amount.toString(),
78
90
  vnonce: vnonce.toString(),
79
91
  },
80
92
  status: "pending",
@@ -101,11 +113,11 @@ class SyncDepositEvents extends BaseTask {
101
113
  getRpcProviderUrl(this.chainId)
102
114
  );
103
115
 
104
- this.contract = new ethers.Contract(
116
+ this.contract = getContract<InteropXGateway>(
105
117
  this.contractAddress,
106
118
  abi.interopXGateway,
107
119
  new ethers.Wallet(config.privateKey!, this.provider)
108
- ) as InteropXGateway;
120
+ );
109
121
 
110
122
  await super.start()
111
123
  }
@@ -1,10 +1,15 @@
1
1
  import { BaseTask } from "./BaseTask";
2
- import SyncInteropXGatewayDepositEvents from "./InteropXGateway/SyncDepositEvents";
2
+ import InteropXGatewayProcessDepositEvents from "./InteropXGateway/ProcessDepositEvents";
3
+ import InteropXGatewaySyncDepositEvents from "./InteropXGateway/SyncDepositEvents";
3
4
 
4
5
  export class Tasks {
5
6
 
6
7
  tasks: BaseTask[] = [
7
- new SyncInteropXGatewayDepositEvents({
8
+ new InteropXGatewaySyncDepositEvents({
9
+ chainId: 43114
10
+ }),
11
+
12
+ new InteropXGatewayProcessDepositEvents({
8
13
  chainId: 43114
9
14
  })
10
15
  ];
@@ -3,9 +3,14 @@
3
3
  */
4
4
  import axios from 'axios'
5
5
  import axiosRetry from "axios-retry";
6
- import { addresses } from '@/constants';
6
+ import { addresses, itokens, tokens } from '@/constants';
7
7
  import { ChainId } from '@/types'
8
8
  import { ethers } from 'ethers';
9
+ import { encodeMulti, MetaTransaction, OperationType } from 'ethers-multisend';
10
+ import { Transaction } from '@/db';
11
+ import config from '@/config';
12
+ import abi from '@/abi';
13
+ import { InteropBridgeToken } from '@/typechain';
9
14
 
10
15
  export const http = axios.create();
11
16
 
@@ -119,11 +124,115 @@ export const asyncCallWithTimeout = async <T>(asyncPromise: Promise<T>, timeout:
119
124
  }
120
125
 
121
126
 
122
- export const generateInteropTransactionHash = (data: { type: string, sourceTransactionHash: string, sourceChainId: string | number, targetChainId: string | number }) => {
127
+ export const generateInteropTransactionHash = (data: { action: string, submitTransactionHash: string, sourceChainId: string | number, targetChainId: string | number }) => {
123
128
  return ethers.utils.solidityKeccak256(['string', 'string', 'string', 'string'], [
124
- String(data.type),
125
- String(data.sourceTransactionHash),
129
+ String(data.action),
130
+ String(data.submitTransactionHash),
126
131
  String(data.sourceChainId),
127
132
  String(data.targetChainId),
128
133
  ]);
134
+ }
135
+
136
+ export const buildDataForTransaction = async (transaction: Transaction, type?: 'source' | 'target') => {
137
+ type = type || transaction.sourceStatus === 'pending' ? 'source' : 'target';
138
+
139
+ const transactions: MetaTransaction[] = [];
140
+
141
+ if (transaction.action != 'deposit') {
142
+ throw new Error('Invalid action');
143
+ }
144
+
145
+ if (transaction.action === 'deposit' && transaction.sourceStatus === 'pending') {
146
+ throw Error('Cannot build data for pending deposit transaction');
147
+ }
148
+
149
+ if (!transaction.submitEvent) {
150
+ throw Error('Cannot build data for transaction without submitEvent');
151
+ }
152
+
153
+
154
+ const token = tokens[transaction.sourceChainId].find(token => token.address.toLowerCase() === transaction.submitEvent.token.toLowerCase());
155
+
156
+ if (!token) {
157
+ throw Error('Cannot build data for transaction without token');
158
+ }
159
+
160
+ const itoken = itokens[transaction.targetChainId].find(itoken => itoken.symbol.toLowerCase() === token.symbol.toLowerCase());
161
+
162
+ if (!itoken) {
163
+ throw Error('Cannot build data for transaction without itoken');
164
+ }
165
+
166
+ const targetChainProvider = new ethers.providers.JsonRpcProvider(getRpcProviderUrl(transaction.targetChainId as ChainId));
167
+ const targetWallet = new ethers.Wallet(config.privateKey, targetChainProvider);
168
+ const interopBridgeContract = getContract<InteropBridgeToken>(itoken.address, abi.interopBridgeToken, targetWallet);
169
+
170
+ const { data } = await interopBridgeContract.populateTransaction.mint(
171
+ transaction.submitEvent.user,
172
+ ethers.BigNumber.from(transaction.submitEvent.amount.toString()),
173
+ ethers.BigNumber.from(transaction.submitEvent.sourceChainId.toString()),
174
+ transaction.sourceTransactionHash,
175
+ );
176
+
177
+ transactions.push({
178
+ to: itoken.address,
179
+ data: data!,
180
+ value: '0',
181
+ operation: OperationType.Call,
182
+ });
183
+
184
+ return encodeMulti(transactions).data
185
+ }
186
+
187
+
188
+ export function getContract<TContract extends ethers.Contract>(address: string, contractInterface: ethers.ContractInterface | any, signerOrProvider?: ethers.Signer | ethers.providers.Provider) {
189
+ if (!ethers.utils.getAddress(address) || address === ethers.constants.AddressZero) {
190
+ throw Error(`Invalid 'address' parameter '${address}'.`)
191
+ }
192
+
193
+ const contract = new ethers.Contract(
194
+ address,
195
+ contractInterface,
196
+ signerOrProvider
197
+ ) as TContract
198
+
199
+
200
+ return new Proxy(contract, {
201
+ get(target, prop, receiver) {
202
+ const value = Reflect.get(target, prop, receiver);
203
+
204
+ if (typeof value === 'function' && (contract.functions.hasOwnProperty(prop) || ['queryFilter'].includes(String(prop)))) {
205
+ return async (...args: any[]) => {
206
+ try {
207
+ return await value.bind(contract)(...args);
208
+ } catch (error) {
209
+ throw new Error(`Error calling "${String(prop)}" on "${address}": ${error.reason || error.message}`)
210
+ }
211
+ }
212
+ }
213
+
214
+
215
+ if (typeof value === 'object' && ['populateTransaction', 'estimateGas', 'functions', 'callStatic'].includes(String(prop))) {
216
+ const parentProp = String(prop);
217
+
218
+ return new Proxy(value, {
219
+ get(target, prop, receiver) {
220
+ const value = Reflect.get(target, prop, receiver);
221
+
222
+ if (typeof value === 'function') {
223
+ return async (...args: any[]) => {
224
+ try {
225
+ return await value.bind(contract)(...args);
226
+ } catch (error) {
227
+ throw new Error(`Error calling "${String(prop)}" using "${parentProp}" on "${address}": ${error.reason || error.message}`)
228
+ }
229
+ }
230
+ }
231
+ }
232
+ })
233
+ }
234
+
235
+ return value;
236
+ },
237
+ });
129
238
  }
@@ -1,101 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateInteropTransactionHash = exports.asyncCallWithTimeout = exports.buildSignatureBytes = exports.getRpcProviderUrl = exports.signGnosisSafeTx = exports.short = exports.http = void 0;
7
- /**
8
- * @module util
9
- */
10
- const axios_1 = __importDefault(require("axios"));
11
- const axios_retry_1 = __importDefault(require("axios-retry"));
12
- const constants_1 = require("@/constants");
13
- const ethers_1 = require("ethers");
14
- exports.http = axios_1.default.create();
15
- (0, axios_retry_1.default)(exports.http, { retries: 3, retryDelay: axios_retry_1.default.exponentialDelay });
16
- function short(buffer) {
17
- return buffer.toString('hex').slice(0, 8) + '...';
18
- }
19
- exports.short = short;
20
- const signGnosisSafeTx = async ({ to, data = null, value = '0', operation = '1', baseGas = '0', gasPrice = "0", gasToken = "0x0000000000000000000000000000000000000000", refundReceiver = "0x0000000000000000000000000000000000000000", safeTxGas = "79668", nonce = "0", chainId = 137, }, { signer }) => {
21
- const gnosisSafe = constants_1.addresses[chainId].gnosisSafe;
22
- const domain = {
23
- verifyingContract: gnosisSafe,
24
- chainId,
25
- };
26
- const types = {
27
- SafeTx: [
28
- { type: 'address', name: 'to' },
29
- { type: 'uint256', name: 'value' },
30
- { type: 'bytes', name: 'data' },
31
- { type: 'uint8', name: 'operation' },
32
- { type: 'uint256', name: 'safeTxGas' },
33
- { type: 'uint256', name: 'baseGas' },
34
- { type: 'uint256', name: 'gasPrice' },
35
- { type: 'address', name: 'gasToken' },
36
- { type: 'address', name: 'refundReceiver' },
37
- { type: 'uint256', name: 'nonce' },
38
- ],
39
- };
40
- const message = {
41
- baseGas,
42
- data,
43
- gasPrice,
44
- gasToken,
45
- nonce: Number(nonce),
46
- operation,
47
- refundReceiver,
48
- safeAddress: gnosisSafe,
49
- safeTxGas: String(safeTxGas),
50
- to,
51
- value,
52
- };
53
- return await signer._signTypedData(domain, types, message);
54
- };
55
- exports.signGnosisSafeTx = signGnosisSafeTx;
56
- const getRpcProviderUrl = (chainId) => {
57
- switch (chainId) {
58
- case 1:
59
- return 'https://rpc.instadapp.io/mainnet';
60
- case 137:
61
- return 'https://rpc.instadapp.io/polygon';
62
- case 43114:
63
- return 'https://rpc.instadapp.io/avalanche';
64
- default:
65
- throw new Error(`Unknown chainId: ${chainId}`);
66
- }
67
- };
68
- exports.getRpcProviderUrl = getRpcProviderUrl;
69
- const buildSignatureBytes = (signatures) => {
70
- signatures.sort((left, right) => left.signer.toLowerCase().localeCompare(right.signer.toLowerCase()));
71
- let signatureBytes = "0x";
72
- for (const sig of signatures) {
73
- signatureBytes += sig.data.slice(2);
74
- }
75
- return signatureBytes;
76
- };
77
- exports.buildSignatureBytes = buildSignatureBytes;
78
- /**
79
- * Call an async function with a maximum time limit (in milliseconds) for the timeout
80
- * Resolved promise for async function call, or an error if time limit reached
81
- */
82
- const asyncCallWithTimeout = async (asyncPromise, timeout) => {
83
- let timeoutHandle;
84
- const timeoutPromise = new Promise((_resolve, reject) => {
85
- timeoutHandle = setTimeout(() => reject(new Error('Async call timeout limit reached')), timeout);
86
- });
87
- return Promise.race([asyncPromise, timeoutPromise]).then(result => {
88
- clearTimeout(timeoutHandle);
89
- return result;
90
- });
91
- };
92
- exports.asyncCallWithTimeout = asyncCallWithTimeout;
93
- const generateInteropTransactionHash = (data) => {
94
- return ethers_1.ethers.utils.solidityKeccak256(['string', 'string', 'string', 'string'], [
95
- String(data.type),
96
- String(data.sourceTransactionHash),
97
- String(data.sourceChainId),
98
- String(data.targetChainId),
99
- ]);
100
- };
101
- exports.generateInteropTransactionHash = generateInteropTransactionHash;