Yul¶
| Compiler | solc 0.8.26 --strict-assembly |
| EVM target | --evm-version cancun |
| ABI | None generated — you write the dispatcher and declare the ABI yourself |
| Status | ✅ Tested: compile, deploy, call |
Example¶
The // @abi comments are the convention the Wallet Studio reads to build a call interface for Yul and Huff.
Counter.yul
// Starter counter (Yul, compiled by solc 0.8.26). Unaudited example.
// The ABI is declared here because Yul has none:
// @abi function increment() nonpayable returns ()
// @abi function get() view returns (uint256)
// @abi event Incremented(uint256 value)
object "Counter" {
code {
datacopy(0, dataoffset("runtime"), datasize("runtime"))
return(0, datasize("runtime"))
}
object "runtime" {
code {
if callvalue() { revert(0, 0) }
switch shr(224, calldataload(0))
case 0xd09de08a /* increment() */ {
let v := add(sload(0), 1)
sstore(0, v)
mstore(0, v)
// keccak256("Incremented(uint256)")
log1(0, 32, 0x20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d84)
return(0, 0)
}
case 0x6d4ce63c /* get() */ {
mstore(0, sload(0))
return(0, 32)
}
default { revert(0, 0) }
}
}
}
Compile and deploy¶
solc --strict-assembly --evm-version cancun --optimize --bin Counter.yul \
| sed -n '/Binary representation:/{n;p;}' > Counter.bin
TX=$(cast send --async --keystore "$KEYSTORE" --password-file "$PASSWORD_FILE" --rpc-url "$RPC" --create "0x$(cat Counter.bin)")
ADDR=$(cast receipt "$TX" contractAddress --rpc-url "$RPC")
cast send "$ADDR" "increment()" --keystore "$KEYSTORE" --password-file "$PASSWORD_FILE" --rpc-url "$RPC"
cast call "$ADDR" "get()(uint256)" --rpc-url "$RPC"
Manual ABI for tools (Counter.abi.json):
[{"type":"function","name":"increment","inputs":[],"outputs":[],"stateMutability":"nonpayable"},
{"type":"function","name":"get","inputs":[],"outputs":[{"name":"","type":"uint256"}],"stateMutability":"view"},
{"type":"event","name":"Incremented","inputs":[{"name":"value","type":"uint256","indexed":false}],"anonymous":false}]
Measured: 93 runtime bytes, 73,278 deployment gas, 44,248 gas for increment().
Caveats¶
- No overflow checks, no ABI decoding, no reentrancy protection unless you write them.
- Selectors and event topics are hard-coded; a typo silently breaks the interface — test every function.
- Prefer Yul inside Solidity (
assembly { … }) for a few hot paths over whole-contract Yul.
Sources at 72057fe3ec: developers/examples/languages/Counter.yul
Found a problem? Report a documentation issue · Build testnet-rc1+72057fe3ec