@instadapp/interop-x 0.0.0-dev.1abc1ca → 0.0.0-dev.1dc43c9

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 (79) hide show
  1. package/.github/workflows/ci.yml +19 -0
  2. package/bin/interop-x +1 -1
  3. package/dist/package.json +21 -16
  4. package/dist/src/abi/index.js +2 -4
  5. package/dist/src/abi/interopX.json +1436 -0
  6. package/dist/src/alias.js +10 -0
  7. package/dist/src/api/index.js +6 -3
  8. package/dist/src/config/index.js +11 -1
  9. package/dist/src/constants/addresses.js +2 -7
  10. package/dist/src/constants/index.js +0 -1
  11. package/dist/src/constants/tokens.js +62 -39
  12. package/dist/src/db/models/transaction.js +29 -11
  13. package/dist/src/gnosis/actions/index.js +9 -0
  14. package/dist/src/gnosis/actions/withdraw/index.js +114 -0
  15. package/dist/src/gnosis/index.js +20 -0
  16. package/dist/src/index.js +75 -24
  17. package/dist/src/net/peer/index.js +8 -3
  18. package/dist/src/net/pool/index.js +32 -9
  19. package/dist/src/net/protocol/dial/SignatureDialProtocol.js +8 -2
  20. package/dist/src/net/protocol/dial/TransactionStatusDialProtocol.js +30 -0
  21. package/dist/src/net/protocol/index.js +51 -1
  22. package/dist/src/tasks/AutoUpdateTask.js +70 -0
  23. package/dist/src/tasks/BaseTask.js +12 -4
  24. package/dist/src/tasks/InteropX/SyncLogSubmitEvents.js +84 -0
  25. package/dist/src/tasks/Transactions/SyncTransactionStatusTask.js +57 -0
  26. package/dist/src/tasks/index.js +11 -4
  27. package/dist/src/typechain/{InteropBridgeToken.js → InteropX.js} +0 -0
  28. package/dist/src/typechain/factories/InteropX__factory.js +1928 -0
  29. package/dist/src/typechain/factories/index.js +3 -5
  30. package/dist/src/typechain/index.js +3 -5
  31. package/dist/src/utils/index.js +97 -39
  32. package/package.json +21 -16
  33. package/patches/@ethersproject+properties+5.6.0.patch +13 -0
  34. package/src/abi/index.ts +2 -4
  35. package/src/abi/interopX.json +1436 -0
  36. package/src/alias.ts +6 -0
  37. package/src/api/index.ts +5 -2
  38. package/src/config/index.ts +11 -1
  39. package/src/constants/addresses.ts +3 -8
  40. package/src/constants/index.ts +0 -1
  41. package/src/constants/tokens.ts +63 -40
  42. package/src/db/models/transaction.ts +65 -25
  43. package/src/gnosis/actions/index.ts +5 -0
  44. package/src/gnosis/actions/withdraw/index.ts +155 -0
  45. package/src/gnosis/index.ts +19 -0
  46. package/src/index.ts +96 -26
  47. package/src/net/peer/index.ts +9 -7
  48. package/src/net/pool/index.ts +41 -11
  49. package/src/net/protocol/dial/SignatureDialProtocol.ts +10 -4
  50. package/src/net/protocol/dial/TransactionStatusDialProtocol.ts +33 -0
  51. package/src/net/protocol/index.ts +67 -1
  52. package/src/tasks/AutoUpdateTask.ts +82 -0
  53. package/src/tasks/BaseTask.ts +14 -4
  54. package/src/tasks/InteropX/SyncLogSubmitEvents.ts +136 -0
  55. package/src/tasks/Transactions/SyncTransactionStatusTask.ts +69 -0
  56. package/src/tasks/index.ts +17 -5
  57. package/src/typechain/InteropX.ts +1216 -0
  58. package/src/typechain/factories/InteropX__factory.ts +1932 -0
  59. package/src/typechain/factories/index.ts +1 -2
  60. package/src/typechain/index.ts +2 -4
  61. package/src/utils/index.ts +153 -49
  62. package/tsconfig.json +7 -2
  63. package/dist/src/abi/interopBridgeToken.json +0 -286
  64. package/dist/src/abi/interopXGateway.json +0 -184
  65. package/dist/src/constants/itokens.js +0 -13
  66. package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +0 -140
  67. package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +0 -75
  68. package/dist/src/typechain/InteropXGateway.js +0 -2
  69. package/dist/src/typechain/factories/InteropBridgeToken__factory.js +0 -459
  70. package/dist/src/typechain/factories/InteropXGateway__factory.js +0 -265
  71. package/src/abi/interopBridgeToken.json +0 -286
  72. package/src/abi/interopXGateway.json +0 -184
  73. package/src/constants/itokens.ts +0 -10
  74. package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +0 -232
  75. package/src/tasks/InteropXGateway/SyncDepositEvents.ts +0 -126
  76. package/src/typechain/InteropBridgeToken.ts +0 -686
  77. package/src/typechain/InteropXGateway.ts +0 -407
  78. package/src/typechain/factories/InteropBridgeToken__factory.ts +0 -466
  79. package/src/typechain/factories/InteropXGateway__factory.ts +0 -272
