Ga naar de hoofdinhoud

Wat is Yul?

Bijgewerkt op
7 augustus 2026

33 minuten leestijd

Overzicht

Solidity is tot nu toe de dominante taal geweest voor het schrijven van slimme contracten op Ethereum, maar naarmate het ecosysteem blijft groeien en zich verder ontwikkelt, zoeken ontwikkelaars naar nieuwe manieren om hun code te optimaliseren en aan te passen. Yul is een laaggeplaatste taal die een gedetailleerdere controle biedt over de uitvoering van slimme contracten, waardoor het een ideale keuze is voor ontwikkelaars die elke greintje efficiëntie uit hun code willen halen.

Wat je nodig hebt

  • Basiskennis van Ethereum en Solidity (je kunt hier aan de slag)
  • De wil om te leren!

Wat je gaat doen

  • Meer informatie over Yul
  • Duik dieper in de Yul-syntaxis
  • Vergelijk Yul en Solidity

Wat is Yul?

Yul is een tussentaal die wordt gecompileerd tot bytecode voor de Ethereum Virtual Machine (EVM). Het is ontworpen als een laag-niveau-taal die ontwikkelaars een hoge mate van controle biedt over de uitvoering van hun slimme contracten. Het vertoont in veel opzichten gelijkenissen met Assembly, maar beschikt over functies op een hoger niveau die het gebruik ervan vergemakkelijken.

Yul-syntaxis

Gegevenstypen

Yul bevat verschillende ingebouwde gegevenstypen die worden gebruikt om waarden op te slaan en te bewerken. Hieronder volgen enkele van de meest voorkomende gegevenstypen in Yul:

Gehele getallen: Gehele getallen worden gebruikt om gehele getallen weer te geven. In Yul kunnen gehele getallen met of zonder teken zijn en verschillende bitgroottes hebben. Een uint256 is bijvoorbeeld een geheel getal zonder teken met 256 bits. Byte-arrays: Byte-arrays worden gebruikt om reeksen bytes op te slaan. Ze worden vaak gebruikt om gegevens zoals hashes of openbare sleutels weer te geven. In Yul worden byte-arrays gedeclareerd met het sleutelwoord `bytes`, gevolgd door het aantal toe te wijzen bytes. Structuren: Structuren worden gebruikt om gerelateerde gegevens te groeperen. Ze zijn vergelijkbaar met objecten in andere programmeertalen. In Yul worden structuren gedeclareerd met het sleutelwoord `struct`, gevolgd door de namen en typen van elk veld in de structuur. Hier is een voorbeeld van hoe je een structuur in Yul kunt declareren en gebruiken:

struct Persoon {
stringnaam;
uint leeftijd;
}

Variabelen en constanten

Variabelen en constanten worden in Yul gebruikt om gegevens op te slaan en te bewerken. Hier volgt een kort overzicht van hoe je variabelen en constanten in Yul kunt declareren en gebruiken:

Variabelen: Variabelen worden gedeclareerd met het sleutelwoord `let `, gevolgd door de variabelenaam en de waarde. Hier volgt een voorbeeld van hoe je een variabele in Yul declareert:

laat x = 100
laat x //er wordt een beginwaarde van 0 toegewezen

Exploitanten

Operatoren in Yul worden gebruikt om rekenkundige en logische bewerkingen op waarden uit te voeren. Hieronder volgen enkele van de meest voorkomende operatoren in Yul:

Optelling (+): Hiermee worden twee waarden bij elkaar opgeteld. Bijvoorbeeld:

toevoegen(x,y) // x + y

Aftrekken (-): Hiermee trek je de ene waarde van de andere af. Bijvoorbeeld:

sub(x,y) // x - y

Vermenigvuldiging (*): Vermenigvuldigt twee waarden met elkaar. Bijvoorbeeld:

mul(x,y) // x * y

Deling (/): Deelt de ene waarde door de andere. Bijvoorbeeld:

div(x,y) //x / y

Modulus (%): Berekent de rest van een deling. Bijvoorbeeld:

mod(x,y) //x % y

Gelijkwaardig: Controleert of de waarde gelijkwaardig is. Bijvoorbeeld:

x := y // x = y

Controle- Flow -instructies

