@exodus/ethereum-lib 2.7.4 → 2.8.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.7.4",
3
+ "version": "2.8.0",
4
4
  "description": "Ethereum Library",
5
5
  "main": "src/index.js",
6
6
  "author": "Exodus Movement, Inc.",
@@ -10,12 +10,13 @@
10
10
  "access": "restricted"
11
11
  },
12
12
  "dependencies": {
13
+ "@ethereumjs/common": "^2.3.1",
14
+ "@ethereumjs/tx": "^3.2.1",
13
15
  "@exodus/asset-lib": "^3.4.0",
14
16
  "@exodus/models": "^8.5.12",
15
17
  "@exodus/solidity-contract": "^0.1.3",
16
18
  "base-x": "^3.0.2",
17
- "ethereumjs-tx": "^1.3.7",
18
- "ethereumjs-util": "^5.2.0",
19
+ "ethereumjs-util": "^7.0.10",
19
20
  "lodash": "^4.17.15",
20
21
  "ms": "^2.1.1",
21
22
  "reselect": "~3.0.1"
@@ -23,5 +24,5 @@
23
24
  "peerDependencies": {
24
25
  "@exodus/assets": "8.0.x"
25
26
  },
26
- "gitHead": "14b8266879ea622f272c94f98e71c1a16dd274f1"
27
+ "gitHead": "a9971be6cc00557bc1581c6801c90ae8702b4712"
27
28
  }
package/src/constants.js CHANGED
@@ -1,9 +1,10 @@
1
- export const CHAIN_IDS = { ethereum: 1, ethereumclassic: 61, quorum: 10, bsc: 56 }
1
+ export const CHAIN_IDS = { ethereum: 1, ethereumclassic: 61, bsc: 56 }
2
2
  export const MIN_GASPRICE = 1e9 // 1 gwei
3
3
  export const DEFAULT_FEE_MONITOR_INTERVAL = '1m'
4
4
  export const CONFIRMATIONS_NUMBER = {
5
5
  ethereum: 30,
6
6
  ethereumclassic: 5000,
7
- quorum: 4,
8
7
  bsc: 15,
9
8
  }
9
+ export const ETHEREUM_LIKE_ASSETS = ['bsc', 'ethereum', 'ethereumclassic']
10
+ export const ETHEREUM_LIKE_TOKEN_TYPES = ['ETHEREUM_ERC20', 'BSC_BEP20']
package/src/encode.js CHANGED
@@ -1,4 +1,4 @@
1
- import etherUtil from 'ethereumjs-util'
1
+ import * as etherUtil from 'ethereumjs-util'
2
2
 
