Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Japanese version: /ja/doc/introduction.html

What is Kasane

TL;DR

Kasane is a project that provides EVM execution on ICP canisters.
It exposes two public access paths: the canister Candid API and a Gateway JSON-RPC endpoint.
Its JSON-RPC is not full Ethereum compatibility; it is a restricted compatibility layer for development workflows.
The compatibility target is Ethereum JSON-RPC plus EVM execution semantics, while OP/Superchain compatibility is out of scope.

What You Can Do

  • Use Ethereum-style JSON-RPC for basic reads and transaction submission
  • Call EVM functionality directly through canister query/update methods
  • Pull export_blocks in an indexer and persist data to Postgres

Key Constraints (Current Implementation)

  • Ethereum JSON-RPC compatibility is partial (see compatibility pages for unsupported methods)
  • Node operation workflows are out of scope for this book

Compatibility Positioning

  • Explicit target: restricted Ethereum JSON-RPC compatibility
  • Non-goal: OP Stack / Superchain compatibility
  • Important: success of eth_sendRawTransaction means submit success only; execution success must be checked with receipt status=0x1

Intended Readers

  • EVM dApp developers
  • Smart contract developers
  • Backend integration developers
  • Indexer developers

Sources

  • README.md (operational summary and compatibility policy)
  • tools/rpc-gateway/README.md (Gateway compatibility matrix)
  • crates/ic-evm-wrapper/evm_canister.did (public interface)

Source of Truth for Compatibility

  • Canonical JSON-RPC policy: ./rpc/overview.md
  • Detailed method differences: ./compatibility/json-rpc-deviations.md

Japanese version: /ja/doc/quickstart.html

Quickstart (Gateway + Candid)

TL;DR

  • Default network is public testnet (chain_id=4801360, RPC: https://rpc-testnet.kasane.network).
  • There are two paths: Path A (Gateway JSON-RPC) / Path B (direct canister Candid).
  • Do not use submit response as final success signal; use eth_getTransactionReceipt.status.
  • tx_id and eth_tx_hash are different identifiers.
  • For deploy/call, standardize on signed raw-tx submission flow.

What You Can / Cannot Do

You Can

  • Verify connectivity (chain id / block number)
  • Send native transfers (submit signed raw tx)
  • Monitor receipt (success/failure)
  • Read state via query methods (balance/code/storage/call/estimate)

You Cannot (Current)

  • Use Ethereum-standard pending/mempool workflows (eth_pendingTransactions, etc.)
  • Note: with direct canister calls, per-transaction tracking is possible via get_pending(tx_id)
  • Use WebSocket subscriptions (eth_subscribe)
  • Use full-compatible eth_getLogs (filter constraints apply)

For compatibility details, see ./rpc/overview.md and ./compatibility/json-rpc-deviations.md.


Prerequisites

  • Public RPC: https://rpc-testnet.kasane.network
  • chain id: 4801360
  • canister id (current testnet value): 4c52m-aiaaa-aaaam-agwwa-cai
  • dfx (if using canister query/update path)
  • Signed raw tx if sending through Gateway

Path A: Gateway JSON-RPC

1) Connectivity Check

RPC_URL="https://rpc-testnet.kasane.network"

curl -s -X POST "$RPC_URL" -H 'content-type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'

curl -s -X POST "$RPC_URL" -H 'content-type: application/json' \
  --data '{"jsonrpc":"2.0","id":2,"method":"eth_blockNumber","params":[]}'

Expected:

  • eth_chainId returns 0x4944d0 (decimal 4801360)
  • eth_blockNumber returns a 0x... value

2) Transfer (Signed Raw Tx)

RAW_TX="0x<signed_raw_tx_hex>"

curl -s -X POST "$RPC_URL" -H 'content-type: application/json' \
  --data "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"eth_sendRawTransaction\",\"params\":[\"$RAW_TX\"]}"

Expected:

  • result returns 0x... tx hash (Gateway resolves tx_id to eth_tx_hash)

3) Receipt Monitoring (Success Determination)

TX_HASH="0x<tx_hash_from_send>"

curl -s -X POST "$RPC_URL" -H 'content-type: application/json' \
  --data "{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"eth_getTransactionReceipt\",\"params\":[\"$TX_HASH\"]}"

Interpretation:

  • status == 0x1: execution succeeded
  • status == 0x0: execution failed (submit can succeed while execution fails)
  • result == null: not yet mined/included

Typical Errors

  • -32602 invalid params: invalid argument format
  • -32001 resource not found: pruned boundary or missing target
  • -32000 state unavailable: migration/corrupt state, etc.

Pitfalls

  • Treating eth_sendRawTransaction success as completion
  • Confusing tx_id with eth_tx_hash

Path B: Direct canister Candid call

1) Connectivity Check (query)

CANISTER_ID="4c52m-aiaaa-aaaam-agwwa-cai"
NETWORK="ic"

dfx canister call --network "$NETWORK" --query "$CANISTER_ID" rpc_eth_chain_id '( )'
dfx canister call --network "$NETWORK" --query "$CANISTER_ID" rpc_eth_block_number '( )'

2) submit_ic_tx (IcSynthetic)

submit_ic_tx accepts a Candid record with:

  • to: opt vec nat8 (Some must be 20 bytes, None means create)
  • value: nat
  • gas_limit: nat64
  • nonce: nat64
  • max_fee_per_gas: nat
  • max_priority_fee_per_gas: nat
  • data: vec nat8

In IcSynthetic, payload does not include from.
The wrapper injects msg_caller() and canister_self() and passes it to core as TxIn::IcSynthetic to derive sender.

# Example: to=0x...01 / value=0 / gas_limit=500000 / data=""
# Note: set fee at or above current minimum acceptance conditions (min_gas_price/min_priority_fee).
TO_BYTES="$(python - <<'PY'
to = bytes.fromhex('0000000000000000000000000000000000000001')
print('; '.join(str(b) for b in to))
PY
)"

dfx canister call --network "$NETWORK" "$CANISTER_ID" submit_ic_tx "(record {
  to = opt vec { $TO_BYTES };
  value = 0 : nat;
  gas_limit = 500000 : nat64;
  nonce = 0 : nat64;
  max_fee_per_gas = 500000000000 : nat;
  max_priority_fee_per_gas = 250000000000 : nat;
  data = vec { };
})"

