@octaflowlabs/onchain-sdk 1.3.9 → 1.4.2

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,20 @@
1
+ /** local imports */
2
+ import { GAS_LIMIT_PER_TX_TYPE } from '../constants/constants';
3
+ import { FeeDataInput } from '../types/common';
4
+ export type FeeSnapshotTxKind = keyof typeof GAS_LIMIT_PER_TX_TYPE;
5
+ export type FetchFeeSnapshotOptions = {
6
+ rpcUrl: string;
7
+ chainId: number;
8
+ /**
9
+ * Selects a default `gasLimit` for the returned `FeeDataInput` (e.g. for `getFeePresets`).
10
+ * Does not trigger `eth_estimateGas`; only `gasLimit` on the returned object changes.
11
+ */
12
+ txKind?: FeeSnapshotTxKind;
13
+ /** When set, overrides the gas limit implied by `txKind`. */
14
+ gasLimit?: bigint;
15
+ };
16
+ /**
17
+ * Reads current fee fields from the node (`getFeeData` → `eth_feeHistory` / `eth_gasPrice`, etc.).
18
+ * Does not call `eth_estimateGas` or `eth_getTransactionCount`.
19
+ */
20
+ export declare const fetchFeeSnapshot: (options: FetchFeeSnapshotOptions) => Promise<FeeDataInput>;
@@ -0,0 +1,30 @@
1
+ /** local imports */
2
+ import { GAS_LIMIT_PER_TX_TYPE } from '../constants/constants';
3
+ import { getProvider } from './getProvider';
4
+ /**
5
+ * Reads current fee fields from the node (`getFeeData` → `eth_feeHistory` / `eth_gasPrice`, etc.).
6
+ * Does not call `eth_estimateGas` or `eth_getTransactionCount`.
7
+ */
8
+ export const fetchFeeSnapshot = async (options) => {
9
+ const { rpcUrl, chainId, txKind = 'DEFAULT_TRANSFER_NATIVE', gasLimit: gasLimitOverride, } = options;
10
+ const provider = getProvider(rpcUrl, chainId);
11
+ if (!provider)
12
+ throw new Error('Could not create provider with given rpcUrl and chainId');
13
+ const raw = await provider.getFeeData();
14
+ const feeData = {
15
+ maxFeePerGas: raw.maxFeePerGas ?? undefined,
16
+ maxPriorityFeePerGas: raw.maxPriorityFeePerGas ?? undefined,
17
+ gasPrice: raw.gasPrice ?? undefined,
18
+ };
19
+ const has1559 = feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null;
20
+ const hasLegacy = feeData.gasPrice != null;
21
+ if (!has1559 && !hasLegacy) {
22
+ throw new Error('fetchFeeSnapshot: provider returned no usable fee fields (EIP-1559 or legacy gas price)');
23
+ }
24
+ const gasLimit = gasLimitOverride ?? GAS_LIMIT_PER_TX_TYPE[txKind];
25
+ return {
26
+ chainId,
27
+ gasLimit,
28
+ feeData,
29
+ };
30
+ };
@@ -0,0 +1,20 @@
1
+ /** local imports */
2
+ import { GAS_LIMIT_PER_TX_TYPE } from '../constants/constants';
3
+ import { FeeDataInput } from '../types/common';
4
+ export type FeeSnapshotTxKind = keyof typeof GAS_LIMIT_PER_TX_TYPE;
5
+ export type FetchFeeSnapshotOptions = {
6
+ rpcUrl: string;
7
+ chainId: number;
8
+ /**
9
+ * Selects a default `gasLimit` for the returned `FeeDataInput` (e.g. for `getFeePresets`).
10
+ * Does not trigger `eth_estimateGas`; only `gasLimit` on the returned object changes.
11
+ */
12
+ txKind?: FeeSnapshotTxKind;
13
+ /** When set, overrides the gas limit implied by `txKind`. */
14
+ gasLimit?: bigint;
15
+ };
16
+ /**
17
+ * Reads current fee fields from the node (`getFeeData` → `eth_feeHistory` / `eth_gasPrice`, etc.).
18
+ * Does not call `eth_estimateGas` or `eth_getTransactionCount`.
19
+ */
20
+ export declare const fetchFeeSnapshot: (options: FetchFeeSnapshotOptions) => Promise<FeeDataInput>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchFeeSnapshot = void 0;
4
+ /** local imports */
5
+ const constants_1 = require("../constants/constants");
6
+ const getProvider_1 = require("./getProvider");
7
+ /**
8
+ * Reads current fee fields from the node (`getFeeData` → `eth_feeHistory` / `eth_gasPrice`, etc.).
9
+ * Does not call `eth_estimateGas` or `eth_getTransactionCount`.
10
+ */
11
+ const fetchFeeSnapshot = async (options) => {
12
+ const { rpcUrl, chainId, txKind = 'DEFAULT_TRANSFER_NATIVE', gasLimit: gasLimitOverride, } = options;
13
+ const provider = (0, getProvider_1.getProvider)(rpcUrl, chainId);
14
+ if (!provider)
15
+ throw new Error('Could not create provider with given rpcUrl and chainId');
16
+ const raw = await provider.getFeeData();
17
+ const feeData = {
18
+ maxFeePerGas: raw.maxFeePerGas ?? undefined,
19
+ maxPriorityFeePerGas: raw.maxPriorityFeePerGas ?? undefined,
20
+ gasPrice: raw.gasPrice ?? undefined,
21
+ };
22
+ const has1559 = feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null;
23
+ const hasLegacy = feeData.gasPrice != null;
24
+ if (!has1559 && !hasLegacy) {
25
+ throw new Error('fetchFeeSnapshot: provider returned no usable fee fields (EIP-1559 or legacy gas price)');
26
+ }
27
+ const gasLimit = gasLimitOverride ?? constants_1.GAS_LIMIT_PER_TX_TYPE[txKind];
28
+ return {
29
+ chainId,
30
+ gasLimit,
31
+ feeData,
32
+ };
33
+ };
34
+ exports.fetchFeeSnapshot = fetchFeeSnapshot;
@@ -8,6 +8,7 @@ export interface NetworkField {
8
8
  iconUrl: string;
9
9
  symbol: string;
10
10
  failoverRpcUrl?: string;
11
+ blockTime?: number;
11
12
  }
