@sip-protocol/sdk 0.7.3 → 0.8.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/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +47556 -19603
- package/dist/browser.mjs +628 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
- package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48396 -19623
- package/dist/index.mjs +537 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +44 -11
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +252 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +47 -6
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +186 -33
- package/src/chains/solana/providers/index.ts +31 -0
- package/src/chains/solana/providers/interface.ts +61 -18
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +338 -67
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +83 -66
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +57 -6
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +23 -0
- package/src/compliance/range-sas.ts +398 -33
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +686 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +254 -4
- package/src/privacy-backends/interface.ts +649 -6
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash.ts +13 -17
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +414 -2
- package/src/privacy-backends/router.ts +283 -3
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +3 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +110 -29
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-2XIVXWHA.mjs +0 -1930
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-7RFRWDCW.mjs +0 -1504
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-F6F73W35.mjs +0 -16166
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-OFDBEIEK.mjs +0 -16166
- package/dist/chunk-SF7YSLF5.mjs +0 -1515
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/chunk-WWUSGOXE.mjs +0 -17129
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-B71aXVzk.d.ts +0 -13264
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-pOIIuwfV.d.mts +0 -13264
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-4O4K45VU.mjs +0 -46
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-NDABAZ6P.mjs +0 -56
- package/dist/solana-Q4NAVBTS.mjs +0 -46
- package/dist/solana-ZYO63LY5.mjs +0 -46
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ethereum/EVM Chain-Specific Optimizations
|
|
3
|
+
*
|
|
4
|
+
* Provides optimized configurations for EVM transactions:
|
|
5
|
+
* - Gas optimization strategies
|
|
6
|
+
* - Storage packing recommendations
|
|
7
|
+
* - L2-specific optimizations (Arbitrum, Optimism, Base)
|
|
8
|
+
* - EIP-4844 blob transaction support
|
|
9
|
+
* - Batch transaction strategies
|
|
10
|
+
*
|
|
11
|
+
* @module chains/ethereum/optimizations
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
DEFAULT_GAS_LIMITS,
|
|
16
|
+
ONE_GWEI,
|
|
17
|
+
ONE_ETH,
|
|
18
|
+
type EthereumNetwork,
|
|
19
|
+
isL2Network,
|
|
20
|
+
} from './constants'
|
|
21
|
+
|
|
22
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Gas optimization profile
|
|
26
|
+
*/
|
|
27
|
+
export type GasProfile =
|
|
28
|
+
| 'economy' // Wait for lower gas, may take longer
|
|
29
|
+
| 'standard' // Balanced cost/speed
|
|
30
|
+
| 'fast' // Higher gas, faster confirmation
|
|
31
|
+
| 'instant' // Maximum priority, immediate confirmation
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* L2 optimization strategy
|
|
35
|
+
*/
|
|
36
|
+
export type L2Strategy =
|
|
37
|
+
| 'calldata' // Optimize calldata encoding
|
|
38
|
+
| 'blob' // Use EIP-4844 blobs (where supported)
|
|
39
|
+
| 'compressed' // Use compression for calldata
|
|
40
|
+
| 'batched' // Batch multiple operations
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Transaction complexity estimate for EVM
|
|
44
|
+
*/
|
|
45
|
+
export interface EVMTransactionComplexity {
|
|
46
|
+
/** Estimated gas limit */
|
|
47
|
+
estimatedGas: bigint
|
|
48
|
+
/** Calldata size in bytes */
|
|
49
|
+
calldataSize: number
|
|
50
|
+
/** Number of storage slots written */
|
|
51
|
+
storageWrites: number
|
|
52
|
+
/** Number of storage slots read */
|
|
53
|
+
storageReads: number
|
|
54
|
+
/** Number of external calls */
|
|
55
|
+
externalCalls: number
|
|
56
|
+
/** Whether multicall is recommended */
|
|
57
|
+
multicallRecommended: boolean
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gas estimate with L2 considerations
|
|
62
|
+
*/
|
|
63
|
+
export interface L2GasEstimate {
|
|
64
|
+
/** L2 execution gas */
|
|
65
|
+
l2Gas: bigint
|
|
66
|
+
/** L1 data/security gas (for rollups) */
|
|
67
|
+
l1DataGas: bigint
|
|
68
|
+
/** Total gas */
|
|
69
|
+
totalGas: bigint
|
|
70
|
+
/** L1 data cost in wei (for rollups) */
|
|
71
|
+
l1DataCostWei: bigint
|
|
72
|
+
/** Total estimated cost in wei */
|
|
73
|
+
totalCostWei: bigint
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* EVM optimization result
|
|
78
|
+
*/
|
|
79
|
+
export interface EVMOptimizationResult {
|
|
80
|
+
/** Recommended gas limit */
|
|
81
|
+
gasLimit: bigint
|
|
82
|
+
/** Recommended max fee per gas */
|
|
83
|
+
maxFeePerGas: bigint
|
|
84
|
+
/** Recommended max priority fee */
|
|
85
|
+
maxPriorityFeePerGas: bigint
|
|
86
|
+
/** L2-specific estimate (if applicable) */
|
|
87
|
+
l2Estimate?: L2GasEstimate
|
|
88
|
+
/** Recommended strategies */
|
|
89
|
+
strategies: string[]
|
|
90
|
+
/** Whether to use multicall */
|
|
91
|
+
useMulticall: boolean
|
|
92
|
+
/** Whether to use EIP-4844 blobs */
|
|
93
|
+
useBlobs: boolean
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Storage packing recommendation
|
|
98
|
+
*/
|
|
99
|
+
export interface StoragePackingAdvice {
|
|
100
|
+
/** Current storage slots used */
|
|
101
|
+
currentSlots: number
|
|
102
|
+
/** Optimized slots (after packing) */
|
|
103
|
+
optimizedSlots: number
|
|
104
|
+
/** Gas savings estimate */
|
|
105
|
+
gasSavings: bigint
|
|
106
|
+
/** Recommendations */
|
|
107
|
+
recommendations: string[]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Gas costs for common EVM operations
|
|
114
|
+
*/
|
|
115
|
+
export const EVM_GAS_COSTS = {
|
|
116
|
+
/** Base transaction cost */
|
|
117
|
+
txBase: 21000n,
|
|
118
|
+
/** Zero byte in calldata */
|
|
119
|
+
calldataZeroByte: 4n,
|
|
120
|
+
/** Non-zero byte in calldata */
|
|
121
|
+
calldataNonZeroByte: 16n,
|
|
122
|
+
/** Storage read (cold) */
|
|
123
|
+
sloadCold: 2100n,
|
|
124
|
+
/** Storage read (warm) */
|
|
125
|
+
sloadWarm: 100n,
|
|
126
|
+
/** Storage write (zero to non-zero) */
|
|
127
|
+
sstoreSet: 20000n,
|
|
128
|
+
/** Storage write (non-zero to non-zero) */
|
|
129
|
+
sstoreUpdate: 5000n,
|
|
130
|
+
/** Storage write (non-zero to zero, refund) */
|
|
131
|
+
sstoreClear: -15000n, // Refund
|
|
132
|
+
/** External call (cold address) */
|
|
133
|
+
callCold: 2600n,
|
|
134
|
+
/** External call (warm address) */
|
|
135
|
+
callWarm: 100n,
|
|
136
|
+
/** Log (base) */
|
|
137
|
+
logBase: 375n,
|
|
138
|
+
/** Log per topic */
|
|
139
|
+
logTopic: 375n,
|
|
140
|
+
/** Log per byte */
|
|
141
|
+
logByte: 8n,
|
|
142
|
+
/** keccak256 per word */
|
|
143
|
+
keccak256Word: 6n,
|
|
144
|
+
/** Memory expansion per word */
|
|
145
|
+
memoryWord: 3n,
|
|
146
|
+
} as const
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Profile multipliers for gas price
|
|
150
|
+
*/
|
|
151
|
+
const GAS_PROFILE_MULTIPLIERS: Record<GasProfile, number> = {
|
|
152
|
+
economy: 0.8,
|
|
153
|
+
standard: 1.0,
|
|
154
|
+
fast: 1.5,
|
|
155
|
+
instant: 2.5,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* L2 data gas multipliers (approximate)
|
|
160
|
+
* L2s charge for L1 data posting differently
|
|
161
|
+
*/
|
|
162
|
+
const L2_DATA_MULTIPLIERS: Partial<Record<EthereumNetwork, number>> = {
|
|
163
|
+
arbitrum: 16, // ~16x L1 calldata cost
|
|
164
|
+
'arbitrum-sepolia': 16,
|
|
165
|
+
optimism: 16,
|
|
166
|
+
'optimism-sepolia': 16,
|
|
167
|
+
base: 16,
|
|
168
|
+
'base-sepolia': 16,
|
|
169
|
+
zksync: 1, // Different model
|
|
170
|
+
scroll: 16,
|
|
171
|
+
linea: 16,
|
|
172
|
+
mantle: 4, // Lower data costs
|
|
173
|
+
blast: 16,
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
// ─── Gas Estimation ───────────────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Estimate gas for privacy transaction
|
|
181
|
+
*
|
|
182
|
+
* @param options - Transaction options
|
|
183
|
+
* @returns Transaction complexity estimate
|
|
184
|
+
*/
|
|
185
|
+
export function estimatePrivacyTxComplexity(options: {
|
|
186
|
+
/** Number of transfers */
|
|
187
|
+
transferCount: number
|
|
188
|
+
/** Whether includes ERC-20 approval */
|
|
189
|
+
includesApproval: boolean
|
|
190
|
+
/** Whether includes announcement */
|
|
191
|
+
includesAnnouncement: boolean
|
|
192
|
+
/** Custom calldata size */
|
|
193
|
+
customCalldataSize?: number
|
|
194
|
+
}): EVMTransactionComplexity {
|
|
195
|
+
let estimatedGas = EVM_GAS_COSTS.txBase
|
|
196
|
+
|
|
197
|
+
// Transfer gas
|
|
198
|
+
if (options.transferCount > 0) {
|
|
199
|
+
// ERC-20 transfer: storage read + storage write + emit event
|
|
200
|
+
const perTransfer =
|
|
201
|
+
EVM_GAS_COSTS.sloadCold + // Balance read
|
|
202
|
+
EVM_GAS_COSTS.sstoreUpdate + // Balance update sender
|
|
203
|
+
EVM_GAS_COSTS.sstoreUpdate + // Balance update receiver
|
|
204
|
+
EVM_GAS_COSTS.logBase +
|
|
205
|
+
EVM_GAS_COSTS.logTopic * 3n + // Transfer event
|
|
206
|
+
EVM_GAS_COSTS.callCold // External call to token
|
|
207
|
+
|
|
208
|
+
estimatedGas += perTransfer * BigInt(options.transferCount)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Approval gas
|
|
212
|
+
if (options.includesApproval) {
|
|
213
|
+
estimatedGas +=
|
|
214
|
+
EVM_GAS_COSTS.sstoreSet + // Allowance storage
|
|
215
|
+
EVM_GAS_COSTS.logBase +
|
|
216
|
+
EVM_GAS_COSTS.logTopic * 3n // Approval event
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Announcement gas
|
|
220
|
+
if (options.includesAnnouncement) {
|
|
221
|
+
estimatedGas += DEFAULT_GAS_LIMITS.announcement
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Calldata estimation
|
|
225
|
+
const baseCalldata = 4 + 32 * 3 // Function selector + 3 params
|
|
226
|
+
const perTransferCalldata = 32 * 2 // Address + amount
|
|
227
|
+
const calldataSize =
|
|
228
|
+
options.customCalldataSize ??
|
|
229
|
+
baseCalldata + perTransferCalldata * options.transferCount
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
estimatedGas,
|
|
233
|
+
calldataSize,
|
|
234
|
+
storageWrites: options.transferCount * 2 + (options.includesApproval ? 1 : 0),
|
|
235
|
+
storageReads: options.transferCount * 2,
|
|
236
|
+
externalCalls: options.transferCount + (options.includesApproval ? 1 : 0),
|
|
237
|
+
multicallRecommended: options.transferCount > 2,
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Calculate L2 gas estimate with L1 data costs
|
|
243
|
+
*
|
|
244
|
+
* @param network - Target L2 network
|
|
245
|
+
* @param complexity - Transaction complexity
|
|
246
|
+
* @param l2GasPrice - L2 gas price in wei
|
|
247
|
+
* @param l1BaseFee - L1 base fee in wei (for data cost calculation)
|
|
248
|
+
* @returns L2 gas estimate
|
|
249
|
+
*/
|
|
250
|
+
export function calculateL2GasEstimate(
|
|
251
|
+
network: EthereumNetwork,
|
|
252
|
+
complexity: EVMTransactionComplexity,
|
|
253
|
+
l2GasPrice: bigint,
|
|
254
|
+
l1BaseFee: bigint
|
|
255
|
+
): L2GasEstimate {
|
|
256
|
+
const multiplier = L2_DATA_MULTIPLIERS[network] ?? 1
|
|
257
|
+
|
|
258
|
+
// L2 execution gas
|
|
259
|
+
const l2Gas = complexity.estimatedGas
|
|
260
|
+
|
|
261
|
+
// L1 data gas (calldata posted to L1)
|
|
262
|
+
// Approximate: each non-zero byte costs 16 L1 gas, zero byte costs 4
|
|
263
|
+
// Assume 70% non-zero bytes for typical transactions
|
|
264
|
+
const nonZeroBytes = Math.ceil(complexity.calldataSize * 0.7)
|
|
265
|
+
const zeroBytes = complexity.calldataSize - nonZeroBytes
|
|
266
|
+
const l1CalldataGas =
|
|
267
|
+
BigInt(nonZeroBytes) * EVM_GAS_COSTS.calldataNonZeroByte +
|
|
268
|
+
BigInt(zeroBytes) * EVM_GAS_COSTS.calldataZeroByte
|
|
269
|
+
|
|
270
|
+
// L1 data gas scaled by multiplier
|
|
271
|
+
const l1DataGas = l1CalldataGas * BigInt(multiplier)
|
|
272
|
+
|
|
273
|
+
// Total gas
|
|
274
|
+
const totalGas = l2Gas + l1DataGas
|
|
275
|
+
|
|
276
|
+
// Cost calculation
|
|
277
|
+
const l2Cost = l2Gas * l2GasPrice
|
|
278
|
+
const l1DataCostWei = l1DataGas * l1BaseFee
|
|
279
|
+
const totalCostWei = l2Cost + l1DataCostWei
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
l2Gas,
|
|
283
|
+
l1DataGas,
|
|
284
|
+
totalGas,
|
|
285
|
+
l1DataCostWei,
|
|
286
|
+
totalCostWei,
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ─── Optimization Functions ───────────────────────────────────────────────────
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Get full optimization result for a transaction
|
|
294
|
+
*
|
|
295
|
+
* @param network - Target network
|
|
296
|
+
* @param complexity - Transaction complexity
|
|
297
|
+
* @param profile - Gas profile
|
|
298
|
+
* @param baseFee - Current base fee
|
|
299
|
+
* @param l1BaseFee - L1 base fee (for L2 networks)
|
|
300
|
+
* @returns Optimization result
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```typescript
|
|
304
|
+
* const complexity = estimatePrivacyTxComplexity({
|
|
305
|
+
* transferCount: 1,
|
|
306
|
+
* includesApproval: true,
|
|
307
|
+
* includesAnnouncement: true
|
|
308
|
+
* })
|
|
309
|
+
*
|
|
310
|
+
* const result = optimizeTransaction('arbitrum', complexity, 'standard', baseFee)
|
|
311
|
+
* console.log(result.gasLimit) // Recommended gas limit
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
export function optimizeTransaction(
|
|
315
|
+
network: EthereumNetwork,
|
|
316
|
+
complexity: EVMTransactionComplexity,
|
|
317
|
+
profile: GasProfile = 'standard',
|
|
318
|
+
baseFee: bigint,
|
|
319
|
+
l1BaseFee?: bigint
|
|
320
|
+
): EVMOptimizationResult {
|
|
321
|
+
const multiplier = GAS_PROFILE_MULTIPLIERS[profile]
|
|
322
|
+
|
|
323
|
+
// Add 20% buffer to gas estimate
|
|
324
|
+
const gasLimit = (complexity.estimatedGas * 120n) / 100n
|
|
325
|
+
|
|
326
|
+
// Priority fee based on profile
|
|
327
|
+
const basePriorityFee = ONE_GWEI * 2n // 2 gwei base
|
|
328
|
+
const maxPriorityFeePerGas = BigInt(
|
|
329
|
+
Math.ceil(Number(basePriorityFee) * multiplier)
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
// Max fee = base fee * 2 + priority (for price stability)
|
|
333
|
+
const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas
|
|
334
|
+
|
|
335
|
+
const strategies: string[] = []
|
|
336
|
+
let l2Estimate: L2GasEstimate | undefined
|
|
337
|
+
|
|
338
|
+
// L2-specific optimizations
|
|
339
|
+
if (isL2Network(network)) {
|
|
340
|
+
if (l1BaseFee) {
|
|
341
|
+
l2Estimate = calculateL2GasEstimate(
|
|
342
|
+
network,
|
|
343
|
+
complexity,
|
|
344
|
+
maxFeePerGas,
|
|
345
|
+
l1BaseFee
|
|
346
|
+
)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
strategies.push('Compress calldata for lower L1 data costs')
|
|
350
|
+
|
|
351
|
+
if (complexity.calldataSize > 500) {
|
|
352
|
+
strategies.push('Consider batching to amortize L1 data overhead')
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Multicall recommendation
|
|
357
|
+
if (complexity.multicallRecommended) {
|
|
358
|
+
strategies.push('Use multicall to batch operations in single transaction')
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Storage optimization
|
|
362
|
+
if (complexity.storageWrites > 3) {
|
|
363
|
+
strategies.push(
|
|
364
|
+
'Minimize storage writes - each write costs 5000+ gas'
|
|
365
|
+
)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// EIP-4844 blob consideration (for large data)
|
|
369
|
+
const useBlobs =
|
|
370
|
+
complexity.calldataSize > 10000 && supportsEIP4844(network)
|
|
371
|
+
|
|
372
|
+
if (useBlobs) {
|
|
373
|
+
strategies.push('Use EIP-4844 blobs for cheaper large data posting')
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
gasLimit,
|
|
378
|
+
maxFeePerGas,
|
|
379
|
+
maxPriorityFeePerGas,
|
|
380
|
+
l2Estimate,
|
|
381
|
+
strategies,
|
|
382
|
+
useMulticall: complexity.multicallRecommended,
|
|
383
|
+
useBlobs,
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Check if network supports EIP-4844 blobs
|
|
389
|
+
*/
|
|
390
|
+
export function supportsEIP4844(network: EthereumNetwork): boolean {
|
|
391
|
+
// EIP-4844 (Dencun) is live on mainnet and major L2s
|
|
392
|
+
const supported: EthereumNetwork[] = [
|
|
393
|
+
'mainnet',
|
|
394
|
+
'sepolia',
|
|
395
|
+
'arbitrum',
|
|
396
|
+
'arbitrum-sepolia',
|
|
397
|
+
'optimism',
|
|
398
|
+
'optimism-sepolia',
|
|
399
|
+
'base',
|
|
400
|
+
'base-sepolia',
|
|
401
|
+
]
|
|
402
|
+
return supported.includes(network)
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// ─── Batch Optimization ───────────────────────────────────────────────────────
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Calculate optimal batch size for multiple operations
|
|
409
|
+
*
|
|
410
|
+
* @param operationCount - Total operations
|
|
411
|
+
* @param network - Target network
|
|
412
|
+
* @param options - Batch options
|
|
413
|
+
* @returns Array of batch sizes
|
|
414
|
+
*/
|
|
415
|
+
export function calculateOptimalBatches(
|
|
416
|
+
operationCount: number,
|
|
417
|
+
network: EthereumNetwork,
|
|
418
|
+
options: {
|
|
419
|
+
/** Max gas per transaction */
|
|
420
|
+
maxGasPerTx?: bigint
|
|
421
|
+
/** Gas per operation */
|
|
422
|
+
gasPerOperation?: bigint
|
|
423
|
+
} = {}
|
|
424
|
+
): number[] {
|
|
425
|
+
const {
|
|
426
|
+
maxGasPerTx = isL2Network(network) ? 3_000_000n : 15_000_000n,
|
|
427
|
+
gasPerOperation = DEFAULT_GAS_LIMITS.erc20Transfer,
|
|
428
|
+
} = options
|
|
429
|
+
|
|
430
|
+
// Account for base gas
|
|
431
|
+
const availableGas = maxGasPerTx - EVM_GAS_COSTS.txBase
|
|
432
|
+
const maxOpsPerBatch = Number(availableGas / gasPerOperation)
|
|
433
|
+
|
|
434
|
+
const batches: number[] = []
|
|
435
|
+
let remaining = operationCount
|
|
436
|
+
|
|
437
|
+
while (remaining > 0) {
|
|
438
|
+
const batchSize = Math.min(remaining, maxOpsPerBatch)
|
|
439
|
+
batches.push(batchSize)
|
|
440
|
+
remaining -= batchSize
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return batches
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// ─── Storage Packing ──────────────────────────────────────────────────────────
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Analyze storage packing opportunities
|
|
450
|
+
*
|
|
451
|
+
* Ethereum storage is organized in 32-byte slots.
|
|
452
|
+
* Packing multiple values into single slots saves gas.
|
|
453
|
+
*
|
|
454
|
+
* @param variables - Array of variable sizes in bytes
|
|
455
|
+
* @returns Storage packing advice
|
|
456
|
+
*/
|
|
457
|
+
export function analyzeStoragePacking(
|
|
458
|
+
variables: Array<{ name: string; size: number }>
|
|
459
|
+
): StoragePackingAdvice {
|
|
460
|
+
// Current: each variable gets its own slot
|
|
461
|
+
const currentSlots = variables.length
|
|
462
|
+
|
|
463
|
+
// Optimized: pack variables into slots
|
|
464
|
+
const SLOT_SIZE = 32
|
|
465
|
+
let optimizedSlots = 0
|
|
466
|
+
let currentSlotRemaining = SLOT_SIZE
|
|
467
|
+
|
|
468
|
+
// Sort by size (largest first) for better packing
|
|
469
|
+
const sorted = [...variables].sort((a, b) => b.size - a.size)
|
|
470
|
+
|
|
471
|
+
for (const variable of sorted) {
|
|
472
|
+
if (variable.size > currentSlotRemaining) {
|
|
473
|
+
optimizedSlots++
|
|
474
|
+
currentSlotRemaining = SLOT_SIZE
|
|
475
|
+
}
|
|
476
|
+
currentSlotRemaining -= variable.size
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (currentSlotRemaining < SLOT_SIZE) {
|
|
480
|
+
optimizedSlots++
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Calculate gas savings
|
|
484
|
+
// SSTORE for new slot: 20000 gas
|
|
485
|
+
// Reading additional slots: 2100 gas each (cold)
|
|
486
|
+
const slotsSaved = currentSlots - optimizedSlots
|
|
487
|
+
const gasSavings = BigInt(slotsSaved) * EVM_GAS_COSTS.sstoreSet
|
|
488
|
+
|
|
489
|
+
const recommendations: string[] = []
|
|
490
|
+
|
|
491
|
+
if (slotsSaved > 0) {
|
|
492
|
+
recommendations.push(
|
|
493
|
+
`Pack variables to save ${slotsSaved} storage slots (~${gasSavings} gas on writes)`
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
// Specific packing recommendations
|
|
497
|
+
const smallVars = variables.filter((v) => v.size <= 16)
|
|
498
|
+
if (smallVars.length >= 2) {
|
|
499
|
+
recommendations.push(
|
|
500
|
+
`Pack small variables (${smallVars.map((v) => v.name).join(', ')}) into single slot`
|
|
501
|
+
)
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return {
|
|
506
|
+
currentSlots,
|
|
507
|
+
optimizedSlots,
|
|
508
|
+
gasSavings,
|
|
509
|
+
recommendations,
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// ─── Utility Functions ────────────────────────────────────────────────────────
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Convert wei to ETH
|
|
517
|
+
*/
|
|
518
|
+
export function weiToEth(wei: bigint): string {
|
|
519
|
+
const eth = Number(wei) / Number(ONE_ETH)
|
|
520
|
+
return eth.toFixed(6)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Convert gwei to wei
|
|
525
|
+
*/
|
|
526
|
+
export function gweiToWei(gwei: number): bigint {
|
|
527
|
+
return BigInt(Math.floor(gwei * 1e9))
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Format gas price for display
|
|
532
|
+
*/
|
|
533
|
+
export function formatGasPrice(wei: bigint): string {
|
|
534
|
+
const gwei = Number(wei) / 1e9
|
|
535
|
+
if (gwei < 0.01) {
|
|
536
|
+
return `${(gwei * 1000).toFixed(2)} mGwei`
|
|
537
|
+
}
|
|
538
|
+
return `${gwei.toFixed(2)} Gwei`
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Get gas profile from user-friendly name
|
|
543
|
+
*/
|
|
544
|
+
export function parseGasProfile(name: string): GasProfile {
|
|
545
|
+
const normalized = name.toLowerCase().trim()
|
|
546
|
+
switch (normalized) {
|
|
547
|
+
case 'economy':
|
|
548
|
+
case 'eco':
|
|
549
|
+
case 'low':
|
|
550
|
+
case 'slow':
|
|
551
|
+
return 'economy'
|
|
552
|
+
case 'standard':
|
|
553
|
+
case 'normal':
|
|
554
|
+
case 'default':
|
|
555
|
+
case 'medium':
|
|
556
|
+
return 'standard'
|
|
557
|
+
case 'fast':
|
|
558
|
+
case 'high':
|
|
559
|
+
case 'quick':
|
|
560
|
+
return 'fast'
|
|
561
|
+
case 'instant':
|
|
562
|
+
case 'max':
|
|
563
|
+
case 'urgent':
|
|
564
|
+
case 'turbo':
|
|
565
|
+
return 'instant'
|
|
566
|
+
default:
|
|
567
|
+
return 'standard'
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Estimate calldata cost
|
|
573
|
+
*
|
|
574
|
+
* @param data - Calldata bytes
|
|
575
|
+
* @returns Gas cost for calldata
|
|
576
|
+
*/
|
|
577
|
+
export function estimateCalldataCost(data: Uint8Array | string): bigint {
|
|
578
|
+
const bytes =
|
|
579
|
+
typeof data === 'string'
|
|
580
|
+
? Uint8Array.from(Buffer.from(data.replace('0x', ''), 'hex'))
|
|
581
|
+
: data
|
|
582
|
+
|
|
583
|
+
let cost = 0n
|
|
584
|
+
for (const byte of bytes) {
|
|
585
|
+
cost += byte === 0 ? EVM_GAS_COSTS.calldataZeroByte : EVM_GAS_COSTS.calldataNonZeroByte
|
|
586
|
+
}
|
|
587
|
+
return cost
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Compare gas costs between networks
|
|
592
|
+
*
|
|
593
|
+
* @param complexity - Transaction complexity
|
|
594
|
+
* @param networks - Networks to compare
|
|
595
|
+
* @param gasPrices - Gas prices per network (wei)
|
|
596
|
+
* @returns Cost comparison
|
|
597
|
+
*/
|
|
598
|
+
export function compareNetworkCosts(
|
|
599
|
+
complexity: EVMTransactionComplexity,
|
|
600
|
+
networks: EthereumNetwork[],
|
|
601
|
+
gasPrices: Record<EthereumNetwork, bigint>
|
|
602
|
+
): Array<{ network: EthereumNetwork; costWei: bigint; costEth: string }> {
|
|
603
|
+
return networks
|
|
604
|
+
.map((network) => {
|
|
605
|
+
const gasPrice = gasPrices[network] ?? ONE_GWEI * 10n
|
|
606
|
+
const costWei = complexity.estimatedGas * gasPrice
|
|
607
|
+
return {
|
|
608
|
+
network,
|
|
609
|
+
costWei,
|
|
610
|
+
costEth: weiToEth(costWei),
|
|
611
|
+
}
|
|
612
|
+
})
|
|
613
|
+
.sort((a, b) => (a.costWei < b.costWei ? -1 : 1))
|
|
614
|
+
}
|