2.0) submit_ic_tx Send Procedure

Fixing this order reduces operational mistakes.

  1. Verify chain/network before sending
    • Ensure rpc_eth_chain_id is 4801360
  2. Check sender nonce
    • Call expected_nonce_by_address(20 bytes) and get current nonce
  3. Decide fee/gas
    • Refer to rpc_eth_gas_price / rpc_eth_max_priority_fee_per_gas; set values at or above minimum
  4. Send submit_ic_tx(record) once
    • Store returned tx_id
  5. Track execution result
    • Check status with get_pending(tx_id)
    • Once get_receipt(tx_id) is available, determine success/failure by status

Notes:

  • submit_ic_tx success means “accepted”. Determine execution success from receipt.status.
  • tx_id is an internal key and different from eth_tx_hash.

2.1) submit_ic_tx Validation Flow (Important)

  • pre-submit guard
    • reject anonymous (auth.anonymous_forbidden)
    • reject writes during migration/cycle state (ops.write.*)
  • decode/validation
    • payload size/format
    • sender derivation failure: arg.principal_to_evm_derivation_failed
    • invalid fee condition: submit.invalid_fee
    • nonce mismatch: submit.nonce_too_low / submit.nonce_gap / submit.nonce_conflict
  • on success, returns tx_id; mining is asynchronous (auto-production)

3) Nonce Retrieval

ADDR_BLOB='"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"'
dfx canister call --network "$NETWORK" --query "$CANISTER_ID" expected_nonce_by_address "(blob $ADDR_BLOB)"

Notes:

  • expected_nonce_by_address accepts only 20-byte addresses
  • 32-byte input (for example mistaken bytes32-encoded principal) returns an explicit error

4) Raw tx submission (EthSigned)

Use existing helper eth_raw_tx to create raw tx bytes:

CHAIN_ID=4801360
PRIVKEY="<YOUR_PRIVKEY_HEX>"
RAW_TX_BYTES=$(cargo run -q -p ic-evm-core --features local-signer-bin --bin eth_raw_tx -- \
  --mode raw \
  --privkey "$PRIVKEY" \
  --to "0000000000000000000000000000000000000001" \
  --value "0" \
  --gas-price "500000000000" \
  --gas-limit "21000" \
  --nonce "0" \
  --chain-id "$CHAIN_ID")

dfx canister call --network "$NETWORK" "$CANISTER_ID" rpc_eth_send_raw_transaction "(vec { $RAW_TX_BYTES })"

5) tx_id Tracking (IcSynthetic)

submit_ic_tx returns internal key tx_id, not eth_tx_hash.
Track with:

  • get_pending(tx_id) (Queued/Included/Dropped/Unknown)
  • get_receipt(tx_id) (execution result)

6) eth_sendRawTransaction Return Caveat (Gateway)

  • Normally returns eth_tx_hash.
  • But if internal tx_id -> eth_tx_hash resolution fails, returns -32000 (submit succeeded but eth hash is unavailable).

Pitfalls

  • Calling query methods as update and failing
  • Violating 20-byte address requirement (expected_nonce_by_address)
  • Treating submit_ic_tx tx_id as eth_tx_hash
  • Treating submit_ic_tx success as execution success

Deploy & Call (Operational Procedure)

Prerequisites

  • Bytecode has been built (data field set to deploy bytecode)
  • Signing environment is ready (private key / matching chain id)
  • Nonce and fee are pre-fetched and configured

Execution Flow

  1. Estimate deploy tx gas using eth_estimateGas.
  2. Build deploy raw tx and submit via eth_sendRawTransaction.
  3. Track returned eth_tx_hash with eth_getTransactionReceipt.
  4. Confirm deployed address appears in receipt.contractAddress.

Sources

  • README.md
  • tools/rpc-gateway/README.md
  • docs/api/rpc_eth_send_raw_transaction_payload.md
  • crates/evm-core/src/test_bin/eth_raw_tx.rs
  • crates/ic-evm-wrapper/evm_canister.did
  • tools/rpc-gateway/src/handlers.ts
  • crates/ic-evm-wrapper/src/lib.rs (submit_ic_tx, expected_nonce_by_address)
  • crates/evm-core/src/chain.rs (TxIn::IcSynthetic, submit validation)

Japanese version: /ja/doc/concepts/accounts-keys.html

Accounts & Keys

TL;DR

  • Sender derivation path differs between EthSigned and IcSynthetic.
  • expected_nonce_by_address assumes a 20-byte address.
  • IcSynthetic does not take from in payload; sender is derived from caller context.

What You Can Do

  • Use sender recovered from Ethereum signed tx
  • Use principal-derived sender (IcSynthetic)

Constraint

  • Treating bytes32-like values as 20-byte addresses is invalid.

Difference Between EthSigned and IcSynthetic

  • EthSigned
    • Recovers sender from signed raw tx
    • Includes chain id validation
  • IcSynthetic
    • Wrapper injects msg_caller() and canister_self() and submits as TxIn::IcSynthetic
    • Payload has no from
    • Sender derivation failure yields AddressDerivationFailed-class errors

Must-Know Points for IcSynthetic

  • Input to submit_ic_tx is Candid record (to/value/gas_limit/nonce/max_fee_per_gas/max_priority_fee_per_gas/data)
  • Canonical stored bytes use to_flag(0/1) representation
  • Use expected_nonce_by_address for nonce
  • Return value is tx_id, not eth_tx_hash
  • Execution finality is decided from later block receipts, not submit return

Safe Usage

  1. Resolve the caller’s 20-byte address
  2. Fetch nonce via expected_nonce_by_address
  3. Send submit_ic_tx
  4. Track with get_pending(tx_id) / get_receipt(tx_id)

For canonical pending/mempool policy, see ../rpc/overview.md.

Pitfalls

  • Submitting principal-encoded values directly as address
  • Passing non-20-byte value to expected_nonce_by_address
  • Treating tx_id as eth_tx_hash
  • Treating submit success as execution success

Sources

  • crates/ic-evm-wrapper/src/lib.rs (expected_nonce_by_address)
  • crates/evm-core/src/tx_decode.rs (IcSynthetic / EthSigned)
  • crates/evm-core/src/chain.rs (TxIn::IcSynthetic)
  • README.md

