@getomnichain/omnichain 0.2.0 → 0.3.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/dist/cjs/abstract_gas_pricing.js +27 -0
- package/dist/cjs/abstract_gas_pricing.js.map +1 -0
- package/dist/cjs/address.factory.js +81 -0
- package/dist/cjs/address.factory.js.map +1 -0
- package/dist/cjs/address.js +17 -0
- package/dist/cjs/address.js.map +1 -0
- package/dist/cjs/address_field.decorator.js +37 -0
- package/dist/cjs/address_field.decorator.js.map +1 -0
- package/dist/cjs/chain.base.js +118 -0
- package/dist/cjs/chain.base.js.map +1 -0
- package/dist/cjs/chain_ids.js +205 -0
- package/dist/cjs/chain_ids.js.map +1 -0
- package/dist/cjs/errors.js +118 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/evm/evm_address.js +63 -0
- package/dist/cjs/evm/evm_address.js.map +1 -0
- package/dist/cjs/evm/evm_chain.js +1109 -0
- package/dist/cjs/evm/evm_chain.js.map +1 -0
- package/dist/cjs/evm/evm_chains.js +530 -0
- package/dist/cjs/evm/evm_chains.js.map +1 -0
- package/dist/cjs/evm/evm_gas_estimate.js +76 -0
- package/dist/cjs/evm/evm_gas_estimate.js.map +1 -0
- package/dist/cjs/evm/evm_gas_pricing.js +62 -0
- package/dist/cjs/evm/evm_gas_pricing.js.map +1 -0
- package/dist/cjs/evm/evm_token.js +26 -0
- package/dist/cjs/evm/evm_token.js.map +1 -0
- package/dist/cjs/evm/evm_tokens.js +109 -0
- package/dist/cjs/evm/evm_tokens.js.map +1 -0
- package/dist/cjs/evm/evm_transaction_status.js +187 -0
- package/dist/cjs/evm/evm_transaction_status.js.map +1 -0
- package/dist/cjs/evm/index.js +26 -0
- package/dist/cjs/evm/index.js.map +1 -0
- package/dist/cjs/evm/unsigned_evm_transaction.js +34 -0
- package/dist/cjs/evm/unsigned_evm_transaction.js.map +1 -0
- package/dist/cjs/index.js +34 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/is_address.decorator.js +54 -0
- package/dist/cjs/is_address.decorator.js.map +1 -0
- package/dist/cjs/network_type.js +152 -0
- package/dist/cjs/network_type.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/priority.js +26 -0
- package/dist/cjs/priority.js.map +1 -0
- package/dist/cjs/solana/index.js +25 -0
- package/dist/cjs/solana/index.js.map +1 -0
- package/dist/cjs/solana/solana_address.js +49 -0
- package/dist/cjs/solana/solana_address.js.map +1 -0
- package/dist/cjs/solana/solana_chain.js +1305 -0
- package/dist/cjs/solana/solana_chain.js.map +1 -0
- package/dist/cjs/solana/solana_chains.js +88 -0
- package/dist/cjs/solana/solana_chains.js.map +1 -0
- package/dist/cjs/solana/solana_gas_pricing.js +30 -0
- package/dist/cjs/solana/solana_gas_pricing.js.map +1 -0
- package/dist/cjs/solana/solana_token.js +38 -0
- package/dist/cjs/solana/solana_token.js.map +1 -0
- package/dist/cjs/solana/solana_tokens.js +29 -0
- package/dist/cjs/solana/solana_tokens.js.map +1 -0
- package/dist/cjs/solana/solana_transaction_status.js +149 -0
- package/dist/cjs/solana/solana_transaction_status.js.map +1 -0
- package/dist/cjs/solana/unsigned_solana_transaction.js +63 -0
- package/dist/cjs/solana/unsigned_solana_transaction.js.map +1 -0
- package/dist/cjs/token.js +66 -0
- package/dist/cjs/token.js.map +1 -0
- package/dist/cjs/ton/index.js +18 -0
- package/dist/cjs/ton/index.js.map +1 -0
- package/dist/cjs/ton/ton_address.js +57 -0
- package/dist/cjs/ton/ton_address.js.map +1 -0
- package/dist/cjs/transaction_status.js +283 -0
- package/dist/cjs/transaction_status.js.map +1 -0
- package/dist/cjs/unsigned_transaction.js +13 -0
- package/dist/cjs/unsigned_transaction.js.map +1 -0
- package/dist/cjs/utxo/btc/btc_address.js +43 -0
- package/dist/cjs/utxo/btc/btc_address.js.map +1 -0
- package/dist/cjs/utxo/btc/btc_chain.js +66 -0
- package/dist/cjs/utxo/btc/btc_chain.js.map +1 -0
- package/dist/cjs/utxo/btc/btc_chains.js +49 -0
- package/dist/cjs/utxo/btc/btc_chains.js.map +1 -0
- package/dist/cjs/utxo/btc/btc_token.js +15 -0
- package/dist/cjs/utxo/btc/btc_token.js.map +1 -0
- package/dist/cjs/utxo/btc/index.js +30 -0
- package/dist/cjs/utxo/btc/index.js.map +1 -0
- package/dist/cjs/utxo/btc/network_params.js +196 -0
- package/dist/cjs/utxo/btc/network_params.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/asset_outpoint.js +16 -0
- package/dist/cjs/utxo/btc/tools/asset_outpoint.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/bitcoin_core.tool.js +179 -0
- package/dist/cjs/utxo/btc/tools/bitcoin_core.tool.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/esplora.tool.js +120 -0
- package/dist/cjs/utxo/btc/tools/esplora.tool.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/inscription_index.js +3 -0
- package/dist/cjs/utxo/btc/tools/inscription_index.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/ordiscan.tool.js +60 -0
- package/dist/cjs/utxo/btc/tools/ordiscan.tool.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/rare_sat_index.js +3 -0
- package/dist/cjs/utxo/btc/tools/rare_sat_index.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/rune_index.js +3 -0
- package/dist/cjs/utxo/btc/tools/rune_index.js.map +1 -0
- package/dist/cjs/utxo/btc/tools/unisat.tool.js +56 -0
- package/dist/cjs/utxo/btc/tools/unisat.tool.js.map +1 -0
- package/dist/cjs/utxo/coin_selection.js +160 -0
- package/dist/cjs/utxo/coin_selection.js.map +1 -0
- package/dist/cjs/utxo/doge/doge_chains.js +32 -0
- package/dist/cjs/utxo/doge/doge_chains.js.map +1 -0
- package/dist/cjs/utxo/doge/index.js +19 -0
- package/dist/cjs/utxo/doge/index.js.map +1 -0
- package/dist/cjs/utxo/doge/network_params.js +30 -0
- package/dist/cjs/utxo/doge/network_params.js.map +1 -0
- package/dist/cjs/utxo/ecc.js +47 -0
- package/dist/cjs/utxo/ecc.js.map +1 -0
- package/dist/cjs/utxo/fee.js +61 -0
- package/dist/cjs/utxo/fee.js.map +1 -0
- package/dist/cjs/utxo/index.js +36 -0
- package/dist/cjs/utxo/index.js.map +1 -0
- package/dist/cjs/utxo/ltc/index.js +19 -0
- package/dist/cjs/utxo/ltc/index.js.map +1 -0
- package/dist/cjs/utxo/ltc/ltc_chains.js +32 -0
- package/dist/cjs/utxo/ltc/ltc_chains.js.map +1 -0
- package/dist/cjs/utxo/ltc/network_params.js +33 -0
- package/dist/cjs/utxo/ltc/network_params.js.map +1 -0
- package/dist/cjs/utxo/script.js +59 -0
- package/dist/cjs/utxo/script.js.map +1 -0
- package/dist/cjs/utxo/tools/broadcaster.js +3 -0
- package/dist/cjs/utxo/tools/broadcaster.js.map +1 -0
- package/dist/cjs/utxo/tools/chain_tip_provider.js +3 -0
- package/dist/cjs/utxo/tools/chain_tip_provider.js.map +1 -0
- package/dist/cjs/utxo/tools/fee_estimator.js +3 -0
- package/dist/cjs/utxo/tools/fee_estimator.js.map +1 -0
- package/dist/cjs/utxo/tools/raw_transaction_provider.js +3 -0
- package/dist/cjs/utxo/tools/raw_transaction_provider.js.map +1 -0
- package/dist/cjs/utxo/tools/utxo_provider.js +3 -0
- package/dist/cjs/utxo/tools/utxo_provider.js.map +1 -0
- package/dist/cjs/utxo/unsigned_utxo_transaction.js +36 -0
- package/dist/cjs/utxo/unsigned_utxo_transaction.js.map +1 -0
- package/dist/cjs/utxo/utxo.js +3 -0
- package/dist/{utxo → cjs/utxo}/utxo.js.map +1 -1
- package/dist/cjs/utxo/utxo_chain.js +612 -0
- package/dist/cjs/utxo/utxo_chain.js.map +1 -0
- package/dist/cjs/utxo/utxo_chains.js +68 -0
- package/dist/cjs/utxo/utxo_chains.js.map +1 -0
- package/dist/cjs/utxo/utxo_gas_pricing.js +24 -0
- package/dist/cjs/utxo/utxo_gas_pricing.js.map +1 -0
- package/dist/cjs/utxo/utxo_network_params.js +18 -0
- package/dist/cjs/utxo/utxo_network_params.js.map +1 -0
- package/dist/cjs/utxo/utxo_transaction_status.js +95 -0
- package/dist/cjs/utxo/utxo_transaction_status.js.map +1 -0
- package/dist/esm/abstract_gas_pricing.d.ts.map +1 -0
- package/dist/esm/abstract_gas_pricing.js.map +1 -0
- package/dist/esm/address.d.ts.map +1 -0
- package/dist/esm/address.factory.d.ts.map +1 -0
- package/dist/esm/address.factory.js.map +1 -0
- package/dist/esm/address.js.map +1 -0
- package/dist/esm/address_field.decorator.d.ts.map +1 -0
- package/dist/esm/address_field.decorator.js.map +1 -0
- package/dist/{chain.base.d.ts → esm/chain.base.d.ts} +38 -1
- package/dist/esm/chain.base.d.ts.map +1 -0
- package/dist/esm/chain.base.js.map +1 -0
- package/dist/esm/chain_ids.d.ts.map +1 -0
- package/dist/esm/chain_ids.js.map +1 -0
- package/dist/{errors.d.ts → esm/errors.d.ts} +13 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +107 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/evm/evm_address.d.ts.map +1 -0
- package/dist/esm/evm/evm_address.js.map +1 -0
- package/dist/{evm → esm/evm}/evm_chain.d.ts +48 -2
- package/dist/esm/evm/evm_chain.d.ts.map +1 -0
- package/dist/{evm → esm/evm}/evm_chain.js +423 -4
- package/dist/esm/evm/evm_chain.js.map +1 -0
- package/dist/esm/evm/evm_chains.d.ts.map +1 -0
- package/dist/esm/evm/evm_chains.js.map +1 -0
- package/dist/esm/evm/evm_gas_estimate.d.ts.map +1 -0
- package/dist/esm/evm/evm_gas_estimate.js.map +1 -0
- package/dist/esm/evm/evm_gas_pricing.d.ts.map +1 -0
- package/dist/esm/evm/evm_gas_pricing.js.map +1 -0
- package/dist/esm/evm/evm_token.d.ts.map +1 -0
- package/dist/esm/evm/evm_token.js.map +1 -0
- package/dist/esm/evm/evm_tokens.d.ts.map +1 -0
- package/dist/esm/evm/evm_tokens.js.map +1 -0
- package/dist/{evm → esm/evm}/evm_transaction_status.d.ts +4 -0
- package/dist/esm/evm/evm_transaction_status.d.ts.map +1 -0
- package/dist/{evm → esm/evm}/evm_transaction_status.js +4 -0
- package/dist/esm/evm/evm_transaction_status.js.map +1 -0
- package/dist/esm/evm/index.d.ts.map +1 -0
- package/dist/esm/evm/index.js.map +1 -0
- package/dist/{evm → esm/evm}/unsigned_evm_transaction.d.ts +13 -0
- package/dist/esm/evm/unsigned_evm_transaction.d.ts.map +1 -0
- package/dist/{evm → esm/evm}/unsigned_evm_transaction.js +12 -0
- package/dist/esm/evm/unsigned_evm_transaction.js.map +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/is_address.decorator.d.ts.map +1 -0
- package/dist/esm/is_address.decorator.js.map +1 -0
- package/dist/esm/network_type.d.ts.map +1 -0
- package/dist/esm/network_type.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/priority.d.ts.map +1 -0
- package/dist/esm/priority.js.map +1 -0
- package/dist/esm/solana/index.d.ts.map +1 -0
- package/dist/esm/solana/index.js.map +1 -0
- package/dist/esm/solana/solana_address.d.ts.map +1 -0
- package/dist/esm/solana/solana_address.js.map +1 -0
- package/dist/{solana → esm/solana}/solana_chain.d.ts +87 -3
- package/dist/esm/solana/solana_chain.d.ts.map +1 -0
- package/dist/{solana → esm/solana}/solana_chain.js +618 -23
- package/dist/esm/solana/solana_chain.js.map +1 -0
- package/dist/esm/solana/solana_chains.d.ts.map +1 -0
- package/dist/esm/solana/solana_chains.js.map +1 -0
- package/dist/esm/solana/solana_gas_pricing.d.ts.map +1 -0
- package/dist/esm/solana/solana_gas_pricing.js.map +1 -0
- package/dist/esm/solana/solana_token.d.ts.map +1 -0
- package/dist/esm/solana/solana_token.js.map +1 -0
- package/dist/esm/solana/solana_tokens.d.ts.map +1 -0
- package/dist/esm/solana/solana_tokens.js.map +1 -0
- package/dist/esm/solana/solana_transaction_status.d.ts.map +1 -0
- package/dist/esm/solana/solana_transaction_status.js.map +1 -0
- package/dist/{solana → esm/solana}/unsigned_solana_transaction.d.ts +20 -1
- package/dist/esm/solana/unsigned_solana_transaction.d.ts.map +1 -0
- package/dist/esm/solana/unsigned_solana_transaction.js +59 -0
- package/dist/esm/solana/unsigned_solana_transaction.js.map +1 -0
- package/dist/esm/token.d.ts.map +1 -0
- package/dist/esm/token.js.map +1 -0
- package/dist/esm/ton/index.d.ts.map +1 -0
- package/dist/esm/ton/index.js.map +1 -0
- package/dist/esm/ton/ton_address.d.ts.map +1 -0
- package/dist/esm/ton/ton_address.js.map +1 -0
- package/dist/esm/transaction_status.d.ts.map +1 -0
- package/dist/esm/transaction_status.js.map +1 -0
- package/dist/esm/unsigned_transaction.d.ts.map +1 -0
- package/dist/esm/unsigned_transaction.js.map +1 -0
- package/dist/esm/utxo/btc/btc_address.d.ts.map +1 -0
- package/dist/esm/utxo/btc/btc_address.js.map +1 -0
- package/dist/esm/utxo/btc/btc_chain.d.ts.map +1 -0
- package/dist/esm/utxo/btc/btc_chain.js.map +1 -0
- package/dist/esm/utxo/btc/btc_chains.d.ts.map +1 -0
- package/dist/esm/utxo/btc/btc_chains.js.map +1 -0
- package/dist/esm/utxo/btc/btc_token.d.ts.map +1 -0
- package/dist/esm/utxo/btc/btc_token.js.map +1 -0
- package/dist/esm/utxo/btc/index.d.ts.map +1 -0
- package/dist/esm/utxo/btc/index.js.map +1 -0
- package/dist/esm/utxo/btc/network_params.d.ts.map +1 -0
- package/dist/esm/utxo/btc/network_params.js.map +1 -0
- package/dist/esm/utxo/btc/tools/asset_outpoint.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/asset_outpoint.js.map +1 -0
- package/dist/esm/utxo/btc/tools/bitcoin_core.tool.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/bitcoin_core.tool.js.map +1 -0
- package/dist/esm/utxo/btc/tools/esplora.tool.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/esplora.tool.js.map +1 -0
- package/dist/esm/utxo/btc/tools/inscription_index.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/inscription_index.js.map +1 -0
- package/dist/esm/utxo/btc/tools/ordiscan.tool.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/ordiscan.tool.js.map +1 -0
- package/dist/esm/utxo/btc/tools/rare_sat_index.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/rare_sat_index.js.map +1 -0
- package/dist/esm/utxo/btc/tools/rune_index.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/rune_index.js.map +1 -0
- package/dist/esm/utxo/btc/tools/unisat.tool.d.ts.map +1 -0
- package/dist/esm/utxo/btc/tools/unisat.tool.js.map +1 -0
- package/dist/esm/utxo/coin_selection.d.ts.map +1 -0
- package/dist/esm/utxo/coin_selection.js.map +1 -0
- package/dist/esm/utxo/doge/doge_chains.d.ts.map +1 -0
- package/dist/esm/utxo/doge/doge_chains.js.map +1 -0
- package/dist/esm/utxo/doge/index.d.ts.map +1 -0
- package/dist/esm/utxo/doge/index.js.map +1 -0
- package/dist/esm/utxo/doge/network_params.d.ts.map +1 -0
- package/dist/esm/utxo/doge/network_params.js.map +1 -0
- package/dist/esm/utxo/ecc.d.ts.map +1 -0
- package/dist/esm/utxo/ecc.js.map +1 -0
- package/dist/esm/utxo/fee.d.ts.map +1 -0
- package/dist/esm/utxo/fee.js.map +1 -0
- package/dist/esm/utxo/index.d.ts.map +1 -0
- package/dist/esm/utxo/index.js.map +1 -0
- package/dist/esm/utxo/ltc/index.d.ts.map +1 -0
- package/dist/esm/utxo/ltc/index.js.map +1 -0
- package/dist/{utxo/doge/doge_chains.d.ts.map → esm/utxo/ltc/ltc_chains.d.ts.map} +1 -1
- package/dist/{utxo/doge/doge_chains.js.map → esm/utxo/ltc/ltc_chains.js.map} +1 -1
- package/dist/esm/utxo/ltc/network_params.d.ts.map +1 -0
- package/dist/esm/utxo/ltc/network_params.js.map +1 -0
- package/dist/esm/utxo/script.d.ts.map +1 -0
- package/dist/esm/utxo/script.js.map +1 -0
- package/dist/esm/utxo/tools/broadcaster.d.ts.map +1 -0
- package/dist/esm/utxo/tools/broadcaster.js.map +1 -0
- package/dist/esm/utxo/tools/chain_tip_provider.d.ts.map +1 -0
- package/dist/esm/utxo/tools/chain_tip_provider.js.map +1 -0
- package/dist/esm/utxo/tools/fee_estimator.d.ts.map +1 -0
- package/dist/esm/utxo/tools/fee_estimator.js.map +1 -0
- package/dist/esm/utxo/tools/raw_transaction_provider.d.ts.map +1 -0
- package/dist/esm/utxo/tools/raw_transaction_provider.js.map +1 -0
- package/dist/esm/utxo/tools/utxo_provider.d.ts.map +1 -0
- package/dist/esm/utxo/tools/utxo_provider.js.map +1 -0
- package/dist/esm/utxo/unsigned_utxo_transaction.d.ts.map +1 -0
- package/dist/esm/utxo/unsigned_utxo_transaction.js.map +1 -0
- package/dist/esm/utxo/utxo.d.ts.map +1 -0
- package/dist/esm/utxo/utxo.js.map +1 -0
- package/dist/{utxo → esm/utxo}/utxo_chain.d.ts +15 -2
- package/dist/esm/utxo/utxo_chain.d.ts.map +1 -0
- package/dist/{utxo → esm/utxo}/utxo_chain.js +96 -13
- package/dist/esm/utxo/utxo_chain.js.map +1 -0
- package/dist/esm/utxo/utxo_chains.d.ts.map +1 -0
- package/dist/esm/utxo/utxo_chains.js.map +1 -0
- package/dist/esm/utxo/utxo_gas_pricing.d.ts.map +1 -0
- package/dist/esm/utxo/utxo_gas_pricing.js.map +1 -0
- package/dist/esm/utxo/utxo_network_params.d.ts.map +1 -0
- package/dist/esm/utxo/utxo_network_params.js.map +1 -0
- package/dist/esm/utxo/utxo_transaction_status.d.ts.map +1 -0
- package/dist/esm/utxo/utxo_transaction_status.js.map +1 -0
- package/docs/CONNECTIONS.md +33 -0
- package/docs/EIP7702.md +77 -0
- package/docs/JITO.md +41 -0
- package/docs/MULTI_RPC.md +28 -0
- package/package.json +32 -16
- package/dist/abstract_gas_pricing.d.ts.map +0 -1
- package/dist/abstract_gas_pricing.js.map +0 -1
- package/dist/address.d.ts.map +0 -1
- package/dist/address.factory.d.ts.map +0 -1
- package/dist/address.factory.js.map +0 -1
- package/dist/address.js.map +0 -1
- package/dist/address_field.decorator.d.ts.map +0 -1
- package/dist/address_field.decorator.js.map +0 -1
- package/dist/chain.base.d.ts.map +0 -1
- package/dist/chain.base.js.map +0 -1
- package/dist/chain_ids.d.ts.map +0 -1
- package/dist/chain_ids.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -62
- package/dist/errors.js.map +0 -1
- package/dist/evm/evm_address.d.ts.map +0 -1
- package/dist/evm/evm_address.js.map +0 -1
- package/dist/evm/evm_chain.d.ts.map +0 -1
- package/dist/evm/evm_chain.js.map +0 -1
- package/dist/evm/evm_chains.d.ts.map +0 -1
- package/dist/evm/evm_chains.js.map +0 -1
- package/dist/evm/evm_gas_estimate.d.ts.map +0 -1
- package/dist/evm/evm_gas_estimate.js.map +0 -1
- package/dist/evm/evm_gas_pricing.d.ts.map +0 -1
- package/dist/evm/evm_gas_pricing.js.map +0 -1
- package/dist/evm/evm_token.d.ts.map +0 -1
- package/dist/evm/evm_token.js.map +0 -1
- package/dist/evm/evm_tokens.d.ts.map +0 -1
- package/dist/evm/evm_tokens.js.map +0 -1
- package/dist/evm/evm_transaction_status.d.ts.map +0 -1
- package/dist/evm/evm_transaction_status.js.map +0 -1
- package/dist/evm/index.d.ts.map +0 -1
- package/dist/evm/index.js.map +0 -1
- package/dist/evm/unsigned_evm_transaction.d.ts.map +0 -1
- package/dist/evm/unsigned_evm_transaction.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/is_address.decorator.d.ts.map +0 -1
- package/dist/is_address.decorator.js.map +0 -1
- package/dist/network_type.d.ts.map +0 -1
- package/dist/network_type.js.map +0 -1
- package/dist/priority.d.ts.map +0 -1
- package/dist/priority.js.map +0 -1
- package/dist/solana/index.d.ts.map +0 -1
- package/dist/solana/index.js.map +0 -1
- package/dist/solana/solana_address.d.ts.map +0 -1
- package/dist/solana/solana_address.js.map +0 -1
- package/dist/solana/solana_chain.d.ts.map +0 -1
- package/dist/solana/solana_chain.js.map +0 -1
- package/dist/solana/solana_chains.d.ts.map +0 -1
- package/dist/solana/solana_chains.js.map +0 -1
- package/dist/solana/solana_gas_pricing.d.ts.map +0 -1
- package/dist/solana/solana_gas_pricing.js.map +0 -1
- package/dist/solana/solana_token.d.ts.map +0 -1
- package/dist/solana/solana_token.js.map +0 -1
- package/dist/solana/solana_tokens.d.ts.map +0 -1
- package/dist/solana/solana_tokens.js.map +0 -1
- package/dist/solana/solana_transaction_status.d.ts.map +0 -1
- package/dist/solana/solana_transaction_status.js.map +0 -1
- package/dist/solana/unsigned_solana_transaction.d.ts.map +0 -1
- package/dist/solana/unsigned_solana_transaction.js +0 -26
- package/dist/solana/unsigned_solana_transaction.js.map +0 -1
- package/dist/token.d.ts.map +0 -1
- package/dist/token.js.map +0 -1
- package/dist/ton/index.d.ts.map +0 -1
- package/dist/ton/index.js.map +0 -1
- package/dist/ton/ton_address.d.ts.map +0 -1
- package/dist/ton/ton_address.js.map +0 -1
- package/dist/transaction_status.d.ts.map +0 -1
- package/dist/transaction_status.js.map +0 -1
- package/dist/unsigned_transaction.d.ts.map +0 -1
- package/dist/unsigned_transaction.js.map +0 -1
- package/dist/utxo/btc/btc_address.d.ts.map +0 -1
- package/dist/utxo/btc/btc_address.js.map +0 -1
- package/dist/utxo/btc/btc_chain.d.ts.map +0 -1
- package/dist/utxo/btc/btc_chain.js.map +0 -1
- package/dist/utxo/btc/btc_chains.d.ts.map +0 -1
- package/dist/utxo/btc/btc_chains.js.map +0 -1
- package/dist/utxo/btc/btc_token.d.ts.map +0 -1
- package/dist/utxo/btc/btc_token.js.map +0 -1
- package/dist/utxo/btc/index.d.ts.map +0 -1
- package/dist/utxo/btc/index.js.map +0 -1
- package/dist/utxo/btc/network_params.d.ts.map +0 -1
- package/dist/utxo/btc/network_params.js.map +0 -1
- package/dist/utxo/btc/tools/asset_outpoint.d.ts.map +0 -1
- package/dist/utxo/btc/tools/asset_outpoint.js.map +0 -1
- package/dist/utxo/btc/tools/bitcoin_core.tool.d.ts.map +0 -1
- package/dist/utxo/btc/tools/bitcoin_core.tool.js.map +0 -1
- package/dist/utxo/btc/tools/esplora.tool.d.ts.map +0 -1
- package/dist/utxo/btc/tools/esplora.tool.js.map +0 -1
- package/dist/utxo/btc/tools/inscription_index.d.ts.map +0 -1
- package/dist/utxo/btc/tools/inscription_index.js.map +0 -1
- package/dist/utxo/btc/tools/ordiscan.tool.d.ts.map +0 -1
- package/dist/utxo/btc/tools/ordiscan.tool.js.map +0 -1
- package/dist/utxo/btc/tools/rare_sat_index.d.ts.map +0 -1
- package/dist/utxo/btc/tools/rare_sat_index.js.map +0 -1
- package/dist/utxo/btc/tools/rune_index.d.ts.map +0 -1
- package/dist/utxo/btc/tools/rune_index.js.map +0 -1
- package/dist/utxo/btc/tools/unisat.tool.d.ts.map +0 -1
- package/dist/utxo/btc/tools/unisat.tool.js.map +0 -1
- package/dist/utxo/coin_selection.d.ts.map +0 -1
- package/dist/utxo/coin_selection.js.map +0 -1
- package/dist/utxo/doge/index.d.ts.map +0 -1
- package/dist/utxo/doge/index.js.map +0 -1
- package/dist/utxo/doge/network_params.d.ts.map +0 -1
- package/dist/utxo/doge/network_params.js.map +0 -1
- package/dist/utxo/ecc.d.ts.map +0 -1
- package/dist/utxo/ecc.js.map +0 -1
- package/dist/utxo/fee.d.ts.map +0 -1
- package/dist/utxo/fee.js.map +0 -1
- package/dist/utxo/index.d.ts.map +0 -1
- package/dist/utxo/index.js.map +0 -1
- package/dist/utxo/ltc/index.d.ts.map +0 -1
- package/dist/utxo/ltc/index.js.map +0 -1
- package/dist/utxo/ltc/ltc_chains.d.ts.map +0 -1
- package/dist/utxo/ltc/ltc_chains.js.map +0 -1
- package/dist/utxo/ltc/network_params.d.ts.map +0 -1
- package/dist/utxo/ltc/network_params.js.map +0 -1
- package/dist/utxo/script.d.ts.map +0 -1
- package/dist/utxo/script.js.map +0 -1
- package/dist/utxo/tools/broadcaster.d.ts.map +0 -1
- package/dist/utxo/tools/broadcaster.js.map +0 -1
- package/dist/utxo/tools/chain_tip_provider.d.ts.map +0 -1
- package/dist/utxo/tools/chain_tip_provider.js.map +0 -1
- package/dist/utxo/tools/fee_estimator.d.ts.map +0 -1
- package/dist/utxo/tools/fee_estimator.js.map +0 -1
- package/dist/utxo/tools/raw_transaction_provider.d.ts.map +0 -1
- package/dist/utxo/tools/raw_transaction_provider.js.map +0 -1
- package/dist/utxo/tools/utxo_provider.d.ts.map +0 -1
- package/dist/utxo/tools/utxo_provider.js.map +0 -1
- package/dist/utxo/unsigned_utxo_transaction.d.ts.map +0 -1
- package/dist/utxo/unsigned_utxo_transaction.js.map +0 -1
- package/dist/utxo/utxo.d.ts.map +0 -1
- package/dist/utxo/utxo_chain.d.ts.map +0 -1
- package/dist/utxo/utxo_chain.js.map +0 -1
- package/dist/utxo/utxo_chains.d.ts.map +0 -1
- package/dist/utxo/utxo_chains.js.map +0 -1
- package/dist/utxo/utxo_gas_pricing.d.ts.map +0 -1
- package/dist/utxo/utxo_gas_pricing.js.map +0 -1
- package/dist/utxo/utxo_network_params.d.ts.map +0 -1
- package/dist/utxo/utxo_network_params.js.map +0 -1
- package/dist/utxo/utxo_transaction_status.d.ts.map +0 -1
- package/dist/utxo/utxo_transaction_status.js.map +0 -1
- /package/dist/{abstract_gas_pricing.d.ts → esm/abstract_gas_pricing.d.ts} +0 -0
- /package/dist/{abstract_gas_pricing.js → esm/abstract_gas_pricing.js} +0 -0
- /package/dist/{address.d.ts → esm/address.d.ts} +0 -0
- /package/dist/{address.factory.d.ts → esm/address.factory.d.ts} +0 -0
- /package/dist/{address.factory.js → esm/address.factory.js} +0 -0
- /package/dist/{address.js → esm/address.js} +0 -0
- /package/dist/{address_field.decorator.d.ts → esm/address_field.decorator.d.ts} +0 -0
- /package/dist/{address_field.decorator.js → esm/address_field.decorator.js} +0 -0
- /package/dist/{chain.base.js → esm/chain.base.js} +0 -0
- /package/dist/{chain_ids.d.ts → esm/chain_ids.d.ts} +0 -0
- /package/dist/{chain_ids.js → esm/chain_ids.js} +0 -0
- /package/dist/{evm → esm/evm}/evm_address.d.ts +0 -0
- /package/dist/{evm → esm/evm}/evm_address.js +0 -0
- /package/dist/{evm → esm/evm}/evm_chains.d.ts +0 -0
- /package/dist/{evm → esm/evm}/evm_chains.js +0 -0
- /package/dist/{evm → esm/evm}/evm_gas_estimate.d.ts +0 -0
- /package/dist/{evm → esm/evm}/evm_gas_estimate.js +0 -0
- /package/dist/{evm → esm/evm}/evm_gas_pricing.d.ts +0 -0
- /package/dist/{evm → esm/evm}/evm_gas_pricing.js +0 -0
- /package/dist/{evm → esm/evm}/evm_token.d.ts +0 -0
- /package/dist/{evm → esm/evm}/evm_token.js +0 -0
- /package/dist/{evm → esm/evm}/evm_tokens.d.ts +0 -0
- /package/dist/{evm → esm/evm}/evm_tokens.js +0 -0
- /package/dist/{evm → esm/evm}/index.d.ts +0 -0
- /package/dist/{evm → esm/evm}/index.js +0 -0
- /package/dist/{index.d.ts → esm/index.d.ts} +0 -0
- /package/dist/{index.js → esm/index.js} +0 -0
- /package/dist/{is_address.decorator.d.ts → esm/is_address.decorator.d.ts} +0 -0
- /package/dist/{is_address.decorator.js → esm/is_address.decorator.js} +0 -0
- /package/dist/{network_type.d.ts → esm/network_type.d.ts} +0 -0
- /package/dist/{network_type.js → esm/network_type.js} +0 -0
- /package/dist/{priority.d.ts → esm/priority.d.ts} +0 -0
- /package/dist/{priority.js → esm/priority.js} +0 -0
- /package/dist/{solana → esm/solana}/index.d.ts +0 -0
- /package/dist/{solana → esm/solana}/index.js +0 -0
- /package/dist/{solana → esm/solana}/solana_address.d.ts +0 -0
- /package/dist/{solana → esm/solana}/solana_address.js +0 -0
- /package/dist/{solana → esm/solana}/solana_chains.d.ts +0 -0
- /package/dist/{solana → esm/solana}/solana_chains.js +0 -0
- /package/dist/{solana → esm/solana}/solana_gas_pricing.d.ts +0 -0
- /package/dist/{solana → esm/solana}/solana_gas_pricing.js +0 -0
- /package/dist/{solana → esm/solana}/solana_token.d.ts +0 -0
- /package/dist/{solana → esm/solana}/solana_token.js +0 -0
- /package/dist/{solana → esm/solana}/solana_tokens.d.ts +0 -0
- /package/dist/{solana → esm/solana}/solana_tokens.js +0 -0
- /package/dist/{solana → esm/solana}/solana_transaction_status.d.ts +0 -0
- /package/dist/{solana → esm/solana}/solana_transaction_status.js +0 -0
- /package/dist/{token.d.ts → esm/token.d.ts} +0 -0
- /package/dist/{token.js → esm/token.js} +0 -0
- /package/dist/{ton → esm/ton}/index.d.ts +0 -0
- /package/dist/{ton → esm/ton}/index.js +0 -0
- /package/dist/{ton → esm/ton}/ton_address.d.ts +0 -0
- /package/dist/{ton → esm/ton}/ton_address.js +0 -0
- /package/dist/{transaction_status.d.ts → esm/transaction_status.d.ts} +0 -0
- /package/dist/{transaction_status.js → esm/transaction_status.js} +0 -0
- /package/dist/{unsigned_transaction.d.ts → esm/unsigned_transaction.d.ts} +0 -0
- /package/dist/{unsigned_transaction.js → esm/unsigned_transaction.js} +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_address.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_address.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_chain.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_chain.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_chains.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_chains.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_token.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/btc_token.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/index.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/index.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/network_params.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/network_params.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/asset_outpoint.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/asset_outpoint.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/bitcoin_core.tool.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/bitcoin_core.tool.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/esplora.tool.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/esplora.tool.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/inscription_index.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/inscription_index.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/ordiscan.tool.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/ordiscan.tool.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/rare_sat_index.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/rare_sat_index.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/rune_index.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/rune_index.js +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/unisat.tool.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/btc/tools/unisat.tool.js +0 -0
- /package/dist/{utxo → esm/utxo}/coin_selection.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/coin_selection.js +0 -0
- /package/dist/{utxo → esm/utxo}/doge/doge_chains.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/doge/doge_chains.js +0 -0
- /package/dist/{utxo → esm/utxo}/doge/index.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/doge/index.js +0 -0
- /package/dist/{utxo → esm/utxo}/doge/network_params.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/doge/network_params.js +0 -0
- /package/dist/{utxo → esm/utxo}/ecc.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/ecc.js +0 -0
- /package/dist/{utxo → esm/utxo}/fee.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/fee.js +0 -0
- /package/dist/{utxo → esm/utxo}/index.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/index.js +0 -0
- /package/dist/{utxo → esm/utxo}/ltc/index.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/ltc/index.js +0 -0
- /package/dist/{utxo → esm/utxo}/ltc/ltc_chains.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/ltc/ltc_chains.js +0 -0
- /package/dist/{utxo → esm/utxo}/ltc/network_params.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/ltc/network_params.js +0 -0
- /package/dist/{utxo → esm/utxo}/script.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/script.js +0 -0
- /package/dist/{utxo → esm/utxo}/tools/broadcaster.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/tools/broadcaster.js +0 -0
- /package/dist/{utxo → esm/utxo}/tools/chain_tip_provider.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/tools/chain_tip_provider.js +0 -0
- /package/dist/{utxo → esm/utxo}/tools/fee_estimator.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/tools/fee_estimator.js +0 -0
- /package/dist/{utxo → esm/utxo}/tools/raw_transaction_provider.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/tools/raw_transaction_provider.js +0 -0
- /package/dist/{utxo → esm/utxo}/tools/utxo_provider.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/tools/utxo_provider.js +0 -0
- /package/dist/{utxo → esm/utxo}/unsigned_utxo_transaction.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/unsigned_utxo_transaction.js +0 -0
- /package/dist/{utxo → esm/utxo}/utxo.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/utxo.js +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_chains.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_chains.js +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_gas_pricing.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_gas_pricing.js +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_network_params.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_network_params.js +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_transaction_status.d.ts +0 -0
- /package/dist/{utxo → esm/utxo}/utxo_transaction_status.js +0 -0
|
@@ -0,0 +1,1109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EvmChain = void 0;
|
|
4
|
+
exports.decodeRevertData = decodeRevertData;
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
6
|
+
const network_type_ts_1 = require("../network_type.js");
|
|
7
|
+
const chain_base_ts_1 = require("../chain.base.js");
|
|
8
|
+
const errors_ts_1 = require("../errors.js");
|
|
9
|
+
const priority_ts_1 = require("../priority.js");
|
|
10
|
+
const evm_gas_estimate_ts_1 = require("./evm_gas_estimate.js");
|
|
11
|
+
const transaction_status_ts_1 = require("../transaction_status.js");
|
|
12
|
+
const evm_transaction_status_ts_1 = require("./evm_transaction_status.js");
|
|
13
|
+
const evm_address_ts_1 = require("./evm_address.js");
|
|
14
|
+
const evm_token_ts_1 = require("./evm_token.js");
|
|
15
|
+
const unsigned_evm_transaction_ts_1 = require("./unsigned_evm_transaction.js");
|
|
16
|
+
// Priority profile mirrors omnichain-py/impl/evm/base.py:440-444
|
|
17
|
+
// (`_FEE_PRIORITY_PROFILE`): the reward-percentile is used for the 1559
|
|
18
|
+
// path (get_1559_fees's reward_percentile arg); the legacy multiplier
|
|
19
|
+
// applies ONLY when supportsEip1559 is false (Python does not fall back
|
|
20
|
+
// to the multiplier on the 1559 path).
|
|
21
|
+
const PRIORITY_REWARD_PERCENTILE = {
|
|
22
|
+
[priority_ts_1.Priority.SLOW]: 25,
|
|
23
|
+
[priority_ts_1.Priority.NORMAL]: 50,
|
|
24
|
+
[priority_ts_1.Priority.FAST]: 75,
|
|
25
|
+
};
|
|
26
|
+
// Legacy gas-price multiplier per priority tier — for the legacy branch only.
|
|
27
|
+
// Expressed as basis points × 100 so integer bigint arithmetic works.
|
|
28
|
+
const GAS_MULTIPLIER_PCT = {
|
|
29
|
+
[priority_ts_1.Priority.SLOW]: 100n,
|
|
30
|
+
[priority_ts_1.Priority.NORMAL]: 120n,
|
|
31
|
+
[priority_ts_1.Priority.FAST]: 150n,
|
|
32
|
+
};
|
|
33
|
+
// Empty-reward fallback tip: 2 gwei — matches Python `Web3.to_wei(2, 'gwei')`
|
|
34
|
+
// at impl/evm/base.py:1124.
|
|
35
|
+
const EMPTY_REWARD_FALLBACK_TIP = 2000000000n;
|
|
36
|
+
// Number of latest blocks sampled by eth_feeHistory. Python default 10
|
|
37
|
+
// (impl/evm/base.py:1099).
|
|
38
|
+
const FEE_HISTORY_BLOCK_COUNT = 10;
|
|
39
|
+
// Final-tip percentile picked across the sampled blocks after sorting.
|
|
40
|
+
// Python default 90.0 (impl/evm/base.py:1102).
|
|
41
|
+
const FINAL_TIP_PERCENTILE = 90;
|
|
42
|
+
// TS-only safety floor applied to any suggested gas price / tip. Python does
|
|
43
|
+
// NOT enforce a minimum: `sorted_tips[idx]` can be 0 on quiet L2 blocks.
|
|
44
|
+
// Silently unmineable transactions are unacceptable for a signing SDK, so
|
|
45
|
+
// TS clamps to 0.05 gwei.
|
|
46
|
+
const MIN_GAS_PRICE_FLOOR = 50000000n;
|
|
47
|
+
function atLeast(n, min) {
|
|
48
|
+
return n < min ? min : n;
|
|
49
|
+
}
|
|
50
|
+
const ERC20_TRANSFER_TOPIC = evm_transaction_status_ts_1.ERC20_TRANSFER_TOPIC;
|
|
51
|
+
const ERC20_ABI = [
|
|
52
|
+
'function balanceOf(address owner) view returns (uint256)',
|
|
53
|
+
'function decimals() view returns (uint8)',
|
|
54
|
+
'function symbol() view returns (string)',
|
|
55
|
+
'function transfer(address to, uint256 value)',
|
|
56
|
+
];
|
|
57
|
+
const ERC20_INTERFACE = new ethers_1.Interface(ERC20_ABI);
|
|
58
|
+
class EvmChain extends chain_base_ts_1.Chain {
|
|
59
|
+
rpcUrl;
|
|
60
|
+
rpcUrls;
|
|
61
|
+
supportsEip1559;
|
|
62
|
+
hasL1Fee;
|
|
63
|
+
/**
|
|
64
|
+
* Default gas limit for native transfers. Matches Python's public attribute
|
|
65
|
+
* at `impl/evm/base.py:495` — v0 does not consume it inside the TS SDK
|
|
66
|
+
* (see `createTransferUnsignedTransaction`) but exposes it so consumers
|
|
67
|
+
* building their own transfer paths get identical numbers to Python. Wired
|
|
68
|
+
* into the SDK-owned transfer builder in a follow-up branch.
|
|
69
|
+
*/
|
|
70
|
+
nativeTransferGasLimit;
|
|
71
|
+
/**
|
|
72
|
+
* Legacy `eth_gasPrice` multiplier for native transfers on non-1559 chains.
|
|
73
|
+
* Matches Python's public attribute at `impl/evm/base.py:496`. Same
|
|
74
|
+
* "declarative for consumers, unused internally in v0" note as
|
|
75
|
+
* `nativeTransferGasLimit`.
|
|
76
|
+
*/
|
|
77
|
+
nativeTransferGasMultiplier;
|
|
78
|
+
supports7702;
|
|
79
|
+
_nativeToken;
|
|
80
|
+
_provider = null;
|
|
81
|
+
_resolvedRpcUrl = null;
|
|
82
|
+
constructor(init) {
|
|
83
|
+
// Conflict guard — refuse to construct an EvmChain over a chainId that
|
|
84
|
+
// the static family seeds have already registered as non-EVM. Prevents
|
|
85
|
+
// the case where `new EvmChain({ chainId: 728126428, … })` would silently
|
|
86
|
+
// succeed and then contradict `addressFor(728126428, …)` /
|
|
87
|
+
// `networkTypeOf(728126428)` (both return TRON). Mirrors
|
|
88
|
+
// `registerNonEvmChain`'s throw-on-conflict guard.
|
|
89
|
+
const existing = (0, network_type_ts_1.tryNetworkTypeOf)(init.chainId);
|
|
90
|
+
if (existing !== undefined && existing !== network_type_ts_1.NetworkType.EVM) {
|
|
91
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `chainId ${init.chainId} is registered as ${existing}; refusing to construct EvmChain for it`, { chainId: init.chainId });
|
|
92
|
+
}
|
|
93
|
+
super(init.chainId, init.name, network_type_ts_1.NetworkType.EVM, init.blockTimeSeconds, init.nativeSymbol, init.explorerBaseUrl);
|
|
94
|
+
this.rpcUrl = init.rpcUrl;
|
|
95
|
+
this.rpcUrls = init.rpcUrls ?? [];
|
|
96
|
+
if (this.rpcUrls.length > 1) {
|
|
97
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EvmChainInit.rpcUrls accepts only ONE endpoint in 0.3.0 (got ${this.rpcUrls.length}). Automatic failover retry is deferred to a follow-up release; passing >1 endpoint would silently discard entries.`, { chainId: init.chainId });
|
|
98
|
+
}
|
|
99
|
+
this.supportsEip1559 = init.supportsEip1559 ?? true;
|
|
100
|
+
this.hasL1Fee = init.hasL1Fee ?? false;
|
|
101
|
+
this.nativeTransferGasLimit = init.nativeTransferGasLimit ?? 21000;
|
|
102
|
+
this.nativeTransferGasMultiplier = init.nativeTransferGasMultiplier ?? 1.4;
|
|
103
|
+
this.supports7702 = init.supports7702 ?? false;
|
|
104
|
+
this._nativeToken = evm_token_ts_1.EvmToken.native(init.chainId, init.nativeSymbol, init.nativeDecimals ?? 18);
|
|
105
|
+
// NOTE: no `registerNonEvmChain(id, EVM)` call — a module-scope write on
|
|
106
|
+
// 48 pre-baked chains would let a consumer's earlier
|
|
107
|
+
// `registerNonEvmChain(id, COSMOS)` turn `import '@getomnichain/omnichain'`
|
|
108
|
+
// into a permanently-poisoned module. Conflict detection lives in a
|
|
109
|
+
// single place: `registerNonEvmChain` reads `tryNetworkTypeOf` (which
|
|
110
|
+
// synthesizes EVM for positive-unregistered ids), so claiming a positive
|
|
111
|
+
// id for a non-EVM family requires `unregisterChain(id)` first.
|
|
112
|
+
}
|
|
113
|
+
get nativeToken() {
|
|
114
|
+
return this._nativeToken;
|
|
115
|
+
}
|
|
116
|
+
getErc20Token(symbol, contractAddress, decimals) {
|
|
117
|
+
// `EvmToken.erc20` → `new EvmToken` normalizes the identifier internally;
|
|
118
|
+
// no need to checksum here as well.
|
|
119
|
+
return evm_token_ts_1.EvmToken.erc20(this.chainId, symbol, contractAddress, decimals);
|
|
120
|
+
}
|
|
121
|
+
getProvider() {
|
|
122
|
+
if (this._provider)
|
|
123
|
+
return this._provider;
|
|
124
|
+
const rpcUrl = this.readRpcUrl();
|
|
125
|
+
this._resolvedRpcUrl = rpcUrl;
|
|
126
|
+
this._provider = new ethers_1.JsonRpcProvider(rpcUrl);
|
|
127
|
+
return this._provider;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Suggest gas fees for a priority tier. Mirrors Python's `_resolve_gas_pricing`
|
|
131
|
+
* dispatch (impl/evm/base.py:807-833):
|
|
132
|
+
*
|
|
133
|
+
* - legacy chains (`supportsEip1559 === false`): scale `eth_gasPrice` by
|
|
134
|
+
* the priority tier's legacy multiplier.
|
|
135
|
+
* - 1559 chains: sample eth_feeHistory across the last 10 blocks at the
|
|
136
|
+
* tier's reward percentile, sort, pick the p90 across blocks. On empty
|
|
137
|
+
* rewards, use 2 gwei. On RPC failure, bubble as `ChainError(RpcError)`
|
|
138
|
+
* (Python bubbles too — no defensive fallback).
|
|
139
|
+
*/
|
|
140
|
+
async suggestGas(priority) {
|
|
141
|
+
const provider = this.getProvider();
|
|
142
|
+
if (!this.supportsEip1559) {
|
|
143
|
+
const mult = GAS_MULTIPLIER_PCT[priority];
|
|
144
|
+
// Direct `eth_gasPrice` — one round-trip, matches Python
|
|
145
|
+
// impl/evm/base.py:831-833. Avoids getFeeData's implicit
|
|
146
|
+
// `getBlock("latest")` + potential `eth_maxPriorityFeePerGas` extra
|
|
147
|
+
// calls, and dodges the trap where getFeeData's maxFeePerGas is
|
|
148
|
+
// `2×baseFee + tip` (not a legacy price) — using that as the legacy
|
|
149
|
+
// gasPrice would 3-4× overpay.
|
|
150
|
+
let gasPriceHex;
|
|
151
|
+
try {
|
|
152
|
+
gasPriceHex = (await provider.send('eth_gasPrice', []));
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
throw this.rpcError('legacy eth_gasPrice transport failed', err);
|
|
156
|
+
}
|
|
157
|
+
let providerHint;
|
|
158
|
+
try {
|
|
159
|
+
providerHint = BigInt(gasPriceHex);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Genuinely unparseable response — bubble as RpcError so on-call
|
|
163
|
+
// triage sees the RPC returned nonsense, not "0 gas price".
|
|
164
|
+
throw this.rpcError(`legacy eth_gasPrice returned unparseable response`, new Error(`could not parse ${String(gasPriceHex)} as bigint`));
|
|
165
|
+
}
|
|
166
|
+
// Zero-or-negative gasPrice: clamp up to MIN_GAS_PRICE_FLOOR, mirroring
|
|
167
|
+
// the 1559 branch's floor-on-sub-floor-tips behavior (evm_chain.ts:307).
|
|
168
|
+
// Python (`impl/evm/base.py:831-833`) multiplies whatever `eth_gasPrice`
|
|
169
|
+
// returns and never throws; the TS floor is the safety measure that
|
|
170
|
+
// prevents an unmineable suggestion. Consistent policy across branches.
|
|
171
|
+
const base = providerHint > 0n ? providerHint : MIN_GAS_PRICE_FLOOR;
|
|
172
|
+
const scaled = atLeast((base * mult) / 100n, MIN_GAS_PRICE_FLOOR);
|
|
173
|
+
// Legacy chains: only `gasPrice` is authoritative — matches Python
|
|
174
|
+
// (`impl/evm/base.py:830-833` returns `EvmGasPricing(gas_price=...)`).
|
|
175
|
+
// Populating maxFeePerGas/maxPriorityFeePerGas as duplicates would let
|
|
176
|
+
// a consumer build a type-2 tx paying the full gasPrice as a tip on
|
|
177
|
+
// top of base fee.
|
|
178
|
+
return new evm_gas_estimate_ts_1.EvmGasEstimate({ kind: 'legacy', gasPrice: scaled });
|
|
179
|
+
}
|
|
180
|
+
// 1559 path — mirrors omnichain-py get_1559_fees (impl/evm/base.py:1098-1132).
|
|
181
|
+
// NB: Python reads `base_fee_per_gas` from `eth_getBlock("latest")` (line
|
|
182
|
+
// 1109-1110); TS reuses `feeHistory.baseFeePerGas[-1]` — the JSON-RPC
|
|
183
|
+
// "next block projection", up to ±12.5% off. Deliberate: saves an RPC
|
|
184
|
+
// round-trip. (See the local SINAN questions doc for the upstream
|
|
185
|
+
// discussion — TS uses feeHistory's projection to skip the extra RPC.)
|
|
186
|
+
const rewardPercentile = PRIORITY_REWARD_PERCENTILE[priority];
|
|
187
|
+
let raw;
|
|
188
|
+
// Narrow try — only the RPC call. Response-shape and parse errors are
|
|
189
|
+
// distinct from transport failures and get a distinct ChainError kind.
|
|
190
|
+
try {
|
|
191
|
+
raw = (await provider.send('eth_feeHistory', [
|
|
192
|
+
`0x${FEE_HISTORY_BLOCK_COUNT.toString(16)}`,
|
|
193
|
+
'latest',
|
|
194
|
+
[rewardPercentile],
|
|
195
|
+
]));
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
throw this.rpcError('eth_feeHistory transport failed', err);
|
|
199
|
+
}
|
|
200
|
+
// Narrow parse — only the shape checks + BigInt() coercions can throw
|
|
201
|
+
// for structural reasons here. `EvmGasEstimate` construction and the
|
|
202
|
+
// pure-arithmetic tip selection happen outside so that a defect there
|
|
203
|
+
// isn't mislabelled as an RPC-response malformed error.
|
|
204
|
+
let latestBaseFee;
|
|
205
|
+
let tips;
|
|
206
|
+
try {
|
|
207
|
+
const baseFees = raw.baseFeePerGas;
|
|
208
|
+
if (!Array.isArray(baseFees) || baseFees.length === 0) {
|
|
209
|
+
throw new Error('missing baseFeePerGas');
|
|
210
|
+
}
|
|
211
|
+
latestBaseFee = BigInt(baseFees[baseFees.length - 1] ?? '0x0');
|
|
212
|
+
const rewardRows = Array.isArray(raw.reward) ? raw.reward : [];
|
|
213
|
+
tips = rewardRows
|
|
214
|
+
.map((row) => (Array.isArray(row) ? row[0] : undefined))
|
|
215
|
+
.filter((v) => typeof v === 'string')
|
|
216
|
+
.map((v) => BigInt(v));
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
// Distinct from the RpcError raised by the provider.send catch above:
|
|
220
|
+
// parse/shape failures indict the response, not the transport. Routed
|
|
221
|
+
// through rpcError() so the URL sanitizer scrubs the response body.
|
|
222
|
+
throw this.rpcError(`eth_feeHistory response malformed`, err);
|
|
223
|
+
}
|
|
224
|
+
let selectedTip;
|
|
225
|
+
if (tips.length === 0) {
|
|
226
|
+
selectedTip = EMPTY_REWARD_FALLBACK_TIP;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
const sortedTips = [...tips].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
230
|
+
const idx = Math.min(Math.floor((sortedTips.length * FINAL_TIP_PERCENTILE) / 100), sortedTips.length - 1);
|
|
231
|
+
selectedTip = sortedTips[idx] ?? 0n;
|
|
232
|
+
}
|
|
233
|
+
// TS safety floor — Python doesn't clamp (see MIN_GAS_PRICE_FLOOR).
|
|
234
|
+
const finalTip = atLeast(selectedTip, MIN_GAS_PRICE_FLOOR);
|
|
235
|
+
// Safety buffer: base fee can climb 12.5%/block; caller may wait multiple blocks.
|
|
236
|
+
const maxFeePerGas = latestBaseFee * 2n + finalTip;
|
|
237
|
+
return new evm_gas_estimate_ts_1.EvmGasEstimate({
|
|
238
|
+
kind: 'eip1559',
|
|
239
|
+
maxPriorityFeePerGas: finalTip,
|
|
240
|
+
maxFeePerGas,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
readRpcUrl() {
|
|
244
|
+
if (this.rpcUrl && this.rpcUrl.trim().length > 0)
|
|
245
|
+
return this.rpcUrl.trim();
|
|
246
|
+
if (this.rpcUrls.length > 0) {
|
|
247
|
+
for (const candidate of this.rpcUrls) {
|
|
248
|
+
if (candidate && candidate.trim().length > 0)
|
|
249
|
+
return candidate.trim();
|
|
250
|
+
}
|
|
251
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcNotConfigured, `${this.name}: rpcUrls was supplied but every entry is blank; refusing to fall back to env or public defaults`, { chainId: this.chainId });
|
|
252
|
+
}
|
|
253
|
+
const env = globalThis.process?.env;
|
|
254
|
+
const candidates = envCandidatesFor(this.name, this.chainId);
|
|
255
|
+
for (const key of candidates) {
|
|
256
|
+
const value = env?.[key];
|
|
257
|
+
if (value && value.trim().length > 0)
|
|
258
|
+
return value.trim();
|
|
259
|
+
}
|
|
260
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcNotConfigured, `${this.name} RPC URL is not configured (pass rpcUrl, rpcUrls at construction, or set one of: ${candidates.join(', ')})`, { chainId: this.chainId, envCandidates: candidates });
|
|
261
|
+
}
|
|
262
|
+
rpcHost() {
|
|
263
|
+
const url = this._resolvedRpcUrl ?? this.rpcUrl;
|
|
264
|
+
if (!url)
|
|
265
|
+
return undefined;
|
|
266
|
+
try {
|
|
267
|
+
const u = new URL(url);
|
|
268
|
+
return `${u.protocol}//${u.host}`;
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
getWalletExplorerUrl(address) {
|
|
275
|
+
return `${this.explorerBaseUrl}/address/${address}`;
|
|
276
|
+
}
|
|
277
|
+
getTokenExplorerUrl(tokenIdentifier) {
|
|
278
|
+
if (tokenIdentifier === undefined) {
|
|
279
|
+
return this.explorerBaseUrl;
|
|
280
|
+
}
|
|
281
|
+
return `${this.explorerBaseUrl}/token/${tokenIdentifier}`;
|
|
282
|
+
}
|
|
283
|
+
getTransactionExplorerUrl(txHash) {
|
|
284
|
+
const prefixed = txHash.startsWith('0x') ? txHash : `0x${txHash}`;
|
|
285
|
+
return `${this.explorerBaseUrl}/tx/${prefixed}`;
|
|
286
|
+
}
|
|
287
|
+
validateAddress(raw) {
|
|
288
|
+
try {
|
|
289
|
+
new evm_address_ts_1.EvmAddress(raw);
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
normalizeAddressOrThrow(raw, field) {
|
|
297
|
+
const body = raw.replace(/^0[xX]/, '');
|
|
298
|
+
try {
|
|
299
|
+
return (0, ethers_1.getAddress)(`0x${body}`);
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address for ${field}: ${raw}`, { chainId: this.chainId, address: raw }, err instanceof Error ? err : undefined);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
validateTokenIdentifier(raw) {
|
|
306
|
+
if (raw === undefined)
|
|
307
|
+
return true;
|
|
308
|
+
return this.validateAddress(raw);
|
|
309
|
+
}
|
|
310
|
+
async getBalance(owner, tokenIdentifier) {
|
|
311
|
+
if (!this.validateAddress(owner)) {
|
|
312
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address: ${owner}`, {
|
|
313
|
+
chainId: this.chainId,
|
|
314
|
+
address: owner,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
if (!this.validateTokenIdentifier(tokenIdentifier)) {
|
|
318
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidTokenIdentifier, `Invalid EVM token identifier: ${tokenIdentifier}`, { chainId: this.chainId, identifier: tokenIdentifier });
|
|
319
|
+
}
|
|
320
|
+
const provider = this.getProvider();
|
|
321
|
+
try {
|
|
322
|
+
if (tokenIdentifier === undefined) {
|
|
323
|
+
return await provider.getBalance(owner);
|
|
324
|
+
}
|
|
325
|
+
const contract = new ethers_1.Contract(tokenIdentifier, ERC20_ABI, provider);
|
|
326
|
+
return (await contract.balanceOf(owner));
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
throw this.rpcError(`Failed to read balance for ${owner}`, err);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async createTransferUnsignedTransaction(req) {
|
|
333
|
+
if (!this.validateAddress(req.to)) {
|
|
334
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid recipient address: ${req.to}`, {
|
|
335
|
+
chainId: this.chainId,
|
|
336
|
+
address: req.to,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (req.from !== undefined && !this.validateAddress(req.from)) {
|
|
340
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid sender address: ${req.from}`, {
|
|
341
|
+
chainId: this.chainId,
|
|
342
|
+
address: req.from,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
if (!this.validateTokenIdentifier(req.tokenIdentifier)) {
|
|
346
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidTokenIdentifier, `Invalid token identifier: ${req.tokenIdentifier}`, { chainId: this.chainId, identifier: req.tokenIdentifier });
|
|
347
|
+
}
|
|
348
|
+
// gasPricing is on the CreateTransferRequest interface (Python
|
|
349
|
+
// parity) but per-chain wiring is deferred to a follow-up card.
|
|
350
|
+
// Rejecting it here rather than silently ignoring — a money knob
|
|
351
|
+
// that fails open is worse than not shipping it.
|
|
352
|
+
if (req.gasPricing !== undefined) {
|
|
353
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateTransferRequest.gasPricing is not yet consumed by EvmChain (Phase 2 follow-up). Use ethers tx builder options directly for now.', { chainId: this.chainId });
|
|
354
|
+
}
|
|
355
|
+
// isFullBalance is on the CreateTransferRequest interface (Python
|
|
356
|
+
// parity) but needs a fee-reserve computation before it can be
|
|
357
|
+
// safely wired — sending `value = balance` on native leaves 0 for
|
|
358
|
+
// gas → guaranteed insufficient-funds; on SPL it leaves 0 for rent.
|
|
359
|
+
// Deferred to a follow-up card that lands the estimated-fee subtract.
|
|
360
|
+
if (req.isFullBalance === true) {
|
|
361
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateTransferRequest.isFullBalance is not yet supported on EvmChain — pass `amount` or `amountHr` explicitly and reserve fees yourself.', { chainId: this.chainId });
|
|
362
|
+
}
|
|
363
|
+
// Only fetch decimals when amountHr is the input form — avoids two
|
|
364
|
+
// extra eth_calls on every bigint-amount transfer. Native path uses
|
|
365
|
+
// the SDK-declared decimals; ERC-20 path uses a STRICT resolver
|
|
366
|
+
// that throws on RPC failure (the defensive fallback to decimals=0
|
|
367
|
+
// would silently produce a wildly wrong minor-units amount).
|
|
368
|
+
let tokenDecimals = 0;
|
|
369
|
+
if (req.amountHr !== undefined) {
|
|
370
|
+
tokenDecimals =
|
|
371
|
+
req.tokenIdentifier === undefined
|
|
372
|
+
? this._nativeToken.decimals
|
|
373
|
+
: await this.resolveErc20DecimalsStrict(req.tokenIdentifier);
|
|
374
|
+
}
|
|
375
|
+
const resolved = (0, chain_base_ts_1.resolveTransferAmount)(req, tokenDecimals);
|
|
376
|
+
const amountMr = resolved.kind === 'exact' ? resolved.amountMr : 0n;
|
|
377
|
+
if (req.tokenIdentifier === undefined) {
|
|
378
|
+
return new unsigned_evm_transaction_ts_1.UnsignedEvmTransaction({
|
|
379
|
+
chainId: this.chainId,
|
|
380
|
+
from: req.from,
|
|
381
|
+
to: req.to,
|
|
382
|
+
value: amountMr,
|
|
383
|
+
data: '0x',
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
const data = ERC20_INTERFACE.encodeFunctionData('transfer', [req.to, amountMr]);
|
|
387
|
+
return new unsigned_evm_transaction_ts_1.UnsignedEvmTransaction({
|
|
388
|
+
chainId: this.chainId,
|
|
389
|
+
from: req.from,
|
|
390
|
+
to: req.tokenIdentifier,
|
|
391
|
+
value: 0n,
|
|
392
|
+
data,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
async getChainTipHeight() {
|
|
396
|
+
try {
|
|
397
|
+
return await this.getProvider().getBlockNumber();
|
|
398
|
+
}
|
|
399
|
+
catch (err) {
|
|
400
|
+
throw this.rpcError('Failed to read chain tip', err);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async broadcast(signed, opts) {
|
|
404
|
+
if (opts && opts.signal !== undefined) {
|
|
405
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM broadcast: signal is not honored in 0.3.0 (silently ignoring would let a caller conclude 'not sent' while the tx still lands). Cancellation returns in 0.3.1.`, { chainId: this.chainId });
|
|
406
|
+
}
|
|
407
|
+
let hex;
|
|
408
|
+
if (typeof signed === 'string') {
|
|
409
|
+
const stripped = signed.startsWith('0x') ? signed.slice(2) : signed;
|
|
410
|
+
if (!/^[0-9a-fA-F]+$/.test(stripped) || stripped.length % 2 !== 0 || stripped.length === 0) {
|
|
411
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EVM broadcast: signed transaction must be 0x-prefixed hex or Uint8Array (got malformed string of length ${signed.length})`, { chainId: this.chainId });
|
|
412
|
+
}
|
|
413
|
+
hex = `0x${stripped}`;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
if (signed.length === 0) {
|
|
417
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EVM broadcast: signed transaction bytes are empty`, { chainId: this.chainId });
|
|
418
|
+
}
|
|
419
|
+
hex = (0, ethers_1.hexlify)(signed);
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
const resp = await this.getProvider().broadcastTransaction(hex);
|
|
423
|
+
return resp.hash;
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
const rawMsg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
|
427
|
+
if (/already[-_ ]?known|known\s+transaction|transaction[-_ ]?already[-_ ]?known|already\s+in\s+(?:the\s+)?(?:mempool|pool)|already[-_ ]?present/.test(rawMsg)) {
|
|
428
|
+
// Node "already known" is authoritative for THAT node's mempool —
|
|
429
|
+
// the identical signed bytes are pending or landed. Return the
|
|
430
|
+
// deterministic hash so the consumer stays on the polling path.
|
|
431
|
+
// Do NOT gate on a follow-up getTransaction read: load-balanced
|
|
432
|
+
// providers (Alchemy/Infura/QuickNode round-robin) routinely serve
|
|
433
|
+
// the confirmation read from a different backend that has not yet
|
|
434
|
+
// seen the pending tx → null → falsely-terminal BroadcastRejected
|
|
435
|
+
// → consumer re-signs against a fresh nonce → double-send while
|
|
436
|
+
// the original is live. If the tx really never lands, the
|
|
437
|
+
// consumer's getTransactionStatus poll will surface NotFound and
|
|
438
|
+
// the safe-broadcast rule (re-broadcast same bytes, never re-sign)
|
|
439
|
+
// still applies. Matches SolanaChain/UtxoChain already-known paths.
|
|
440
|
+
return (0, ethers_1.keccak256)(hex);
|
|
441
|
+
}
|
|
442
|
+
throw this.classifyBroadcastError(err);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async getPendingNonce(address) {
|
|
446
|
+
if (!this.validateAddress(address)) {
|
|
447
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address for getPendingNonce: ${address}`, { chainId: this.chainId, address });
|
|
448
|
+
}
|
|
449
|
+
const normalized = this.normalizeAddressOrThrow(address, 'getPendingNonce.address');
|
|
450
|
+
try {
|
|
451
|
+
const n = await this.getProvider().getTransactionCount(normalized, 'pending');
|
|
452
|
+
return BigInt(n);
|
|
453
|
+
}
|
|
454
|
+
catch (err) {
|
|
455
|
+
throw this.rpcError(`Failed to read pending nonce for ${normalized}`, err, { address: normalized });
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
async getDelegation(address) {
|
|
459
|
+
if (!this.supports7702) {
|
|
460
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM chain ${this.name} was not initialized with supports7702: true`, { chainId: this.chainId });
|
|
461
|
+
}
|
|
462
|
+
try {
|
|
463
|
+
(0, ethers_1.getAddress)(address);
|
|
464
|
+
}
|
|
465
|
+
catch (err) {
|
|
466
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address: ${address}`, { chainId: this.chainId, address }, err instanceof Error ? err : undefined);
|
|
467
|
+
}
|
|
468
|
+
let code;
|
|
469
|
+
try {
|
|
470
|
+
code = await this.getProvider().getCode(address);
|
|
471
|
+
}
|
|
472
|
+
catch (err) {
|
|
473
|
+
throw this.rpcError(`Failed to read code for ${address}`, err, { address });
|
|
474
|
+
}
|
|
475
|
+
if (!code.startsWith('0x'))
|
|
476
|
+
return null;
|
|
477
|
+
const stripped = code.slice(2).toLowerCase();
|
|
478
|
+
if (stripped.length !== 46)
|
|
479
|
+
return null;
|
|
480
|
+
if (!stripped.startsWith('ef0100'))
|
|
481
|
+
return null;
|
|
482
|
+
return { delegate: (0, ethers_1.getAddress)(`0x${stripped.slice(6)}`) };
|
|
483
|
+
}
|
|
484
|
+
async call(req) {
|
|
485
|
+
if (!this.validateAddress(req.to)) {
|
|
486
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'to' address for call: ${req.to}`, { chainId: this.chainId, address: req.to });
|
|
487
|
+
}
|
|
488
|
+
if (req.from !== undefined && !this.validateAddress(req.from)) {
|
|
489
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'from' address for call: ${req.from}`, { chainId: this.chainId, address: req.from });
|
|
490
|
+
}
|
|
491
|
+
if (!/^0x([0-9a-fA-F]{2})*$/.test(req.data)) {
|
|
492
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EvmCallRequest.data must be 0x-prefixed even-length hex`, { chainId: this.chainId });
|
|
493
|
+
}
|
|
494
|
+
const provider = this.getProvider();
|
|
495
|
+
const tx = {
|
|
496
|
+
to: this.normalizeAddressOrThrow(req.to, 'call.to'),
|
|
497
|
+
data: req.data,
|
|
498
|
+
from: req.from === undefined ? undefined : this.normalizeAddressOrThrow(req.from, 'call.from'),
|
|
499
|
+
value: req.value,
|
|
500
|
+
};
|
|
501
|
+
if (req.estimateGas && req.blockTag !== undefined) {
|
|
502
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EvmChain.call: blockTag is not honored when estimateGas: true (ethers v6 eth_estimateGas has no block-tag plumbing). Split the call: use estimateGas without blockTag, or drop estimateGas to run eth_call at the tag.`, { chainId: this.chainId });
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
if (req.estimateGas) {
|
|
506
|
+
const g = await provider.estimateGas(tx);
|
|
507
|
+
return { gasEstimate: BigInt(g) };
|
|
508
|
+
}
|
|
509
|
+
const result = await provider.call(req.blockTag !== undefined ? { ...tx, blockTag: req.blockTag } : tx);
|
|
510
|
+
return { result };
|
|
511
|
+
}
|
|
512
|
+
catch (err) {
|
|
513
|
+
const strCode = ethersErrCode(err);
|
|
514
|
+
const rawData = err.data
|
|
515
|
+
?? err.info?.error?.data;
|
|
516
|
+
const revertData = typeof rawData === 'string' && /^0x[0-9a-fA-F]*$/.test(rawData) ? rawData : undefined;
|
|
517
|
+
if (strCode === 'CALL_EXCEPTION' || revertData !== undefined) {
|
|
518
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.SimulationFailed, (0, errors_ts_1.sanitizeMessage)(`eth_${req.estimateGas ? 'estimateGas' : 'call'} on ${req.to} reverted`, this._resolvedRpcUrl), { chainId: this.chainId, revertData }, (0, errors_ts_1.sanitizeCause)(err, this._resolvedRpcUrl));
|
|
519
|
+
}
|
|
520
|
+
if (strCode === 'INSUFFICIENT_FUNDS') {
|
|
521
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InsufficientFunds, (0, errors_ts_1.sanitizeMessage)(`eth_${req.estimateGas ? 'estimateGas' : 'call'} on ${req.to}: insufficient funds`, this._resolvedRpcUrl), { chainId: this.chainId }, (0, errors_ts_1.sanitizeCause)(err, this._resolvedRpcUrl));
|
|
522
|
+
}
|
|
523
|
+
throw this.rpcError(`eth_${req.estimateGas ? 'estimateGas' : 'call'} on ${req.to} failed`, err);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
buildAuthorizationDigest(input) {
|
|
527
|
+
if (!this.supports7702) {
|
|
528
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM chain ${this.name} was not initialized with supports7702: true`, { chainId: this.chainId });
|
|
529
|
+
}
|
|
530
|
+
if (input.chainId !== this.chainId) {
|
|
531
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization chainId ${input.chainId} does not match ${this.chainId}. Cross-chain replay guard: chainId=0 wildcards are rejected by default.`, { chainId: this.chainId });
|
|
532
|
+
}
|
|
533
|
+
if (input.nonce < 0n) {
|
|
534
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization nonce must be >= 0`, { chainId: this.chainId });
|
|
535
|
+
}
|
|
536
|
+
let normalizedDelegate;
|
|
537
|
+
try {
|
|
538
|
+
normalizedDelegate = (0, ethers_1.getAddress)(input.delegate);
|
|
539
|
+
}
|
|
540
|
+
catch (err) {
|
|
541
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `buildAuthorizationDigest: delegate is not a valid EVM address: ${input.delegate}`, { chainId: this.chainId, address: input.delegate }, err instanceof Error ? err : undefined);
|
|
542
|
+
}
|
|
543
|
+
const rlp = (0, ethers_1.encodeRlp)([
|
|
544
|
+
(0, ethers_1.toBeArray)(BigInt(input.chainId)),
|
|
545
|
+
normalizedDelegate,
|
|
546
|
+
(0, ethers_1.toBeArray)(input.nonce),
|
|
547
|
+
]);
|
|
548
|
+
const payload = (0, ethers_1.concat)(['0x05', rlp]);
|
|
549
|
+
return (0, ethers_1.getBytes)((0, ethers_1.keccak256)(payload));
|
|
550
|
+
}
|
|
551
|
+
async createUnsignedTransaction(req) {
|
|
552
|
+
if (req && req.signal !== undefined) {
|
|
553
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM createUnsignedTransaction: signal is not honored in 0.3.0 (silently ignoring would let a caller conclude 'not built' while the blockhash fetch/build proceeds against stale state). Cancellation returns in 0.3.1.`, { chainId: this.chainId });
|
|
554
|
+
}
|
|
555
|
+
if (!req.from) {
|
|
556
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateEvmUnsignedTransactionRequest.from is required', { chainId: this.chainId });
|
|
557
|
+
}
|
|
558
|
+
if (!this.validateAddress(req.from)) {
|
|
559
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'from' address (fails EIP-55 checksum or byte length): ${req.from}`, { chainId: this.chainId, address: req.from });
|
|
560
|
+
}
|
|
561
|
+
if (!req.to) {
|
|
562
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateEvmUnsignedTransactionRequest.to is required', { chainId: this.chainId });
|
|
563
|
+
}
|
|
564
|
+
if (!this.validateAddress(req.to)) {
|
|
565
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'to' address (fails EIP-55 checksum or byte length): ${req.to}`, { chainId: this.chainId, address: req.to });
|
|
566
|
+
}
|
|
567
|
+
if (req.data !== undefined && !/^0x([0-9a-fA-F]{2})*$/.test(req.data)) {
|
|
568
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `CreateEvmUnsignedTransactionRequest.data must be a 0x-prefixed even-length hex string`, { chainId: this.chainId });
|
|
569
|
+
}
|
|
570
|
+
if (req.authorizationList !== undefined) {
|
|
571
|
+
if (!Array.isArray(req.authorizationList) || req.authorizationList.length === 0) {
|
|
572
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'authorizationList must be a non-empty array when provided', { chainId: this.chainId });
|
|
573
|
+
}
|
|
574
|
+
if (!this.supports7702) {
|
|
575
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM chain ${this.name} was not initialized with supports7702: true`, { chainId: this.chainId });
|
|
576
|
+
}
|
|
577
|
+
for (let i = 0; i < req.authorizationList.length; i++) {
|
|
578
|
+
const auth = req.authorizationList[i];
|
|
579
|
+
if (auth.chainId !== this.chainId) {
|
|
580
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].chainId ${auth.chainId} does not match ${this.chainId}. Cross-chain replay guard: chainId=0 wildcards are rejected by default.`, { chainId: this.chainId });
|
|
581
|
+
}
|
|
582
|
+
if (!this.validateAddress(auth.address)) {
|
|
583
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Authorization[${i}].address is not a valid EVM address: ${auth.address}`, { chainId: this.chainId, address: auth.address });
|
|
584
|
+
}
|
|
585
|
+
if (typeof auth.nonce !== 'bigint' || auth.nonce < 0n) {
|
|
586
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].nonce must be a non-negative bigint (got ${typeof auth.nonce})`, { chainId: this.chainId });
|
|
587
|
+
}
|
|
588
|
+
const sig = auth.signature;
|
|
589
|
+
if (!sig || typeof sig !== 'object'
|
|
590
|
+
|| typeof sig.r !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(sig.r)
|
|
591
|
+
|| typeof sig.s !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(sig.s)
|
|
592
|
+
|| (sig.yParity !== 0 && sig.yParity !== 1)) {
|
|
593
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].signature must be { r: 0x + 64-hex, s: 0x + 64-hex, yParity: 0 | 1 }`, { chainId: this.chainId });
|
|
594
|
+
}
|
|
595
|
+
const rBig = BigInt(sig.r);
|
|
596
|
+
const sBig = BigInt(sig.s);
|
|
597
|
+
if (rBig === 0n || sBig === 0n) {
|
|
598
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].signature: r and s must both be non-zero`, { chainId: this.chainId });
|
|
599
|
+
}
|
|
600
|
+
// EIP-2 low-s canonical form. An authorization with s > secp256k1n/2
|
|
601
|
+
// is silently rejected by the EVM at execution — tx lands, gas is
|
|
602
|
+
// spent, no delegation installed. Catch at build time.
|
|
603
|
+
const SECP256K1_HALF_N = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0n;
|
|
604
|
+
if (sBig > SECP256K1_HALF_N) {
|
|
605
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].signature.s violates EIP-2 low-s canonical form (s must be <= secp256k1n/2). Non-canonical authorizations are silently skipped by the EVM.`, { chainId: this.chainId });
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
if (!this.supportsEip1559 && (req.maxFeePerGas !== undefined || req.maxPriorityFeePerGas !== undefined)) {
|
|
610
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EVM chain ${this.name} is legacy (supportsEip1559=false); maxFeePerGas/maxPriorityFeePerGas are not accepted. Use gasPrice via UnsignedEvmTransaction consumers.`, { chainId: this.chainId });
|
|
611
|
+
}
|
|
612
|
+
const emittedType = req.authorizationList !== undefined ? 4 : this.supportsEip1559 ? 2 : 0;
|
|
613
|
+
return new unsigned_evm_transaction_ts_1.UnsignedEvmTransaction({
|
|
614
|
+
chainId: this.chainId,
|
|
615
|
+
from: this.normalizeAddressOrThrow(req.from, 'createUnsignedTransaction.from'),
|
|
616
|
+
to: this.normalizeAddressOrThrow(req.to, 'createUnsignedTransaction.to'),
|
|
617
|
+
value: req.value ?? 0n,
|
|
618
|
+
data: req.data ?? '0x',
|
|
619
|
+
type: emittedType,
|
|
620
|
+
authorizationList: req.authorizationList,
|
|
621
|
+
gasLimit: req.gasLimit,
|
|
622
|
+
nonce: req.nonce,
|
|
623
|
+
maxFeePerGas: req.maxFeePerGas,
|
|
624
|
+
maxPriorityFeePerGas: req.maxPriorityFeePerGas,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
classifyBroadcastError(err) {
|
|
628
|
+
const rpc = this._resolvedRpcUrl;
|
|
629
|
+
const strCode = ethersErrCode(err);
|
|
630
|
+
const numCode = errCode(err);
|
|
631
|
+
const rawMsg = err instanceof Error ? err.message : String(err);
|
|
632
|
+
const msg = rawMsg.toLowerCase();
|
|
633
|
+
const safeCause = (0, errors_ts_1.sanitizeCause)(err, rpc);
|
|
634
|
+
if (strCode === 'NONCE_EXPIRED' || msg.includes('nonce too low') || msg.includes('nonce_too_low') || msg.includes('nonce has already been used')) {
|
|
635
|
+
return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.NonceTooLow, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected: nonce too low on ${this.name}`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
|
|
636
|
+
}
|
|
637
|
+
if (strCode === 'INSUFFICIENT_FUNDS' || msg.includes('insufficient funds')) {
|
|
638
|
+
return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InsufficientFunds, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected: insufficient funds on ${this.name}`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
|
|
639
|
+
}
|
|
640
|
+
if (strCode === 'REPLACEMENT_UNDERPRICED' || msg.includes('replacement') || msg.includes('underpriced')) {
|
|
641
|
+
return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.BroadcastRejected, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected on ${this.name} (replacement/known-nonce)`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
|
|
642
|
+
}
|
|
643
|
+
const rateLimitCodes = new Set([-32005, -32007, -32016, -32029, 429]);
|
|
644
|
+
if (numCode !== undefined && rateLimitCodes.has(numCode)) {
|
|
645
|
+
return this.rpcError(`EVM broadcast rate-limited on ${this.name}`, err);
|
|
646
|
+
}
|
|
647
|
+
const transportSignals = /econnreset|econnrefused|econnaborted|etimedout|enotfound|network request failed|fetch failed|socket hang up|too\s+many\s+requests|rate.?limit|network error/;
|
|
648
|
+
const httpStatus = err.info?.status
|
|
649
|
+
?? err.status;
|
|
650
|
+
const isTransportHttp = typeof httpStatus === 'number' && (httpStatus === 429 || httpStatus === 502 || httpStatus === 503 || httpStatus === 504);
|
|
651
|
+
if (transportSignals.test(msg) || isTransportHttp
|
|
652
|
+
|| strCode === 'NETWORK_ERROR' || strCode === 'SERVER_ERROR' || strCode === 'TIMEOUT') {
|
|
653
|
+
return this.rpcError(`EVM broadcast transport failure on ${this.name}`, err);
|
|
654
|
+
}
|
|
655
|
+
// Default terminal: any unrecognized rejection is a node reject, NOT a
|
|
656
|
+
// transient transport failure. This matches Solana/UTXO defaults and
|
|
657
|
+
// prevents a relayer retry-loop from re-broadcasting a permanently-
|
|
658
|
+
// invalid tx forever.
|
|
659
|
+
return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.BroadcastRejected, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected on ${this.name}`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
|
|
660
|
+
}
|
|
661
|
+
async getTransactionStatus(txHash, opts) {
|
|
662
|
+
if (Array.isArray(txHash)) {
|
|
663
|
+
return runBatchStatus(txHash, (h, batchSignal) => {
|
|
664
|
+
const composedSignal = opts?.signal
|
|
665
|
+
? anySignal(opts.signal, batchSignal)
|
|
666
|
+
: batchSignal;
|
|
667
|
+
return this.getSingleTransactionStatus(h, { ...opts, signal: composedSignal });
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return this.getSingleTransactionStatus(txHash, opts);
|
|
671
|
+
}
|
|
672
|
+
async getSingleTransactionStatus(txHash, opts) {
|
|
673
|
+
if (opts?.confirmations !== undefined && opts.confirmations > 1 && !opts.wait) {
|
|
674
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus: confirmations > 1 requires wait: true (a single status read cannot enforce block depth)`, { chainId: this.chainId, txHash });
|
|
675
|
+
}
|
|
676
|
+
if (!opts?.wait)
|
|
677
|
+
return this.getTransactionStatusOnce(txHash);
|
|
678
|
+
if (opts.signal?.aborted) {
|
|
679
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus aborted before first poll`, { chainId: this.chainId, txHash });
|
|
680
|
+
}
|
|
681
|
+
if (opts.timeoutMs === undefined) {
|
|
682
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus: wait: true requires an explicit timeoutMs. Unbounded polling would pin an RPC worker + connection forever if the tx is dropped.`, { chainId: this.chainId, txHash });
|
|
683
|
+
}
|
|
684
|
+
if (opts.timeoutMs < 0) {
|
|
685
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus: timeoutMs must be >= 0`, { chainId: this.chainId, txHash });
|
|
686
|
+
}
|
|
687
|
+
const deadline = Date.now() + opts.timeoutMs;
|
|
688
|
+
const pollMs = Math.max(500, this.blockTimeSeconds * 1000);
|
|
689
|
+
const minConfirmations = Math.max(1, opts.confirmations ?? 1);
|
|
690
|
+
let last;
|
|
691
|
+
while (true) {
|
|
692
|
+
last = await this.getTransactionStatusOnce(txHash);
|
|
693
|
+
if (last.status === 'Success' || last.status === 'Failed') {
|
|
694
|
+
if (minConfirmations <= 1)
|
|
695
|
+
return last;
|
|
696
|
+
let tip;
|
|
697
|
+
try {
|
|
698
|
+
tip = await this.getProvider().getBlockNumber();
|
|
699
|
+
}
|
|
700
|
+
catch (err) {
|
|
701
|
+
throw this.rpcError(`Failed to read chain tip for confirmations check`, err, { txHash });
|
|
702
|
+
}
|
|
703
|
+
const depth = last.blockNumber === null ? 0 : tip - last.blockNumber + 1;
|
|
704
|
+
if (depth >= minConfirmations)
|
|
705
|
+
return last;
|
|
706
|
+
if (Date.now() >= deadline) {
|
|
707
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `getTransactionStatus timed out after ${opts.timeoutMs}ms with only ${depth} confirmation(s); required ${minConfirmations}. Consumer must NOT credit as final.`, { chainId: this.chainId, txHash });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
else if (Date.now() >= deadline) {
|
|
711
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `getTransactionStatus timed out after ${opts.timeoutMs}ms; last observed status was ${last.status}. Consumer must NOT credit as final AND must NOT re-sign — the tx may still land. Re-broadcast the same signed bytes or continue polling with the same txHash.`, { chainId: this.chainId, txHash });
|
|
712
|
+
}
|
|
713
|
+
await interruptibleSleep(pollMs, opts.signal);
|
|
714
|
+
if (opts.signal?.aborted) {
|
|
715
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus aborted mid-poll`, { chainId: this.chainId, txHash });
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
async getTransactionStatusOnce(txHash) {
|
|
720
|
+
const provider = this.getProvider();
|
|
721
|
+
let tx = null;
|
|
722
|
+
let receipt = null;
|
|
723
|
+
try {
|
|
724
|
+
[tx, receipt] = await Promise.all([
|
|
725
|
+
provider.getTransaction(txHash),
|
|
726
|
+
provider.getTransactionReceipt(txHash),
|
|
727
|
+
]);
|
|
728
|
+
}
|
|
729
|
+
catch (err) {
|
|
730
|
+
throw this.rpcError(`Failed to read tx ${txHash}`, err, { txHash });
|
|
731
|
+
}
|
|
732
|
+
if (tx === null && receipt === null)
|
|
733
|
+
return evm_transaction_status_ts_1.EvmTransactionStatus.notFound(this.chainId, null);
|
|
734
|
+
if (receipt === null)
|
|
735
|
+
return evm_transaction_status_ts_1.EvmTransactionStatus.pending(this.chainId);
|
|
736
|
+
// Receipt exists but the tx body doesn't — real race on load-balanced/
|
|
737
|
+
// pruned RPC endpoints where getTransactionReceipt succeeds while
|
|
738
|
+
// getTransactionByHash returns null. `tx.value` and `tx.to` are load-
|
|
739
|
+
// bearing for the native transfer legs of decodeBalanceChanges; falling
|
|
740
|
+
// back to `?? 0n` / `?? null` would emit a Success with a silently
|
|
741
|
+
// truncated balanceChanges map (recipient row missing entirely,
|
|
742
|
+
// sender debit off by the transfer value). Python parity: omnichain-py's
|
|
743
|
+
// impl/evm/base.py accesses `tx.value` directly and blows up on a
|
|
744
|
+
// missing body. TS returns Pending — receipt-only is transient node
|
|
745
|
+
// state; the consumer's next poll will land on a node with the full tx.
|
|
746
|
+
if (tx === null)
|
|
747
|
+
return evm_transaction_status_ts_1.EvmTransactionStatus.pending(this.chainId);
|
|
748
|
+
const succeeded = receipt.status === 1;
|
|
749
|
+
// Parallelize the two independent post-receipt lookups: getBlock (for
|
|
750
|
+
// inclusionAt) and the OP-stack raw-receipt fetch (for l1Fee). Both
|
|
751
|
+
// depend only on receipt.blockNumber / txHash, not on each other.
|
|
752
|
+
const [inclusionAt, l1Fee] = await Promise.all([
|
|
753
|
+
(async () => {
|
|
754
|
+
try {
|
|
755
|
+
const block = await provider.getBlock(receipt.blockNumber);
|
|
756
|
+
if (block?.timestamp !== undefined) {
|
|
757
|
+
return new Date(Number(block.timestamp) * 1000);
|
|
758
|
+
}
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
catch {
|
|
762
|
+
// leave null — a 1970-01-01 sentinel would silently pass
|
|
763
|
+
// through consumer SLA/age math as a real inclusion time.
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
})(),
|
|
767
|
+
(async () => {
|
|
768
|
+
// OP-stack rollups charge an L1 data fee (`l1Fee` on the raw
|
|
769
|
+
// receipt). ethers v6 strips it in its parsed TransactionReceipt
|
|
770
|
+
// shape, so a second raw fetch is required. Gated on `hasL1Fee`.
|
|
771
|
+
// Return undefined for "provider did not surface it" (either
|
|
772
|
+
// hasL1Fee=false or the raw send failed/omitted the field) —
|
|
773
|
+
// tracked separately from "l1Fee is genuinely 0n" so
|
|
774
|
+
// fees.l1FeeWei reflects presence, not value.
|
|
775
|
+
if (!this.hasL1Fee)
|
|
776
|
+
return undefined;
|
|
777
|
+
try {
|
|
778
|
+
const raw = (await provider.send('eth_getTransactionReceipt', [txHash]));
|
|
779
|
+
const rawL1 = raw?.l1Fee;
|
|
780
|
+
if (rawL1 === undefined || rawL1 === null)
|
|
781
|
+
return undefined;
|
|
782
|
+
if (typeof rawL1 === 'bigint')
|
|
783
|
+
return rawL1;
|
|
784
|
+
if (typeof rawL1 === 'number')
|
|
785
|
+
return BigInt(rawL1);
|
|
786
|
+
if (typeof rawL1 === 'string' && rawL1.length > 0)
|
|
787
|
+
return BigInt(rawL1);
|
|
788
|
+
return undefined;
|
|
789
|
+
}
|
|
790
|
+
catch {
|
|
791
|
+
return undefined;
|
|
792
|
+
}
|
|
793
|
+
})(),
|
|
794
|
+
]);
|
|
795
|
+
// gasLimit: the sender-set limit from tx.gasLimit. `null` when the tx
|
|
796
|
+
// body isn't available (pruned/receipt-only) — falling back to
|
|
797
|
+
// receipt.gasUsed here would fabricate a "100% utilization" that
|
|
798
|
+
// consumers can't distinguish from a real observation.
|
|
799
|
+
const fees = new evm_transaction_status_ts_1.EvmTransactionGasFees({
|
|
800
|
+
gasLimit: tx?.gasLimit ?? null,
|
|
801
|
+
gasLimitUsed: receipt.gasUsed,
|
|
802
|
+
effectiveGasPrice: receipt.gasPrice,
|
|
803
|
+
gasPrice: tx?.gasPrice ?? undefined,
|
|
804
|
+
maxFeePerGas: tx?.maxFeePerGas ?? undefined,
|
|
805
|
+
maxPriorityFeePerGas: tx?.maxPriorityFeePerGas ?? undefined,
|
|
806
|
+
l1FeeWei: l1Fee,
|
|
807
|
+
});
|
|
808
|
+
if (!succeeded) {
|
|
809
|
+
const errorInfo = await extractRevertInfo(provider, tx, receipt);
|
|
810
|
+
return evm_transaction_status_ts_1.EvmTransactionStatus.failed({
|
|
811
|
+
chainId: this.chainId,
|
|
812
|
+
inclusionAt,
|
|
813
|
+
error: errorInfo,
|
|
814
|
+
fees,
|
|
815
|
+
blockNumber: receipt.blockNumber,
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
// Only allocated on the Success path — failed txs carry logs: null.
|
|
819
|
+
const logs = (receipt.logs ?? []).map((l) => new evm_transaction_status_ts_1.EvmParsedTransactionLog(l.address, [...l.topics], l.data));
|
|
820
|
+
const nativeValue = tx?.value ?? 0n;
|
|
821
|
+
let balanceChanges;
|
|
822
|
+
try {
|
|
823
|
+
balanceChanges = await this.decodeBalanceChanges({
|
|
824
|
+
from: tx ? tx.from : (receipt.from ?? ''),
|
|
825
|
+
to: tx?.to ?? receipt.to ?? null,
|
|
826
|
+
value: nativeValue,
|
|
827
|
+
gasCost: fees.totalNativeDebitWei,
|
|
828
|
+
receipt,
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
catch (err) {
|
|
832
|
+
if (err instanceof errors_ts_1.ChainError)
|
|
833
|
+
throw err;
|
|
834
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Failed to decode receipt logs for tx ${txHash}`, { chainId: this.chainId, txHash, rpcHost: this.rpcHost() }, err);
|
|
835
|
+
}
|
|
836
|
+
return evm_transaction_status_ts_1.EvmTransactionStatus.successful({
|
|
837
|
+
chainId: this.chainId,
|
|
838
|
+
inclusionAt,
|
|
839
|
+
balanceChanges,
|
|
840
|
+
logs,
|
|
841
|
+
fees,
|
|
842
|
+
blockNumber: receipt.blockNumber,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
async decodeBalanceChanges(args) {
|
|
846
|
+
const { from, to, value, gasCost, receipt } = args;
|
|
847
|
+
if (!receipt || !Array.isArray(receipt.logs)) {
|
|
848
|
+
throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, 'Receipt is missing required fields', { chainId: this.chainId, txHash: receipt?.hash, rpcHost: this.rpcHost() });
|
|
849
|
+
}
|
|
850
|
+
const rawChanges = new Map();
|
|
851
|
+
const fromAddr = (from ?? '').toLowerCase();
|
|
852
|
+
const toAddr = to ? to.toLowerCase() : null;
|
|
853
|
+
// Sender's native debit = value + gasCost (matches Python
|
|
854
|
+
// impl/evm/base.py:_get_balance_changes fee-inclusive semantics).
|
|
855
|
+
// Credit toAddr whenever value>0 — for self-transfers (from===to) the
|
|
856
|
+
// per-(wallet,token) netting in upsert cancels the +value against the
|
|
857
|
+
// -value component of the debit, leaving the -gasCost we actually want.
|
|
858
|
+
if (fromAddr) {
|
|
859
|
+
addRaw(rawChanges, fromAddr, '', -(value + gasCost));
|
|
860
|
+
}
|
|
861
|
+
if (value > 0n && toAddr) {
|
|
862
|
+
addRaw(rawChanges, toAddr, '', value);
|
|
863
|
+
}
|
|
864
|
+
const tokenContracts = new Set();
|
|
865
|
+
const transferLogs = [];
|
|
866
|
+
for (const log of receipt.logs) {
|
|
867
|
+
if (log.topics.length !== 3)
|
|
868
|
+
continue;
|
|
869
|
+
if (log.topics[0].toLowerCase() !== ERC20_TRANSFER_TOPIC)
|
|
870
|
+
continue;
|
|
871
|
+
const contractAddr = log.address.toLowerCase();
|
|
872
|
+
const logFrom = `0x${log.topics[1].slice(26)}`.toLowerCase();
|
|
873
|
+
const logTo = `0x${log.topics[2].slice(26)}`.toLowerCase();
|
|
874
|
+
let amount;
|
|
875
|
+
try {
|
|
876
|
+
amount = BigInt(log.data);
|
|
877
|
+
}
|
|
878
|
+
catch {
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
tokenContracts.add(contractAddr);
|
|
882
|
+
transferLogs.push({ contract: contractAddr, from: logFrom, to: logTo, amount });
|
|
883
|
+
}
|
|
884
|
+
const tokensByContract = new Map();
|
|
885
|
+
const resolved = await Promise.all([...tokenContracts].map((addr) => this.resolveErc20TokenDefensive(addr).then((t) => ({ addr, token: t }))));
|
|
886
|
+
for (const { addr, token } of resolved)
|
|
887
|
+
tokensByContract.set(addr, token);
|
|
888
|
+
for (const t of transferLogs) {
|
|
889
|
+
// Symmetric with the native path: always add both legs. Self-transfer
|
|
890
|
+
// nets to zero at the per-(wallet, contract) map level and is dropped
|
|
891
|
+
// by the `delta === 0n` filter below — the explicit gate here would
|
|
892
|
+
// over-suppress the credit if a future decoder gained non-cancelling
|
|
893
|
+
// side effects.
|
|
894
|
+
addRaw(rawChanges, t.from, t.contract, -t.amount);
|
|
895
|
+
addRaw(rawChanges, t.to, t.contract, t.amount);
|
|
896
|
+
}
|
|
897
|
+
const result = new Map();
|
|
898
|
+
for (const [wallet, perTokenAddr] of rawChanges) {
|
|
899
|
+
for (const [tokenAddr, delta] of perTokenAddr) {
|
|
900
|
+
if (delta === 0n)
|
|
901
|
+
continue;
|
|
902
|
+
const token = tokenAddr === '' ? this._nativeToken : tokensByContract.get(tokenAddr);
|
|
903
|
+
if (!token)
|
|
904
|
+
continue;
|
|
905
|
+
transaction_status_ts_1.AssetBalanceChange.upsert(result, wallet, token, transaction_status_ts_1.AssetBalanceChange.fromMr(delta, token.decimals));
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return result;
|
|
909
|
+
}
|
|
910
|
+
async resolveErc20TokenDefensive(contractAddress) {
|
|
911
|
+
const checksum = (() => {
|
|
912
|
+
try {
|
|
913
|
+
return new evm_address_ts_1.EvmAddress(contractAddress).toChecksum();
|
|
914
|
+
}
|
|
915
|
+
catch {
|
|
916
|
+
return contractAddress;
|
|
917
|
+
}
|
|
918
|
+
})();
|
|
919
|
+
const placeholder = () => new evm_token_ts_1.EvmToken(this.chainId, `UNKNOWN_${checksum.slice(2, 8)}`, checksum, 0);
|
|
920
|
+
let provider;
|
|
921
|
+
try {
|
|
922
|
+
provider = this.getProvider();
|
|
923
|
+
}
|
|
924
|
+
catch {
|
|
925
|
+
return placeholder();
|
|
926
|
+
}
|
|
927
|
+
const contract = new ethers_1.Contract(contractAddress, ERC20_ABI, provider);
|
|
928
|
+
try {
|
|
929
|
+
const [symbol, decimals] = await Promise.all([
|
|
930
|
+
contract.symbol(),
|
|
931
|
+
contract.decimals(),
|
|
932
|
+
]);
|
|
933
|
+
return new evm_token_ts_1.EvmToken(this.chainId, symbol, checksum, Number(decimals));
|
|
934
|
+
}
|
|
935
|
+
catch {
|
|
936
|
+
return placeholder();
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* STRICT decimals resolver for the transfer builder — throws
|
|
941
|
+
* `ChainError(RpcError)` on any failure to reach the contract.
|
|
942
|
+
* Used exclusively when converting `amountHr: Decimal` →
|
|
943
|
+
* `amountMr: bigint`, where a defensive fallback to `decimals=0`
|
|
944
|
+
* would silently sign a transaction for a wildly wrong amount
|
|
945
|
+
* (e.g. `1.5 USDC` → `1n` minor units instead of `1_500_000n`).
|
|
946
|
+
* The receipt-decoder still uses the defensive variant, since a
|
|
947
|
+
* placeholder token there is a display concern, not a money one.
|
|
948
|
+
*/
|
|
949
|
+
async resolveErc20DecimalsStrict(contractAddress) {
|
|
950
|
+
const provider = this.getProvider();
|
|
951
|
+
const contract = new ethers_1.Contract(contractAddress, ERC20_ABI, provider);
|
|
952
|
+
try {
|
|
953
|
+
const decimals = (await contract.decimals());
|
|
954
|
+
return Number(decimals);
|
|
955
|
+
}
|
|
956
|
+
catch (err) {
|
|
957
|
+
throw this.rpcError(`Failed to read ERC-20 decimals for ${contractAddress}`, err);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
rpcError(message, cause, extra = {}) {
|
|
961
|
+
const sanitizedMessage = (0, errors_ts_1.sanitizeMessage)(`${message}: ${stringifyErr(cause)}`, this._resolvedRpcUrl);
|
|
962
|
+
return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, sanitizedMessage, { chainId: this.chainId, rpcHost: this.rpcHost(), ...extra }, (0, errors_ts_1.sanitizeCause)(cause, this._resolvedRpcUrl));
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
exports.EvmChain = EvmChain;
|
|
966
|
+
function addRaw(container, wallet, tokenAddr, delta) {
|
|
967
|
+
let perToken = container.get(wallet);
|
|
968
|
+
if (!perToken) {
|
|
969
|
+
perToken = new Map();
|
|
970
|
+
container.set(wallet, perToken);
|
|
971
|
+
}
|
|
972
|
+
perToken.set(tokenAddr, (perToken.get(tokenAddr) ?? 0n) + delta);
|
|
973
|
+
}
|
|
974
|
+
const ERROR_STRING_SELECTOR = '0x08c379a0';
|
|
975
|
+
const PANIC_UINT256_SELECTOR = '0x4e487b71';
|
|
976
|
+
const ABI_CODER = ethers_1.AbiCoder.defaultAbiCoder();
|
|
977
|
+
function decodeRevertData(data) {
|
|
978
|
+
if (typeof data !== 'string' || data.length < 10)
|
|
979
|
+
return undefined;
|
|
980
|
+
const selector = data.slice(0, 10).toLowerCase();
|
|
981
|
+
const payload = '0x' + data.slice(10);
|
|
982
|
+
if (selector === ERROR_STRING_SELECTOR) {
|
|
983
|
+
try {
|
|
984
|
+
const reason = ABI_CODER.decode(['string'], payload)[0];
|
|
985
|
+
return typeof reason === 'string' ? reason : undefined;
|
|
986
|
+
}
|
|
987
|
+
catch {
|
|
988
|
+
return undefined;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
if (selector === PANIC_UINT256_SELECTOR) {
|
|
992
|
+
try {
|
|
993
|
+
const code = ABI_CODER.decode(['uint256'], payload)[0];
|
|
994
|
+
return typeof code === 'bigint' ? `Panic(0x${code.toString(16)})` : undefined;
|
|
995
|
+
}
|
|
996
|
+
catch {
|
|
997
|
+
return undefined;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return undefined;
|
|
1001
|
+
}
|
|
1002
|
+
async function extractRevertInfo(provider, tx, receipt) {
|
|
1003
|
+
if (!tx)
|
|
1004
|
+
return { code: 'REVERTED' };
|
|
1005
|
+
try {
|
|
1006
|
+
await provider.call({
|
|
1007
|
+
from: tx.from,
|
|
1008
|
+
to: tx.to ?? undefined,
|
|
1009
|
+
data: tx.data,
|
|
1010
|
+
value: tx.value,
|
|
1011
|
+
blockTag: receipt.blockNumber,
|
|
1012
|
+
});
|
|
1013
|
+
return { code: 'REVERTED' };
|
|
1014
|
+
}
|
|
1015
|
+
catch (err) {
|
|
1016
|
+
const data = err?.data ??
|
|
1017
|
+
err?.info?.error?.data;
|
|
1018
|
+
const reason = typeof data === 'string' ? decodeRevertData(data) : undefined;
|
|
1019
|
+
return reason !== undefined ? { code: 'REVERTED', reason } : { code: 'REVERTED' };
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
function stringifyErr(err) {
|
|
1023
|
+
if (err instanceof Error)
|
|
1024
|
+
return err.message;
|
|
1025
|
+
return String(err);
|
|
1026
|
+
}
|
|
1027
|
+
const BATCH_STATUS_CONCURRENCY = 8;
|
|
1028
|
+
async function runBatchStatus(items, fetchOne) {
|
|
1029
|
+
const results = new Array(items.length);
|
|
1030
|
+
const ac = new AbortController();
|
|
1031
|
+
let cursor = 0;
|
|
1032
|
+
const workers = [];
|
|
1033
|
+
const spawn = async () => {
|
|
1034
|
+
while (!ac.signal.aborted) {
|
|
1035
|
+
const idx = cursor++;
|
|
1036
|
+
if (idx >= items.length)
|
|
1037
|
+
return;
|
|
1038
|
+
try {
|
|
1039
|
+
results[idx] = await fetchOne(items[idx], ac.signal);
|
|
1040
|
+
}
|
|
1041
|
+
catch (err) {
|
|
1042
|
+
ac.abort();
|
|
1043
|
+
throw err;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
const workerCount = Math.min(BATCH_STATUS_CONCURRENCY, items.length);
|
|
1048
|
+
for (let i = 0; i < workerCount; i++)
|
|
1049
|
+
workers.push(spawn());
|
|
1050
|
+
await Promise.all(workers);
|
|
1051
|
+
return results;
|
|
1052
|
+
}
|
|
1053
|
+
function anySignal(a, b) {
|
|
1054
|
+
if (typeof AbortSignal.any === 'function')
|
|
1055
|
+
return AbortSignal.any([a, b]);
|
|
1056
|
+
const ac = new AbortController();
|
|
1057
|
+
const onAbort = () => ac.abort();
|
|
1058
|
+
if (a.aborted || b.aborted)
|
|
1059
|
+
ac.abort();
|
|
1060
|
+
else {
|
|
1061
|
+
a.addEventListener('abort', onAbort, { once: true });
|
|
1062
|
+
b.addEventListener('abort', onAbort, { once: true });
|
|
1063
|
+
}
|
|
1064
|
+
return ac.signal;
|
|
1065
|
+
}
|
|
1066
|
+
async function interruptibleSleep(ms, signal) {
|
|
1067
|
+
if (signal?.aborted)
|
|
1068
|
+
return;
|
|
1069
|
+
await new Promise((resolve) => {
|
|
1070
|
+
const t = setTimeout(() => {
|
|
1071
|
+
signal?.removeEventListener('abort', onAbort);
|
|
1072
|
+
resolve();
|
|
1073
|
+
}, ms);
|
|
1074
|
+
const onAbort = () => {
|
|
1075
|
+
clearTimeout(t);
|
|
1076
|
+
resolve();
|
|
1077
|
+
};
|
|
1078
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
function errCode(err) {
|
|
1082
|
+
if (typeof err !== 'object' || err === null)
|
|
1083
|
+
return undefined;
|
|
1084
|
+
const e = err;
|
|
1085
|
+
const candidates = [
|
|
1086
|
+
typeof e.code === 'number' ? e.code : undefined,
|
|
1087
|
+
e.error?.code,
|
|
1088
|
+
e.info?.error?.code,
|
|
1089
|
+
typeof e.code === 'string' && /^-?\d+$/.test(e.code) ? e.code : undefined,
|
|
1090
|
+
];
|
|
1091
|
+
for (const raw of candidates) {
|
|
1092
|
+
if (typeof raw === 'number')
|
|
1093
|
+
return raw;
|
|
1094
|
+
if (typeof raw === 'string' && /^-?\d+$/.test(raw))
|
|
1095
|
+
return Number(raw);
|
|
1096
|
+
}
|
|
1097
|
+
return undefined;
|
|
1098
|
+
}
|
|
1099
|
+
function ethersErrCode(err) {
|
|
1100
|
+
if (typeof err !== 'object' || err === null)
|
|
1101
|
+
return undefined;
|
|
1102
|
+
const e = err;
|
|
1103
|
+
return typeof e.code === 'string' ? e.code : undefined;
|
|
1104
|
+
}
|
|
1105
|
+
function envCandidatesFor(name, chainId) {
|
|
1106
|
+
const normalized = name.replace(/ /g, '_').toUpperCase() + '_RPC_URL';
|
|
1107
|
+
return [normalized, `EVM_${chainId}_RPC_URL`];
|
|
1108
|
+
}
|
|
1109
|
+
//# sourceMappingURL=evm_chain.js.map
|