@@ -3,5 +3,4 @@
3
3
  /* eslint-disable */
4
4
  export { Erc20__factory } from "./Erc20__factory";
5
5
  export { GnosisSafe__factory } from "./GnosisSafe__factory";
6
- export { InteropBridgeToken__factory } from "./InteropBridgeToken__factory";
7
- export { InteropXGateway__factory } from "./InteropXGateway__factory";
6
+ export { InteropX__factory } from "./InteropX__factory";
@@ -3,10 +3,8 @@
3
3
  /* eslint-disable */
4
4
  export type { Erc20 } from "./Erc20";
5
5
  export type { GnosisSafe } from "./GnosisSafe";
6
- export type { InteropBridgeToken } from "./InteropBridgeToken";
7
- export type { InteropXGateway } from "./InteropXGateway";
6
+ export type { InteropX } from "./InteropX";
8
7
  export * as factories from "./factories";
9
8
  export { Erc20__factory } from "./factories/Erc20__factory";
10
9
  export { GnosisSafe__factory } from "./factories/GnosisSafe__factory";
11
- export { InteropBridgeToken__factory } from "./factories/InteropBridgeToken__factory";
12
- export { InteropXGateway__factory } from "./factories/InteropXGateway__factory";
10
+ export { InteropX__factory } from "./factories/InteropX__factory";
@@ -3,20 +3,29 @@
3
3
  */
4
4
  import axios from 'axios'
5
5
  import axiosRetry from "axios-retry";
6
- import { addresses, itokens, tokens } from '@/constants';
6
+ import { addresses } 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
+ import { GnosisSafe } from '@/typechain';
10
+ import retry from 'async-retry'
14
11
 
15
12
  export const http = axios.create();
16
13
 
17
14
  axiosRetry(http, { retries: 3, retryDelay: axiosRetry.exponentialDelay });
18
15
 
19
16
 
17
+ export function shortenHash(hash: string, length: number = 4) {
18
+ if (!hash) return;
19
+
20
+ if (hash.length < 12) return hash;
21
+
22
+ const beginningChars = hash.startsWith("0x") ? length + 2 : length;
23
+
24
+ const shortened = hash.substr(0, beginningChars) + "…" + hash.substr(-length);
25
+
26
+ return shortened;
27
+ }
28
+
20
29
  export function short(buffer: Buffer): string {
21
30
  return buffer.toString('hex').slice(0, 8) + '...'
22
31
  }