Japanese version: /ja/doc/concepts/transactions-fees.html

Transactions & Fees

TL;DR

  • Supported tx types: Legacy/2930/1559. 4844/7702 are unsupported.
  • Fee model is base fee + priority fee (with constraints).

Fee Model

  • compute_next_base_fee updates next block base fee
  • compute_effective_gas_price computes effective price

Pitfalls

  • Sending tx with mismatched chain id
  • Violating priority/max fee consistency constraints

Sources

  • crates/evm-core/src/tx_decode.rs
  • crates/evm-core/src/base_fee.rs
  • crates/evm-core/src/revm_exec.rs

Japanese version: /ja/doc/concepts/blocks-receipts-logs.html

Blocks, Receipts, Logs

TL;DR

  • Blocks/receipts/logs are exposed via Candid types.
  • Receipt includes status, gas_used, effective_gas_price, contract_address, and logs.

Key Points

  • logs[].logIndex is the in-block ordinal index
  • receipt lookup can return Found/NotFound/PossiblyPruned/Pruned

Pitfalls

  • Designing as if pruned history is always permanently queryable
  • Mixing tx_id and eth_tx_hash lookup paths

Sources

  • crates/ic-evm-wrapper/evm_canister.did
  • crates/ic-evm-rpc/src/lib.rs
  • tools/rpc-gateway/src/handlers.ts

Japanese version: /ja/doc/concepts/finality-reorg.html

Finality & Reorg

TL;DR

  • Current implementation assumes a single block producer (sequencer), not a reorg-first model.
  • Submit and execute are separated, so receipt monitoring is required.

Behavior

  • eth_sendRawTransaction submits tx
  • Execution finality appears in subsequent blocks

Cautions

  • Treating submit success as state finality
  • Bringing Ethereum L1 fork/reorg assumptions directly into integration logic

Sources

  • README.md
  • tools/rpc-gateway/README.md
  • crates/ic-evm-wrapper/src/lib.rs

Japanese version: /ja/doc/compatibility/ethereum-differences.html

Ethereum Differences

TL;DR

  • Compatibility target is Ethereum JSON-RPC plus EVM execution semantics (not full parity).
  • Accepted tx types: Legacy / EIP-2930 / EIP-1559. EIP-4844 and EIP-7702 are currently rejected.
  • Kasane does not add or override opcodes; it follows the active revm spec (currently PRAGUE).
  • Some pending/mempool APIs are not implemented (eth_pendingTransactions, etc.).
  • The canister Candid API provides per-transaction tracking via get_pending(tx_id).
  • The runtime assumes a single block producer (sequencer), not a reorg-driven model.

Note: the canonical pending/mempool policy is ../rpc/overview.md.

Scope

Supported

  • Submit, execute, and read receipts for Ethereum-signed transactions
  • eth_call / eth_estimateGas (with restrictions)
  • Read blocks/transactions/receipts/logs

Restricted Areas

  • 4844 blob tx / 7702 authorization tx are currently unsupported
  • mempool, filter, and WebSocket subscriptions are partially supported or unsupported

Transaction Compatibility

  • Supported
    • Legacy (RLP)
    • EIP-2930 (tx_type=1)
    • EIP-1559 (tx_type=2)
  • Currently rejected
    • EIP-4844 (type=0x03)
    • EIP-7702 (type=0x04)

Opcode Differences

  • Kasane does not introduce custom opcode behavior.
  • Effective opcode set depends on revm spec selection; current default is PRAGUE.

Fee Model Differences

  • base_fee is persisted and updated by compute_next_base_fee.
  • effective_gas_price is derived from max_fee, max_priority_fee, and base_fee.
  • eth_gasPrice returns max(base_fee + max(estimated_priority, min_priority), min_gas_price).

Finality/Reorg Differences

  • Assumes a single block producer (sequencer).
  • Blocks after auto-production are treated as final.
  • Some tags such as latest/pending/safe/finalized effectively map to head-level behavior.

Common Errors

  • DecodeError::UnsupportedType (4844/7702)
  • DecodeError::WrongChainId
  • DecodeError::LegacyChainIdMissing

Pitfalls

  • Assuming Ethereum L1 pending/finality behavior applies as-is
  • Sending 4844/7702 tx assuming compatibility

Sources

  • crates/evm-core/src/tx_decode.rs
  • crates/evm-core/tests/phase1_eth_decode.rs
  • crates/evm-core/src/base_fee.rs
  • crates/evm-core/src/revm_exec.rs
  • vendor/revm/crates/handler/src/mainnet_builder.rs
  • vendor/revm/crates/primitives/src/hardfork.rs
  • tools/rpc-gateway/README.md
  • README.md

Japanese version: /ja/doc/compatibility/json-rpc-deviations.html

JSON-RPC Deviations

TL;DR

  • Implemented methods are intentionally limited.
  • eth_getLogs is constrained; blockHash is conditionally supported, and topics[0] OR arrays are supported.
  • blockTag support depends on method. latest family plus earliest/QUANTITY are accepted, but historical support is limited.
  • eth_sendRawTransaction delegates to submit API; execution success must be confirmed from receipt.
  • eth_feeHistory is supported (blockCount accepts number/QUANTITY/decimal string).
  • eth_gasPrice returns an acceptance-oriented estimate, not raw base_fee.

Scope: this page documents JSON-RPC-level differences. Canonical overall policy is ../rpc/overview.md.

Method-Level Differences (Highlights)

  • eth_getBalance
    • Accepts latest/pending/safe/finalized/earliest/QUANTITY
    • Historical queries often return exec.state.unavailable or invalid.block_range.out_of_window
  • eth_getTransactionCount
    • Accepts latest/pending/safe/finalized/earliest/QUANTITY
    • pending returns pending nonce
    • earliest and historical nonce are currently unavailable
  • eth_getCode
    • Accepts latest/pending/safe/finalized/earliest/QUANTITY
    • Historical queries are generally unavailable
  • eth_getStorageAt
    • Accepts latest/pending/safe/finalized/earliest/QUANTITY
    • slot accepts QUANTITY or 32-byte DATA
    • Historical queries are generally unavailable
  • eth_call, eth_estimateGas
    • Accepts latest/pending/safe/finalized/earliest/QUANTITY
    • Historical execution is unavailable (exec.state.unavailable / invalid.block_range.out_of_window)
    • Unsupported fields return -32602
  • eth_getLogs
    • blockHash is conditionally supported (cannot combine with fromBlock/toBlock; resolved by scanning recent N blocks)
    • single address only
    • topics[0] OR array supported (max 16)
    • topics[1+] conditions unsupported
    • oversized range returns -32005
  • eth_feeHistory
    • blockCount accepts number / QUANTITY / decimal string
    • blockCount <= 256
    • pending is currently treated as latest
  • eth_maxPriorityFeePerGas
    • returns -32000 (state unavailable) when observed data is insufficient
  • eth_gasPrice
    • returns max(base_fee + max(estimated_priority, min_priority), min_gas_price)

