What does not work
Everything below follows from one fact: BKC accounts have no ECDSA key.
Tools
| Tool | Status | Why / what to use |
|---|---|---|
| Hardhat 2 | ✅ with @bkc-network-lib/hardhat | the plugin signs writes as Cosmos messages |
| ethers v6 | ✅ with BkcSigner | an ordinary ethers Signer |
Blockscout verify / hardhat verify | ✅ | Verify contracts |
Foundry (forge create, cast send) | ❌ writes · ✅ reads | signs locally with secp256k1; forge build, cast call and cast calldata work |
| Remix (Injected / MetaMask) | ❌ writes | compile in Remix, deploy with Hardhat or the CLI |
| viem wallet client | ❌ writes · ✅ reads | use createBkcEip1193Provider() from the SDK as a custom transport |
| MetaMask and other ECDSA wallets | ❌ | cannot hold an ML-DSA account — use the BKC Wallet |
| Hardhat 3 | ❌ | the plugin targets the Hardhat 2 line |
Foundry, Remix and viem could work through a local proxy that decodes a signed Ethereum transaction and re-signs it as a Cosmos message — the same translation the plugin does, on the wire. Ask the BKC team if you need one.
JSON-RPC methods
| Method | Behaviour |
|---|---|
eth_sendRawTransaction | refused: no ECDSA-signed transaction can be valid |
eth_sendTransaction | not served by the node; the SDK/plugin intercepts it client-side |
eth_sign, personal_sign, eth_signTypedData_v4 | no key to sign with — use ADR-36 signMessage() and the precompile |
eth_subscribe("logs"), eth_newFilter | do not include wrapped-call logs — poll eth_getLogs |
eth_getLogs over > 10,000 blocks | rejected — page with getLogsPaged() or a block range |
debug_*, txpool_*, personal_* | not enabled on the public endpoint (only eth, net, web3) |
Behaviour that differs from Ethereum
receipt.feeis 0. The fee is paid on the Cosmos side; usegetEvmTransactionCost().- Gas figures are larger. An ML-DSA transaction is ~5.5 KB and gas is per byte; budget from
bkcChain.baseGasLimit, not Ethereum intuition. - Gas cannot be simulated for the Cosmos side (
--gas autofails). - One write at a time per account.
call_nonceis the Cosmos sequence; concurrent writes from one account reject each other. The SDK and plugin queue them. signer.signMessage()throws. ethers nests the explanation aterror.error.message.