Controle- flow -instructies in Yul worden gebruikt om de flow van de uitvoering binnen een contract te sturen. Hieronder volgen enkele van de meest voorkomende controle- flow -instructies in Yul. Let op: een “else”-blok kan niet worden gedefinieerd. Overweeg in plaats daarvan “switch” te gebruiken (zie hieronder) als je meerdere alternatieven nodig hebt.

If-instructie:

als lt(calldatasize(), 4) { terugzetten(0, 0) }

Switch-instructie:

{
laat x := 0
schakelaar calldataload(4)
geval 0 {
x := calldataload(0x24)
}
standaard {
x := calldataload(0x44)
}
sstore(0, div(x, 2))
}

For-lus:

// Simple for loop
for {let i := 0} lt(i, 10) {i := add(i, 10)} {
laat p := funcCall(i, 10)
als eq(p, 5) {
verdergaan
}

als eq(p, 90) {
pauze
}
}

Functies

Functies in Yul worden gebruikt om codeblokken in te kapselen die op een later moment kunnen worden uitgevoerd. Hier volgt een voorbeeld van hoe je een functie in Yul declareert en gebruikt:

functie som(a, b) -> ret : u64
{
ret := optellen(b, a)
}

Houd er rekening mee dat Yul-functies uitsluitend mogen werken met de variabelen die als argumenten aan hen worden doorgegeven, aangezien ze geen toegang hebben tot variabelen buiten hun bereik. Het is mogelijk om de typen van de argumenten en retourwaarden te specificeren; als er geen type wordt opgegeven, gebruikt de compiler standaard het type u256.

Montage

Yul bevat ook een inline assemblagetaal waarmee je rechtstreeks in je Yul-contracten code op laag niveau kunt schrijven. Dit kan handig zijn om bepaalde bewerkingen te optimaliseren of om rechtstreeks met de Ethereum Virtual Machine (EVM) te communiceren. Hier volgt een voorbeeld van hoe je inline assemblage in Yul kunt gebruiken:

montage {
laat x := 0
laat y := 1
toevoegen(x, y)
}

Andere ingebouwde functies zijn onder meer:

  • calldata: Een speciale gegevenslocatie in Yul die verwijst naar de invoergegevens die worden doorgegeven aan een functie- of contractaanroep. Deze is alleen-lezen, wat betekent dat je de calldata niet rechtstreeks kunt wijzigen. In plaats daarvan kun je gegevens uit calldata kopiëren naar andere gegevenslocaties, zoals het geheugen of de opslag, met behulp van de calldataload-opcode.
  • revert: Een functie op laag niveau in Yul die wordt gebruikt om de uitvoering van een transactie af te breken en alle aangebrachte statuswijzigingen ongedaan te maken. Deze functie wordt vaak gebruikt om foutcondities in smart contracts af te handelen. Wanneer `revert` wordt aangeroepen, wordt eventueel niet-gebruikte gas terugbetaald aan de aanroeper. De functie accepteert een optioneel argument: een bericht dat aan de aanroeper kan worden teruggestuurd om aanvullende informatie over de fout te verstrekken.

De rest van de lijst vind je hier. Daarnaast werk je in Yul op dezelfde manier met opmerkingen als in Solidity: je kunt // en / / om opmerkingen aan te duiden. Er is echter één uitzondering: identificatoren in Yul mogen punten bevatten (bijv. .).

Raadpleeg de documentatie voor meer informatie over de syntaxis van Yul.

Voorbeelden van Yul

Yul-code wordt geschreven in een teksteditor en gecompileerd met de Solidity-compiler solc. Yul-code bestaat uit een reeks instructies, die elk een specifieke bewerking op de EVM uitvoeren. Deze bewerkingen omvatten rekenkundige en logische bewerkingen, geheugenbeheer en instructies voor besturings flow .

Hier is een voorbeeld van een smart contract voor een ERC-20-token (bron), geschreven in Yul en Solidity:

object "Token" {
code {
// Store the creator in slot zero.
sstore(0, caller())

// Deploy the contract
datacopy(0, dataoffset("runtime"), datasize("runtime"))
terug(0, datasize("runtime"))
}
object "runtime" {
code {
// Protection against sending Ether
vereisen(iszero(callvalue()))

// Dispatcher
schakelaar keuzeschakelaar()
geval 0x70a08231 /* "balanceOf(adres)" */ {
returnUint(saldoVan(decodeAsAddress(0)))
}
geval 0x18160ddd /* "totalSupply()" */ {
returnUint(totalSupply())
}
geval 0xa9059cbb /* "transfer(address,uint256)" */ {
overdracht(decodeAsAddress(0), decodeAsUint(1))
returnTrue()
}
geval 0x23b872dd /* "transferFrom(address,address,uint256)" */ {
transferFrom(decodeAsAddress(0), decodeAsAddress(1), decodeAsUint(2))
returnTrue()
}
geval 0x095ea7b3 /* "approve(address,uint256)" */ {
goedkeuren(decodeAsAddress(0), decodeAsUint(1))
returnTrue()
}
geval 0xdd62ed3e /* "allowance(adres,adres)" */ {
returnUint(toelage(decodeAsAddress(0), decodeAsAddress(1)))
}
geval 0x40c10f19 /* "mint(adres, uint256)" */ {
munt(decodeAsAddress(0), decodeAsUint(1))
returnTrue()
}
standaard {
terugzetten(0, 0)
}

functie munt(account, bedrag) {
vereisen(calledByOwner(())

mintTokens(bedrag)
addToBalance(rekening, bedrag)
emitTransfer(0, rekening, bedrag)
}
functie overdracht(naar, bedrag) {
executeTransfer(caller(), naar, bedrag)
}
functie goedkeuren(betaler, bedrag) {
revertIfZeroAddress(betaler)
setAllowance(aanroeper(), betaler, bedrag)
emitApproval(aanroeper(), betaler, bedrag)
}
functie transferFrom(van, naar, bedrag) {
verlaagToeslagMet(van, beller(), bedrag)
executeTransfer(van, naar, bedrag)
}

functie executeTransfer(van, naar, bedrag) {
revertIfZeroAddress(naar)
van het saldo aftrekken(van, bedrag)
addToBalance(naar, bedrag)
emitTransfer(van, naar, bedrag)
}


/* ---------- Functies voor het decoderen van calldata ----------- */
functie selector() -> s {
s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000)
}

functie decodeAsAddress(offset) -> v {
v := decodeAsUint(offset)
als iszero(iszero(en(v, niet(0xffffffffffffffffffffffffffffffffffffffff)))) {
terugzetten(0, 0)
}
}
functie decodeAsUint(offset) -> v {
laat pos := optellen(4, vermenigvuldigen(offset, 0x20))
als lt(calldatasize(), add(pos, 0x20)) {
terugzetten(0, 0)
}
v := calldataload(pos)
}
/* ---------- functies voor het coderen van calldata ---------- */
functie returnUint(v) {
mstore(0, v)
terug(0, 0x20)
}
functie returnTrue() {
returnUint(1)
}

/* -------- gebeurtenissen ---------- */
functie emitTransfer(van, naar, bedrag) {
laat signatureHash := 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
emitEvent(signatureHash, van, naar, bedrag)
}
functie emitApproval(van, betaler, bedrag) {
laat signatureHash := 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
emitEvent(signatureHash, van, betaler, bedrag)
}
functie emitEvent(signatureHash, indexed1, indexed2, niet-geïndexeerd) {
mstore(0, niet-geïndexeerd)
log3(0, 0x20, signatureHash, indexed1, indexed2)
}

/* -------- opslagindeling ---------- */
function ownerPos() -> p { p := 0 }
function totalSupplyPos() -> p { p := 1 }
functie accountToStorageOffset(account) -> offset {
offset := optellen(0x1000, account)
}
functie allowanceStorageOffset(account, betaler) -> offset {
offset := accountToStorageOffset(account)
mstore(0, offset)
mstore(0x20, betaler)
offset := keccak256(0, 0x40)
}

/* -------- toegang tot opslag ---------- */
functie eigenaar() -> o {
o := sload(ownerPos())
}
functie totalSupply() -> aanbod {
levering := sload(totalSupplyPos())
}
functie mintTokens(bedrag) {
sstore(totalSupplyPos(), safeAdd(totalSupply(), bedrag))
}
functie saldoVan(rekening) -> bal {
bal := sload(accountToStorageOffset(account))
}
functie addToBalance(rekening, bedrag) {
laat offset := accountToStorageOffset(account)
sstore(offset, safeAdd(sload(offset), bedrag))
}
functie aftrekken-van-saldo(rekening, bedrag) {
laat offset := accountToStorageOffset(account)
laat bal := sload(offset)
vereisen(lte(bedrag, saldo))
sstore(offset, sub(bal, bedrag))
}
functie toelage(rekening, uitgever) -> bedrag {
bedrag := sload(allowanceStorageOffset(account, betaler))
}
functie setAllowance(account, betaler, bedrag) {
sstore(opslagverschuiving(account, betaler), bedrag)
}
functie verlaagToelageMet(rekening, betaler, bedrag) {
laat offset := opslagoffset(account, betaler)
laat currentAllowance := sload(offset)
vereisen(lte(bedrag, huidigeToelage))
sstore(offset, sub(currentAllowance, bedrag))
}

/* ---------- hulpprogrammafuncties ---------- */
functie lte(a, b) -> r {
r := iszero(gt(a, b))
}
functie gte(a, b) -> r {
r := iszero(lt(a, b))
}
functie safeAdd(een, b) -> r {
r := optellen(a, b)
als of(lt(r, a), lt(r, b)) { terugzetten(0, 0) }
}
functie calledByOwner() -> cbo {
cbo := eq(eigenaar(), beller())
}
functie revertIfZeroAddress(addr) {
vereisen(addr)
}
functie require(voorwaarde) {
als iszero(voorwaarde) { terugzetten(0, 0) }
}
}
}
}