Unsupported Methods

  • eth_getBlockByHash
  • eth_newFilter / eth_getFilterChanges / eth_uninstallFilter
  • eth_subscribe / eth_unsubscribe
  • eth_pendingTransactions

Error Design

  • -32602: invalid params
  • -32000: state unavailable / execution failed
  • -32001: resource not found (including pruned cases)
  • -32005: limit exceeded (logs)
  • Note: internal submit failures can surface as -32603 on specific paths

Pitfalls

  • Reusing standard node eth_getLogs filters as-is (address[] or topics[1+])
  • Treating eth_sendRawTransaction success as final execution success
  • Assuming blockHash in eth_getLogs is always resolvable (scan window is bounded)

Sources

  • tools/rpc-gateway/src/handlers.ts
  • tools/rpc-gateway/README.md
  • crates/ic-evm-rpc/src/lib.rs

Japanese version: /ja/doc/compatibility/precompiles-system-contracts.html

Precompiles & System Contracts

TL;DR

  • Precompile failures are classified as exec.halt.precompile_error.
  • Kasane uses revm mainnet precompile set without custom address overrides.
  • Current default is SpecId::default = PRAGUE, so OSAKA-added 0x0100 (P256VERIFY) is not enabled by default.
  • Opcode-level discussion is out of scope for this page (see ethereum-differences.md).

Operational Policy

  • Use exec.halt.precompile_error as the primary classifier for precompile failures.
  • Smoke-test precompile-dependent paths before mainnet rollout.

Supported Precompiles (Current Default: PRAGUE)

AddressNameIntroduced InNotes
0x01ECRECHomesteadsecp256k1 ecrecover
0x02SHA256Homestead
0x03RIPEMD160Homestead
0x04IDHomesteadidentity
0x05MODEXPByzantiumBerlin gas formula applies under Prague
0x06BN254_ADDByzantiumgas-updated since Istanbul
0x07BN254_MULByzantiumgas-updated since Istanbul
0x08BN254_PAIRINGByzantiumgas-updated since Istanbul
0x09BLAKE2FIstanbul
0x0aKZG_POINT_EVALUATIONCancunenabled in current build (c-kzg / blst / arkworks)
0x0bBLS12_G1ADDPragueEIP-2537
0x0cBLS12_G1MSMPragueEIP-2537
0x0dBLS12_G2ADDPragueEIP-2537
0x0eBLS12_G2MSMPragueEIP-2537
0x0fBLS12_PAIRING_CHECKPragueEIP-2537
0x10BLS12_MAP_FP_TO_G1PragueEIP-2537
0x11BLS12_MAP_FP2_TO_G2PragueEIP-2537

Added in OSAKA but disabled by current default

  • 0x0100 (P256VERIFY, RIP-7212)

Implementation Assumptions

  • evm-core uses Context::mainnet().build_mainnet_with_inspector(...) and directly relies on revm mainnet builder.
  • Precompile set is selected via EthPrecompiles::new(spec) on the mainnet builder side.
  • SpecId::default() is PRAGUE.

Observable Facts

  • Execution error taxonomy includes PrecompileError.
  • Wrapper maps it to exec.halt.precompile_error.

Safe Usage

  • For precompile-dependent features, monitor/classify exec.halt.precompile_error separately from retry logic.
  • For precompile-critical dApps, smoke-test the exact path before mainnet rollout.

Pitfalls

  • Mixing ingress validation responsibility with runtime precompile responsibility
  • Assuming 0x0100 (P256VERIFY) is always enabled
  • Ignoring backend differences for 0x0a (KZG) (c-kzg / blst / arkworks)
  • ethereum-differences.md (opcode/tx type/finality differences)

Sources

  • crates/ic-evm-wrapper/src/lib.rs (exec.halt.precompile_error)
  • crates/evm-core/src/revm_exec.rs
  • crates/evm-core/Cargo.toml (revm feature)
  • vendor/revm/crates/handler/src/mainnet_builder.rs
  • vendor/revm/crates/primitives/src/hardfork.rs
  • vendor/revm/crates/precompile/src/lib.rs
  • vendor/revm/crates/precompile/src/id.rs
  • vendor/revm/crates/precompile/src/bls12_381_const.rs
  • vendor/revm/crates/precompile/src/secp256r1.rs

Japanese version: /ja/doc/rpc/overview.html

RPC Overview

TL;DR

  • Gateway is the layer that translates canister Candid API into JSON-RPC 2.0.
  • Compatibility is restricted, and some methods are not implemented.
  • Invalid input mainly returns -32602; state inconsistency mainly returns -32000/-32001.

Scope

  • A subset of web3_*, net_*, and eth_*
  • Implemented methods are canonically defined by the handleRpc switch

Main Use Cases and Constraints

  • Supports basic reads, call, estimate, and raw transaction submission
  • filter/ws/pending have compatibility differences (see dedicated pages)

Pending/Mempool Policy

  • Ethereum-compatible pending/mempool APIs (for example eth_pendingTransactions, eth_subscribe) are currently not implemented.
  • However, Candid provides get_pending(tx_id) for per-transaction tracking after submit.
  • Determine execution success from receipt (status), not submit return value.
  • See:
    • ../quickstart.md
    • ../compatibility/json-rpc-deviations.md
    • ../compatibility/ethereum-differences.md
    • ../concepts/accounts-keys.md
    • ../_generated/interfaces.md

