@exodus/web3-ethereum-utils 1.18.0 → 1.20.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.
|
@@ -5,13 +5,13 @@ const SIMULATION_API_DEFAULT = 'https://simulation.a.exodus.io/simulate';
|
|
|
5
5
|
const SERVICE_PROVIDER_DEFAULT = 'blowfish';
|
|
6
6
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
7
7
|
export const createSimulateTransaction = ({ serviceProvider = SERVICE_PROVIDER_DEFAULT, apiEndpoint = SIMULATION_API_DEFAULT, }) => async ({ transaction, asset, shouldCallPreviewApi = true, }) => {
|
|
8
|
-
if (!transaction.to) {
|
|
9
|
-
return createEmptySimulationResult({ asset });
|
|
10
|
-
}
|
|
11
8
|
const simulationResult = createEmptySimulationResult({ asset });
|
|
12
9
|
simulationResult.balanceChanges.willPayFee.push({
|
|
13
10
|
balance: estimateFee({ asset, transaction }),
|
|
14
11
|
});
|
|
12
|
+
if (!transaction.to) {
|
|
13
|
+
return simulationResult;
|
|
14
|
+
}
|
|
15
15
|
if (!shouldCallPreviewApi) {
|
|
16
16
|
tryEstimatingChangesLocally({ asset, simulationResult, transaction });
|
|
17
17
|
return simulationResult;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/*
|
|
2
|
-
This utility determines a fee a transaction is going to pay based on
|
|
2
|
+
This utility determines a preliminary fee a transaction is going to pay based on
|
|
3
3
|
its "gas", "gasPrice" and "maxFeePerGas" properties.
|
|
4
4
|
|
|
5
|
-
Note: if EIP-1559 is enabled a transaction will have the "maxFeePerGas" field. In that case
|
|
6
|
-
a final
|
|
7
|
-
If a transaction has
|
|
5
|
+
Note: if EIP-1559 is enabled, a transaction will have the "maxFeePerGas" field. In that case,
|
|
6
|
+
a final gas price will be determined on-chain (the utility uses a maximum possible gas price value).
|
|
7
|
+
If a transaction has only "gasPrice", it can be considered as a final gas price.
|
|
8
|
+
However, a final fee for non-simple transfers is always calculated on-chain once the EVM executes a transaction
|
|
9
|
+
and has the number of gas consumed.
|
|
8
10
|
*/
|
|
9
11
|
import { hexToBN } from '@exodus/web3-utils';
|
|
10
12
|
export const estimateFee = ({ asset, transaction, }) => {
|
|
@@ -3,5 +3,5 @@ import type { AggregatedTransactionSimulationResult, CreateSimulateTransactionPa
|
|
|
3
3
|
declare type SimulateTransactionParams = Required<CreateSimulateTransactionParams> & Pick<EthSimulateTransactionParams, 'transaction' | 'origin'> & {
|
|
4
4
|
simulationResult: AggregatedTransactionSimulationResult;
|
|
5
5
|
};
|
|
6
|
-
export declare const simulateTransaction: ({ transaction, apiEndpoint, origin, }: SimulateTransactionParams) => Promise<void> | never;
|
|
6
|
+
export declare const simulateTransaction: ({ transaction, apiEndpoint, origin, simulationResult, }: SimulateTransactionParams) => Promise<void> | never;
|
|
7
7
|
export {};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
This utility makes an API call to a simulation service, parses the response and mutates the supplied "simulationResult" object
|
|
3
3
|
with the according balance changes.
|
|
4
4
|
*/
|
|
5
|
-
import { makeSimulationAPICall } from '@exodus/web3-utils';
|
|
5
|
+
import { createCurrency, makeSimulationAPICall } from '@exodus/web3-utils';
|
|
6
6
|
const convertTransactionToApiPayload = (transaction, origin) => ({
|
|
7
7
|
txObject: {
|
|
8
8
|
from: transaction.from,
|
|
@@ -15,12 +15,102 @@ const convertTransactionToApiPayload = (transaction, origin) => ({
|
|
|
15
15
|
},
|
|
16
16
|
userAccount: transaction.from,
|
|
17
17
|
});
|
|
18
|
-
|
|
18
|
+
const createBalanceAmount = (amount, { decimals, symbol }) => {
|
|
19
|
+
const beforeAmount = createCurrency({
|
|
20
|
+
amount: amount.before,
|
|
21
|
+
symbol: symbol,
|
|
22
|
+
denominator: decimals,
|
|
23
|
+
});
|
|
24
|
+
const afterAmount = createCurrency({
|
|
25
|
+
amount: amount.after,
|
|
26
|
+
symbol: symbol,
|
|
27
|
+
denominator: decimals,
|
|
28
|
+
});
|
|
29
|
+
return beforeAmount.sub(afterAmount);
|
|
30
|
+
};
|
|
31
|
+
const handleExpectedBalanceChange = (expectedBalanceChange, simulationResult) => {
|
|
32
|
+
const { willApprove, willSend, willReceive } = simulationResult.balanceChanges;
|
|
33
|
+
const { data, kind } = expectedBalanceChange.rawInfo;
|
|
34
|
+
const { asset } = data;
|
|
35
|
+
// ERC1155 is a multi-token standard (https://eips.ethereum.org/EIPS/eip-1155) and can be used for NFTs as well.
|
|
36
|
+
const isNftTransfer = kind === 'ERC721_TRANSFER' ||
|
|
37
|
+
(kind === 'ERC1155_TRANSFER' && !asset.decimals);
|
|
38
|
+
const symbol = asset.symbol;
|
|
39
|
+
const decimals = isNftTransfer ? 1 : asset.decimals;
|
|
40
|
+
if (kind === 'ERC20_APPROVAL' ||
|
|
41
|
+
kind === 'ERC721_APPROVAL_FOR_ALL' ||
|
|
42
|
+
kind === 'ERC1155_APPROVAL_FOR_ALL' ||
|
|
43
|
+
kind === 'ERC721_APPROVAL') {
|
|
44
|
+
willApprove.push({
|
|
45
|
+
spender: data.spender.address,
|
|
46
|
+
unitName: symbol,
|
|
47
|
+
balance: createCurrency({
|
|
48
|
+
amount: data.amount.after,
|
|
49
|
+
symbol: symbol,
|
|
50
|
+
denominator: decimals,
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const { amount } = data;
|
|
56
|
+
const balance = createBalanceAmount(amount, { decimals, symbol });
|
|
57
|
+
if (balance.isZero) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const balanceChange = {
|
|
61
|
+
balance,
|
|
62
|
+
};
|
|
63
|
+
if (isNftTransfer) {
|
|
64
|
+
balanceChange.nft = {
|
|
65
|
+
title: asset.name,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (balance.isNegative) {
|
|
69
|
+
willReceive.push(balanceChange);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
willSend.push(balanceChange);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const simulationResultHasAssets = (expectedStateChanges) => {
|
|
76
|
+
for (const expectedChange of expectedStateChanges) {
|
|
77
|
+
const { asset } = expectedChange.rawInfo
|
|
78
|
+
.data;
|
|
79
|
+
if (!asset) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
};
|
|
85
|
+
export const simulateTransaction = async ({ transaction, apiEndpoint, origin, simulationResult, }) => {
|
|
86
|
+
const userAddress = transaction.from;
|
|
19
87
|
const payload = convertTransactionToApiPayload(transaction, origin);
|
|
20
|
-
await makeSimulationAPICall({
|
|
88
|
+
const response = await makeSimulationAPICall({
|
|
21
89
|
url: apiEndpoint,
|
|
22
90
|
network: 'ethereum',
|
|
23
91
|
payload,
|
|
24
92
|
});
|
|
25
|
-
|
|
93
|
+
const { expectedStateChanges = {}, error } = response.simulationResults.aggregated;
|
|
94
|
+
if (error) {
|
|
95
|
+
// ToDo: accept a logger dep and log the error
|
|
96
|
+
// ToDo: consider pushing an error to the "warnings" list
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const userExpectedChanges = Object.keys(expectedStateChanges).reduce((prev, address) => {
|
|
100
|
+
if (userAddress !== address) {
|
|
101
|
+
return prev;
|
|
102
|
+
}
|
|
103
|
+
const result = (Object.prototype.hasOwnProperty.call(expectedStateChanges, address) &&
|
|
104
|
+
expectedStateChanges[address]) ||
|
|
105
|
+
[];
|
|
106
|
+
return [...prev, ...result];
|
|
107
|
+
}, []);
|
|
108
|
+
// Return and log if asset is not present in the expectedStateChanges
|
|
109
|
+
if (!simulationResultHasAssets(userExpectedChanges)) {
|
|
110
|
+
// ToDo: accept a logger dep and log the error
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
userExpectedChanges.forEach((expectedChange) => {
|
|
114
|
+
handleExpectedBalanceChange(expectedChange, simulationResult);
|
|
115
|
+
});
|
|
26
116
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/web3-ethereum-utils",
|
|
3
3
|
"description": "Web3 Ethereum utils.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.20.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"module": "lib/index.js",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"build": "yarn clean && tsc"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@exodus/web3-types": "^1.
|
|
29
|
+
"@exodus/web3-types": "^1.25.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@exodus/ethereumjs-common": "^2.4.0-exodus.6",
|
|
33
33
|
"@exodus/ethereumjs-tx": "^3.3.0-exodus.6",
|
|
34
|
-
"@exodus/web3-utils": "^1.
|
|
34
|
+
"@exodus/web3-utils": "^1.16.0",
|
|
35
35
|
"@metamask/eth-sig-util": "^4.0.1"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "8f42c066e1d289271e5db5b859e090d06626ef0f"
|
|
38
38
|
}
|