12
13
  export interface NetworkRegistry {
13
14
  category: string;
@@ -15,6 +15,7 @@ exports.NETWORKS_REGISTRY = [
15
15
  iconUrl: 'https://assets.coingecko.com/coins/images/279/large/ethereum.png',
16
16
  symbol: 'ETH',
17
17
  failoverRpcUrl: 'https://eth.llamarpc.com',
18
+ blockTime: 12,
18
19
  },
19
20
  {
20
21
  id: 'bnb-smart-chain',
@@ -26,6 +27,7 @@ exports.NETWORKS_REGISTRY = [
26
27
  iconUrl: 'https://assets.coingecko.com/coins/images/825/large/bnb-icon2_2x.png',
27
28
  symbol: 'BNB',
28
29
  failoverRpcUrl: 'https://bsc.llamarpc.com',
30
+ blockTime: 3,
29
31
  },
30
32
  {
31
33
  id: 'polygon-mainnet',
@@ -37,6 +39,7 @@ exports.NETWORKS_REGISTRY = [
37
39
  explorerUrl: 'https://polygonscan.com',
38
40
  symbol: 'POL',
39
41
  failoverRpcUrl: 'https://polygon.llamarpc.com',
42
+ blockTime: 2,
40
43
  },
41
44
  {
42
45
  id: 'arbitrum-mainnet',
@@ -48,6 +51,7 @@ exports.NETWORKS_REGISTRY = [
48
51
  iconUrl: 'https://assets.coingecko.com/coins/images/16547/large/photo_2023-03-29_21.47.00.jpeg',
49
52
  symbol: 'ARB',
50
53
  failoverRpcUrl: 'https://arb.llamarpc.com',
54
+ blockTime: 1,
51
55
  },
52
56
  ],
53
57
  },
@@ -64,6 +68,7 @@ exports.NETWORKS_REGISTRY = [
64
68
  iconUrl: 'https://assets.coingecko.com/coins/images/279/large/ethereum.png',
65
69
  symbol: 'ETH',
66
70
  failoverRpcUrl: 'https://eth-sepolia.llamarpc.com',
71
+ blockTime: 12,
67
72
  },
68
73
  ],
69
74
  },
@@ -3,7 +3,7 @@ import ERC20_TOKEN_CONTRACT_ABI from './ABIs/ERC20_TOKEN_CONTRACT_ABI';
3
3
  export { ERC20_TOKEN_CONTRACT_ABI };
4
4
  /** constants exports */
5
5
  export { GAS_LIMIT_PER_TX_TYPE, MULTICALL3_ADDRESS } from './constants/constants';
6
- export { NetworkField, NetworkRegistry, NETWORKS_REGISTRY, } from './constants/NETWORKS_REGISTRY';
6
+ export { NetworkField, NetworkRegistry, NETWORKS_REGISTRY } from './constants/NETWORKS_REGISTRY';
7
7
  export { BASIC_TOKENS_BY_CHAIN, BasicTokenData, BasicTokenSymbol, ChainTokenDataMap, } from './constants/BASIC_TOKENS_REGISTRY';
8
8
  /** basic blockchain exports */
9
9
  export { buildBaseUnsignedTransferTx, buildMaxNativeTransferTx, buildUnsignedTransferTx, } from './blockchain/buildUnsignedTransferTx';
@@ -14,6 +14,7 @@ export { txStatus } from './blockchain/txStatus';
14
14
  export { getBalance, getBalances } from './blockchain/getBalances';
15
15
  export { estimateTransaction } from './blockchain/estimateTransaction';
16
16
  export { prepareTransaction } from './blockchain/prepareTransaction';
17
+ export { fetchFeeSnapshot, type FetchFeeSnapshotOptions, type FeeSnapshotTxKind, } from './blockchain/fetchFeeSnapshot';
17
18
  /** services exports */
18
19
  export { EvmWalletService, EvmGeneratedWallet, EvmDerivedWallet, } from './services/evm-wallet-core/evmWalletService';
19
20
  export { EntropySource } from './services/evm-wallet-core/entropy';
@@ -26,5 +27,7 @@ export { NATIVE_TOKENS };
26
27
  export { formattedAmountForDisplay, parsedAmount } from './utils/formatAmount';
27
28
  export { handleErrorMessages, errorMessagesForBroadcast, errorMessagesForGasLimitEstimation, } from './utils/handleErrorMessages';
28
29
  export { normalizeAddress } from './utils/normalizeAddress';
30
+ export { toGwei, tryParseGweiToWei, parseGasLimit } from './utils/parseGasFees';
31
+ export { getFeePresets, calcReserve, estimateSeconds, getBlockTime, BLOCK_TIME_BY_CHAIN, } from './utils/feePresets';
29
32
  /** types exports */