Sources

  • tools/rpc-gateway/src/handlers.ts (handleRpc)
  • tools/rpc-gateway/README.md
  • crates/ic-evm-wrapper/src/lib.rs (get_pending)

Japanese version: /ja/doc/rpc/chain-and-block.html

Chain & Block Methods

TL;DR

  • Provides eth_chainId, net_version, eth_blockNumber, and eth_getBlockByNumber.
  • eth_getBlockByNumber returns -32001 in pruned ranges.

Methods

  • eth_chainId -> canister rpc_eth_chain_id
  • net_version -> decimal string conversion of rpc_eth_chain_id
  • eth_blockNumber -> canister rpc_eth_block_number
  • eth_getBlockByNumber -> canister rpc_eth_get_block_by_number_with_status

blockTag Constraints

  • latest/pending/safe/finalized are treated as head-level tags
  • pruned data returns resource not found

Sources

  • tools/rpc-gateway/src/handlers.ts
  • crates/ic-evm-rpc/src/lib.rs

For detailed constraints, see ../compatibility/json-rpc-deviations.md.

Japanese version: /ja/doc/rpc/transactions-and-receipts.html

Transaction & Receipt Methods

TL;DR

  • Transaction lookups are keyed by eth_tx_hash.
  • Receipt lookups can explicitly return PossiblyPruned/Pruned.

Methods

  • eth_getTransactionByHash -> rpc_eth_get_transaction_by_eth_hash
  • eth_getTransactionReceipt -> rpc_eth_get_transaction_receipt_with_status_by_eth_hash

Notes

  • tx_id is an internal key; use eth_tx_hash for external integrations.
  • For internal operations that directly use tx_id, call rpc_eth_get_transaction_receipt_with_status_by_tx_id.
  • During migration/corrupt states, methods can return state unavailable.

Sources

  • tools/rpc-gateway/src/handlers.ts
  • crates/ic-evm-rpc/src/lib.rs

Japanese version: /ja/doc/rpc/state.html

State Methods

TL;DR

  • Provides eth_getBalance, eth_getTransactionCount, eth_getCode, and eth_getStorageAt.
  • blockTag accepts latest/pending/safe/finalized/earliest/QUANTITY, but historical support is limited for many methods.

Methods

  • eth_getBalance -> rpc_eth_get_balance
  • eth_getTransactionCount -> rpc_eth_get_transaction_count_at
  • eth_getCode -> rpc_eth_get_code
  • eth_getStorageAt -> rpc_eth_get_storage_at

Key Constraints

  • balance/code/storage: historical reads other than head-equivalent can return state unavailable / out-of-window
  • tx count: pending returns pending nonce; earliest and historical nonce are currently unavailable

See ../compatibility/json-rpc-deviations.md and ./overview.md for details.

Sources

  • tools/rpc-gateway/src/handlers.ts
  • crates/ic-evm-rpc/src/lib.rs
  • tools/rpc-gateway/README.md

Japanese version: /ja/doc/rpc/call-estimate-send.html

Call, Estimate, Send

TL;DR

  • eth_call / eth_estimateGas have callObject constraints.
  • eth_estimateGas returns minimum successful gas, not gas_used.
  • eth_sendRawTransaction delegates to canister submit API.

Methods

  • eth_call -> rpc_eth_call_object
  • eth_estimateGas -> rpc_eth_estimate_gas_object
  • eth_sendRawTransaction -> rpc_eth_send_raw_transaction

callObject Constraints

  • Supported keys: to/from/gas/gasPrice/value/data/nonce/maxFeePerGas/maxPriorityFeePerGas/chainId/type/accessList
  • type=0x0 / 0x2 only
  • Fee parameter combinations must follow validation rules

Send Operation

  • Always monitor receipt status after submit success

Sources

  • tools/rpc-gateway/README.md
  • tools/rpc-gateway/src/handlers.ts
  • crates/ic-evm-rpc/src/lib.rs

Japanese version: /ja/doc/rpc/logs.html

Logs

TL;DR

  • eth_getLogs is a constrained implementation built on rpc_eth_get_logs_paged.
  • Exceeding range/filter limits returns -32005.

Supported Patterns

  • Single-address + topic0-centered retrieval
  • OR arrays in topics[0] (up to 16)
  • blockHash mode (without fromBlock/toBlock, within scan limits)

Constraints

  • topics[1+] conditions are currently unsupported
  • multiple addresses in one request are unsupported

Common Errors

  • logs.range_too_large
  • logs.too_many_results
  • UnsupportedFilter

Sources

  • crates/ic-evm-rpc/src/lib.rs (rpc_eth_get_logs_paged)
  • tools/rpc-gateway/src/handlers.ts

Japanese version: /ja/doc/rpc/errors-and-limits.html

Errors & Limits

TL;DR

  • Control is applied in two layers: HTTP constraints (body/batch/depth) and RPC constraints (blockTag/filter/range).
  • Main error codes are -32602/-32000/-32001/-32005.

Gateway HTTP Limits

  • RPC_GATEWAY_MAX_HTTP_BODY_SIZE
  • RPC_GATEWAY_MAX_BATCH_LEN
  • RPC_GATEWAY_MAX_JSON_DEPTH

RPC Errors

  • -32602 invalid params
  • -32000 state unavailable / execution failed
  • -32001 resource not found
  • -32005 limit exceeded

Sources

  • tools/rpc-gateway/src/server.ts
  • tools/rpc-gateway/src/handlers.ts
  • tools/rpc-gateway/src/config.ts

Japanese version: /ja/doc/contracts/solidity-vyper-compatibility.html

Solidity/Vyper Compatibility

TL;DR

  • As core EVM execution path, you can use eth_call / eth_estimateGas / eth_sendRawTransaction.
  • For compatibility details, treat Gateway implementation and compatibility matrix as source of truth.

Main Methods Available

  • eth_call
  • eth_estimateGas
  • eth_sendRawTransaction

References

  • tools/rpc-gateway/README.md
  • crates/evm-core/src/tx_decode.rs

Japanese version: /ja/doc/contracts/tooling.html

Tooling (Hardhat/Foundry/ethers/viem)

TL;DR

  • Smoke tests for ethers/viem/foundry are available in the repository.
  • Start with a minimal set: reads + call/estimate + receipt monitoring.

Minimal Flow

  • viem: tools/rpc-gateway/smoke/viem_smoke.ts
  • ethers: tools/rpc-gateway/smoke/ethers_smoke.ts
  • foundry: tools/rpc-gateway/smoke/foundry_smoke.sh

Pitfalls

  • Dropping revert data and losing root-cause visibility
  • Not storing tx hash and losing observability

Sources

  • tools/rpc-gateway/smoke/viem_smoke.ts
  • tools/rpc-gateway/smoke/ethers_smoke.ts
  • tools/rpc-gateway/smoke/foundry_smoke.sh

Japanese version: /ja/doc/contracts/verification.html

Verification

TL;DR

  • Verify feature is provided on the Explorer side.
  • For preflight checks, key rotation, and monitoring operation, use docs/ops/verify_runbook.md as the source of truth.

Operational Steps (Overview)

  1. Set EXPLORER_VERIFY_ENABLED=1 and allow-listed compiler version environment variables.
  2. Run npm run verify:preflight in tools/explorer to verify allowed solc availability.
  3. Submit verification via POST /api/verify/submit and track status via GET /api/verify/status.

Sources

  • tools/explorer/README.md
  • docs/ops/verify_runbook.md

Japanese version: /ja/doc/integration/sdks.html

SDKs

TL;DR

  • Instead of a dedicated SDK, primary usage is standard JSON-RPC clients (ethers/viem/foundry).
  • Direct canister access is available through Candid.

Sources

  • tools/rpc-gateway/package.json
  • crates/ic-evm-wrapper/evm_canister.did

Japanese version: /ja/doc/integration/signing-nonce-retries.html

Signing, Nonce, Retries

TL;DR

  • Always fetch nonce before submit.
  • Ensure chain id matches 4801360.
  • After submit success, determine final result by polling receipt.
  1. Resolve sender address
  2. Fetch nonce with eth_getTransactionCount or expected_nonce_by_address
  3. Set fees (consider base fee + priority)
  4. Submit via eth_sendRawTransaction
  5. Poll eth_getTransactionReceipt

Pitfalls

  • Hard-coding nonce
  • Resending on receipt timeout and causing nonce conflicts

Sources

  • README.md
  • tools/rpc-gateway/README.md
  • crates/ic-evm-wrapper/src/lib.rs

Japanese version: /ja/doc/integration/indexer-integration-points.html

Indexer Integration Points

TL;DR

  • Pull entrypoint is export_blocks(cursor,max_bytes).
  • Log backfill helper is rpc_eth_get_logs_paged.
  • Design cursor workflow with pruning in mind.

Sources

  • crates/ic-evm-wrapper/evm_canister.did
  • tools/indexer/README.md
  • docs/specs/indexer-v1.md

Japanese version: /ja/doc/indexer/data-model.html

Data Model

TL;DR

  • Indexer is Postgres-first.
  • It stores entities such as txs, receipts, token_transfers, and ops_metrics_samples.

Key Points

  • receipt_status is stored on txs
  • token transfers are extracted from receipt logs

Sources

  • tools/indexer/README.md
  • tools/indexer/src/db.ts

Japanese version: /ja/doc/indexer/resync-pagination-missing-data.html

Resync, Pagination, Missing Data

TL;DR

  • Cursor format is fixed JSON of block_number/segment/byte_offset.
  • On Err.Pruned, continue by correcting cursor position.

Pitfalls

  • Pruning progresses while indexer is down and causes history gaps
  • Segment limit mismatch prevents recovery

Sources

  • tools/indexer/README.md
  • docs/specs/indexer-v1.md
  • tools/indexer/src/config.ts

Japanese version: /ja/doc/indexer/event-decoding-tips.html

Event Decoding Tips

TL;DR

  • For ERC-20 Transfer extraction, strictly validate topic/data lengths.
  • Malformed logs should be skipped per row to avoid stopping the full pipeline.

Sources

  • tools/indexer/README.md
  • tools/indexer/src/decode_receipt.ts

Japanese version: /ja/doc/security.html

Security Guide

TL;DR

  • Minimum baseline: signing-key management, chain-id correctness, and receipt monitoring.
  • Typical incidents come from low-fee settings, nonce mistakes, and prune-unaware assumptions.

Safe Usage

  • Pin chain id (4801360)
  • Fetch nonce every time
  • Judge success from receipt after eth_sendRawTransaction
  • Do not over-relax gateway limits

Dangerous Pitfalls

  • Missing status=0x0 and treating failed execution as success
  • Re-sending tx signed with wrong chain id repeatedly
  • Assuming pruned history remains permanently queryable
  • Keep RPC_GATEWAY_MAX_BATCH_LEN within default range
  • Match INDEXER_CHAIN_ID to target network
  • Match INDEXER_MAX_SEGMENT to canister specification

Sources

  • tools/rpc-gateway/src/config.ts
  • tools/indexer/src/config.ts
  • tools/rpc-gateway/README.md
  • crates/evm-core/tests/phase1_eth_decode.rs

Japanese version: /ja/doc/troubleshooting.html

Troubleshooting Guide

TL;DR

  • First classify issues into one of: invalid input, state unavailable, or pruned.
  • Observe submit and execute as separate phases.

Common Errors and Fixes

  • invalid params (-32602)
    • Cause: invalid address/hash length, invalid blockTag, callObject constraint violation
    • Action: re-check hex lengths and supported keys
  • state unavailable (-32000)
    • Cause: migration in progress, critical_corrupt, execution failure
    • Action: check get_ops_status
  • resource not found (-32001)
    • Cause: pruned range or missing resource
    • Action: use indexer history
  • limit exceeded (-32005)
    • Cause: too wide logs range / too many results
    • Action: split by block range

Pitfalls

  • Calling eth_getLogs over a large range in one request
  • Resending without monitoring and amplifying nonce conflicts

Sources

  • tools/rpc-gateway/src/handlers.ts
  • tools/rpc-gateway/README.md
  • crates/ic-evm-wrapper/src/lib.rs (get_ops_status)

Japanese version: /ja/doc/appendix/glossary.html

Glossary

  • tx_id: internal canister identifier
  • eth_tx_hash: Ethereum-compatible transaction hash
  • IcSynthetic: canister-specific transaction type
  • EthSigned: signed Ethereum transaction
  • auto-production: timer-driven automatic block production
  • PossiblyPruned: ambiguous existence near prune boundary
  • Pruned: already pruned and no longer queryable

