@exodus/ethereum-lib 2.5.0 → 2.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/ethereum-lib",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "description": "Ethereum Library",
5
5
  "main": "src/index.js",
6
6
  "author": "Exodus Movement, Inc.",
@@ -23,5 +23,5 @@
23
23
  "peerDependencies": {
24
24
  "@exodus/assets": "8.0.x"
25
25
  },
26
- "gitHead": "20021e426b0554c029a3c223cb5a2e06711358e3"
26
+ "gitHead": "71d126e789b161f5877db4a651a641061f00c7af"
27
27
  }
package/src/abi/index.js CHANGED
@@ -2,6 +2,7 @@ import ant from './ant'
2
2
  import cdai from './cdai'
3
3
  import dai from './dai'
4
4
  import gnt from './gnt'
5
+ import kyberv2 from './kyberv2.js'
5
6
  import loomv2Swap from './loomv2-swap'
6
7
  import repv2 from './repv2'
7
8
  import scdMcdMigration from './scd-mcd-migration'
@@ -11,6 +12,7 @@ export default {
11
12
  cdai,
12
13
  dai,
13
14
  gnt,
15
+ kyberv2,
14
16
  loomv2Swap,
15
17
  repv2,
16
18
  scdMcdMigration,
@@ -0,0 +1,253 @@
1
+ // https://etherscan.io/address/0xe5e8e834086f1a964f9a089eb6ae11796862e4ce#code
2
+
3
+ export default [
4
+ {
5
+ anonymous: false,
6
+ inputs: [
7
+ { indexed: true, internalType: 'address', name: 'owner', type: 'address' },
8
+ { indexed: true, internalType: 'address', name: 'spender', type: 'address' },
9
+ { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256' },
10
+ ],
11
+ name: 'Approval',
12
+ type: 'event',
13
+ },
14
+ {
15
+ anonymous: false,
16
+ inputs: [
17
+ { indexed: true, internalType: 'address', name: 'account', type: 'address' },
18
+ { indexed: true, internalType: 'uint256', name: 'amount', type: 'uint256' },
19
+ ],
20
+ name: 'Migrated',
21
+ type: 'event',
22
+ },
23
+ {
24
+ anonymous: false,
25
+ inputs: [
26
+ { indexed: true, internalType: 'address', name: 'account', type: 'address' },
27
+ { indexed: true, internalType: 'uint256', name: 'amount', type: 'uint256' },
28
+ { indexed: true, internalType: 'address', name: 'minter', type: 'address' },
29
+ ],
30
+ name: 'Minted',
31
+ type: 'event',
32
+ },
33
+ {
34
+ anonymous: false,
35
+ inputs: [
36
+ { indexed: true, internalType: 'address', name: 'oldMinter', type: 'address' },
37
+ { indexed: true, internalType: 'address', name: 'newMinter', type: 'address' },
38
+ ],
39
+ name: 'MinterChanged',
40
+ type: 'event',
41
+ },
42
+ {
43
+ anonymous: false,
44
+ inputs: [
45
+ { indexed: true, internalType: 'address', name: 'previousOwner', type: 'address' },
46
+ { indexed: true, internalType: 'address', name: 'newOwner', type: 'address' },
47
+ ],
48
+ name: 'OwnershipTransferred',
49
+ type: 'event',
50
+ },
51
+ {
52
+ anonymous: false,
53
+ inputs: [
54
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
55
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
56
+ { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256' },
57
+ ],
58
+ name: 'Transfer',
59
+ type: 'event',
60
+ },
61
+ {
62
+ inputs: [
63
+ { internalType: 'address', name: 'owner', type: 'address' },
64
+ { internalType: 'address', name: 'spender', type: 'address' },
65
+ ],
66
+ name: 'allowance',
67
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
68
+ stateMutability: 'view',
69
+ type: 'function',
70
+ },
71
+ {
72
+ inputs: [
73
+ { internalType: 'address', name: 'spender', type: 'address' },
74
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
75
+ ],
76
+ name: 'approve',
77
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
78
+ stateMutability: 'nonpayable',
79
+ type: 'function',
80
+ },
81
+ {
82
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
83
+ name: 'balanceOf',
84
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
85
+ stateMutability: 'view',
86
+ type: 'function',
87
+ },
88
+ {
89
+ inputs: [{ internalType: 'uint256', name: 'amount', type: 'uint256' }],
90
+ name: 'burn',
91
+ outputs: [],
92
+ stateMutability: 'nonpayable',
93
+ type: 'function',
94
+ },
95
+ {
96
+ inputs: [
97
+ { internalType: 'address', name: 'account', type: 'address' },
98
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
99
+ ],
100
+ name: 'burnFrom',
101
+ outputs: [],
102
+ stateMutability: 'nonpayable',
103
+ type: 'function',
104
+ },
105
+ {
106
+ inputs: [{ internalType: 'address', name: 'newMinter', type: 'address' }],
107
+ name: 'changeMinter',
108
+ outputs: [],
109
+ stateMutability: 'nonpayable',
110
+ type: 'function',
111
+ },
112
+ {
113
+ inputs: [],
114
+ name: 'decimals',
115
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
116
+ stateMutability: 'view',
117
+ type: 'function',
118
+ },
119
+ {
120
+ inputs: [
121
+ { internalType: 'address', name: 'spender', type: 'address' },
122
+ { internalType: 'uint256', name: 'subtractedValue', type: 'uint256' },
123
+ ],
124
+ name: 'decreaseAllowance',
125
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
126
+ stateMutability: 'nonpayable',
127
+ type: 'function',
128
+ },
129
+ {
130
+ inputs: [
131
+ { internalType: 'contract IERC20', name: 'token', type: 'address' },
132
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
133
+ ],
134
+ name: 'emergencyERC20Drain',
135
+ outputs: [],
136
+ stateMutability: 'nonpayable',
137
+ type: 'function',
138
+ },
139
+ {
140
+ inputs: [
141
+ { internalType: 'address', name: 'spender', type: 'address' },
142
+ { internalType: 'uint256', name: 'addedValue', type: 'uint256' },
143
+ ],
144
+ name: 'increaseAllowance',
145
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
146
+ stateMutability: 'nonpayable',
147
+ type: 'function',
148
+ },
149
+ {
150
+ inputs: [
151
+ { internalType: 'address', name: '_oldKNC', type: 'address' },
152
+ { internalType: 'address', name: '_minter', type: 'address' },
153
+ ],
154
+ name: 'initialize',
155
+ outputs: [],
156
+ stateMutability: 'nonpayable',
157
+ type: 'function',
158
+ },
159
+ {
160
+ inputs: [
161
+ { internalType: 'address', name: 'account', type: 'address' },
162
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
163
+ ],
164
+ name: 'mint',
165
+ outputs: [],
166
+ stateMutability: 'nonpayable',
167
+ type: 'function',
168
+ },
169
+ {
170
+ inputs: [{ internalType: 'uint256', name: 'amount', type: 'uint256' }],
171
+ name: 'mintWithOldKnc',
172
+ outputs: [],
173
+ stateMutability: 'nonpayable',
174
+ type: 'function',
175
+ },
176
+ {
177
+ inputs: [],
178
+ name: 'minter',
179
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
180
+ stateMutability: 'view',
181
+ type: 'function',
182
+ },
183
+ {
184
+ inputs: [],
185
+ name: 'name',
186
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
187
+ stateMutability: 'view',
188
+ type: 'function',
189
+ },
190
+ {
191
+ inputs: [],
192
+ name: 'oldKNC',
193
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
194
+ stateMutability: 'view',
195
+ type: 'function',
196
+ },
197
+ {
198
+ inputs: [],
199
+ name: 'owner',
200
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
201
+ stateMutability: 'view',
202
+ type: 'function',
203
+ },
204
+ {
205
+ inputs: [],
206
+ name: 'renounceOwnership',
207
+ outputs: [],
208
+ stateMutability: 'nonpayable',
209
+ type: 'function',
210
+ },
211
+ {
212
+ inputs: [],
213
+ name: 'symbol',
214
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
215
+ stateMutability: 'view',
216
+ type: 'function',
217
+ },
218
+ {
219
+ inputs: [],
220
+ name: 'totalSupply',
221
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
222
+ stateMutability: 'view',
223
+ type: 'function',
224
+ },
225
+ {
226
+ inputs: [
227
+ { internalType: 'address', name: 'recipient', type: 'address' },
228
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
229
+ ],
230
+ name: 'transfer',
231
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
232
+ stateMutability: 'nonpayable',
233
+ type: 'function',
234
+ },
235
+ {
236
+ inputs: [
237
+ { internalType: 'address', name: 'sender', type: 'address' },
238
+ { internalType: 'address', name: 'recipient', type: 'address' },
239
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
240
+ ],
241
+ name: 'transferFrom',
242
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
243
+ stateMutability: 'nonpayable',
244
+ type: 'function',
245
+ },
246
+ {
247
+ inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }],
248
+ name: 'transferOwnership',
249
+ outputs: [],
250
+ stateMutability: 'nonpayable',
251
+ type: 'function',
252
+ },
253
+ ]
@@ -2,6 +2,7 @@ import SolidityContract from '@exodus/solidity-contract'
2
2
  import ABI from '../abi'
3
3
 
4
4
  export default function createContract(address, assetName) {
5
+ // keep switch logic in anticipation of support for ERC721
5
6
  switch (assetName) {
6
7
  // case 'dai':
7
8
  // return new SolidityContract(ABI.dai, address)
@@ -15,6 +16,8 @@ export default function createContract(address, assetName) {
15
16
  return new SolidityContract(ABI.gnt, address)
16
17
  case 'loomv2Swap':
17
18
  return new SolidityContract(ABI.loomv2Swap, address)
19
+ case 'kyberv2':
20
+ return new SolidityContract(ABI.kyberv2, address)
18
21
  default:
19
22
  return SolidityContract.erc20(address)
20
23
  }
@@ -5,5 +5,6 @@ export { default as isConsideredSentTokenTx } from './is-considered-sent-token-t
5
5
  export { default as getHistoryFromServer } from './get-history-from-server'
6
6
  export { default as checkPendingTransactions } from './check-pending-transactions'
7
7
  export { default as getDeriveTransactionsToCheck } from './get-derive-transactions-to-check'
8
+ export { subscribeToWSNotifications, enableWSUpdates } from './ws-updates'
8
9
 
9
10
  export type { PendingTransactionsDictionary } from './types'
@@ -0,0 +1,59 @@
1
+ import ms from 'ms'
2
+
3
+ const subscribedToAddressNotificationsMap = new Map()
4
+ const UPDATE_LOOP_INTERVAL = ms('5m')
5
+
6
+ export function subscribeToWSNotifications({
7
+ addressesByWalletAccount,
8
+ tick,
9
+ getState,
10
+ server,
11
+ beforeStart = false,
12
+ }) {
13
+ Object.entries(addressesByWalletAccount).forEach(([walletAccount, addresses]) => {
14
+ const address = String(Array.from(addresses)[0]).toLowerCase() // Only check m/0/0
15
+ const mapKey = `${server.getURL()}:${address}` // different chains might have the same addresses
16
+ if (subscribedToAddressNotificationsMap.has(mapKey)) return
17
+
18
+ server.ws.watch(address)
19
+ server.ws.events.on(`address-${address}`, () => {
20
+ tick({ refresh: false, getState, walletAccount })
21
+ })
22
+ subscribedToAddressNotificationsMap.set(mapKey, true)
23
+ if (!beforeStart) {
24
+ // tick for a new wallet account
25
+ tick({ refresh: false, getState, walletAccount })
26
+ }
27
+ })
28
+ }
29
+
30
+ export function enableWSUpdates({
31
+ interval,
32
+ server,
33
+ timer,
34
+ dispatch,
35
+ getState,
36
+ tickAllWalletAccounts,
37
+ tick,
38
+ addressesByWalletAccount,
39
+ beforeStart = false,
40
+ }) {
41
+ const defaultInterval = interval
42
+
43
+ subscribeToWSNotifications({
44
+ server,
45
+ getState,
46
+ beforeStart,
47
+ tick,
48
+ addressesByWalletAccount,
49
+ })
50
+
51
+ server.ws.events.on('open', () => {
52
+ timer.setNewInterval(UPDATE_LOOP_INTERVAL)
53
+ })
54
+ server.ws.events.on('close', async () => {
55
+ await timer.setNewInterval(defaultInterval)
56
+ return tickAllWalletAccounts({ dispatch, getState })
57
+ })
58
+ server.ws.open()
59
+ }
@@ -8,16 +8,28 @@ const BumpType = {
8
8
  RBF: 2,
9
9
  }
10
10
 
11
+ // Legacy compatibility with wallets
11
12
  export function getPendingNonExchangeTxs(activeWalletAccount, getTxLog, getIsExchangeTx) {
13
+ console.log('Using deprecated function getPendingNonExchangeTxs()')
14
+ return getAssetPendingNonExchangeTxs('ethereum', activeWalletAccount, getTxLog, getIsExchangeTx)
15
+ }
16
+
17
+ export function getAssetPendingNonExchangeTxs(
18
+ baseAssetName,
19
+ activeWalletAccount,
20
+ getTxLog,
21
+ getIsExchangeTx
22
+ ) {
12
23
  // check if the tx log even has pending transactions
13
24
  const result = isQueuedPendingTx(
14
25
  { data: { nonce: Number.MAX_SAFE_INTEGER } },
26
+ baseAssetName,
15
27
  activeWalletAccount,
16
28
  getTxLog
17
29
  )
18
30
  if (!result) return []
19
31
 
20
- const txLog = getTxLog('ethereum', activeWalletAccount)
32
+ const txLog = getTxLog(baseAssetName, activeWalletAccount)
21
33
  const pendingNonExchangeTxs = []
22
34
  for (let index = isQueuedPendingTx.minIndex; index < txLog.size; index++) {
23
35
  const _tx = txLog.getAt(index)
@@ -29,8 +41,8 @@ export function getPendingNonExchangeTxs(activeWalletAccount, getTxLog, getIsExc
29
41
  return pendingNonExchangeTxs
30
42
  }
31
43
 
32
- function isQueuedPendingTx(tx, activeWalletAccount, getTxLog) {
33
- const txLog = getTxLog('ethereum', activeWalletAccount)
44
+ function isQueuedPendingTx(tx, baseAssetName, activeWalletAccount, getTxLog) {
45
+ const txLog = getTxLog(baseAssetName, activeWalletAccount)
34
46
  if (!txLog || txLog.size === 0) return false
35
47
 
36
48
  const txAtMinIndex = txLog.getAt(isQueuedPendingTx.minIndex)
@@ -105,11 +117,11 @@ export default (
105
117
  getIsExchangeTx
106
118
  ) => (tx) => {
107
119
  const assetName = tx.coinName
108
- const asset = assets[assetName]
120
+ const baseAssetName = assets[assetName].baseAsset.name
109
121
  if (!getIsRbfEnabled(assetName))
110
122
  return wrapResponseToObject({ errorMessage: 'rbf is disabled' })
111
- if (!['ETHEREUM_ERC20', 'ETHEREUM_LIKE'].includes(asset.assetType))
112
- return wrapResponseToObject({ errorMessage: `not an ETH/ERC20 asset supplied` })
123
+ if (!['ethereum', 'bsc'].includes(baseAssetName))
124
+ return wrapResponseToObject({ errorMessage: `not an ETH/ERC20/BSC/BEP20 asset supplied` })
113
125
  if (!tx.pending || !tx.sent)
114
126
  return wrapResponseToObject({ errorMessage: 'can not bump a pending or received TX' })
115
127
  if (!tx.data || !tx.data.gasLimit)
@@ -119,16 +131,14 @@ export default (
119
131
  const personalNote = getPersonalNoteByTxId(tx.txId)
120
132
  if (personalNote && personalNote.dapp)
121
133
  return wrapResponseToObject({ errorMessage: 'can not bump a dapp TX' })
122
- if (isQueuedPendingTx(tx, activeWalletAccount, getTxLog))
134
+ if (isQueuedPendingTx(tx, baseAssetName, activeWalletAccount, getTxLog))
123
135
  return wrapResponseToObject({ errorMessage: 'there is a stuck TX with lower nonce' })
124
136
 
125
137
  const { gasPrice: currentGasPrice } = getFeeData(assetName)
126
138
  const gasPriceToUse = calculateBumpedGasPrice(tx, currentGasPrice)
127
139
  const replacementFee = gasPriceToUse.mul(tx.data.gasLimit)
128
140
  const extraEthNeeded = replacementFee.sub(tx.feeAmount)
129
- if (
130
- !getIsEnoughBalanceToAccelerate(activeWalletAccount, asset.baseAsset.name, extraEthNeeded)
131
- )
141
+ if (!getIsEnoughBalanceToAccelerate(activeWalletAccount, baseAssetName, extraEthNeeded))
132
142
  return wrapResponseToObject({ errorMessage: 'insufficient funds' })
133
143
 
134
144
  return wrapResponseToObject({ bumpType: BumpType.RBF })
@@ -2,6 +2,7 @@ export {
2
2
  default as getCanAccelerateTxFactory,
3
3
  calculateBumpedGasPrice,
4
4
  getPendingNonExchangeTxs,
5
+ getAssetPendingNonExchangeTxs,
5
6
  } from './get-can-accelerate-tx-factory'
6
7
 
7
8
  export { default as getIsEnoughBalanceToAccelerateSelectorFactory } from './get-is-enough-balance-to-accelerate-factory'
@@ -0,0 +1,15 @@
1
+ const defaultMultiplier = 1.1
2
+
3
+ // if a wallet has 0 ETH the deposit needed should be more than the fee needed by <multiplier>
4
+ // if a wallet has <N> ETH, the deposit needed should be the fee * <multiplier> - <N>
5
+ export default function({ fee, balance, multiplier = defaultMultiplier }) {
6
+ if (typeof multiplier !== 'number' || multiplier < 1) multiplier = defaultMultiplier
7
+ if (balance.gt(fee)) return balance.unitType.ZERO
8
+
9
+ return fee
10
+ .mul(multiplier)
11
+ .toDefault()
12
+ .sub(balance)
13
+ .toFixed(4, 'ceil')
14
+ .toString()
15
+ }
package/src/utils.js CHANGED
@@ -6,6 +6,7 @@ const base10 = baseX('0123456789')
6
6
  const base16 = baseX('0123456789abcdef')
7
7
 
8
8
  export const isEthereumToken = (asset) => asset.assetType === 'ETHEREUM_ERC20'
9
+ export const isBscToken = (asset) => asset.assetType === 'BSC_BEP20'
9
10
  export const isQuorumToken = (asset) => asset.assetType === 'QUORUM_ERC20'
10
11
 
11
12
  export function buffer2currency({ asset, value }) {