H160 Precompile Gateway: Standardized EVM Access for Polkadot DApps

Hi Polkadot community,

I would like to highlight the need to standardize the use of Ethereum-style H160 addresses and the adoption of EVM standards for dApp development on Polkadot. The ecosystem already includes functioning EVM and PVM runtimes; this effort focuses on aligning dApp development with industry standards, while keeping Substrate as a low-level layer for parachain and system developers.

The goal is to reduce operational costs and complexity for developers by providing a standardized interface compatible with existing Ethereum tooling (wallets, ethers.js, viem), while keeping Substrate accessible as a low-level layer for parachain and system developers.

Key highlights:

1- H160 Address Standard Compliance
Ethereum-style H160 addresses standardized for accounts and “virtual contract” endpoints.
H160 is used strictly for identity and routing, not for executing EVM bytecode.
Ensures seamless integration with wallets and Ethereum tooling (MetaMask, WalletConnect, ethers.js, viem), fully aligning with industry standards.

2- Precompile Gateway for Standardized ABI Dispatch
A runtime precompile dispatches Ethereum-formatted transactions from the adapter to native Substrate pallets.
Responsibilities:
Verify EIP-155 signatures
Map H160 → Substrate AccountId32
Decode calldata and route to the correct pallet
Supports standard ABI calls for transfers, assets, governance, and other operations without requiring developers to understand Substrate internals.

3- Efficiency & Developer Experience
No unnecessary EVM execution → drastically reduces operational costs, gas overhead, and runtime complexity
Frontend devs see a clean Ethereum-compatible interface, while Substrate remains fully available for parachain/system developers
Simplifies dApp development, improves safety, and accelerates time-to-market.

4- Benefits
Plug-and-play developer UX for dApps
Security-first: avoids common EVM risks (reentrancy, gas griefing, storage collisions)
Industry standard compliance: consistent H160 and ABI interface
Clear separation of layers: dApp developers use the adapter gateway; Substrate remains for advanced system development

This development will be carried out exclusively by Parity Technologies and the Fellowship, ensuring consistency, security, and maintainability across the ecosystem.


Appendix 1

Example for Governance:

interface Governance {
function vote(uint256 referendumId, bool support) external;
}

support = true for “yes”, false for “no”

This is exactly what a developer would see from the EVM perspective
Completely hides Substrate / pallet complexity

What happens internally:
1- Gateway receives the transaction from MetaMask / ethers.js

2-Verifies the EVM signature (secp256k1) → obtains H160 sender

3-Maps H160 → Substrate AccountId

4-Decodes ABI data (referendumId, support)

5- Constructs the corresponding Substrate pallet call:

pallet_conviction_voting::Call::vote { referendumId, aye: support }

6- Dispatches the call in the runtime with Signed(origin)

Developer only sees vote(referendumId, support) — completely unaware of Substrate internals.


Appendix 2

Example: Accessing Virtual Contracts via Ethers.js

Developers interact with virtual contracts exactly like standard EVM contracts.

1. Contract address (H160)

const GOVERNANCE_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000000801";

2. Standard ABI (generated from Solidity interface)

const governanceAbi = [
  "function vote(uint256 referendumId, bool support) external"
];

3. Create a contract instance

import { ethers } from "ethers";

const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();

const governance = new ethers.Contract(
  GOVERNANCE_CONTRACT_ADDRESS,
  governanceAbi,
  signer
);

4. Call the method

// Vote YES on referendum 42
await governance.vote(42, true);

What the developer sees:

“I am calling a standard EVM contract.”

Under the hood:

  1. The transaction goes through eth_sendTransaction / eth_call

  2. The virtual contract address is recognized by the gateway/precompile

  3. Calldata is decoded according to the ABI

  4. EVM signature (H160) is verified and mapped to Substrate AccountId

  5. The corresponding Substrate pallet call is constructed

  6. The call is dispatched in the runtime

Key point:

From the developer’s perspective, virtual contracts are indistinguishable from regular EVM contracts, while the runtime handles all Substrate-specific type conversions.