@@ -76,11 +85,11 @@ export const signGnosisSafeTx = async ({
76
85
  export const getRpcProviderUrl = (chainId: ChainId) => {
77
86
  switch (chainId) {
78
87
  case 1:
79
- return 'https://rpc.instadapp.io/mainnet';
88
+ return 'https://rpc.ankr.com/eth';
80
89
  case 137:
81
- return 'https://rpc.instadapp.io/polygon';
90
+ return 'https://rpc.ankr.com/polygon';
82
91
  case 43114:
83
- return 'https://rpc.instadapp.io/avalanche';
92
+ return 'https://rpc.ankr.com/avalanche';
84
93
  default:
85
94
  throw new Error(`Unknown chainId: ${chainId}`);
86
95
  }
@@ -124,62 +133,157 @@ export const asyncCallWithTimeout = async <T>(asyncPromise: Promise<T>, timeout:
124
133
  }
125
134
 
126
135
 
127
- export const generateInteropTransactionHash = (data: { action: string, submitTransactionHash: string, sourceChainId: string | number, targetChainId: string | number }) => {
128
- return ethers.utils.solidityKeccak256(['string', 'string', 'string', 'string'], [
129
- String(data.action),
130
- String(data.submitTransactionHash),
131
- String(data.sourceChainId),
132
- String(data.targetChainId),
133
- ]);
136
+ type GenerateInteropTransactionHashParam = {
137
+ actionId: string,
138
+ vnonce: string,
139
+ sourceSender: string,
140
+ sourceChainId: string | number,
141
+ sourceDsaId: string,
142
+ targetChainId: string | number,
143
+ targetDsaId: string,
144
+ };
145
+
146
+ export const generateInteropTransactionHash = (data: GenerateInteropTransactionHashParam) => {
147
+ return ethers.utils.solidityKeccak256(
148
+ Array.from({ length : 7 }, () => 'string'),
149
+ [
150
+ String(data.actionId),
151
+ String(data.vnonce),
152
+ String(data.sourceSender),
153
+ String(data.sourceChainId),
154
+ String(data.sourceDsaId),
155
+ String(data.targetChainId),
156
+ String(data.targetDsaId),
157
+ ]);
134
158
  }
135
159
 
136
- export const buildDataForTransaction = async (transaction: Transaction, type?: 'source' | 'target') => {
137
- type = type || transaction.sourceStatus === 'pending' ? 'source' : 'target';
138
160
 
139
- const transactions: MetaTransaction[] = [];
161
+ export class ContractError extends Error {
162
+ method: string;
163
+ address: string;
164
+ args: any[];
165
+ }
140
166
 
141
- if(transaction.action != 'deposit') {
142
- throw new Error('Invalid action');
167
+ export function getContract<TContract extends ethers.Contract>(address: string, contractInterface: ethers.ContractInterface | any, signerOrProvider?: ethers.Signer | ethers.providers.Provider) {
168
+ if (!ethers.utils.getAddress(address) || address === ethers.constants.AddressZero) {
169
+ throw Error(`Invalid 'address' parameter '${address}'.`)
143
170
  }
144
171
 
145
- if (transaction.action === 'deposit' && transaction.sourceStatus === 'pending') {
146
- throw Error('Cannot build data for pending deposit transaction');
147
- }
172
+ const contract = new ethers.Contract(
173
+ address,
174
+ contractInterface,
175
+ signerOrProvider
176
+ ) as TContract
177
+
178
+ // Make sure the contract properties is writable
179
+ const desc = Object.getOwnPropertyDescriptor(contract, 'functions');
148
180
 
149
- if (!transaction.submitEvent) {
150
- throw Error('Cannot build data for transaction without submitEvent');
181
+ if (!desc || desc.writable !== true) {
182
+ return contract
151
183
  }
152
184
 
185
+ return new Proxy(contract, {
186
+ get(target, prop, receiver) {
187
+ const value = Reflect.get(target, prop, receiver);
153
188
 
154
- const token = tokens[transaction.sourceChainId].find(token => token.address.toLowerCase() === transaction.submitEvent.token.toLowerCase());
189
+ if (typeof value === 'function' && (contract.functions.hasOwnProperty(prop) || ['queryFilter'].includes(String(prop)))) {
190
+ let isConstant = false;
155
191
 
156
- if (!token) {
157
- throw Error('Cannot build data for transaction without token');
158
- }
192
+ try {
193
+ isConstant = contract.interface.getFunction(String(prop)).constant
194
+ } catch (error) {
195
+ }
159
196
 
160
- const itoken = itokens[transaction.targetChainId].find(itoken => token.symbol.toLowerCase() === token.symbol.toLowerCase());
197
+ return async (...args: any[]) => {
198
+ try {
199
+ return await retry(async () => await value.bind(contract)(...args), { retries: isConstant ? 1 : 3 });
200
+ } catch (error) {
201
+ const err = new ContractError(`Error calling "${String(prop)}" on "${address}": ${error.reason || error.message}`)
161
202
 
162
- if (!itoken) {
163
- throw Error('Cannot build data for transaction without itoken');
164
- }
203
+ err.method = String(prop)
204
+ err.address = address
205
+ err.args = [...args]
165
206
 
166
- const targetChainProvider = new ethers.providers.JsonRpcProvider(getRpcProviderUrl(transaction.targetChainId as ChainId));
167
- const targetWallet = new ethers.Wallet(config.privateKey, targetChainProvider);
168
- const interopBridgeContract = new ethers.Contract(itoken.address, abi.interopBridgeToken, targetWallet) as InteropBridgeToken;
207
+ throw err
208
+ }
209
+ }
210
+ }
169
211
 
170
- const { data } = await interopBridgeContract.populateTransaction.mint(
171
- transaction.submitEvent.to,
172
- transaction.submitEvent.amount,
173
- transaction.sourceChainId,
174
- transaction.sourceTransactionHash,
175
- );
176
212
 
177
- transactions.push({
178
- to: itoken.address,
179
- data: data!,
180
- value: '0',
181
- operation: OperationType.Call,
213
+ if (typeof value === 'object' && ['populateTransaction', 'estimateGas', 'functions', 'callStatic'].includes(String(prop))) {
214
+ const parentProp = String(prop);
215
+
216
+ return new Proxy(value, {
217
+ get(target, prop, receiver) {
218
+ const value = Reflect.get(target, prop, receiver);
219
+
220
+ if (typeof value === 'function') {
221
+ return async (...args: any[]) => {
222
+ try {
223
+ return await retry(async () => await value.bind(contract)(...args), { retries: parentProp === 'callStatic' ? 3 : 1 });
224
+ } catch (error) {
225
+ const err = new ContractError(`Error calling "${String(prop)}" using "${parentProp}" on "${address}": ${error.reason || error.message}`)
226
+
227
+ err.method = String(prop)
228
+ err.address = address
229
+ err.args = [...args]
230
+
231
+ throw err
232
+ }
233
+ }
234
+ }
235
+ }
236
+ })
237
+ }
238
+
239
+ return value;
240
+ },
182
241
  });
242
+ }
243
+
244
+ export const generateGnosisTransaction = async (transactionData: any, safeContract: GnosisSafe) => {
245
+ console.log(transactionData);
183
246
 
184
- return encodeMulti(transactions).data
247
+ let isExecuted = await safeContract.dataHashes(
248
+ await safeContract.getTransactionHash(
249
+ transactionData.to,
250
+ transactionData.value,
251
+ transactionData.data,
252
+ transactionData.operation,
253
+ transactionData.safeTxGas,
254
+ transactionData.baseGas,
255
+ transactionData.gasPrice,
256
+ transactionData.gasToken,
257
+ transactionData.refundReceiver,
258
+ transactionData.nonce
259
+ )
260
+ )
261
+
262
+ while (isExecuted == 1) {
263
+ transactionData.safeTxGas = ethers.BigNumber.from(String(transactionData.safeTxGas)).add(1).toString()
264
+
265
+ isExecuted = await safeContract.dataHashes(
266
+ await safeContract.getTransactionHash(
267
+ transactionData.to,
268
+ transactionData.value,
269
+ transactionData.data,
270
+ transactionData.operation,
271
+ transactionData.safeTxGas,
272
+ transactionData.baseGas,
273
+ transactionData.gasPrice,
274
+ transactionData.gasToken,
275
+ transactionData.refundReceiver,
276
+ transactionData.nonce
277
+ )
278
+ )
279
+ }
280
+
281
+ return transactionData
185
282
  }
283
+
284
+ export class LiquidityError extends Error {
285
+ constructor(message?: string) {
286
+ super(message || 'Not enough liquidity');
287
+ Object.setPrototypeOf(this, new.target.prototype);
288
+ }
289
+ }
package/tsconfig.json CHANGED
@@ -16,8 +16,13 @@
16
16
  "noEmit": false,
17
17
  "outDir": "dist",
18
18
  "baseUrl": "src",
19
- "paths": {
20
- "@/*" : ["./*" ]
19
+ "paths": {
20
+ "@/*": [
21
+ "*"
22
+ ],
23
+ "@": [
24
+ "/"
25
+ ]
21
26
  },
22
27
  "typeRoots": [
23
28
  "./node_modules/@types",
@@ -1,286 +0,0 @@
1
- [
2
- {
3
- "inputs": [
4
- { "internalType": "address", "name": "__owner", "type": "address" }
5
- ],
6
- "stateMutability": "nonpayable",
7
- "type": "constructor"
8
- },
9
- {
10
- "anonymous": false,
11
- "inputs": [
12
- {
13
- "indexed": true,
14
- "internalType": "address",
15
- "name": "owner",
16
- "type": "address"
17
- },
18
- {
19
- "indexed": true,
20
- "internalType": "address",
21
- "name": "spender",
22
- "type": "address"
23
- },
24
- {
25
- "indexed": false,
26
- "internalType": "uint256",
27
- "name": "value",
28
- "type": "uint256"
29
- }
30
- ],
31
- "name": "Approval",
32
- "type": "event"
33
- },
34
- {
35
- "anonymous": false,
36
- "inputs": [
37
- {
38
- "indexed": true,
39
- "internalType": "address",
40
- "name": "to",
41
- "type": "address"
42
- },
43
- {
44
- "indexed": false,
45
- "internalType": "uint256",
46
- "name": "amount",
47
- "type": "uint256"
48
- },
49
- {
50
- "indexed": true,
51
- "internalType": "uint256",
52
- "name": "chainId",
53
- "type": "uint256"
54
- }
55
- ],
56
- "name": "Burn",
57
- "type": "event"
58
- },
59
- {
60
- "anonymous": false,
61
- "inputs": [
62
- {
63
- "indexed": true,
64
- "internalType": "address",
65
- "name": "to",
66
- "type": "address"
67
- },
68
- {
69
- "indexed": false,
70
- "internalType": "uint256",
71
- "name": "amount",
72
- "type": "uint256"
73
- },
74
- {
75
- "indexed": true,
76
- "internalType": "uint256",
77
- "name": "chainId",
78
- "type": "uint256"
79
- },
80
- {
81
- "indexed": true,
82
- "internalType": "bytes32",
83
- "name": "transactionHash",
84
- "type": "bytes32"
85
- }
86
- ],
87
- "name": "Mint",
88
- "type": "event"
89
- },
90
- {
91
- "anonymous": false,
92
- "inputs": [
93
- {
94
- "indexed": true,
95
- "internalType": "address",
96
- "name": "previousOwner",
97
- "type": "address"
98
- },
99
- {
100
- "indexed": true,
101
- "internalType": "address",
102
- "name": "newOwner",
103
- "type": "address"
104
- }
105
- ],
106
- "name": "OwnershipTransferred",
107
- "type": "event"
108
- },
109
- {
110
- "anonymous": false,
111
- "inputs": [
112
- {
113
- "indexed": true,
114
- "internalType": "address",
115
- "name": "from",
116
- "type": "address"
117
- },
118
- {
119
- "indexed": true,
120
- "internalType": "address",
121
- "name": "to",
122
- "type": "address"
123
- },
124
- {
125
- "indexed": false,
126
- "internalType": "uint256",
127
- "name": "value",
128
- "type": "uint256"
129
- }
130
- ],
131
- "name": "Transfer",
132
- "type": "event"
133
- },
134
- {
135
- "inputs": [
136
- { "internalType": "address", "name": "owner", "type": "address" },
137
- { "internalType": "address", "name": "spender", "type": "address" }
138
- ],
139
- "name": "allowance",
140
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
141
- "stateMutability": "view",
142
- "type": "function"
143
- },
144
- {
145
- "inputs": [
146
- { "internalType": "address", "name": "spender", "type": "address" },
147
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
148
- ],
149
- "name": "approve",
150
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
151
- "stateMutability": "nonpayable",
152
- "type": "function"
153
- },
154
- {
155
- "inputs": [
156
- { "internalType": "address", "name": "account", "type": "address" }
157
- ],
158
- "name": "balanceOf",
159
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
160
- "stateMutability": "view",
161
- "type": "function"
162
- },
163
- {
164
- "inputs": [
165
- { "internalType": "address", "name": "to", "type": "address" },
166
- { "internalType": "uint256", "name": "amount", "type": "uint256" },
167
- { "internalType": "uint256", "name": "chainId", "type": "uint256" }
168
- ],
169
- "name": "burn",
170
- "outputs": [],
171
- "stateMutability": "nonpayable",
172
- "type": "function"
173
- },
174
- {
175
- "inputs": [],
176
- "name": "decimals",
177
- "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
178
- "stateMutability": "view",
179
- "type": "function"
180
- },
181
- {
182
- "inputs": [
183
- { "internalType": "address", "name": "spender", "type": "address" },
184
- {
185
- "internalType": "uint256",
186
- "name": "subtractedValue",
187
- "type": "uint256"
188
- }
189
- ],
190
- "name": "decreaseAllowance",
191
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
192
- "stateMutability": "nonpayable",
193
- "type": "function"
194
- },
195
- {
196
- "inputs": [
197
- { "internalType": "address", "name": "spender", "type": "address" },
198
- { "internalType": "uint256", "name": "addedValue", "type": "uint256" }
199
- ],
200
- "name": "increaseAllowance",
201
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
202
- "stateMutability": "nonpayable",
203
- "type": "function"
204
- },
205
- {
206
- "inputs": [
207
- { "internalType": "address", "name": "to", "type": "address" },
208
- { "internalType": "uint256", "name": "amount", "type": "uint256" },
209
- { "internalType": "uint256", "name": "chainId", "type": "uint256" },
210
- {
211
- "internalType": "bytes32",
212
- "name": "transactionHash",
213
- "type": "bytes32"
214
- }
215
- ],
216
- "name": "mint",
217
- "outputs": [],
218
- "stateMutability": "nonpayable",
219
- "type": "function"
220
- },
221
- {
222
- "inputs": [],
223
- "name": "name",
224
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
225
- "stateMutability": "view",
226
- "type": "function"
227
- },
228
- {
229
- "inputs": [],
230
- "name": "owner",
231
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
232
- "stateMutability": "view",
233
- "type": "function"
234
- },
235
- {
236
- "inputs": [],
237
- "name": "renounceOwnership",
238
- "outputs": [],
239
- "stateMutability": "nonpayable",
240
- "type": "function"
241
- },
242
- {
243
- "inputs": [],
244
- "name": "symbol",
245
- "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
246
- "stateMutability": "view",
247
- "type": "function"
248
- },
249
- {
250
- "inputs": [],
251
- "name": "totalSupply",
252
- "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
253
- "stateMutability": "view",
254
- "type": "function"
255
- },
256
- {
257
- "inputs": [
258
- { "internalType": "address", "name": "to", "type": "address" },
259
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
260
- ],
261
- "name": "transfer",
262
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
263
- "stateMutability": "nonpayable",
264
- "type": "function"
265
- },
266
- {
267
- "inputs": [
268
- { "internalType": "address", "name": "from", "type": "address" },
269
- { "internalType": "address", "name": "to", "type": "address" },
270
- { "internalType": "uint256", "name": "amount", "type": "uint256" }
271
- ],
272
- "name": "transferFrom",
273
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
274
- "stateMutability": "nonpayable",
275
- "type": "function"
276
- },
277
- {
278
- "inputs": [
279
- { "internalType": "address", "name": "newOwner", "type": "address" }
280
- ],
281
- "name": "transferOwnership",
282
- "outputs": [],
283
- "stateMutability": "nonpayable",
284
- "type": "function"
285
- }
286
- ]