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
- cargo-contract
pop new contract my_contract -t standard
cd my_contract
cargo contract new --abi sol my_contract
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
- cargo-contract
pop build --release --metadata solidity
cargo contract 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
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:
- Call Solidity Contracts from ink!
- Set up MetaMask and other Ethereum tools
- Check Type Reference for advanced type mappings