2 Likes

Thanks for sharing this. I’m trying to understand the status and scope of what’s being proposed here.

In the post you write:

Is this meant as an announcement of an already-approved initiative, or is it a proposal intended to gather feedback? If it’s the former, could you point to the relevant governance/Fellowship context (e.g., an RFC, motion, minutes, or prior discussion) that establishes the mandate and decision path?

Also, could you clarify your role/affiliation (Parity / Fellowship / other) and in what capacity you’re presenting this? The wording reads quite definitive, so understanding who is speaking and with what mandate would help frame feedback appropriately.

Finally: are you explicitly looking for technical review and tradeoff analysis at this stage? If yes, I’m happy to provide detailed feedback, but I want to confirm the decision is still open and that there’s a clear channel for incorporating community input.

One more thing for transparency: this account appears relatively new and doesn’t have much public context behind it. Would you be comfortable sharing who you are (at least at the level of “real name / team / org” or a verifiable link to your work), so people can have a better understanding about where this proposal is coming from?

It's a proposal in the forum like any other.

I must insist: who are you?

I prefer to remain anonymous. The proposal should be evaluated based on its technical merit, not on the identity of the contributor. This is in line with the forum’s guidelines.

I’m happy to provide clarifications about the proposal itself, but I do not wish to disclose personal details.

And I think that if you insist, you’re crossing the line of what’s allowed on the forum.

2 Likes

For what it’s worth (from a semi-anon account, though you could find my real info via my failed W3F grant), ultracoconut has been active on X for a year and a half showcasing his work. He mainly focuses on customer-facing dApps, and from what I’ve observed, his output matches his persona of moving from hardware into web dev. So, if you’re worried he’s just another bot, he is not. Whether the time spent here is worth it, I can’t say, but he does seem earnest every time we have talked.

Decode calldata and route to the correct pallet

Purely with respects to implementation, many substrate extrinsics use parameter types that Solidity does not support natively. Especially ADTs such as enums.

For example, this custom Solidity→SCALE encoder for a Rust type, since Solidity doesn’t support enums: snowbridge/contracts/src/SubstrateTypes.sol at 2716aeebf77dfb00f0a5a665bf866ffcee71fa5f · Snowfork/snowbridge · GitHub

So you’re gonna need to write custom codecs to support those, or alternatively implement virtual contracts/precompiles that abstract heavily from the underlying substrate extrinsics. Which is fine! Just sharing experience in this area.

1 Like

Thanks for sharing the experience, that’s a fair point.
This proposal is intentionally scoped around standard Solidity-compatible interfaces, not around exposing arbitrary Substrate extrinsics 1:1.
The goal is not to make Solidity understand all Substrate types (ADTs, enums, complex SCALE layouts), but to abstract them behind stable, EVM-native interfaces.
In practice, this means:
Virtual contracts / precompiles define Solidity-first ABIs
Complex Substrate types are normalized into Solidity-supported primitives (e.g. uint, bool, address)
Any necessary mapping or decoding happens inside the runtime, not in userland Solidity
This avoids pushing custom codecs and SCALE complexity onto application developers, while keeping the underlying implementation flexible.
In other words, Solidity interfaces are the specification layer, and Substrate extrinsics remain an internal implementation detail.

Cool, perfect!

Then a follow-up question:

Working from the user backwards, do you have an idea of which APIs you intend to support initially? That’s going to determine the scope, and factors into cost/benefit considerations.

For example, I think EVM access to pallet_scheduler (not sure if this is safe) for Solidity contracts would be really cool and would unlock new kinds of dapps that are not possible on Ethereum mainnet.

Support for OpenGov? I don’t see that as a big draw for the average EVM user.

1 Like

With EVM access to pallet_scheduler, you unlock a lot of really interesting use cases that aren’t possible on Ethereum mainnet. Developers can automate actions on-chain in new ways. And with governance, building governance apps becomes super easy to program, and easy to maintain, all using familiar Solidity tools

Ideal Approach