30
- export { BroadcastTransactionOptions, BuildMaxNativeTransferTxOptions, BuildUnsignedTransferTxOptions, EstimateGasLimitFromProviderProps, GasEstimateResult, TxStatusOptions, BuildBaseUnsignedTransferTxParams, TxStatusResponse, EstimateTransactionOptions, EstimateTransactionResult, PrepareTransactionParams, PrepareTransactionResult, FormatAmountOptions, TransactionRequest, GetBalanceParams, GetBalancesParams, GetBalancesChainRequest, GetBalanceResult, ChainBalances, TokenBalance, ChainGroup, } from './types/common';
33
+ export { BroadcastTransactionOptions, BuildMaxNativeTransferTxOptions, BuildUnsignedTransferTxOptions, EstimateGasLimitFromProviderProps, GasEstimateResult, TxStatusOptions, BuildBaseUnsignedTransferTxParams, TxStatusResponse, EstimateTransactionOptions, EstimateTransactionResult, PrepareTransactionParams, PrepareTransactionResult, FormatAmountOptions, TransactionRequest, GetBalanceParams, GetBalancesParams, GetBalancesChainRequest, GetBalanceResult, ChainBalances, TokenBalance, ChainGroup, FeePreset, FeePresetLabel, FeeEstimateSeconds, ResolvedFees, EIP1559Fees, LegacyFees, FeeModel, FeeHistoryData, FeeDataInput, } from './types/common';
package/dist/cjs/index.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.normalizeAddress = exports.errorMessagesForGasLimitEstimation = exports.errorMessagesForBroadcast = exports.handleErrorMessages = exports.parsedAmount = exports.formattedAmountForDisplay = exports.NATIVE_TOKENS = exports.transformBigInt = exports.getShortenData = exports.getShortenTransactionHashOrAddress = exports.signTransaction = exports.signMessage = exports.createWallet = exports.EvmWalletService = exports.prepareTransaction = exports.estimateTransaction = exports.getBalances = exports.getBalance = exports.txStatus = exports.getProvider = exports.estimateGasLimitFromProvider = exports.broadcastTransaction = exports.buildUnsignedTransferTx = exports.buildMaxNativeTransferTx = exports.buildBaseUnsignedTransferTx = exports.BASIC_TOKENS_BY_CHAIN = exports.NETWORKS_REGISTRY = exports.MULTICALL3_ADDRESS = exports.GAS_LIMIT_PER_TX_TYPE = exports.ERC20_TOKEN_CONTRACT_ABI = void 0;
6
+ exports.BLOCK_TIME_BY_CHAIN = exports.getBlockTime = exports.estimateSeconds = exports.calcReserve = exports.getFeePresets = exports.parseGasLimit = exports.tryParseGweiToWei = exports.toGwei = exports.normalizeAddress = exports.errorMessagesForGasLimitEstimation = exports.errorMessagesForBroadcast = exports.handleErrorMessages = exports.parsedAmount = exports.formattedAmountForDisplay = exports.NATIVE_TOKENS = exports.transformBigInt = exports.getShortenData = exports.getShortenTransactionHashOrAddress = exports.signTransaction = exports.signMessage = exports.createWallet = exports.EvmWalletService = exports.fetchFeeSnapshot = exports.prepareTransaction = exports.estimateTransaction = exports.getBalances = exports.getBalance = exports.txStatus = exports.getProvider = exports.estimateGasLimitFromProvider = exports.broadcastTransaction = exports.buildUnsignedTransferTx = exports.buildMaxNativeTransferTx = exports.buildBaseUnsignedTransferTx = exports.BASIC_TOKENS_BY_CHAIN = exports.NETWORKS_REGISTRY = exports.MULTICALL3_ADDRESS = exports.GAS_LIMIT_PER_TX_TYPE = exports.ERC20_TOKEN_CONTRACT_ABI = void 0;
7
7
  /** ABIs exports */
8
8
  const ERC20_TOKEN_CONTRACT_ABI_1 = __importDefault(require("./ABIs/ERC20_TOKEN_CONTRACT_ABI"));
9
9
  exports.ERC20_TOKEN_CONTRACT_ABI = ERC20_TOKEN_CONTRACT_ABI_1.default;
@@ -35,6 +35,8 @@ var estimateTransaction_1 = require("./blockchain/estimateTransaction");
35
35
  Object.defineProperty(exports, "estimateTransaction", { enumerable: true, get: function () { return estimateTransaction_1.estimateTransaction; } });
36
36
  var prepareTransaction_1 = require("./blockchain/prepareTransaction");
37
37
  Object.defineProperty(exports, "prepareTransaction", { enumerable: true, get: function () { return prepareTransaction_1.prepareTransaction; } });
38
+ var fetchFeeSnapshot_1 = require("./blockchain/fetchFeeSnapshot");
39
+ Object.defineProperty(exports, "fetchFeeSnapshot", { enumerable: true, get: function () { return fetchFeeSnapshot_1.fetchFeeSnapshot; } });
38
40
  /** services exports */
39
41
  var evmWalletService_1 = require("./services/evm-wallet-core/evmWalletService");
40
42
  Object.defineProperty(exports, "EvmWalletService", { enumerable: true, get: function () { return evmWalletService_1.EvmWalletService; } });
