Skip to main content
Version: v6

Use Solidity tooling

Use ink! with Solidity ABI

ink! v6 contracts can be configured to use Solidity ABI encoding, enabling seamless compatibility with Ethereum tools like MetaMask, Hardhat, Wagmi, and ethers.js. This allows you to leverage the Ethereum ecosystem while building on Polkadot networks.

Why Use Solidity ABI?

By enabling Solidity ABI compatibility, you can:

  • Use Ethereum wallets like MetaMask to interact with your ink! contracts
  • Deploy with Hardhat and other familiar Ethereum development tools
  • Build frontends using ethers.js, Wagmi, and other Ethereum frontend libraries
  • Share contracts easily with Solidity developers (Solidity contracts can call your ink! contract as if it was a Solidity contract)

Quick Start

1. Create Your Contract

pop new contract my_contract -t standard
cd my_contract

2. Enable Solidity ABI

Open Cargo.toml, add the ink-lang table under [package.metadata], and configure the ABI mode:

[package.metadata.ink-lang]
abi = "sol"

Setting abi = "sol" puts the contract into Solidity ABI compatibility mode, so all constructor, message, event and error types must mappable to Solidity ABI types. See the Type Reference for details.

3. Build with Solidity Metadata

pop build --release --metadata solidity

This generates Solidity-compatible artifacts in target/ink/:

  • *.abi - Solidity ABI file for contract interaction
  • *.json - Metadata compatible with Ethereum tooling

How It Works

When you specify abi = "sol", the ink! code generator follows the Solidity ABI specification:

Function Selectors

  • Message selectors use keccak256 hashing (Ethereum standard)
  • First 4 bytes of keccak256("functionName(type1,type2,...)")
  • Manual selector overrides via #[ink(selector = ...)] are ignored

Encoding/Decoding

  • Uses Solidity ABI encoding for inputs/outputs
  • Events and errors follow Solidity format
  • Internal storage still uses SCALE codec (no storage changes!)

Constraints

  • Only one constructor can be defined
  • All constructor, message, event and error types must map to Solidity ABI types (see Type Reference)
  • Call builders are generated for Solidity calling conventions
Storage Format

The contract ABI only affects external interactions. Your contract's internal storage remains SCALE-encoded! Using Solidity ABI does not change your storage layout.

Dual ABI Mode ("all")

You can support both ink! and Solidity ABIs simultaneously:

[package.metadata.ink-lang]
abi = "all"

Benefits

  • Contracts callable by both ink! and Solidity tools
  • Each message has two entry points (ink! selector + Solidity selector)
  • Flexibility for cross-ecosystem interoperability

Constraints

  • All constructor, message, event and error types must map to Solidity ABI types (see Type Reference)
  • Must designate a #[ink(constructor, default)] for Solidity instantiation (if more than one constructor is defined)
#[ink(constructor, default)]
pub fn new(initial_value: bool) -> Self {
Self { value: initial_value }
}

Tradeoffs

  • Larger contract size (entry points for both ink! and Solidity ABI selectors compiled in)

Next Steps

Now that your contract is Solidity ABI compatible: