@keplr-wallet/background 0.12.313 → 0.13.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/build/index.d.ts +1 -0
- package/build/index.js +7 -1
- package/build/index.js.map +1 -1
- package/build/keyring-cosmos/service.d.ts +10 -0
- package/build/keyring-cosmos/service.js +100 -0
- package/build/keyring-cosmos/service.js.map +1 -1
- package/build/keyring-ethereum/service.d.ts +5 -0
- package/build/keyring-ethereum/service.js +66 -0
- package/build/keyring-ethereum/service.js.map +1 -1
- package/build/recent-send-history/api.d.ts +31 -0
- package/build/recent-send-history/api.js +97 -0
- package/build/recent-send-history/api.js.map +1 -0
- package/build/recent-send-history/handler.js +36 -0
- package/build/recent-send-history/handler.js.map +1 -1
- package/build/recent-send-history/init.js +5 -0
- package/build/recent-send-history/init.js.map +1 -1
- package/build/recent-send-history/messages.d.ts +76 -1
- package/build/recent-send-history/messages.js +121 -1
- package/build/recent-send-history/messages.js.map +1 -1
- package/build/recent-send-history/service.d.ts +262 -9
- package/build/recent-send-history/service.js +2103 -812
- package/build/recent-send-history/service.js.map +1 -1
- package/build/recent-send-history/types.d.ts +214 -22
- package/build/recent-send-history/types.js +21 -0
- package/build/recent-send-history/types.js.map +1 -1
- package/build/tx/service.d.ts +2 -0
- package/build/tx/service.js +35 -0
- package/build/tx/service.js.map +1 -1
- package/build/tx-ethereum/service.d.ts +2 -0
- package/build/tx-ethereum/service.js +42 -0
- package/build/tx-ethereum/service.js.map +1 -1
- package/build/tx-executor/constants.d.ts +1 -0
- package/build/tx-executor/constants.js +5 -0
- package/build/tx-executor/constants.js.map +1 -0
- package/build/tx-executor/handler.d.ts +3 -0
- package/build/tx-executor/handler.js +45 -0
- package/build/tx-executor/handler.js.map +1 -0
- package/build/tx-executor/index.d.ts +3 -0
- package/build/tx-executor/index.js +20 -0
- package/build/tx-executor/index.js.map +1 -0
- package/build/tx-executor/init.d.ts +3 -0
- package/build/tx-executor/init.js +14 -0
- package/build/tx-executor/init.js.map +1 -0
- package/build/tx-executor/internal.d.ts +4 -0
- package/build/tx-executor/internal.js +24 -0
- package/build/tx-executor/internal.js.map +1 -0
- package/build/tx-executor/messages.d.ts +53 -0
- package/build/tx-executor/messages.js +116 -0
- package/build/tx-executor/messages.js.map +1 -0
- package/build/tx-executor/service.d.ts +67 -0
- package/build/tx-executor/service.js +715 -0
- package/build/tx-executor/service.js.map +1 -0
- package/build/tx-executor/types.d.ts +105 -0
- package/build/tx-executor/types.js +33 -0
- package/build/tx-executor/types.js.map +1 -0
- package/build/tx-executor/utils/cosmos.d.ts +59 -0
- package/build/tx-executor/utils/cosmos.js +526 -0
- package/build/tx-executor/utils/cosmos.js.map +1 -0
- package/build/tx-executor/utils/evm.d.ts +4 -0
- package/build/tx-executor/utils/evm.js +236 -0
- package/build/tx-executor/utils/evm.js.map +1 -0
- package/package.json +13 -13
- package/src/index.ts +24 -1
- package/src/keyring-cosmos/service.ts +151 -0
- package/src/keyring-ethereum/service.ts +103 -6
- package/src/recent-send-history/api.ts +119 -0
- package/src/recent-send-history/handler.ts +84 -0
- package/src/recent-send-history/init.ts +10 -0
- package/src/recent-send-history/messages.ts +163 -1
- package/src/recent-send-history/service.ts +3042 -1153
- package/src/recent-send-history/types.ts +268 -31
- package/src/tx/service.ts +41 -0
- package/src/tx-ethereum/service.ts +57 -0
- package/src/tx-executor/constants.ts +1 -0
- package/src/tx-executor/handler.ts +71 -0
- package/src/tx-executor/index.ts +3 -0
- package/src/tx-executor/init.ts +20 -0
- package/src/tx-executor/internal.ts +9 -0
- package/src/tx-executor/messages.ts +157 -0
- package/src/tx-executor/service.ts +1025 -0
- package/src/tx-executor/types.ts +161 -0
- package/src/tx-executor/utils/cosmos.ts +771 -0
- package/src/tx-executor/utils/evm.ts +310 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { EVMInfo } from "@keplr-wallet/types";
|
|
2
|
+
import { simpleFetch } from "@keplr-wallet/simple-fetch";
|
|
3
|
+
import { UnsignedTransaction } from "@ethersproject/transactions";
|
|
4
|
+
import { Dec } from "@keplr-wallet/unit";
|
|
5
|
+
import { BackgroundTxFeeType } from "../types";
|
|
6
|
+
import { JsonRpcResponse } from "@keplr-wallet/types";
|
|
7
|
+
|
|
8
|
+
const ETH_FEE_HISTORY_REWARD_PERCENTILES = [25, 50, 75];
|
|
9
|
+
const ETH_FEE_SETTINGS_BY_FEE_TYPE: Record<
|
|
10
|
+
BackgroundTxFeeType,
|
|
11
|
+
{
|
|
12
|
+
percentile: number;
|
|
13
|
+
}
|
|
14
|
+
> = {
|
|
15
|
+
low: {
|
|
16
|
+
percentile: ETH_FEE_HISTORY_REWARD_PERCENTILES[0],
|
|
17
|
+
},
|
|
18
|
+
average: {
|
|
19
|
+
percentile: ETH_FEE_HISTORY_REWARD_PERCENTILES[1],
|
|
20
|
+
},
|
|
21
|
+
high: {
|
|
22
|
+
percentile: ETH_FEE_HISTORY_REWARD_PERCENTILES[2],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const FEE_MULTIPLIERS: Record<BackgroundTxFeeType, number> = {
|
|
27
|
+
low: 1.1,
|
|
28
|
+
average: 1.25,
|
|
29
|
+
high: 1.5,
|
|
30
|
+
};
|
|
31
|
+
const GAS_ADJUSTMENT_NUM = BigInt(13);
|
|
32
|
+
const GAS_ADJUSTMENT_DEN = BigInt(10);
|
|
33
|
+
|
|
34
|
+
const TX_COUNT_ID = 1;
|
|
35
|
+
const LATEST_BLOCK_ID = 2;
|
|
36
|
+
const FEE_HISTORY_ID = 3;
|
|
37
|
+
const ESTIMATE_GAS_ID = 4;
|
|
38
|
+
const MAX_PRIORITY_FEE_ID = 5;
|
|
39
|
+
|
|
40
|
+
type BigNumberishLike = string | number | bigint | { toString(): string };
|
|
41
|
+
|
|
42
|
+
const toBigIntFromTxField = (value: BigNumberishLike): bigint => {
|
|
43
|
+
if (
|
|
44
|
+
typeof value === "string" ||
|
|
45
|
+
typeof value === "number" ||
|
|
46
|
+
typeof value === "bigint"
|
|
47
|
+
) {
|
|
48
|
+
return BigInt(value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (value && typeof value === "object" && "toString" in value) {
|
|
52
|
+
return BigInt((value as { toString(): string }).toString());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
throw new Error("Unsupported numeric value in unsigned transaction");
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export async function fillUnsignedEVMTx(
|
|
59
|
+
origin: string,
|
|
60
|
+
evmInfo: EVMInfo,
|
|
61
|
+
signer: string,
|
|
62
|
+
tx: UnsignedTransaction,
|
|
63
|
+
feeType: BackgroundTxFeeType = "average"
|
|
64
|
+
): Promise<UnsignedTransaction> {
|
|
65
|
+
const hasProvidedPriorityFee = tx.maxPriorityFeePerGas != null;
|
|
66
|
+
const hasProvidedGasLimit = tx.gasLimit != null;
|
|
67
|
+
|
|
68
|
+
const getTransactionCountRequest = {
|
|
69
|
+
jsonrpc: "2.0",
|
|
70
|
+
method: "eth_getTransactionCount",
|
|
71
|
+
params: [signer, "pending"],
|
|
72
|
+
id: TX_COUNT_ID,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const getBlockRequest = {
|
|
76
|
+
jsonrpc: "2.0",
|
|
77
|
+
method: "eth_getBlockByNumber",
|
|
78
|
+
params: ["latest", false],
|
|
79
|
+
id: LATEST_BLOCK_ID,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const getFeeHistoryRequest = hasProvidedPriorityFee
|
|
83
|
+
? null
|
|
84
|
+
: {
|
|
85
|
+
jsonrpc: "2.0",
|
|
86
|
+
method: "eth_feeHistory",
|
|
87
|
+
params: [20, "latest", ETH_FEE_HISTORY_REWARD_PERCENTILES],
|
|
88
|
+
id: FEE_HISTORY_ID,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const estimateGasRequest = hasProvidedGasLimit
|
|
92
|
+
? null
|
|
93
|
+
: {
|
|
94
|
+
jsonrpc: "2.0",
|
|
95
|
+
method: "eth_estimateGas",
|
|
96
|
+
params: [
|
|
97
|
+
{
|
|
98
|
+
from: signer,
|
|
99
|
+
to: tx.to,
|
|
100
|
+
value: tx.value,
|
|
101
|
+
data: tx.data,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
id: ESTIMATE_GAS_ID,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const getMaxPriorityFeePerGasRequest = hasProvidedPriorityFee
|
|
108
|
+
? null
|
|
109
|
+
: {
|
|
110
|
+
jsonrpc: "2.0",
|
|
111
|
+
method: "eth_maxPriorityFeePerGas",
|
|
112
|
+
params: [],
|
|
113
|
+
id: MAX_PRIORITY_FEE_ID,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// rpc request in batch (as 2.0 jsonrpc supports batch requests)
|
|
117
|
+
const batchRequest = [
|
|
118
|
+
getTransactionCountRequest,
|
|
119
|
+
getBlockRequest,
|
|
120
|
+
...(getFeeHistoryRequest ? [getFeeHistoryRequest] : []),
|
|
121
|
+
...(estimateGasRequest ? [estimateGasRequest] : []),
|
|
122
|
+
...(getMaxPriorityFeePerGasRequest ? [getMaxPriorityFeePerGasRequest] : []),
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
const { data: rpcResponses } = await simpleFetch<
|
|
126
|
+
Array<JsonRpcResponse<unknown>>
|
|
127
|
+
>(evmInfo.rpc, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: {
|
|
130
|
+
"content-type": "application/json",
|
|
131
|
+
"request-source": origin,
|
|
132
|
+
},
|
|
133
|
+
body: JSON.stringify(batchRequest),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (
|
|
137
|
+
!Array.isArray(rpcResponses) ||
|
|
138
|
+
rpcResponses.length !== batchRequest.length
|
|
139
|
+
) {
|
|
140
|
+
throw new Error("Invalid batch response format");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const getResult = <T = any>(id: number, optional = false): T | undefined => {
|
|
144
|
+
const res = rpcResponses.find((r) => r.id === id);
|
|
145
|
+
if (!res) {
|
|
146
|
+
if (optional) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
throw new Error(`No response for id=${id}`);
|
|
150
|
+
}
|
|
151
|
+
if (res.error) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`RPC error (id=${id}): ${res.error.code} ${res.error.message}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return res.result as T;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// find responses by id
|
|
160
|
+
const nonceHex = getResult<string>(TX_COUNT_ID);
|
|
161
|
+
if (!nonceHex) {
|
|
162
|
+
throw new Error("Failed to get nonce to fill unsigned transaction");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const latestBlock = getResult<{ baseFeePerGas?: string }>(LATEST_BLOCK_ID);
|
|
166
|
+
if (!latestBlock) {
|
|
167
|
+
throw new Error("Failed to get latest block to fill unsigned transaction");
|
|
168
|
+
}
|
|
169
|
+
const feeHistory = hasProvidedPriorityFee
|
|
170
|
+
? undefined
|
|
171
|
+
: getResult<{
|
|
172
|
+
baseFeePerGas?: string[];
|
|
173
|
+
gasUsedRatio: number[];
|
|
174
|
+
oldestBlock: string;
|
|
175
|
+
reward?: string[][];
|
|
176
|
+
}>(FEE_HISTORY_ID);
|
|
177
|
+
const gasLimitHex = hasProvidedGasLimit
|
|
178
|
+
? undefined
|
|
179
|
+
: getResult<string>(ESTIMATE_GAS_ID, true);
|
|
180
|
+
const networkMaxPriorityFeePerGasHex = hasProvidedPriorityFee
|
|
181
|
+
? undefined
|
|
182
|
+
: getResult<string>(MAX_PRIORITY_FEE_ID, true);
|
|
183
|
+
|
|
184
|
+
let maxPriorityFeePerGasDec: Dec | undefined;
|
|
185
|
+
|
|
186
|
+
if (hasProvidedPriorityFee) {
|
|
187
|
+
if (tx.maxPriorityFeePerGas == null) {
|
|
188
|
+
throw new Error("maxPriorityFeePerGas is required but missing");
|
|
189
|
+
}
|
|
190
|
+
maxPriorityFeePerGasDec = new Dec(
|
|
191
|
+
toBigIntFromTxField(tx.maxPriorityFeePerGas)
|
|
192
|
+
);
|
|
193
|
+
} else if (feeHistory?.reward && feeHistory.reward.length > 0) {
|
|
194
|
+
const percentile =
|
|
195
|
+
ETH_FEE_SETTINGS_BY_FEE_TYPE[feeType].percentile ??
|
|
196
|
+
ETH_FEE_HISTORY_REWARD_PERCENTILES[1];
|
|
197
|
+
const percentileIndex =
|
|
198
|
+
ETH_FEE_HISTORY_REWARD_PERCENTILES.indexOf(percentile);
|
|
199
|
+
|
|
200
|
+
if (percentileIndex >= 0) {
|
|
201
|
+
const rewards = feeHistory.reward
|
|
202
|
+
.map((block) => block[percentileIndex])
|
|
203
|
+
.filter((v) => v != null)
|
|
204
|
+
.map((v) => BigInt(v));
|
|
205
|
+
|
|
206
|
+
if (rewards.length > 0) {
|
|
207
|
+
const sum = rewards.reduce((acc, x) => acc + x, BigInt(0));
|
|
208
|
+
const mean = sum / BigInt(rewards.length);
|
|
209
|
+
|
|
210
|
+
const sortedRewards = [...rewards].sort((a, b) =>
|
|
211
|
+
a < b ? -1 : a > b ? 1 : 0
|
|
212
|
+
);
|
|
213
|
+
const median = sortedRewards[Math.floor(sortedRewards.length / 2)];
|
|
214
|
+
|
|
215
|
+
// use 1 Gwei deviation threshold to decide between mean and median
|
|
216
|
+
const deviationThreshold = BigInt(1 * 10 ** 9); // 1 Gwei
|
|
217
|
+
const deviation = mean > median ? mean - median : median - mean;
|
|
218
|
+
const pick =
|
|
219
|
+
deviation > deviationThreshold
|
|
220
|
+
? mean > median
|
|
221
|
+
? mean
|
|
222
|
+
: median
|
|
223
|
+
: mean;
|
|
224
|
+
|
|
225
|
+
maxPriorityFeePerGasDec = new Dec(pick);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (networkMaxPriorityFeePerGasHex) {
|
|
231
|
+
const networkMaxPriorityFeePerGasDec = new Dec(
|
|
232
|
+
BigInt(networkMaxPriorityFeePerGasHex)
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
if (
|
|
236
|
+
!maxPriorityFeePerGasDec ||
|
|
237
|
+
(maxPriorityFeePerGasDec &&
|
|
238
|
+
networkMaxPriorityFeePerGasDec.gt(maxPriorityFeePerGasDec))
|
|
239
|
+
) {
|
|
240
|
+
maxPriorityFeePerGasDec = networkMaxPriorityFeePerGasDec;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!maxPriorityFeePerGasDec) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
"Failed to calculate maxPriorityFeePerGas to fill unsigned transaction"
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!latestBlock.baseFeePerGas) {
|
|
251
|
+
throw new Error("Failed to get baseFeePerGas to fill unsigned transaction");
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const multiplier = new Dec(FEE_MULTIPLIERS[feeType]);
|
|
255
|
+
|
|
256
|
+
// Calculate maxFeePerGas = baseFeePerGas + maxPriorityFeePerGas
|
|
257
|
+
const baseFeePerGasDec = new Dec(BigInt(latestBlock.baseFeePerGas));
|
|
258
|
+
const suggestedFeeFromBase = baseFeePerGasDec.mul(multiplier);
|
|
259
|
+
|
|
260
|
+
const providedMaxFeePerGasDec = tx.maxFeePerGas
|
|
261
|
+
? new Dec(toBigIntFromTxField(tx.maxFeePerGas))
|
|
262
|
+
: undefined;
|
|
263
|
+
|
|
264
|
+
const maxFeePerGasDec =
|
|
265
|
+
providedMaxFeePerGasDec && hasProvidedPriorityFee
|
|
266
|
+
? providedMaxFeePerGasDec.gte(
|
|
267
|
+
suggestedFeeFromBase.add(maxPriorityFeePerGasDec)
|
|
268
|
+
)
|
|
269
|
+
? providedMaxFeePerGasDec
|
|
270
|
+
: suggestedFeeFromBase.add(maxPriorityFeePerGasDec)
|
|
271
|
+
: suggestedFeeFromBase.add(maxPriorityFeePerGasDec);
|
|
272
|
+
|
|
273
|
+
const maxFeePerGasHex = `0x${maxFeePerGasDec
|
|
274
|
+
.truncate()
|
|
275
|
+
.toBigNumber()
|
|
276
|
+
.toString(16)}`;
|
|
277
|
+
|
|
278
|
+
const maxPriorityFeePerGasHex = `0x${maxPriorityFeePerGasDec
|
|
279
|
+
.truncate()
|
|
280
|
+
.toBigNumber()
|
|
281
|
+
.toString(16)}`;
|
|
282
|
+
|
|
283
|
+
const finalNonce =
|
|
284
|
+
tx.nonce != null
|
|
285
|
+
? Math.max(Number(tx.nonce), parseInt(nonceHex, 16))
|
|
286
|
+
: parseInt(nonceHex, 16);
|
|
287
|
+
|
|
288
|
+
let finalGasLimit: UnsignedTransaction["gasLimit"];
|
|
289
|
+
if (tx.gasLimit != null) {
|
|
290
|
+
finalGasLimit = tx.gasLimit;
|
|
291
|
+
} else if (gasLimitHex) {
|
|
292
|
+
const estimatedGas = toBigIntFromTxField(gasLimitHex);
|
|
293
|
+
const adjustedGas =
|
|
294
|
+
(estimatedGas * GAS_ADJUSTMENT_NUM + (GAS_ADJUSTMENT_DEN - BigInt(1))) /
|
|
295
|
+
GAS_ADJUSTMENT_DEN;
|
|
296
|
+
finalGasLimit = `0x${adjustedGas.toString(16)}`;
|
|
297
|
+
} else {
|
|
298
|
+
throw new Error("Failed to estimate gas to fill unsigned transaction");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const newUnsignedTx: UnsignedTransaction = {
|
|
302
|
+
...tx,
|
|
303
|
+
nonce: finalNonce,
|
|
304
|
+
maxFeePerGas: maxFeePerGasHex,
|
|
305
|
+
maxPriorityFeePerGas: maxPriorityFeePerGasHex,
|
|
306
|
+
gasLimit: finalGasLimit,
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
return newUnsignedTx;
|
|
310
|
+
}
|