Skip to main content
Version: v6

Cross Contract Title Picture

Calling Solidity Contracts

ink! v6 contracts can call Solidity ABI-encoded contracts, enabling seamless interoperability between ink!, Solidity, and other Solidity ABI-compatible contracts. This allows you to integrate with existing Ethereum-compatible smart contracts deployed on Polkadot.

There are two main approaches to calling Solidity contracts from ink!:

  1. Contract References (ContractRef) - High-level, type-safe interfaces
  2. Builders (CreateBuilder and CallBuilder) - Low-level control over call parameters

Using Contract References

Contract references provide a high-level type-safe interface for interacting with on-chain contracts. When working with Solidity ABI contracts, you can use manually defined contract references with the #[ink::contract_ref] attribute.

Using CreateBuilder with Solidity ABI

The CreateBuilder allows you to instantiate Solidity ABI-encoded contracts. To instantiate a contract that uses Solidity ABI, use the build_create_sol utility:

use ink::env::call::build_create_sol;

let my_contract: MyContractRefSol = build_create_sol::<MyContractRefSol>()
.code_hash(Hash::from([0x42; 32]))
.ref_time_limit(0)
.endowment(10)
.exec_input(
ExecutionInput::new(Selector::new(ink::selector_bytes!("new")))
.push_arg(42)
.push_arg(true)
)
.salt_bytes(&[0xDE, 0xAD, 0xBE, 0xEF])
.returns::<MyContractRefSol>()
.instantiate();

Using CallBuilder with Solidity ABI

The CallBuilder enables you to call messages from Solidity ABI-encoded contracts using low-level control. This approach is particularly useful when you need to call contracts with different ABIs.

Solidity ABI Calls

To call Solidity ABI-encoded contracts, use the build_call_sol utility. This requires using a Solidity-compatible function selector computed with a keccak256 hash of the function signature:

use ink::env::call::build_call_sol;

let my_return_value = build_call_sol::<DefaultEnvironment>()
.call(H160::from([0x42; 20]))
.ref_time_limit(0)
.transferred_value(10)
.exec_input(
ExecutionInput::new([0xcd, 0xe4, 0xef, 0xa9].into()) // solidity selector: keccak256("flip()")
)
.returns::<bool>()
.invoke();
info

Key differences from ink! calls:

  • Solidity uses keccak256 hashing for function selectors (first 4 bytes)
  • ink! uses blake2b hashing for function selectors
  • Use build_call_sol for Solidity contracts instead of build_call

Error Handling

Both CreateBuilder and CallBuilder offer error handling with try_instantiate() and try_invoke() methods respectively. These allow you to handle:

  1. Errors from the underlying execution environment (e.g. the Contracts pallet)
  2. Errors from the programming language (e.g. LangErrors)

See the documentation for try_instantiate, try_invoke, ink::env::Error, and ink::LangError for more details.

Learn More