@exodus/ethereum-api 2.19.0 → 2.21.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-api",
3
- "version": "2.19.0",
3
+ "version": "2.21.0",
4
4
  "description": "Ethereum Api",
5
5
  "main": "src/index.js",
6
6
  "author": "Exodus Movement, Inc.",
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "@exodus/asset-lib": "^3.5.4",
14
14
  "@exodus/crypto": "^1.0.0-rc.0",
15
- "@exodus/ethereum-lib": "^2.18.0",
15
+ "@exodus/ethereum-lib": "^2.19.0",
16
16
  "@exodus/ethereumjs-util": "^7.1.0-exodus.6",
17
17
  "@exodus/simple-retry": "^0.0.6",
18
18
  "@exodus/solidity-contract": "^1.0.1",
@@ -29,5 +29,5 @@
29
29
  "@exodus/assets-base": "^8.0.136",
30
30
  "@exodus/models": "^8.7.2"
31
31
  },
32
- "gitHead": "de6258fcd05409586558bbffff54c2c2a3c065b1"
32
+ "gitHead": "52d783c8952348157fe767187533498088c52b01"
33
33
  }
@@ -134,12 +134,8 @@ export const getERC20Params = async ({
134
134
  })
135
135
  )
136
136
 
137
- const response = paramNames.reduce(
138
- (accumulatedObj, paramName, index) => ({
139
- ...accumulatedObj,
140
- [paramName]: paramValues[index],
141
- }),
142
- {}
137
+ const response = Object.fromEntries(
138
+ paramNames.map((paramName, index) => [paramName, paramValues[index]])
143
139
  )
144
140
  erc20ParamsCache[cacheKey] = response
145
141
 
@@ -7,18 +7,64 @@ const ethDecimals = assets.ethereum.units.ETH
7
7
 
8
8
  const ethHexToInt = (hexValue) => parseInt(hexValue, '16')
9
9
 
10
- async function getDecimals(type, assetContractAddress = null) {
11
- if (type === 'erc20' && assetContractAddress) {
12
- const { decimals } = await getERC20Params({
13
- address: assetContractAddress,
14
- assetName: 'ethereum',
15
- paramNames: ['decimals'],
16
- })
17
-
18
- return decimals
10
+ async function getAssetSymbolFromContract(contractAddress) {
11
+ const { symbol: assetSymbol } = await getERC20Params({
12
+ address: contractAddress,
13
+ assetName: 'ethereum',
14
+ paramNames: ['symbol'],
15
+ })
16
+
17
+ return assetSymbol
18
+ }
19
+
20
+ async function prepareBalanceChanges(internalTransactions, balanceChanges) {
21
+ const preparedBalanceChanges = [...balanceChanges]
22
+
23
+ const decimals = {}
24
+ const assetSymbols = {}
25
+
26
+ if (internalTransactions && Array.isArray(internalTransactions)) {
27
+ for (const transaction of internalTransactions) {
28
+ const { contractCall } = transaction
29
+
30
+ if (!contractCall) continue
31
+
32
+ if (contractCall.methodName === 'transfer' || contractCall.methodName === 'transferFrom') {
33
+ const assetSymbol =
34
+ contractCall.contractAlias ||
35
+ (await getAssetSymbolFromContract(contractCall.contractAddress))
36
+
37
+ assetSymbols[contractCall.contractAddress] = assetSymbol
38
+ decimals[assetSymbol] = contractCall.contractDecimals
39
+ }
40
+ }
19
41
  }
20
42
 
21
- return ethDecimals
43
+ for (const balanceChange of preparedBalanceChanges) {
44
+ const { asset } = balanceChange
45
+
46
+ if (!asset.symbol) {
47
+ asset.symbol =
48
+ assetSymbols[asset.contractAddress] ||
49
+ (await getAssetSymbolFromContract(asset.contractAddress))
50
+ }
51
+
52
+ if (typeof decimals[asset.symbol] === 'number') {
53
+ asset.decimal = decimals[asset.symbol]
54
+ continue
55
+ }
56
+
57
+ if (asset.type === 'erc20' && asset.contractAddress) {
58
+ const { decimals: assetDecimal } = await getERC20Params({
59
+ address: asset.contractAddress,
60
+ assetName: 'ethereum',
61
+ paramNames: ['decimals'],
62
+ })
63
+
64
+ asset.decimal = assetDecimal
65
+ }
66
+ }
67
+ return preparedBalanceChanges
22
68
  }
23
69
 
24
70
  export async function simulateAndRetrieveSideEffects(transaction) {
@@ -41,31 +87,32 @@ export async function simulateAndRetrieveSideEffects(transaction) {
41
87
  const simulatedTx = await fetchTxPreview(blocknativeTxObject)
42
88
 
43
89
  const [simulatedBalanceChanges] = simulatedTx.netBalanceChanges
90
+ const [internalTransactions] = simulatedTx.internalTransactions
44
91
 
45
92
  const [sender] =
46
93
  simulatedBalanceChanges &&
47
94
  simulatedBalanceChanges.filter(({ address }) => address === transaction.from)
48
95
 
49
96
  if (sender) {
50
- for (const balanceChange of sender.balanceChanges) {
97
+ const preparedBalanceChanges = await prepareBalanceChanges(
98
+ internalTransactions,
99
+ sender.balanceChanges
100
+ )
101
+
102
+ for (const balanceChange of preparedBalanceChanges) {
51
103
  const { delta, asset } = balanceChange
52
104
 
53
- const decimal = await getDecimals(asset.type, asset.contractAddress)
105
+ const account = {
106
+ symbol: asset.symbol,
107
+ balance: delta,
108
+ assetType: asset.type,
109
+ decimal: asset.decimal,
110
+ }
54
111
 
55
112
  if (delta.startsWith('-')) {
56
- willSend.push({
57
- symbol: asset.symbol,
58
- balance: delta.slice(1),
59
- assetType: asset.type,
60
- decimal,
61
- })
113
+ willSend.push(account)
62
114
  } else {
63
- willReceive.push({
64
- symbol: asset.symbol,
65
- balance: delta,
66
- assetType: asset.type,
67
- decimal,
68
- })
115
+ willReceive.push(account)
69
116
  }
70
117
  }
71
118
  }
@@ -73,13 +120,13 @@ export async function simulateAndRetrieveSideEffects(transaction) {
73
120
  if (!willSend.length) {
74
121
  willSend.push({
75
122
  symbol: 'ETH',
76
- balance: ethHexToInt(transaction.value).toString(),
123
+ balance: `-${ethHexToInt(transaction.value)}`,
77
124
  assetType: 'ether',
78
125
  decimal: ethDecimals,
79
126
  })
80
127
  }
81
- } catch (_) {
82
- throw new Error('Simulation of Ethereum transaction failed.')
128
+ } catch (err) {
129
+ throw new Error(err)
83
130
  }
84
131
 
85
132
  return { willSend, willReceive }