3
3
  export function validate(address) {
4
4
  if (typeof address !== 'string') return false
@@ -21,7 +21,7 @@ export function encodePrivate(privKey) {
21
21
 
22
22
  export function encodePublic(compressedPubKey) {
23
23
  const hash160bits = etherUtil.publicToAddress(compressedPubKey, true)
24
- return etherUtil.toChecksumAddress(hash160bits.toString('hex'))
24
+ return etherUtil.toChecksumAddress('0x' + hash160bits.toString('hex'))
25
25
  }
26
26
 
27
27
  export function isValidPrivate(privateKey) {
@@ -10,6 +10,9 @@ export default new FeeData(
10
10
  gasPriceEconomicalRate: 0.7,
11
11
  gasPriceMinimumRate: 0.5,
12
12
  enableFeeDelegation: false,
13
+ tipGasPrice: '2 Gwei',
14
+ baseFeeMultiplier: 1.8,
15
+ eip1559Enabled: false,
13
16
  },
14
17
  'gasPrice',
15
18
  'ethereum'
@@ -1,4 +1,3 @@
1
1
  export { default as ethereum } from './ethereum'
2
2
  export { default as ethereumclassic } from './ethereumclassic'
3
- export { default as quorum } from './quorum'
4
3
  export { default as bsc } from './bsc'
@@ -7,11 +7,15 @@ export default class EthereumLikeFeeMonitor extends FeeMonitor {
7
7
  interval = DEFAULT_FEE_MONITOR_INTERVAL,
8
8
  assetName,
9
9
  getGasPrice,
10
+ getBaseFee,
11
+ eip1559Enabled = false,
10
12
  minGasPrice = 0,
11
13
  }) {
12
14
  super({ updateFee, interval, assetName })
13
15
  this.getGasPrice = getGasPrice
14
16
  this.minGasPrice = minGasPrice
17
+ this.getBaseFee = getBaseFee
18
+ this.eip1559Enabled = eip1559Enabled
15
19
  }
16
20
 
17
21
  async fetchFee() {
@@ -25,8 +29,15 @@ export default class EthereumLikeFeeMonitor extends FeeMonitor {
25
29
  gasPrice = this.minGasPrice
26
30
  }
27
31
 
28
- return {
29
- gasPrice: `${gasPrice} wei`,
32
+ if (this.asset.name === 'ethereum' && this.eip1559Enabled) {
33
+ const baseFee = parseInt(await this.getBaseFee(), 16)
34
+ return {
35
+ gasPrice: `${gasPrice} wei`,
36
+ baseFee: `${baseFee} wei`,
37
+ eip1559Enabled: this.eip1559Enabled,
38
+ }
30
39
  }
40
+
41
+ return { gasPrice: `${gasPrice} wei` }
31
42
  }
32
43
  }
package/src/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import createContract from './create-contract'
2
2
  import ABI from './abi'
3
+ import * as feeData from './fee-data'
4
+
5
+ export { createContract, ABI, feeData }
3
6
 
4
- export { createContract, ABI }
5
7
  export * from './encode'
6
8
  export * from './unsigned-tx'
7
9
  export * from './utils'
@@ -1,5 +1,6 @@
1
1
  import { createSelector } from 'reselect'
2
2
  import ms from 'ms'
3
+ import { isEthereumLike } from '../utils'
3
4
 
4
5
  const MINUTE = ms('1m')
5
6
  const BumpType = {
@@ -122,7 +123,7 @@ export default (
122
123
  const baseAssetName = assets[assetName].baseAsset.name
123
124
  if (!getIsRbfEnabled(assetName))
124
125
  return wrapResponseToObject({ errorMessage: 'rbf is disabled' })
125
- if (!['ethereum', 'bsc'].includes(baseAssetName))
126
+ if (!isEthereumLike(assets[assetName]))
126
127
  return wrapResponseToObject({ errorMessage: `not an ETH/ERC20/BSC/BEP20 asset supplied` })
127
128
  if (!tx.pending || !tx.sent)
128
129
  return wrapResponseToObject({ errorMessage: 'can not bump a confirmed or received TX' })
@@ -1,4 +1,6 @@
1
- import ethUtil from 'ethereumjs-util'
1
+ import { bufferToHex, privateToAddress, toBuffer } from 'ethereumjs-util'
2
+ import { intToBuffer } from 'ethjs-util'
3
+
2
4
  import { isToken, currency2buffer } from '../utils'
3
5
  import { CHAIN_IDS } from '../constants'
4
6
 
@@ -11,13 +13,15 @@ export default function createUnsignedTx({
11
13
  nonce,
12
14
  txInput,
13
15
  gasLimit,
14
- gasPrice,
16
+ gasPrice, // eip 1559: `maxFeePerGas`
17
+ tipGasPrice, // eip 1559: `maxPriorityPerGas`
15
18
  privateKey,
16
19
  fromAddress,
17
20
  chainId,
21
+ eip1559Enabled,
18
22
  }): UnsignedTransaction {
19
23
  if (txInput) {
20
- txInput = ethUtil.toBuffer(txInput) // If txInput is already a Buffer, then it is passed through
24
+ txInput = toBuffer(txInput) // If txInput is already a Buffer, then it is passed through
21
25
  } else {
22
26
  txInput = Buffer.alloc(0)
23
27
  }
@@ -34,14 +38,15 @@ export default function createUnsignedTx({
34
38
  if (value.equals(Buffer.from([0]))) value = Buffer.alloc(0)
35
39
 
36
40
  if (!fromAddress) {
37
- if (privateKey) fromAddress = ethUtil.bufferToHex(ethUtil.privateToAddress(privateKey))
41
+ if (privateKey) fromAddress = bufferToHex(privateToAddress(privateKey))
38
42
  else throw new Error('createTx: Must pass fromAddress or privateKey in options')
39
43
  }
40
44
 
41
45
  const txData = {
42
- nonce: nonce === 0 ? Buffer.alloc(0) : ethUtil.intToBuffer(nonce), // mobile: { nonce: ethUtil.intToBuffer(nonce) }
43
- gasPrice: currency2buffer(gasPrice.toBase()), // mobile: { gasPrice: currency2buffer(gasPrice) }
44
- gasLimit: ethUtil.intToBuffer(gasLimit),
46
+ nonce: nonce === 0 ? Buffer.alloc(0) : intToBuffer(nonce),
47
+ gasPrice: currency2buffer(gasPrice.toBase()),
48
+ tipGasPrice: tipGasPrice ? currency2buffer(tipGasPrice.toBase()) : undefined,
49
+ gasLimit: intToBuffer(gasLimit),
45
50
  to,
46
51
  value,
47
52
  data: txInput,
@@ -53,6 +58,7 @@ export default function createUnsignedTx({
53
58
  // TODO: We should move away from putting the PK into txMeta, it is a bad practice. It is a potential PK exposure risk if the wrong PK gets included here.
54
59
  privateKey, // Used for importing private key
55
60
  fee: baseAsset.currency.baseUnit(gasPrice.toBase().toNumber() * gasLimit),
61
+ eip1559Enabled: !!eip1559Enabled,
56
62
  }
57
63
 
58
64
  return {
@@ -1,5 +1,6 @@
1
1
  /* @flow */
2
- import EthereumTx from 'ethereumjs-tx'
2
+ import { Transaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx'
3
+ import Common from '@ethereumjs/common'
3
4
 
4
5
  import type { UnsignedTransaction, SignedTransaction } from '@exodus/models/lib/types'
5
6
 
@@ -7,13 +8,38 @@ export default function signUnsignedTx(
7
8
  unsignedTx: UnsignedTransaction,
8
9
  privateKey: Buffer
9
10
  ): SignedTransaction {
10
- const { txData } = unsignedTx
11
+ const {
12
+ txData: { gasPrice, tipGasPrice: maxPriorityFeePerGas, chainId: chain, ...txData },
13
+ txMeta: { eip1559Enabled },
14
+ } = unsignedTx
11
15
 
12
- const tx = new EthereumTx(txData)
13
- tx.sign(privateKey)
16
+ let tx
17
+ /*
18
+ To assemble an EIP 1559 tx,
19
+ both `tipGasPrice` and `eip` must have been set in the input object used to build `unsignedTx`.
20
+ Whether bsc will support EIP 1559 is unknown.
21
+ So we must prevent building accidentally an EIP1559 tx on bsc if tipGasPrice is set
22
+ `eip` will be set with s corresponding feature flag in the wallet
23
+ */
24
+ if (maxPriorityFeePerGas && eip1559Enabled) {
25
+ tx = FeeMarketEIP1559Transaction.fromTxData(
26
+ {
27
+ maxFeePerGas: gasPrice,
28
+ maxPriorityFeePerGas,
29
+ type: '0x02', // https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/tx#gas-fee-market-transactions-eip-1559,
30
+ ...txData,
31
+ },
32
+ { common: new Common({ chain, hardfork: 'london' }) }
33
+ )
34
+ } else {
35
+ // Legacy tx
36
+ tx = Transaction.fromTxData({ gasPrice, ...txData }, { common: new Common({ chain }) })
37
+ }
38
+
39
+ const signedTx = tx.sign(privateKey)
14
40
 
15
41
  // serialize and get txId
16
- const rawTx = tx.serialize()
17
- const txId = tx.hash().toString('hex')
42
+ const rawTx = signedTx.serialize()
43
+ const txId = signedTx.hash().toString('hex')
18
44
  return { rawTx, txId }
19
45
  }
@@ -1,6 +1,7 @@
1
1
  import baseX from 'base-x'
2
2
  import * as ethUtil from 'ethereumjs-util'
3
3
  import assets from '@exodus/assets'
4
+ import { ETHEREUM_LIKE_ASSETS, ETHEREUM_LIKE_TOKEN_TYPES } from '../constants'
4
5
 
5
6
  export { default as calculateExtraEth } from './calculate-extra-eth'
6
7
 
@@ -9,9 +10,13 @@ const base16 = baseX('0123456789abcdef')
9
10
 
10
11
  export const isEthereumToken = (asset) => asset.assetType === 'ETHEREUM_ERC20'
11
12
  export const isBscToken = (asset) => asset.assetType === 'BSC_BEP20'
12
- export const isQuorumToken = (asset) => asset.assetType === 'QUORUM_ERC20'
13
- export const isToken = (asset) =>
14
- isEthereumToken(asset) || isBscToken(asset) || isQuorumToken(asset)
13
+ // All ethereum-like tokens
14
+ export const isEthereumLikeToken = (asset) => ETHEREUM_LIKE_TOKEN_TYPES.includes(asset.assetType)
15
+ export const isToken = isEthereumLikeToken
16
+ // All ethereum-like assets (native coins)
17
+ export const isEthereumLikeAsset = (asset) => ETHEREUM_LIKE_ASSETS.includes(asset.name)
18
+ // All ethereum-like assets and tokens
19
+ export const isEthereumLike = (asset) => ETHEREUM_LIKE_ASSETS.includes(asset.baseAsset.name)
15
20
 
16
21
  export function buffer2currency({ asset, value }) {
17
22
  return asset.currency.baseUnit(base10.encode(value)).toDefault()
@@ -41,5 +46,5 @@ export function normalizeTxId(txId: string): string {
41
46
 
42
47
  export function getBaseAsset(asset) {
43
48
  console.log(`calling deprecated function getBaseAsset(${asset.name})`) // Apr. 9th 2021
44
- return isEthereumToken(asset) ? assets.ethereum : isQuorumToken(asset) ? assets.quorum : asset
49
+ return isEthereumToken(asset) ? assets.ethereum : asset
45
50
  }
@@ -1,11 +0,0 @@
1
- import { FeeData } from '@exodus/asset-lib'
2
-
3
- export default new FeeData(
4
- {
5
- gasPrice: '0 Gwei',
6
- max: '0 Gwei',
7
- min: '0 Gwei',
8
- },
9
- 'gasPrice',
10
- 'quorum'
11
- )