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:
- ERC-20 in Yul
- ERC-20 in 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) }
}
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
pragma solidity ^0,8,0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementatie van de {IERC20} interface.
*
* Deze implementatie is onafhankelijk van de manier waarop tokens worden aangemaakt. Dit betekent
* dat er in een afgeleid contract een leveringsmechanisme moet worden toegevoegd met behulp van {_mint}.
* Zie voor een algemeen werkingsmechanisme {ERC20PresetMinterPauser}.
*
* TIP: Zie onze handleiding voor een uitgebreide beschrijving
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[Hoe
* om bevoorradingsmechanismen in te voeren].
*
* De standaardwaarde van {decimale cijfers} is 18. Om dit te wijzigen, moet u
* deze functie, zodat deze een andere waarde retourneert.
*
* We hebben de algemene richtlijnen van OpenZeppelin Contracts gevolgd: functies met de `revert`-methode
* en geeft bij een fout `false` terug. Dit gedrag is niettemin
* conventioneel en in overeenstemming met de verwachtingen van ERC20
* toepassingen.
*
* Daarnaast is er een {Goedkeuring} gebeurtenis bij aanroepen van {transferFrom}.
* Hierdoor kunnen applicaties de toewijzing voor alle rekeningen eenvoudig reconstrueren
* door naar die gebeurtenissen te luisteren. Andere implementaties van de EIP geven mogelijk geen
* deze gebeurtenissen, aangezien dit niet door de specificatie wordt vereist.
*
* Tot slot, de niet-standaard {decreaseAllowance} en {toelageVerhogen}
* er zijn functies toegevoegd om de bekende problemen rond de instelling te verhelpen
* vergoedingen. Zie {IERC20-goedkeuren}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
in kaart brengen(adres => uint256) privé _balances;
in kaart brengen(adres => toewijzing(adres => uint256)) privé _toelagen;
uint256 privé _totalSupply;
tekenreeks privé _naam;
tekenreeks privé _symbool;
/**
* @dev Stelt de waarden in voor {naam} en {symbool}.
*
* Deze twee waarden zijn allebe immutable: ze kunnen slechts één keer worden ingesteld tijdens
* bouw.
*/
constructor(string memory name_, string memory symbol_) {
_naam = naam_;
_symbool = symbool_;
}
/**
* @dev Geeft de naam van het token terug.
*/
functie naam() openbaar weergave virtuele overschrijving retourneert (string geheugen) {
terug _naam;
}
/**
* @dev Geeft het symbool van het token terug, meestal een kortere versie van de
* naam.
*/
functie symbool() openbaar weergave virtuele overschrijving retourneert (string geheugen) {
terug _symbool;
}
/**
* @dev Geeft het aantal decimalen terug dat wordt gebruikt om de gebruikersweergave te genereren.
* Als `decimals` bijvoorbeeld gelijk is aan `2`, zou een saldo van `505` tokens
* aan een gebruiker worden weergegeven als `5,05` (`505 / 10 ** 2`).
*
* Bij tokens wordt meestal gekozen voor een waarde van 18, waarmee de verhouding tussen
* Ether en Wei. Dit is de standaardwaarde die door deze functie wordt geretourneerd, tenzij
* het wordt overschreven.
*
* OPMERKING: Deze informatie wordt uitsluitend gebruikt voor _weergave_doeleinden: deze
* heeft op geen enkele wijze invloed op de rekenkundige aspecten van het contract, met inbegrip van
* {IERC20-saldo van} en {IERC20-transfer}.
*/
functie decimalen() public weergave virtuele overschrijving retourneert (uint8) {
terug 18;
}
/**
* @dev Zie {IERC20-totalSupply}.
*/
functie totalSupply() public weergave virtueel overschrijven retourneert (uint256) {
terug _totalSupply;
}
/**
* @dev Zie {IERC20-saldo van}.
*/
functie saldoVan(adres rekening) public weergave virtueel overschrijven retourneert (uint256) {
terug _saldi[rekening];
}
/**
* @dev Zie {IERC20-overdracht}.
*
* Vereisten:
*
* - `to` mag niet het adres nul zijn.
* - de beller moet een saldo hebben van ten minste `bedrag`.
*/
functie overdracht(adres naar, uint256 bedrag) public virtueel overschrijven retourneert (bool) {
eigenaar van het adres = _msgSender();
_overdracht(eigenaar, naar, bedrag);
terug true;
}
/**
* @dev Zie {IERC20-toelage}.
*/
functie toelage(eigenaar van het adres, adresgebruiker) public weergave virtuele overschrijving retourneert (uint256) {
terug _toelagen[eigenaar][uitgever];
}
/**
* @dev Zie {IERC20-goedkeuren}.
*
* OPMERKING: Als `amount` de maximale waarde voor `uint256` is, wordt de toewijzing niet bijgewerkt op
* `transferFrom`. Dit komt semantisch gezien neer op een oneindige goedkeuring.
*
* Vereisten:
*
* - `spender` mag niet het adres nul zijn.
*/
functie goedkeuren(adres van de betaler, uint256 bedrag) public virtueel overschrijft retourneert (bool) {
eigenaar van het adres = _msgSender();
_goedkeuren(eigenaar, betaler, bedrag);
terug true;
}
/**
* @dev Zie {IERC20-transferFrom}.
*
* Geeft een {Goedkeuring} gebeurtenis die de bijgewerkte toewijzing aangeeft. Dit is geen
* vereist door het EIP. Zie de opmerking aan het begin van {ERC20}.
*
* OPMERKING: De toelage wordt niet bijgewerkt als de huidige toelage
* is de maximale waarde van `uint256`.
*
* Vereisten:
*
* - `from` en `to` mogen niet het adres nul zijn.
* - `from` moet een saldo hebben van ten minste `amount`.
* - de beller moet beschikken over voldoende tegoed voor de tokens van ``from``, namelijk ten minste
* `bedrag`.
*/
functie transferFrom(adres van, adres naar, uint256 bedrag) public virtueel overschrijven retourneert (bool) {
adres van de betaler = _msgSender();
_spendAllowance(van, uitgever, bedrag);
_overdracht(van, naar, bedrag);
terug true;
}
/**
* @dev Verhoogt op atomaire wijze de toewijzing die door de aanroeper aan `spender` is toegekend.
*
* Dit is een alternatief voor {goedkeuren} dat kan worden gebruikt als maatregel ter beperking van
* problemen die worden beschreven in {IERC20-approve}.
*
* Geeft een {Goedkeuring} gebeurtenis die de bijgewerkte toewijzing aangeeft.
*
* Vereisten:
*
* - `spender` mag niet het adres nul zijn.
*/
functie increaseAllowance(adres van de besteder, uint256 toegevoegdeWaarde) public virtueel retourneert (bool) {
eigenaar van het adres = _msgSender();
_goedkeuren(eigenaar, betaler, toelage(eigenaar, uitgever) + toegevoegde waarde);
terug true;
}
/**
* @dev Verlaagt op atomische wijze de toewijzing die door de aanroeper aan `spender` is toegekend.
*
* Dit is een alternatief voor {goedkeuren} dat kan worden gebruikt als maatregel ter beperking van
* problemen die worden beschreven in {IERC20-approve}.
*
* Geeft een {Goedkeuring} gebeurtenis die de bijgewerkte toewijzing aangeeft.
*
* Vereisten:
*
* - `spender` mag niet het adres nul zijn.
* - `spender` moet voor de aanroeper een toewijzing hebben van ten minste
* `subtractedValue`.
*/
functie decreaseAllowance(adres van de besteder, uint256 afgetrokkenWaarde) public virtueel retourneert (bool) {
eigenaar van het adres = _msgSender();
uint256 currentAllowance = toegestane waarde(eigenaar, uitgever);
vereisen(huidigeToelage >= afgetrokkenWaarde, "ERC20: toelage gedaald tot onder nul");
niet aangevinkt {
_goedkeuren(eigenaar, betaler, huidigeToelage - afgetrokkenWaarde);
}
terug true;
}
/**
* @dev Verplaatst `amount` tokens van `from` naar `to`.
*
* Deze interne functie komt overeen met {overdracht}, en kan worden gebruikt om
* bijv. automatische tokenvergoedingen, slashing-mechanismen, enz. implementeren
*
* Geeft een {Overdracht} gebeurtenis.
*
* Vereisten:
*
* - `from` mag niet het adres 0 zijn.
* - `to` mag niet het adres nul zijn.
* - `from` moet een saldo hebben van ten minste `amount`.
*/
functie _transfer(adres van, adres naar, uint256 bedrag) intern virtueel {
vereisen(van != adres(0), "ERC20: overboeking vanaf het nuladres");
vereisen(moet != adres(0), "ERC20: overboeking naar het nuladres");
_beforeTokenTransfer(van, naar, bedrag);
uint256 fromBalance = _balances[van];
vereisen(fromBalance >= bedrag, "ERC20: het over te maken bedrag is hoger dan het saldo");
niet aangevinkt {
_saldi[uit] = fromBalance - bedrag;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_saldi[naar] += bedrag;
}
uitstralen Overdracht(van, naar, bedrag);
_afterTokenTransfer(van, naar, bedrag);
}
/** @dev Maakt `amount` tokens aan en wijst deze toe aan `account`, waardoor
* het totale aanbod.
*
* Geeft een {Overdracht} gebeurtenis waarbij `from` is ingesteld op het adres nul.
*
* Vereisten:
*
* - `account` mag niet het adres nul zijn.
*/
functie _mint(adres account, uint256 bedrag) intern virtueel {
vereisen(account != adres(0), "ERC20: mint naar het nuladres");
_beforeTokenTransfer(adres(0), account, bedrag);
_totaalaanbod += hoeveelheid;
niet aangevinkt {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_saldi[rekening] += bedrag;
}
uitstralen Overdracht(adres(0), account, bedrag);
_afterTokenTransfer(adres(0), account, bedrag);
}
/**
* @dev Verwijdert `amount` tokens van `account`, waardoor het
* totale voorraad.
*
* Geeft een {Overdracht} gebeurtenis waarbij `to` is ingesteld op het adres nul.
*
* Vereisten:
*
* - `account` mag niet het adres nul zijn.
* - `account` moet ten minste `amount` tokens bevatten.
*/
functie _burn(adres account, uint256 bedrag) intern virtueel {
vereisen(account != adres(0), "ERC20: vernietigen vanaf het nuladres");
_beforeTokenTransfer(account, adres(0), bedrag);
uint256 accountBalance = _balances[account];
vereisen(accountBalance >= bedrag, "ERC20: het te vernietigen bedrag is hoger dan het saldo");
niet aangevinkt {
_saldi[rekening] = rekeningsaldo - bedrag;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= hoeveelheid;
}
uitstralen Overdracht(rekening, adres(0), bedrag);
_afterTokenTransfer(account, adres(0), bedrag);
}
/**
* @dev Stelt `amount` in als het bedrag dat `spender` mag besteden van de tokens van `owner`.
*
* Deze interne functie komt overeen met `approve` en kan worden gebruikt om
* bijv. automatische toewijzingen instellen voor bepaalde subsystemen, enz.
*
* Geeft een {Goedkeuring} gebeurtenis uit.
*
* Vereisten:
*
* - `owner` mag niet het adres 0 zijn.
* - `spender` mag niet het adres nul zijn.
*/
functie _approve(adres eigenaar, adres spender, uint256 bedrag) intern virtueel {
vereisen(eigenaar != adres(0), "ERC20: goedkeuring vanaf het nuladres");
vereisen(uitgever != adres(0), "ERC20: goedkeuren naar het nuladres");
_toelagen[eigenaar][uitgever] = bedrag;
uitstoten Goedkeuring(eigenaar, betaler, bedrag);
}
/**
* @dev Past de toelage van `eigenaar` voor `uitgever` aan op basis van het uitgegeven `bedrag`.
*
* Het vergoedingsbedrag wordt niet bijgewerkt als er sprake is van een onbeperkte vergoeding.
* Terugzetten als er onvoldoende tegoed beschikbaar is.
*
* Kan een {Goedkeuring} gebeurtenis.
*/
functie _spendAllowance(adres eigenaar, adres besteder, uint256 bedrag) intern virtueel {
uint256 currentAllowance = toegestane waarde(eigenaar, uitgever);
als (huidigeToelage != type(uint256).max) {
vereisen(huidigeToelage >= bedrag, "ERC20: onvoldoende toewijzing");
niet aangevinkt {
_goedkeuren(eigenaar, betaler, huidigeToelage - bedrag);
}
}
}
/**
* @dev Hook die wordt aangeroepen vóór elke overdracht van tokens. Dit omvat
* uitgifte en vernietiging.
*
* Voorwaarden voor het bellen:
*
* - wanneer `from` en `to` beide niet nul zijn, het `aantal` tokens van ``from``
* wordt overgebracht naar `to`.
* - wanneer `from` nul is, worden er `amount` tokens geslagen voor `to`.
* - wanneer `to` gelijk is aan nul, worden `amount` tokens van ``from`` vernietigd.
* - `from` en `to` zijn nooit allebei nul.
*
* Ga voor meer informatie over hooks naar xref:ROOT:extending-contracts.adoc#using-hooks[Hooks gebruiken].
*/
functie _beforeTokenTransfer(adres van, adres naar, uint256 bedrag) intern virtueel {}
/**
* @dev Hook die wordt aangeroepen na elke overdracht van tokens. Dit omvat
* uitgifte en vernietiging.
*
* Voorwaarden voor het bellen:
*
* - wanneer `from` en `to` beide niet nul zijn, het `aantal` tokens van ``from``
* is overgeheveld naar `to`.
* - wanneer `from` nul is, zijn er `amount` tokens geslagen voor `to`.
* - wanneer `to` gelijk is aan nul, is het `amount` aantal tokens van ``from`` vernietigd.
* - `from` en `to` zijn nooit allebei nul.
*
* Ga voor meer informatie over hooks naar xref:ROOT:extending-contracts.adoc#using-hooks[Hooks gebruiken].
*/
functie _afterTokenTransfer(adres van, adres naar, uint256 bedrag) intern virtueel {}
}
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!
