Language center¶
Each tab is the same contract — increment() (emits Incremented(uint256) where the language supports events),
get() returns (uint256) — so you can compare languages on identical behaviour. Selecting a tab switches every tab
group on the site.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
/// Starter counter (Solidity 0.8.26). Unaudited example.
contract Counter {
uint256 private count;
address public immutable creator;
event Incremented(uint256 value);
constructor() {
creator = msg.sender;
}
function increment() external {
count += 1;
emit Incremented(count);
}
function get() external view returns (uint256) {
return count;
}
}
# pragma version 0.4.3
# Starter counter (Vyper 0.4.3). Unaudited example.
event Incremented:
value: uint256
CREATOR: public(immutable(address))
count: uint256
@deploy
def __init__():
CREATOR = msg.sender
@external
def increment():
self.count += 1
log Incremented(value=self.count)
@view
@external
def get() -> uint256:
return self.count
// 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) }
}
}
}
/* Starter counter (Huff, compiled by Huff Neo hnc 1.7.1). Unaudited example. */
#define function increment() nonpayable returns ()
#define function get() view returns (uint256)
#define event Incremented(uint256 value)
#define constant COUNT_SLOT = FREE_STORAGE_POINTER()
#define macro INCREMENT() = takes (0) returns (0) {
[COUNT_SLOT] sload 0x01 add // [v]
dup1 [COUNT_SLOT] sstore // [v]
0x00 mstore // []
__EVENT_HASH(Incremented) 0x20 0x00 log1
stop
}
#define macro GET() = takes (0) returns (0) {
[COUNT_SLOT] sload 0x00 mstore
0x20 0x00 return
}
#define macro MAIN() = takes (0) returns (0) {
callvalue iszero novalue jumpi
0x00 0x00 revert
novalue:
0x00 calldataload 0xE0 shr
dup1 __FUNC_SIG(increment) eq inc jumpi
dup1 __FUNC_SIG(get) eq get jumpi
0x00 0x00 revert
inc: INCREMENT()
get: GET()
}
// Starter counter (Fe 26.5.1, EXPERIMENTAL). Unaudited example.
use std::abi::sol
msg CounterMsg {
#[selector = sol("increment()")]
Increment,
#[selector = sol("get()")]
Get -> u256,
}
struct CounterStore {
value: u256,
}
pub contract Counter {
mut store: CounterStore
init() uses (mut store) {
store.value = 0
}
recv CounterMsg {
Increment uses (mut store) {
store.value = store.value + 1
}
Get -> u256 uses (store) {
store.value
}
}
}
Measured on chain 77240¶
All five were compiled with the pinned toolchains (target cancun), deployed, incremented once and read back by the
script below on a disposable local testnet.
| Language | Runtime bytes | Deployment gas | increment() gas |
get() after one increment |
|---|---|---|---|---|
| Solidity 0.8.26 (optimizer 200, no metadata hash) | 288 | 115,466 | 44,587 | 1 |
| Vyper 0.4.3 | 207 | 98,394 | 44,431 | 1 |
Yul (solc 0.8.26 --strict-assembly --optimize) |
93 | 73,278 | 44,248 | 1 |
| Huff Neo 1.7.1 | 98 | 74,312 | 44,252 | 1 |
| Fe 26.5.1 (experimental) | 99 | 77,010 | 43,304 | 1 |
increment() cost is dominated by the cold SSTORE from zero to one (~22,100 gas) plus the 21,000 transaction base;
the Solidity and Vyper versions also store an immutable creator at deployment. Fe's counter emits no event, which
is why its call is cheaper — compare behaviour, not just numbers.
# Compile the same Counter (increment(), get()) in five languages, deploy each one, call it, and
# print the measured gas. Compilers: SOLC (solc 0.8.26), VYPER (0.4.3), HNC (Huff Neo 1.7.1), FE (Fe 26.5.1).
SOLC=${SOLC:-solc}; VYPER=${VYPER:-vyper}; HNC=${HNC:-hnc}; FE=${FE:-fe}
W="--keystore $KEYSTORE --password-file $PASSWORD_FILE --rpc-url $RPC"
mkdir -p out
"$SOLC" --evm-version cancun --optimize --metadata-hash none --bin Counter.sol -o out/sol --overwrite >/dev/null
cp out/sol/Counter.bin out/solidity.bin
"$VYPER" --evm-version cancun -f bytecode Counter.vy > out/vyper.bin
"$SOLC" --strict-assembly --evm-version cancun --optimize --bin Counter.yul | sed -n '/Binary representation:/{n;p;}' > out/yul.bin
"$HNC" Counter.huff -b -e cancun | tail -n 1 > out/huff.bin
"$FE" build --standalone Counter.fe >/dev/null && cp out/Counter.bin out/fe.bin
printf '%-9s %8s %10s %10s %s\n' language runtimeB deployGas incrGas "get() after 1 increment"
for L in solidity vyper yul huff fe; do
BIN=0x$(tr -d ' \r\n' < out/$L.bin | sed 's/^0x//')
TX=$(cast send --async $W --create "$BIN")
ADDR=$(cast receipt "$TX" contractAddress --rpc-url "$RPC")
DGAS=$(cast receipt "$TX" gasUsed --rpc-url "$RPC")
RT=$(cast code "$ADDR" --rpc-url "$RPC")
TX2=$(cast send "$ADDR" "increment()" --async $W)
IGAS=$(cast receipt "$TX2" gasUsed --rpc-url "$RPC")
printf '%-9s %8s %10s %10s %s\n' "$L" $(( (${#RT} - 2) / 2 )) "$DGAS" "$IGAS" "$(cast call "$ADDR" 'get()(uint256)' --rpc-url "$RPC")"
done
Choosing a language¶
| Need | Choose |
|---|---|
| OpenZeppelin, audits, largest ecosystem | Solidity |
| Fewer footguns, readable code, no inline assembly | Vyper |
| Tight control in a few hot paths | Yul (inline in Solidity or standalone) |
| Maximal control over every opcode | Huff — only with expert review |
| Research on new language designs | Fe — experimental, never value-bearing |
JavaScript, TypeScript and Python are application languages on PQWERAI: they build transactions and read state, they do not run on chain (details).
Sources at 72057fe3ec: developers/examples/languages/Counter.sol · developers/examples/languages/Counter.vy · developers/examples/languages/Counter.yul · developers/examples/languages/Counter.huff · developers/examples/languages/Counter.fe · developers/examples/languages/build-and-deploy-all.sh
Found a problem? Report a documentation issue · Build testnet-rc1+72057fe3ec