Japanese version: /ja/doc/appendix/config-reference.html

Config Reference (User Scope)

TL;DR

  • This page lists only the settings most frequently used by developers.

Gateway

  • EVM_CANISTER_ID (required)
  • RPC_GATEWAY_IC_HOST
  • RPC_GATEWAY_PORT

Indexer

  • EVM_CANISTER_ID (required)
  • INDEXER_DATABASE_URL (required)
  • INDEXER_IC_HOST
  • INDEXER_CHAIN_ID (default: 4801360)
  • INDEXER_MAX_BYTES

Japanese version: /ja/doc/appendix/versioning-compatibility-policy.html

Versioning & Compatibility Policy

TL;DR

  • The source of truth for compatibility matrix updates is the Gateway README.
  • When adding methods or changing constraints, update this summary in the same PR.

Sources

  • tools/rpc-gateway/README.md
  • README.md

Japanese version: /ja/doc/_generated/repo-map.html

Repo Map

This page organizes “what lives where” in the Kasane repository using primary sources only.

TL;DR

  • Main EVM canister implementation is ic-evm-wrapper in the Rust workspace.
  • Execution logic is in evm-core, persistence/constants in evm-db, and RPC helpers in ic-evm-rpc.
  • Main developer-facing entry points are tools/rpc-gateway (HTTP JSON-RPC) and crates/ic-evm-wrapper/evm_canister.did (Candid).
  • Indexer is tools/indexer (Postgres-first).