The correct way to proceed is to design simple, developer-facing Solidity contracts first, exposing only small, easily digestible methods that application developers can interact with directly.
These contracts define the public interface and express the developer’s intent using standard EVM types and stable ABIs.
Once these Solidity interfaces are finalized and validated from a usability perspective, the implementation work happens at the runtime level, where Substrate:
Adapts the EVM call to the corresponding pallet logic
Fills in any missing context not expressible in Solidity (origin, internal types, execution context, etc.)
Constructs the appropriate Substrate-native data structures and ADTs
Dispatches the actual extrinsic internally
In this model, Solidity defines the interface, while Substrate remains the execution engine and retains full control over internal representation and evolution.

yes, agreed, step 1 is to define the interfaces and user interactions first, and then pass around to stakeholders for review and validation :+1:

To reiterate what @josep said, at this stage its a bit unclear what sort of feedback you’re looking for. So I’m kinda grasping at straws. All I can say is that the high-level idea is good.

1 Like

I’m just seeing if this has community support and if devs like it, so I’m laying the groundwork for us as a community to do a WFC and have Parity and Fellowship implement it.
Man, if Gavin does it, he’ll probably have it done in a couple of days anyway :blush:

2 Likes

Other rough ideas for precompiles:

  • 1st class support for Hyperbridge & Snowbridge
interface EthereumMainnet {
    function transfer(address dest, address token, uint256 amount, uint256 fee)
    function call(address dest, bytes calldata data, uint256 fee)
}
  • XCM-lite for EVM:
interface Parachain {
    function transfer(ParaId dest, address token, uint256 value, bytes errorHandlerData, uint256 fee)
    function call(ParaId dest, bytes calldata data, bytes errorHandlerData, uint256 fee)
    function callWithValue(ParaId dest, bytes calldata data, bytes errorHandlerData, uint256 value, uint256 fee)
}
2 Likes

+1 to this. Right now it’s hard to give useful feedback because the proposal has more holes than a slice of Swiss cheese.

That’s also why I asked about their background: properly reviewing something in this space takes real time, and the “level of rigor” needed depends a lot on whether we’re iterating with someone who already understands the underlying systems, and the different tradeoffs that come to play. I don’t think that’s the case, I think that we are simply dealing with a well-intentioned AI slop producer trying to oversimplify things.

@ultracoconut if you want serious technical review for something like this, please consider opening an issue in the Polkadot Fellows RFC repo.

2 Likes

You’re making a lot of assumptions.
No, I don’t have deep knowledge of Substrate. But for the record, I’m an electronics engineer and I’ve been programming for many years in assembly and C. Don’t assume you’re better than others — you might be in for a surprise. A bit more humility would go a long way.
And by the way, let’s not even get into your incompetence with PAPI.
I’m doing this as a member of the community to help improve Polkadot, expecting nothing in return. You’re focusing far too much on me personally, and that’s something I don’t allow from anyone.

If you say so. There’s no evidence I can check beyond your word. Anyone can create an anonymous account and make these claims, so I tend to default to “verify, don’t trust.” Since there’s no practical way for me to verify this, and given what’s coming from this account so far, I don’t have a strong reason to take those claims at face value. At the moment it reads more like an anon account here to push certain ideas of a certain “leader” of this ecosystem.

I haven’t assumed anything about being “better.” I simply said I’m not going to spend my free time pointing out all the holes I see in the proposal, because I don’t think it’s worth my time.

Classic ad-hominem :joy:

Again, you’re asking me to take this on faith. But you’re not offering any way to verify these claims, and I don’t see enough signal to assume that’s true.

I can’t “focus on you personally” because I don’t even know who you are.

Is that a threat? Should I be scared? :sweat_smile:

I actually spend all day working on PAPI v2 and other PAPI improvements, and I did that during my free time, but hey, whatever you say anon.

Okay, let’s see if a moderator blocks you, because you won’t stop bothering people.

I suggest keeping the discussion constructive and avoiding polemical tones. Let’s try to contribute to Polkadot rather than creating friction. Thank you.

4 Likes