@exodus/ethereum-api 10.0.0 → 10.1.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.
@@ -0,0 +1,37 @@
1
+ export const createRejectionError = ({ operation, check }) => {
2
+ const error = new Error(`Cannot ${operation}: ${check.reasonCode}`)
3
+ error.name = 'StakingRejectionError'
4
+ error.reasonCode = check.reasonCode
5
+ if (check.shortfall) {
6
+ error.shortfall = check.shortfall
7
+ error.shortfallAssetName = check.shortfallAssetName
8
+ }
9
+
10
+ return error
11
+ }
12
+
13
+ export const createSubmitError = ({ error, txIds, failedIndex }) => {
14
+ const submitError = new Error(error.message, { cause: error })
15
+ submitError.name = 'StakingSubmitError'
16
+ submitError.txIds = txIds
17
+ submitError.failedIndex = failedIndex
18
+ return submitError
19
+ }
20
+
21
+ export const fail = (reasonCode, shortfall, shortfallAssetName) => ({
22
+ ok: false,
23
+ reasonCode,
24
+ ...(shortfall && { shortfall, shortfallAssetName }),
25
+ })
26
+
27
+ export const pass = (warnings = []) => (warnings.length > 0 ? { ok: true, warnings } : { ok: true })
28
+
29
+ export const sumOperationFees = ({ estimateOperationFee, operations }) => {
30
+ if (!estimateOperationFee) return
31
+ const fees = operations.map(estimateOperationFee)
32
+ if (fees.some((fee) => !fee)) return
33
+ return fees.reduce((total, fee) => total.add(fee))
34
+ }
35
+
36
+ export const warnIfBelow = ({ balance, required, warning }) =>
37
+ pass(balance && required && balance.lt(required) ? [warning] : [])
@@ -0,0 +1,107 @@
1
+ import assert from 'minimalistic-assert'
2
+
3
+ export const STAKING_TX_MODE = Object.freeze({ single: 'single', bundle: 'bundle' })
4
+
5
+ const createSingleTx = async ({ asset, walletAccount, step, gasPrice, tipGasPrice, feeData }) => {
6
+ const createdTx = await asset.baseAsset.api.createTx({
7
+ asset,
8
+ walletAccount,
9
+ address: step.to,
10
+ amount: step.amount || asset.currency.ZERO,
11
+ txInput: step.txInput,
12
+ gasPrice,
13
+ gasLimit: step.gasLimit,
14
+ tipGasPrice,
15
+ feeData,
16
+ })
17
+ return [createdTx]
18
+ }
19
+
20
+ const createBundleTxs = async ({
21
+ asset,
22
+ walletAccount,
23
+ fromAddress,
24
+ steps,
25
+ gasPrice,
26
+ tipGasPrice,
27
+ }) => {
28
+ const baseNonce = await asset.baseAsset.getNonce({ asset, fromAddress, walletAccount })
29
+
30
+ return Promise.all(
31
+ steps.map((step, index) =>
32
+ asset.baseAsset.api.createTx({
33
+ asset,
34
+ walletAccount,
35
+ fromAddress,
36
+ amount: step.amount || asset.currency.ZERO,
37
+ tipGasPrice,
38
+ gasPrice,
39
+ toAddress: step.to,
40
+ txInput: step.txInput,
41
+ gasLimit: step.gasLimit,
42
+ nonce: baseNonce + index,
43
+ })
44
+ )
45
+ )
46
+ }
47
+
48
+ export async function createStakingTxs({
49
+ asset,
50
+ walletAccount,
51
+ fromAddress,
52
+ steps,
53
+ mode,
54
+ gasPrice,
55
+ tipGasPrice,
56
+ feeData,
57
+ }) {
58
+ assert(steps.length > 0, 'staking txs require at least one step')
59
+ assert(
60
+ steps.every(({ amount }) => !amount || amount.unitType.equals(asset.currency)),
61
+ `staking tx amounts must be in ${asset.name}, the asset sending the txs`
62
+ )
63
+
64
+ switch (mode) {
65
+ case STAKING_TX_MODE.single:
66
+ assert(steps.length === 1, 'single staking tx mode requires exactly one step')
67
+ return createSingleTx({
68
+ asset,
69
+ walletAccount,
70
+ step: steps[0],
71
+ gasPrice,
72
+ tipGasPrice,
73
+ feeData,
74
+ })
75
+ case STAKING_TX_MODE.bundle:
76
+ return createBundleTxs({ asset, walletAccount, fromAddress, steps, gasPrice, tipGasPrice })
77
+ default:
78
+ throw new Error(`Unknown staking tx mode: ${mode}`)
79
+ }
80
+ }
81
+
82
+ export async function sendStakingTxs({ asset, walletAccount, unsignedTxs, mode, onProgress }) {
83
+ switch (mode) {
84
+ case STAKING_TX_MODE.single: {
85
+ assert(unsignedTxs.length === 1, 'single staking tx mode requires exactly one tx')
86
+ onProgress?.({ index: 0, total: 1 })
87
+ const { txId } = await asset.baseAsset.api.sendTx({
88
+ asset,
89
+ walletAccount,
90
+ unsignedTx: unsignedTxs[0],
91
+ })
92
+ return { txIds: [txId] }
93
+ }
94
+
95
+ case STAKING_TX_MODE.bundle: {
96
+ const { bundleHash, txIds } = await asset.baseAsset.sendPrivateBundle({
97
+ unsignedTxBundle: unsignedTxs.map((unsignedTx) => ({ asset, unsignedTx, walletAccount })),
98
+ onBeforeSign: onProgress,
99
+ })
100
+ assert(txIds.length === unsignedTxs.length, 'expected a tx id for every bundled tx')
101
+ return { bundleHash, txIds: [...txIds] }
102
+ }
103
+
104
+ default:
105
+ throw new Error(`Unknown staking tx mode: ${mode}`)
106
+ }
107
+ }
@@ -6,4 +6,5 @@ export {
6
6
  isPolygonReward,
7
7
  isPolygonClaimUndelegate,
8
8
  isPendingPolygonUndelegateTxInEthereumTxLog,
9
+ isPolygonUndelegateTxInEthereumTxLog,
9
10
  } from './matic-staking-utils.js'