Key Directories

  • crates/ic-evm-wrapper
    • canister entrypoints (#[ic_cdk::query] / #[ic_cdk::update])
    • public Candid definition (evm_canister.did)
  • crates/evm-core
    • tx decode / submit / produce / call / estimate implementation
    • EVM execution and fee calculation (revm_exec.rs, base_fee.rs)
  • crates/evm-db
    • stable state, chain constants, runtime defaults, receipt/block/tx types
  • crates/ic-evm-rpc
    • RPC helper logic called by wrapper (eth reads/transforms)
  • tools/rpc-gateway
    • translates canister Candid API to Ethereum JSON-RPC 2.0
  • tools/indexer
    • pulls export API and stores into Postgres
  • scripts
    • smoke, predeploy, and mainnet deploy helpers
  • docs
    • operational runbooks and spec notes (usable as primary references)

Entrypoints

  • canister build/runtime
    • dfx.json canisters.evm_canister
    • crates/ic-evm-wrapper/src/lib.rs
  • gateway runtime
    • tools/rpc-gateway/src/main.ts
    • tools/rpc-gateway/src/server.ts
  • indexer runtime
    • tools/indexer/src/main.ts

Dependency Outline

  • Rust workspace members
    • Cargo.toml [workspace].members
  • JSON-RPC layer responsibilities
    • Gateway: request/response and limits
    • canister: state/execution/persistence

Out of Scope (for this GitBook)

  • node operations (validator/sequencer/full-node operations)
  • internal details of upstream libraries under vendor/

Sources

  • Cargo.toml (workspace members)
  • dfx.json (canister package/candid)
  • icp.yaml (deploy recipe)
  • crates/ic-evm-wrapper/src/lib.rs (canister entrypoint)
  • tools/rpc-gateway/src/main.ts (gateway entrypoint)
  • tools/indexer/README.md (indexer responsibilities)

Japanese version: /ja/doc/_generated/interfaces.html

Interfaces

TL;DR

  • External interfaces are provided via two paths: Candid (direct canister) and HTTP JSON-RPC (gateway).
  • JSON-RPC is not full Ethereum compatibility; it is a constrained implementation.
  • In eth_sendRawTransaction, submit success is not execution success. Use eth_getTransactionReceipt.status for final success.
  • pending/mempool is not available as Ethereum-compatible APIs; use canister get_pending(tx_id) to track submitted tx.

1. Candid API (Public Service)

Public definition: crates/ic-evm-wrapper/evm_canister.did

Main query methods

  • rpc_eth_chain_id
  • rpc_eth_block_number
  • rpc_eth_get_block_by_number
  • rpc_eth_get_block_by_number_with_status
  • rpc_eth_get_transaction_by_eth_hash
  • rpc_eth_get_transaction_by_tx_id
  • rpc_eth_get_transaction_receipt_by_eth_hash
  • rpc_eth_get_transaction_receipt_with_status_by_eth_hash
  • rpc_eth_get_transaction_receipt_with_status_by_tx_id
  • rpc_eth_get_balance
  • rpc_eth_get_code
  • rpc_eth_get_storage_at
  • rpc_eth_call_object
  • rpc_eth_call_rawtx
  • rpc_eth_estimate_gas_object
  • rpc_eth_get_logs_paged
  • rpc_eth_get_block_number_by_hash
  • rpc_eth_gas_price
  • rpc_eth_max_priority_fee_per_gas
  • rpc_eth_fee_history
  • expected_nonce_by_address
  • get_receipt
  • get_pending
  • export_blocks
  • get_ops_status
  • health
  • metrics

Main update methods

  • rpc_eth_send_raw_transaction
  • submit_ic_tx
  • set_block_gas_limit
  • set_instruction_soft_limit
  • set_prune_policy
  • set_pruning_enabled
  • set_log_filter
  • prune_blocks

2. Gateway JSON-RPC

Implementation: handleRpc switch in tools/rpc-gateway/src/handlers.ts

Implemented methods

  • web3_clientVersion
  • net_version
  • eth_chainId
  • eth_blockNumber
  • eth_gasPrice
  • eth_maxPriorityFeePerGas
  • eth_feeHistory
  • eth_syncing
  • eth_getBlockByNumber
  • eth_getTransactionByHash
  • eth_getTransactionReceipt
  • eth_getBalance
  • eth_getTransactionCount
  • eth_getCode
  • eth_getStorageAt
  • eth_getLogs
  • eth_call
  • eth_estimateGas
  • eth_sendRawTransaction

Unsupported methods (README compatibility matrix)

  • eth_getBlockByHash
  • eth_getTransactionByBlockHashAndIndex
  • eth_getTransactionByBlockNumberAndIndex
  • eth_getBlockTransactionCountByHash
  • eth_getBlockTransactionCountByNumber
  • eth_newFilter
  • eth_getFilterChanges
  • eth_uninstallFilter
  • eth_subscribe
  • eth_unsubscribe
  • eth_pendingTransactions

3. Canonical Constraint References

  • Canonical overall policy: ../rpc/overview.md
  • Canonical JSON-RPC differences: ../compatibility/json-rpc-deviations.md
  • Canonical pending/mempool policy: “Pending/Mempool Policy” in ../rpc/overview.md

This page is intentionally limited to interface inventory. Detailed behavior differences belong to the canonical pages above.

4. Return/Identifier Notes

  • Internal canister identifier: tx_id
  • Ethereum-compatible identifier: eth_tx_hash
  • Gateway eth_sendRawTransaction resolves and returns eth_tx_hash from canister-returned tx_id.

5. Type Boundaries (Representative)

  • RpcCallObjectView (Candid)
  • EthBlockView / EthTxView / EthReceiptView
  • RpcBlockLookupView (NotFound / Found / Pruned)
  • RpcReceiptLookupView (NotFound / Found / PossiblyPruned / Pruned)
  • PendingStatusView (Queued / Included / Dropped / Unknown)

Sources

  • crates/ic-evm-wrapper/evm_canister.did
  • tools/rpc-gateway/src/handlers.ts
  • tools/rpc-gateway/README.md
  • crates/ic-evm-wrapper/src/lib.rs (get_pending, rpc_eth_send_raw_transaction)

Japanese version: /ja/doc/_generated/config-reference.html

Config Reference

TL;DR

  • Required settings are Gateway: EVM_CANISTER_ID, Indexer: EVM_CANISTER_ID + INDEXER_DATABASE_URL.
  • Default chain_id is 4801360.
  • Gas/mining/prune defaults are managed as Rust constants.

1. Gateway Environment Variables

Definition: tools/rpc-gateway/src/config.ts

  • Required
    • EVM_CANISTER_ID
  • Optional (default)
    • RPC_GATEWAY_IC_HOST (https://icp-api.io)
    • RPC_GATEWAY_FETCH_ROOT_KEY (false)
    • RPC_GATEWAY_IDENTITY_PEM_PATH (null)
    • RPC_GATEWAY_HOST (127.0.0.1)
    • RPC_GATEWAY_PORT (8545)
    • RPC_GATEWAY_CLIENT_VERSION (kasane/phase2-gateway/v0.1.0)
    • RPC_GATEWAY_MAX_HTTP_BODY_SIZE (262144)
    • RPC_GATEWAY_MAX_BATCH_LEN (20)
    • RPC_GATEWAY_MAX_JSON_DEPTH (20)
    • RPC_GATEWAY_CORS_ORIGIN (*)

2. Indexer Environment Variables

Definition: tools/indexer/src/config.ts

  • Required
    • EVM_CANISTER_ID
    • INDEXER_DATABASE_URL
  • Optional (default)
    • INDEXER_IC_HOST (https://icp-api.io)
    • INDEXER_DB_POOL_MAX (10)
    • INDEXER_RETENTION_DAYS (90)
    • INDEXER_RETENTION_ENABLED (true)
    • INDEXER_RETENTION_DRY_RUN (false)
    • INDEXER_ARCHIVE_GC_DELETE_ORPHANS (false)
    • INDEXER_MAX_BYTES (1200000)
    • INDEXER_BACKOFF_INITIAL_MS (200)
    • INDEXER_BACKOFF_MAX_MS (5000)
    • INDEXER_IDLE_POLL_MS (1000)
    • INDEXER_PRUNE_STATUS_POLL_MS (30000)
    • INDEXER_OPS_METRICS_POLL_MS (30000)
    • INDEXER_FETCH_ROOT_KEY (false)
    • INDEXER_ARCHIVE_DIR (./archive)
    • INDEXER_CHAIN_ID (4801360)
    • INDEXER_ZSTD_LEVEL (3)
    • INDEXER_MAX_SEGMENT (2)

3. Chain / Runtime Constants

chain constants

Definition: crates/evm-db/src/chain_data/constants.rs

  • CHAIN_ID = 4_801_360
  • MAX_TX_SIZE = 128 * 1024
  • MAX_TXS_PER_BLOCK = 1024
  • MAX_PENDING_GLOBAL = 8192
  • MAX_PENDING_PER_SENDER = 64
  • MAX_PENDING_PER_PRINCIPAL = 32
  • MAX_NONCE_WINDOW = 64
  • MAX_LOGS_PER_TX = 64
  • MAX_LOG_TOPICS = 4

runtime defaults

Definition: crates/evm-db/src/chain_data/runtime_defaults.rs

  • DEFAULT_MINING_INTERVAL_MS = 2000
  • DEFAULT_BASE_FEE = 250_000_000_000
  • DEFAULT_MIN_GAS_PRICE = 250_000_000_000
  • DEFAULT_MIN_PRIORITY_FEE = 250_000_000_000
  • DEFAULT_BLOCK_GAS_LIMIT = 3_000_000
  • DEFAULT_INSTRUCTION_SOFT_LIMIT = 4_000_000_000
  • DEFAULT_PRUNE_TIMER_INTERVAL_MS = 3_600_000
  • DEFAULT_PRUNE_MAX_OPS_PER_TICK = 5_000
  • MIN_PRUNE_TIMER_INTERVAL_MS = 1_000
  • MIN_PRUNE_MAX_OPS_PER_TICK = 1

4. Risky Values / Notes

  • If INDEXER_CHAIN_ID does not match the real chain, signing/verification operations can fail.
  • Increasing RPC_GATEWAY_MAX_HTTP_BODY_SIZE too much weakens DoS resistance.
  • Lowering DEFAULT_MIN_GAS_PRICE / DEFAULT_MIN_PRIORITY_FEE without clear rationale reduces low-fee spam resistance.

Sources

  • tools/rpc-gateway/src/config.ts
  • tools/indexer/src/config.ts
  • crates/evm-db/src/chain_data/constants.rs
  • crates/evm-db/src/chain_data/runtime_defaults.rs

Japanese version: /ja/doc/_generated/open-questions.html

Open Questions

There are currently no open items in this documentation set.