@@ -59,3 +61,13 @@ Object.defineProperty(exports, "errorMessagesForBroadcast", { enumerable: true,
59
61
  Object.defineProperty(exports, "errorMessagesForGasLimitEstimation", { enumerable: true, get: function () { return handleErrorMessages_1.errorMessagesForGasLimitEstimation; } });
60
62
  var normalizeAddress_1 = require("./utils/normalizeAddress");
61
63
  Object.defineProperty(exports, "normalizeAddress", { enumerable: true, get: function () { return normalizeAddress_1.normalizeAddress; } });
64
+ var parseGasFees_1 = require("./utils/parseGasFees");
65
+ Object.defineProperty(exports, "toGwei", { enumerable: true, get: function () { return parseGasFees_1.toGwei; } });
66
+ Object.defineProperty(exports, "tryParseGweiToWei", { enumerable: true, get: function () { return parseGasFees_1.tryParseGweiToWei; } });
67
+ Object.defineProperty(exports, "parseGasLimit", { enumerable: true, get: function () { return parseGasFees_1.parseGasLimit; } });
68
+ var feePresets_1 = require("./utils/feePresets");
69
+ Object.defineProperty(exports, "getFeePresets", { enumerable: true, get: function () { return feePresets_1.getFeePresets; } });
70
+ Object.defineProperty(exports, "calcReserve", { enumerable: true, get: function () { return feePresets_1.calcReserve; } });
71
+ Object.defineProperty(exports, "estimateSeconds", { enumerable: true, get: function () { return feePresets_1.estimateSeconds; } });
72
+ Object.defineProperty(exports, "getBlockTime", { enumerable: true, get: function () { return feePresets_1.getBlockTime; } });
73
+ Object.defineProperty(exports, "BLOCK_TIME_BY_CHAIN", { enumerable: true, get: function () { return feePresets_1.BLOCK_TIME_BY_CHAIN; } });
@@ -130,3 +130,46 @@ export interface ChainGroup {
130
130
  nativeBalanceRequests: GetBalanceParams[];
131
131
  tokenBalanceRequests: GetBalanceParams[];
132
132
  }
133
+ export type EIP1559Fees = {
134
+ mode: 'eip1559';
135
+ maxFeePerGas: bigint;
136
+ maxPriorityFeePerGas: bigint;
137
+ gasLimit: bigint;
138
+ };
139
+ export type LegacyFees = {
140
+ mode: 'legacy';
141
+ gasPrice: bigint;
142
+ gasLimit: bigint;
143
+ };
144
+ export type ResolvedFees = EIP1559Fees | LegacyFees;
145
+ export type FeeModel = 'eip1559' | 'legacy';
146
+ export type FeePresetLabel = 'Low' | 'Standard' | 'High';
147
+ export type FeeEstimateSeconds = {
148
+ min: number;
149
+ max: number;
150
+ };
151
+ export type FeePreset = {
152
+ label: FeePresetLabel;
153
+ fees: ResolvedFees;
154
+ humanReadableGasReserve: string;
155
+ humanReadableEstimatedCost: string;
156
+ estimatedSeconds?: FeeEstimateSeconds;
157
+ };
158
+ export type FeeHistoryData = {
159
+ currentBaseFee: string;
160
+ range12h: {
161
+ minBaseFee: string;
162
+ maxBaseFee: string;
163
+ minPriorityFee: string;
164
+ maxPriorityFee: string;
165
+ };
166
+ };
167
+ export type FeeDataInput = {
168
+ chainId?: number;
169
+ gasLimit?: bigint | string | number;
170
+ feeData?: {
171
+ maxFeePerGas?: bigint | string;
172
+ maxPriorityFeePerGas?: bigint | string;
173
+ gasPrice?: bigint | string;
174
+ };
175
+ };
@@ -0,0 +1,6 @@
1
+ import { FeeDataInput, FeeEstimateSeconds, FeePreset } from '../types/common';
2
+ export declare const BLOCK_TIME_BY_CHAIN: Record<number, number>;
3
+ export declare function getBlockTime(chainId: number): number;
4
+ export declare function calcReserve(gasLimit: bigint, pricePerGas: bigint): string;
5
+ export declare function estimateSeconds(presetPriority: bigint, standardPriority: bigint, blockTime: number): FeeEstimateSeconds;
6
+ export declare function getFeePresets(tx: FeeDataInput): FeePreset[];
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BLOCK_TIME_BY_CHAIN = void 0;
4
+ exports.getBlockTime = getBlockTime;
5
+ exports.calcReserve = calcReserve;
6
+ exports.estimateSeconds = estimateSeconds;
7
+ exports.getFeePresets = getFeePresets;
8
+ const NETWORKS_REGISTRY_1 = require("../constants/NETWORKS_REGISTRY");
9
+ const formatAmount_1 = require("./formatAmount");
10
+ const DEFAULT_BLOCK_TIME = 12;
11
+ const FORMAT_OPTS = { useGroupSeparator: false, decimalsToShow: 18 };
12
+ exports.BLOCK_TIME_BY_CHAIN = Object.fromEntries(NETWORKS_REGISTRY_1.NETWORKS_REGISTRY.flatMap((r) => r.networks)
13
+ .filter((n) => n.blockTime != null)
14
+ .map((n) => [n.chainId, n.blockTime]));
15
+ function getBlockTime(chainId) {
16
+ return exports.BLOCK_TIME_BY_CHAIN[chainId] ?? DEFAULT_BLOCK_TIME;
17
+ }
18
+ function calcReserve(gasLimit, pricePerGas) {
19
+ return (0, formatAmount_1.formattedAmountForDisplay)(gasLimit * pricePerGas, 18, FORMAT_OPTS);
20
+ }
21
+ function estimateSeconds(presetPriority, standardPriority, blockTime) {
22
+ if (standardPriority === 0n) {
23
+ return { min: blockTime, max: blockTime * 4 };
24
+ }
25
+ const ratio = Number((presetPriority * 1000n) / standardPriority) / 1000;
26
+ if (ratio >= 1.4)
27
+ return { min: blockTime, max: blockTime * 2 };
28
+ if (ratio >= 0.9)
29
+ return { min: blockTime, max: blockTime * 3 };
30
+ return { min: blockTime, max: blockTime * 4 };
31
+ }
32
+ function getFeePresets(tx) {
33
+ const builtTx = tx;
34
+ const { maxFeePerGas, maxPriorityFeePerGas, gasPrice } = builtTx.feeData ?? {};
35
+ const gasLimit = builtTx.gasLimit
36
+ ? BigInt(builtTx.gasLimit)
37
+ : BigInt(builtTx.unsignedTx?.gasLimit ?? 21000);
38
+ // EIP-1559
39
+ if (maxFeePerGas != null && maxPriorityFeePerGas != null) {
40
+ const priority = BigInt(maxPriorityFeePerGas);
41
+ const baseFee = BigInt(maxFeePerGas) - BigInt(maxPriorityFeePerGas);
42
+ const estimatedCostPerGas = (priority) => baseFee + priority;
43
+ const chainId = builtTx.unsignedTx?.chainId ?? builtTx.chainId ?? 1;
44
+ const blockTime = getBlockTime(chainId);
45
+ const lowPriority = (priority * 75n) / 100n;
46
+ const highPriority = (priority * 150n) / 100n;
47
+ const build = (label, priority, seconds) => {
48
+ const presetMaxFeePerGas = baseFee + priority;
49
+ return {
50
+ label,
51
+ fees: {
52
+ mode: 'eip1559',
53
+ maxFeePerGas: presetMaxFeePerGas,
54
+ maxPriorityFeePerGas: priority,
55
+ gasLimit,
56
+ },
57
+ humanReadableGasReserve: calcReserve(gasLimit, presetMaxFeePerGas),
58
+ humanReadableEstimatedCost: calcReserve(gasLimit, estimatedCostPerGas(priority)),
59
+ estimatedSeconds: seconds,
60
+ };
61
+ };
62
+ return [
63
+ build('Low', lowPriority, estimateSeconds(lowPriority, priority, blockTime)),
64
+ build('Standard', priority, estimateSeconds(priority, priority, blockTime)),
65
+ build('High', highPriority, estimateSeconds(highPriority, priority, blockTime)),
66
+ ];
67
+ }
68
+ // Legacy
69
+ if (gasPrice != null) {
70
+ const price = BigInt(gasPrice);
71
+ const build = (label, price, estimatedSeconds) => ({
72
+ label,
73
+ fees: { mode: 'legacy', gasPrice: price, gasLimit },
74
+ humanReadableGasReserve: calcReserve(gasLimit, price),
75
+ humanReadableEstimatedCost: calcReserve(gasLimit, price),
76
+ estimatedSeconds,
77
+ });
78
+ return [
79
+ build('Low', (price * 90n) / 100n, { min: 180, max: 180 }),
80
+ build('Standard', price, { min: 60, max: 60 }),
81
+ build('High', (price * 115n) / 100n, { min: 20, max: 20 }),
82
+ ];
83
+ }
84
+ throw new Error('feeData missing from unsignedTx');
85
+ }
@@ -0,0 +1,3 @@
1
+ export declare function toGwei(wei: bigint): string;
2
+ export declare function tryParseGweiToWei(input: string): bigint | null;
3
+ export declare function parseGasLimit(input: string): bigint | null;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toGwei = toGwei;
4
+ exports.tryParseGweiToWei = tryParseGweiToWei;
5
+ exports.parseGasLimit = parseGasLimit;
6
+ const __1 = require("..");
7
+ const DECIMAL_PATTERN = /^\d*(\.\d*)?$/;
8
+ const UINT_PATTERN = /^\d+$/;
9
+ function toGwei(wei) {
10
+ return (0, __1.formattedAmountForDisplay)(wei, 9, {
11
+ useGroupSeparator: false,
12
+ decimalsToShow: 9,
13
+ });
14
+ }
15
+ function tryParseGweiToWei(input) {
16
+ const valueNormalized = input.trim().replace(/,/g, '.');
17
+ if (!valueNormalized || valueNormalized === '.')
18
+ return null;
19
+ if (!DECIMAL_PATTERN.test(valueNormalized))
20
+ return null;
21
+ try {
22
+ return (0, __1.parsedAmount)(valueNormalized, 9);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ function parseGasLimit(input) {
29
+ const trimmed = input.trim().replace(/\s/g, '');
30
+ if (!UINT_PATTERN.test(trimmed))
31
+ return null;
32
+ const value = BigInt(trimmed);
33
+ // 21000 is the minimum - protcol-enforced floor for any tx
34
+ if (value < 21000n)
35
+ return null;
36
+ return value;
37
+ }
@@ -8,6 +8,7 @@ export interface NetworkField {
8
8
  iconUrl: string;
9
9
  symbol: string;
10
10
  failoverRpcUrl?: string;
11
+ blockTime?: number;
11
12
  }
12
13
  export interface NetworkRegistry {
13
14
  category: string;
@@ -12,6 +12,7 @@ export const NETWORKS_REGISTRY = [
12
12
  iconUrl: 'https://assets.coingecko.com/coins/images/279/large/ethereum.png',
13
13
  symbol: 'ETH',
14
14
  failoverRpcUrl: 'https://eth.llamarpc.com',
15
+ blockTime: 12,
15
16
  },
16
17
  {
17
18
  id: 'bnb-smart-chain',
@@ -23,6 +24,7 @@ export const NETWORKS_REGISTRY = [
23
24
  iconUrl: 'https://assets.coingecko.com/coins/images/825/large/bnb-icon2_2x.png',
24
25
  symbol: 'BNB',
25
26
  failoverRpcUrl: 'https://bsc.llamarpc.com',
27
+ blockTime: 3,
26
28
  },
27
29
  {
28
30
  id: 'polygon-mainnet',
@@ -34,6 +36,7 @@ export const NETWORKS_REGISTRY = [
34
36
  explorerUrl: 'https://polygonscan.com',
35
37
  symbol: 'POL',
36
38
  failoverRpcUrl: 'https://polygon.llamarpc.com',
39
+ blockTime: 2,
37
40
  },
38
41
  {
39
42
  id: 'arbitrum-mainnet',
@@ -45,6 +48,7 @@ export const NETWORKS_REGISTRY = [
45
48
  iconUrl: 'https://assets.coingecko.com/coins/images/16547/large/photo_2023-03-29_21.47.00.jpeg',
46
49
  symbol: 'ARB',
47
50
  failoverRpcUrl: 'https://arb.llamarpc.com',
51
+ blockTime: 1,
48
52
  },
49
53
  ],
50
54
  },
@@ -61,6 +65,7 @@ export const NETWORKS_REGISTRY = [
61
65
  iconUrl: 'https://assets.coingecko.com/coins/images/279/large/ethereum.png',
62
66
  symbol: 'ETH',
63
67
  failoverRpcUrl: 'https://eth-sepolia.llamarpc.com',
68
+ blockTime: 12,
64
69
  },
65
70
  ],
66
71
  },
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import ERC20_TOKEN_CONTRACT_ABI from './ABIs/ERC20_TOKEN_CONTRACT_ABI';
3
3
  export { ERC20_TOKEN_CONTRACT_ABI };
4
4
  /** constants exports */
5
5
  export { GAS_LIMIT_PER_TX_TYPE, MULTICALL3_ADDRESS } from './constants/constants';
6
- export { NetworkField, NetworkRegistry, NETWORKS_REGISTRY, } from './constants/NETWORKS_REGISTRY';
6
+ export { NetworkField, NetworkRegistry, NETWORKS_REGISTRY } from './constants/NETWORKS_REGISTRY';
7
7
  export { BASIC_TOKENS_BY_CHAIN, BasicTokenData, BasicTokenSymbol, ChainTokenDataMap, } from './constants/BASIC_TOKENS_REGISTRY';
8
8
  /** basic blockchain exports */
9
9
  export { buildBaseUnsignedTransferTx, buildMaxNativeTransferTx, buildUnsignedTransferTx, } from './blockchain/buildUnsignedTransferTx';
@@ -14,6 +14,7 @@ export { txStatus } from './blockchain/txStatus';
14
14
  export { getBalance, getBalances } from './blockchain/getBalances';
15
15
  export { estimateTransaction } from './blockchain/estimateTransaction';
16
16
  export { prepareTransaction } from './blockchain/prepareTransaction';
17
+ export { fetchFeeSnapshot, type FetchFeeSnapshotOptions, type FeeSnapshotTxKind, } from './blockchain/fetchFeeSnapshot';
17
18
  /** services exports */
18
19
  export { EvmWalletService, EvmGeneratedWallet, EvmDerivedWallet, } from './services/evm-wallet-core/evmWalletService';
19
20
  export { EntropySource } from './services/evm-wallet-core/entropy';
@@ -26,5 +27,7 @@ export { NATIVE_TOKENS };
26
27
  export { formattedAmountForDisplay, parsedAmount } from './utils/formatAmount';
27
28
  export { handleErrorMessages, errorMessagesForBroadcast, errorMessagesForGasLimitEstimation, } from './utils/handleErrorMessages';
28
29
  export { normalizeAddress } from './utils/normalizeAddress';
30
+ export { toGwei, tryParseGweiToWei, parseGasLimit } from './utils/parseGasFees';
31
+ export { getFeePresets, calcReserve, estimateSeconds, getBlockTime, BLOCK_TIME_BY_CHAIN, } from './utils/feePresets';
29
32
  /** types exports */
30
- export { BroadcastTransactionOptions, BuildMaxNativeTransferTxOptions, BuildUnsignedTransferTxOptions, EstimateGasLimitFromProviderProps, GasEstimateResult, TxStatusOptions, BuildBaseUnsignedTransferTxParams, TxStatusResponse, EstimateTransactionOptions, EstimateTransactionResult, PrepareTransactionParams, PrepareTransactionResult, FormatAmountOptions, TransactionRequest, GetBalanceParams, GetBalancesParams, GetBalancesChainRequest, GetBalanceResult, ChainBalances, TokenBalance, ChainGroup, } from './types/common';
33
+ export { BroadcastTransactionOptions, BuildMaxNativeTransferTxOptions, BuildUnsignedTransferTxOptions, EstimateGasLimitFromProviderProps, GasEstimateResult, TxStatusOptions, BuildBaseUnsignedTransferTxParams, TxStatusResponse, EstimateTransactionOptions, EstimateTransactionResult, PrepareTransactionParams, PrepareTransactionResult, FormatAmountOptions, TransactionRequest, GetBalanceParams, GetBalancesParams, GetBalancesChainRequest, GetBalanceResult, ChainBalances, TokenBalance, ChainGroup, FeePreset, FeePresetLabel, FeeEstimateSeconds, ResolvedFees, EIP1559Fees, LegacyFees, FeeModel, FeeHistoryData, FeeDataInput, } from './types/common';
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import ERC20_TOKEN_CONTRACT_ABI from './ABIs/ERC20_TOKEN_CONTRACT_ABI';
3
3
  export { ERC20_TOKEN_CONTRACT_ABI };
4
4
  /** constants exports */
5
5
  export { GAS_LIMIT_PER_TX_TYPE, MULTICALL3_ADDRESS } from './constants/constants';
6
- export { NETWORKS_REGISTRY, } from './constants/NETWORKS_REGISTRY';
6
+ export { NETWORKS_REGISTRY } from './constants/NETWORKS_REGISTRY';
7
7
  export { BASIC_TOKENS_BY_CHAIN, } from './constants/BASIC_TOKENS_REGISTRY';
8
8
  /** basic blockchain exports */
9
9
  export { buildBaseUnsignedTransferTx, buildMaxNativeTransferTx, buildUnsignedTransferTx, } from './blockchain/buildUnsignedTransferTx';
@@ -14,6 +14,7 @@ export { txStatus } from './blockchain/txStatus';
14
14
  export { getBalance, getBalances } from './blockchain/getBalances';
15
15
  export { estimateTransaction } from './blockchain/estimateTransaction';
16
16
  export { prepareTransaction } from './blockchain/prepareTransaction';
17
+ export { fetchFeeSnapshot, } from './blockchain/fetchFeeSnapshot';
17
18
  /** services exports */
18
19
  export { EvmWalletService, } from './services/evm-wallet-core/evmWalletService';
19
20
  export { createWallet, signMessage, signTransaction } from './services/evm-wallet-core/signer';
@@ -25,3 +26,5 @@ export { NATIVE_TOKENS };
25
26
  export { formattedAmountForDisplay, parsedAmount } from './utils/formatAmount';
26
27
  export { handleErrorMessages, errorMessagesForBroadcast, errorMessagesForGasLimitEstimation, } from './utils/handleErrorMessages';
27
28
  export { normalizeAddress } from './utils/normalizeAddress';
29
+ export { toGwei, tryParseGweiToWei, parseGasLimit } from './utils/parseGasFees';
30
+ export { getFeePresets, calcReserve, estimateSeconds, getBlockTime, BLOCK_TIME_BY_CHAIN, } from './utils/feePresets';
@@ -130,3 +130,46 @@ export interface ChainGroup {
130
130
  nativeBalanceRequests: GetBalanceParams[];
131
131
  tokenBalanceRequests: GetBalanceParams[];
132
132
  }
133
+ export type EIP1559Fees = {
134
+ mode: 'eip1559';
135
+ maxFeePerGas: bigint;
136
+ maxPriorityFeePerGas: bigint;
137
+ gasLimit: bigint;
138
+ };
139
+ export type LegacyFees = {
140
+ mode: 'legacy';
141
+ gasPrice: bigint;
142
+ gasLimit: bigint;
143
+ };
144
+ export type ResolvedFees = EIP1559Fees | LegacyFees;
145
+ export type FeeModel = 'eip1559' | 'legacy';
146
+ export type FeePresetLabel = 'Low' | 'Standard' | 'High';
147
+ export type FeeEstimateSeconds = {
148
+ min: number;
149
+ max: number;
150
+ };
151
+ export type FeePreset = {
152
+ label: FeePresetLabel;
153
+ fees: ResolvedFees;
154
+ humanReadableGasReserve: string;
155
+ humanReadableEstimatedCost: string;
156
+ estimatedSeconds?: FeeEstimateSeconds;
157
+ };
158
+ export type FeeHistoryData = {
159
+ currentBaseFee: string;
160
+ range12h: {
161
+ minBaseFee: string;
162
+ maxBaseFee: string;
163
+ minPriorityFee: string;
164
+ maxPriorityFee: string;
165
+ };
166
+ };
167
+ export type FeeDataInput = {
168
+ chainId?: number;
169
+ gasLimit?: bigint | string | number;
170
+ feeData?: {
171
+ maxFeePerGas?: bigint | string;
172
+ maxPriorityFeePerGas?: bigint | string;
173
+ gasPrice?: bigint | string;
174
+ };
175
+ };
@@ -0,0 +1,6 @@
1
+ import { FeeDataInput, FeeEstimateSeconds, FeePreset } from '../types/common';
2
+ export declare const BLOCK_TIME_BY_CHAIN: Record<number, number>;
3
+ export declare function getBlockTime(chainId: number): number;
4
+ export declare function calcReserve(gasLimit: bigint, pricePerGas: bigint): string;
5
+ export declare function estimateSeconds(presetPriority: bigint, standardPriority: bigint, blockTime: number): FeeEstimateSeconds;
6
+ export declare function getFeePresets(tx: FeeDataInput): FeePreset[];
@@ -0,0 +1,78 @@
1
+ import { NETWORKS_REGISTRY } from '../constants/NETWORKS_REGISTRY';
2
+ import { formattedAmountForDisplay } from './formatAmount';
3
+ const DEFAULT_BLOCK_TIME = 12;
4
+ const FORMAT_OPTS = { useGroupSeparator: false, decimalsToShow: 18 };
5
+ export const BLOCK_TIME_BY_CHAIN = Object.fromEntries(NETWORKS_REGISTRY.flatMap((r) => r.networks)
6
+ .filter((n) => n.blockTime != null)
7
+ .map((n) => [n.chainId, n.blockTime]));
8
+ export function getBlockTime(chainId) {
9
+ return BLOCK_TIME_BY_CHAIN[chainId] ?? DEFAULT_BLOCK_TIME;
10
+ }
11
+ export function calcReserve(gasLimit, pricePerGas) {
12
+ return formattedAmountForDisplay(gasLimit * pricePerGas, 18, FORMAT_OPTS);
13
+ }
14
+ export function estimateSeconds(presetPriority, standardPriority, blockTime) {
15
+ if (standardPriority === 0n) {
16
+ return { min: blockTime, max: blockTime * 4 };
17
+ }
18
+ const ratio = Number((presetPriority * 1000n) / standardPriority) / 1000;
19
+ if (ratio >= 1.4)
20
+ return { min: blockTime, max: blockTime * 2 };
21
+ if (ratio >= 0.9)
22
+ return { min: blockTime, max: blockTime * 3 };
23
+ return { min: blockTime, max: blockTime * 4 };
24
+ }
25
+ export function getFeePresets(tx) {
26
+ const builtTx = tx;
27
+ const { maxFeePerGas, maxPriorityFeePerGas, gasPrice } = builtTx.feeData ?? {};
28
+ const gasLimit = builtTx.gasLimit
29
+ ? BigInt(builtTx.gasLimit)
30
+ : BigInt(builtTx.unsignedTx?.gasLimit ?? 21000);
31
+ // EIP-1559
32
+ if (maxFeePerGas != null && maxPriorityFeePerGas != null) {
33
+ const priority = BigInt(maxPriorityFeePerGas);
34
+ const baseFee = BigInt(maxFeePerGas) - BigInt(maxPriorityFeePerGas);
35
+ const estimatedCostPerGas = (priority) => baseFee + priority;
36
+ const chainId = builtTx.unsignedTx?.chainId ?? builtTx.chainId ?? 1;
37
+ const blockTime = getBlockTime(chainId);
38
+ const lowPriority = (priority * 75n) / 100n;
39
+ const highPriority = (priority * 150n) / 100n;
40
+ const build = (label, priority, seconds) => {
41
+ const presetMaxFeePerGas = baseFee + priority;
42
+ return {
43
+ label,
44
+ fees: {
45
+ mode: 'eip1559',
46
+ maxFeePerGas: presetMaxFeePerGas,
47
+ maxPriorityFeePerGas: priority,
48
+ gasLimit,
49
+ },
50
+ humanReadableGasReserve: calcReserve(gasLimit, presetMaxFeePerGas),
51
+ humanReadableEstimatedCost: calcReserve(gasLimit, estimatedCostPerGas(priority)),
52
+ estimatedSeconds: seconds,
53
+ };
54
+ };
55
+ return [
56
+ build('Low', lowPriority, estimateSeconds(lowPriority, priority, blockTime)),
57
+ build('Standard', priority, estimateSeconds(priority, priority, blockTime)),
58
+ build('High', highPriority, estimateSeconds(highPriority, priority, blockTime)),
59
+ ];
60
+ }
61
+ // Legacy
62
+ if (gasPrice != null) {
63
+ const price = BigInt(gasPrice);
64
+ const build = (label, price, estimatedSeconds) => ({
65
+ label,
66
+ fees: { mode: 'legacy', gasPrice: price, gasLimit },
67
+ humanReadableGasReserve: calcReserve(gasLimit, price),
68
+ humanReadableEstimatedCost: calcReserve(gasLimit, price),
69
+ estimatedSeconds,
70
+ });
71
+ return [
72
+ build('Low', (price * 90n) / 100n, { min: 180, max: 180 }),
73
+ build('Standard', price, { min: 60, max: 60 }),
74
+ build('High', (price * 115n) / 100n, { min: 20, max: 20 }),
75
+ ];
76
+ }
77
+ throw new Error('feeData missing from unsignedTx');
78
+ }
@@ -0,0 +1,3 @@
1
+ export declare function toGwei(wei: bigint): string;
2
+ export declare function tryParseGweiToWei(input: string): bigint | null;
3
+ export declare function parseGasLimit(input: string): bigint | null;
@@ -0,0 +1,32 @@
1
+ import { formattedAmountForDisplay, parsedAmount } from '..';
2
+ const DECIMAL_PATTERN = /^\d*(\.\d*)?$/;
3
+ const UINT_PATTERN = /^\d+$/;
4
+ export function toGwei(wei) {
5
+ return formattedAmountForDisplay(wei, 9, {
6
+ useGroupSeparator: false,
7
+ decimalsToShow: 9,
8
+ });
9
+ }
10
+ export function tryParseGweiToWei(input) {
11
+ const valueNormalized = input.trim().replace(/,/g, '.');
12
+ if (!valueNormalized || valueNormalized === '.')
13
+ return null;
14
+ if (!DECIMAL_PATTERN.test(valueNormalized))
15
+ return null;
16
+ try {
17
+ return parsedAmount(valueNormalized, 9);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ export function parseGasLimit(input) {
24
+ const trimmed = input.trim().replace(/\s/g, '');
25
+ if (!UINT_PATTERN.test(trimmed))
26
+ return null;
27
+ const value = BigInt(trimmed);
28
+ // 21000 is the minimum - protcol-enforced floor for any tx
29
+ if (value < 21000n)
30
+ return null;
31
+ return value;
32
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@octaflowlabs/onchain-sdk",
3
- "version": "1.3.9",
3
+ "version": "1.4.2",
4
4
  "description": "onchain methods for web3",
5
- "repository": "https://github.com/crisramb665/onchain-sdk.git",
5
+ "repository": {"type": "git", "url": "git+https://github.com/octaflowlabs/onchain-sdk.git"},
6
6
  "license": "MIT",
7
7
  "main": "dist/cjs/index.js",
8
8
  "module": "dist/index.js",
@@ -10,6 +10,10 @@
10
10
  "files": [
11
11
  "dist"
12
12
  ],
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "registry": "https://registry.npmjs.org/"
16
+ },
13
17
  "scripts": {
14
18
  "build": "rm -rf dist && tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && tsc-alias",
15
19
  "prettier": "prettier --write \"src/**/*.ts\"",