Parity Substrate
Solang works with Parity Substrate 3.0. Note that for recent Substrate versions, cross-contract calls as well as using address type as function argument or return values are not supported. We are currently working on fixing any regressions.
The Parity Substrate has the following differences to Ethereum Solidity:
The address type is 32 bytes, not 20 bytes. This is what Substrate calls an “account”
An address literal has to be specified using the
address"5GBWmgdFAMqm8ZgAHGobqDqX6tjLxJhv53ygjNtaaAn3sjeZ"
syntaxABI encoding and decoding is done using the SCALE encoding
Constructors can be named. Constructors with no name will be called
new
in the generated metadata.There is no
ecrecover()
builtin function, or any other function to recover or verify cryptographic signatures at runtimeOnly functions called via rpc may return values; when calling a function in a transaction, the return values cannot be accessed
An assert(), require(), or revert() executes the wasm unreachable instruction. The reason code is lost
There is a solidity example which can be found in the examples directory. Write this to flipper.sol and run:
solang compile --target substrate flipper.sol
Now you should have a file called flipper.contract
. The file contains both the ABI and contract wasm.
It can be used directly in the
Contracts UI, as if the contract was written in ink!.
Builtin Imports
Some builtin functionality is only available after importing. The following types
can be imported via the special import file substrate
.
import {Hash} from 'substrate';
import {chain_extension} from 'substrate';
Note that {Hash}
can be omitted, renamed or imported via
import object.
// Now Hash will be known as InkHash
import {Hash as InkHash} from 'substrate';
Note
The import file substrate
is only available when compiling for the Substrate
target.
Call Flags
The Substrate contracts pallet knows several flags that can be used when calling other contracts.
Solang allows a flags
call argument of type uint32
in the address.call()
function to set desired flags.
By default (if this argument is unset), no flag will be set.
The following example shows how call flags can be used:
library CallFlags {
uint32 constant FORWARD_INPUT = 1;
uint32 constant CLONE_INPUT = 2;
uint32 constant TAIL_CALL = 4;
uint32 constant ALLOW_REENTRY = 8;
}
contract Reentrant {
function reentrant_tail_call(
address _address,
bytes4 selector
) public returns (bytes ret) {
(bool ok, ret) = _address.call{flags: CallFlags.ALLOW_REENTRY}(selector);
require(ok);
}
}