Neem even de tijd om de bovenstaande code door te nemen. Veel van de syntaxis die we in het hoofdstuk ‘Yul-syntaxis’ hebben behandeld, is in de bovenstaande code geïmplementeerd. Je kunt ook overschakelen naar het tabblad ‘ERC-20 in Solidity’ om te zien hoe dit contract in Solidity is geschreven.

Yul versus Solidity

Yul is geen vervanging voor Solidity, maar eerder een aanvullende taal die in combinatie daarmee kan worden gebruikt. Yul is veel lager in niveau dan Solidity en is ontworpen om meer directe controle te bieden over de uitvoering van smart contracts. Hierdoor kan Yul-code efficiënter zijn dan vergelijkbare Solidity-code, maar ook moeilijker te schrijven en te begrijpen.

Daarentegen is Solidity een programmeertaal op een hoger niveau die ontwikkelaars meer abstractie en gebruiksvriendelijkere functies biedt. De taal is zo ontworpen dat ze toegankelijker is voor ontwikkelaars die niet vertrouwd zijn met programmeerconcepten op laag niveau.

Yul-hulpmiddelen en bronnen

Er zijn online tal van bronnen beschikbaar als je meer wilt weten over Yul en hoe je het kunt gebruiken bij het ontwikkelen van slimme contracten. De Solidity-documentatie bevat een hoofdstuk over Yul en een Yul-handleiding. Daarnaast zijn er veel blogberichten, artikelen en video’s waarin Yul uitgebreider wordt behandeld.

Er zijn verschillende hulpmiddelen beschikbaar om met Yul te werken, zoals:

  • Remix.IDE: Voor het compileren en implementeren van smart contracts die in Yul zijn geschreven
  • Hardhat: Plug-ins voor het ontwikkelen van slimme contracten met Yul en/of Yul+
  • Solc-compiler: Yul-code naar bytecode compileren

Afsluitende gedachten

Yul is een krachtig hulpmiddel voor ontwikkelaars van slimme contracten die hun code willen optimaliseren op het gebied van efficiëntie en prestaties. Hoewel het misschien niet voor alle ontwikkelaars geschikt is, zullen degenen die vertrouwd zijn met programmeerconcepten op laag niveau en hun code willen verfijnen, Yul als een waardevolle aanvulling op hun toolkit ervaren. We hopen dat deze handleiding je een goed beeld heeft gegeven van Yul en zijn mogelijkheden, en we moedigen je aan om het verder te verkennen en te ontdekken wat Yul voor jou kan betekenen!

Als je ergens mee zit, vragen hebt of gewoon even wilt praten over wat je aan het bouwen bent, stuur ons dan een berichtje op Discord of Twitter!