Unités et variables disponibles dans le monde entier
Unités d’éther
Un nombre littéral peut prendre un suffixe de wei
, gwei
ou ether
pour spécifier une sous-dénomination d’Ether, où les nombres d’Ether sans postfixe sont supposés être Wei.
assert(1 wei == 1);
assert(1 gwei == 1e9);
assert(1 ether == 1e18);
Le seul effet du suffixe de sous-dénomination est une multiplication par une puissance de dix.
Note
Les dénominations finney
et szabo
ont été supprimées dans la version 0.7.0.
Unités de temps
Les suffixes comme seconds
, minutes
, hours
, days
et weeks
,
après des nombres littéraux, peuvent être utilisés pour spécifier des unités de temps où les secondes sont
l’unité de base et les unités sont considérées naïvement de la manière suivante :
1 == 1 seconds
1 minutes == 60 seconds
1 hours == 60 minutes
1 days == 24 hours
1 weeks == 7 days
Faites attention si vous effectuez des calculs de calendrier en utilisant ces unités, car chaque année n’est pas égale à 365 jours et chaque jour n’a pas 24 heures à cause des secondes intercalaires. En raison du fait que les secondes intercalaires ne peuvent pas être prédites, un calendrier exact doit être mis à jour par une bibliothèque doit être mise à jour par un oracle externe.
Note
Le suffixe years
a été supprimé dans la version 0.5.0 pour les raisons ci-dessus.
Ces suffixes ne peuvent pas être appliqués aux variables. Par exemple, si vous voulez interpréter un paramètre de fonction en jours, vous pouvez le faire de la manière suivante :
function f(uint start, uint daysAfter) public {
if (block.timestamp >= start + daysAfter * 1 days) {
// ...
}
}
Variables et fonctions spéciales
Certaines variables et fonctions spéciales existent toujours dans l’espace de nom global, et sont principalement utilisées pour fournir des informations sur la blockchain, ou sont des fonctions utilitaires d’usage général.
Propriétés des blocs et des transactions
blockhash(uint blockNumber) retourne (bytes32)
: hachage du bloc donné siblocknumber
est l’un des 256 blocs les plus récents ; sinon retourne zéro.block.basefee
(uint
): la redevance de base du bloc actuel (EIP-3198 et EIP-1559)block.chainid
(uint
): identifiant de la chaîne actuelleblock.coinbase
(address payable
): adresse du mineur du bloc actuelblock.difficulty
(uint
): difficulté actuelle du blocblock.gaslimit
(uint
): limite de gaz du bloc actuelblock.number
(uint
): numéro du bloc actuelblock.timestamp
(uint
): horodatage du bloc actuel en secondes depuis l’époque unixgasleft() returns (uint256)
: gaz résiduelmsg.data
(bytes calldata
): données d’appel complètesmsg.sender
(address
): expéditeur du message (appel en cours)msg.sig
(bytes4
): les quatre premiers octets des données d’appel (c’est-à-dire l’identifiant de la fonction)msg.value
(uint
): nombre de wei envoyés avec le messagetx.gasprice
(uint
): prix du gaz de la transactiontx.origin
(address
): expéditeur de la transaction (chaîne d’appel complète)
Note
Les valeurs de tous les membres de msg
, y compris msg.sender
et
msg.value
peuvent changer à chaque appel de fonction externe.
Cela inclut les appels aux fonctions de la bibliothèque.
Note
Lorsque les contrats sont évalués hors chaîne plutôt que dans le contexte d’une transaction comprise dans un
bloc, vous ne devez pas supposer que block.*
et tx.*
font référence à des valeurs
d’un bloc ou d’une transaction spécifique. Ces valeurs sont fournies par l’implémentation EVM qui exécute le
contrat et peuvent être arbitraires.
Note
Ne comptez pas sur block.timestamp
ou blockhash
comme source d’aléatoire,
à moins que vous ne sachiez ce que vous faites.
L’horodatage et le hachage du bloc peuvent tous deux être influencés par les mineurs dans une certaine mesure. De mauvais acteurs dans la communauté minière peuvent par exemple exécuter une fonction de paiement de casino sur un hash choisi et réessayer un autre hash s’ils n’ont pas reçu d’argent.
L’horodatage du bloc actuel doit être strictement plus grand que l’horodatage du dernier bloc, mais la seule garantie est qu’il se situera quelque part entre les horodatages de deux blocs consécutifs dans la chaîne canonique.
Note
Les hachages des blocs ne sont pas disponibles pour tous les blocs pour des raisons d’évolutivité. Vous ne pouvez accéder qu’aux hachages des 256 blocs les plus récents. autres valeurs seront nulles.
Note
La fonction blockhash
était auparavant connue sous le nom de block.blockhash
, qui a été dépréciée dans la
version 0.4.22 et supprimée dans la version 0.5.0.
Note
La fonction gasleft
était auparavant connue sous le nom de msg.gas
, qui a été dépréciée dans la
version 0.4.21 et supprimée dans la version 0.5.0.
Note
Dans la version 0.7.0, l’alias now
(pour block.timestamp
) a été supprimé.
Fonctions de codage et de décodage de l’ABI
abi.decode(bytes memory encodedData, (...)) retourne (...)
: ABI-décode les données données, tandis que les types sont donnés entre parenthèses comme deuxième argument. Exemple :(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))
abi.encode(...) returns (bytes memory)
: ABI-encode les arguments donnésabi.encodePacked(...) returns (bytes memory)
: Effectue l’encodage emballé des arguments donnés. Notez que l’encodage emballé peut être ambigu !abi.encodeWithSelector(bytes4 selector, ...) retourne (bytes memory)
: ABI-encode les arguments donnés en commençant par le deuxième et ajoute en préambule le sélecteur de quatre octets donné.abi.encodeWithSignature(string memory signature, ...) retourne (bytes memory)
: Équivalent àabi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)
abi.encodeCall(function functionPointer, (...)) retourne (bytes memory)
: ABI-encode un appel àfunctionPointer
avec les arguments trouvés dans le tuple. Effectue un contrôle de type complet, en s’assurant que les types correspondent à la signature de la fonction. Le résultat est égal àabi.encodeWithSelector(functionPointer.selector, (...))
Note
Ces fonctions d’encodage peuvent être utilisées pour créer des données pour les appels de fonctions externes sans réellement
appeler une fonction externe. De plus, keccak256(abi.encodePacked(a, b))
est un moyen
de calculer le hachage de données structurées (attention, il est possible
de créer une « collision de hachage » en utilisant différents types de paramètres de fonction).
Reportez-vous à la documentation sur le ABI et le codage étroitement emballé pour plus de détails sur le codage.
Membres des octets
bytes.concat(...) retourne (bytes memory)
: Concatène un nombre variable d’octets et les arguments bytes1, …, bytes32 dans un tableau d’octets.
Traitement des erreurs
Consultez la section dédiée à assert et require pour plus de détails sur la gestion des erreurs et quand utiliser telle ou telle fonction.
assert(bool condition)
provoque une erreur de panique et donc un changement d’état si la condition n’est pas remplie - à utiliser pour les erreurs internes.
require(bool condition)
revient en arrière si la condition n’est pas remplie - à utiliser pour les erreurs dans les entrées ou les composants externes.
require(bool condition, string memory message)
fait marche arrière si la condition n’est pas remplie - à utiliser pour les erreurs dans les entrées ou les composants externes. Fournit également un message d’erreur.
revert()
interrompt l’exécution et renverse les changements d’état
revert(string memory reason)
interrompt l’exécution et annule les changements d’état, en fournissant une chaîne explicative.
Fonctions mathématiques et cryptographiques
addmod(uint x, uint y, uint k) retourne (uint)
calcule
(x + y) % k
où l’addition est effectuée avec une précision arbitraire et ne s’arrête pas à2**256
. Affirme quek != 0
à partir de la version 0.5.0.mulmod(uint x, uint y, uint k) retourne (uint)
calcule
(x * y) % k
où la multiplication est effectuée avec une précision arbitraire et ne s’arrête pas à2**256
. Affirme quek != 0
à partir de la version 0.5.0.keccak256(octets mémoire) retourne (octets32)
calcule le hachage Keccak-256 de l’entrée
Note
Il y avait auparavant un alias pour keccak256
appelé sha3
, qui a été supprimé dans la version 0.5.0.
sha256(bytes memory) retourne (bytes32)
calcule le hachage SHA-256 de l’entrée
ripemd160(bytes memory) retourne (bytes20)
calcule le hachage RIPEMD-160 de l’entrée
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) retourne (address)
récupère l’adresse associée à la clé publique de la signature à courbe elliptique ou renvoie zéro en cas d’erreur. Les paramètres de la fonction correspondent aux valeurs ECDSA de la signature :
r
= premiers 32 octets de la signatures
= deuxième 32 octets de la signaturev
= dernier 1 octet de la signature
ecrecover
retourne uneadresse
, et non uneadresse payable
. Voir address payable pour la conversion, au cas où vous auriez besoin de transférer des fonds à l’adresse récupérée.Pour plus de détails, lisez example usage.
Avertissement
Si vous utilisez ecrecover
, soyez conscient qu’une signature valide peut être transformée en une signature valide différente
sans avoir besoin de connaître la clé privée correspondante. Dans le hard fork de Homestead, ce problème a été corrigé
pour les signatures _transaction_ (voir EIP-2),
mais la fonction ecrecover est restée inchangée.
Ce n’est généralement pas un problème, à moins que vous n’exigiez que les signatures soient uniques
ou que vous les utilisiez pour identifier des éléments. OpenZeppelin a une
ECDSA helper library que vous pouvez
utiliser comme un wrapper pour ecrecover
sans ce problème.
Note
Lorsque vous exécutez les fonctions sha256
, ripemd160
ou ecrecover
sur une blockchain privée, vous pouvez rencontrer des problèmes d’épuisement. Cela est dû au fait que ces fonctions sont implémentées en tant que « contrats précompilés » et n’existent réellement qu’après avoir reçu le premier message (bien que leur code de contrat soit codé en dur). Les messages destinés à des contrats inexistants sont plus coûteux et l’exécution peut donc se heurter à une erreur Out-of-Gas. Une solution à ce problème consiste à envoyer d’abord du Wei (1 par exemple) à chacun des contrats avant de les utiliser dans vos contrats réels. Ce n’est pas un problème sur le réseau principal ou le réseau de test.
Membres des types d’adresses
<address>.balance
(uint256
)solde de l”adresse dans Wei
<address>.code
(bytes memory
)code à l”adresse (peut être vide)
<address>.codehash
(bytes32
)le codehash de l’adresse Address.
<address payable>.transfer(uint256 amount)
envoie une quantité donnée de Wei à adress, revient en arrière en cas d’échec, envoie 2300 de gaz, non réglable
<address payable>.send(uint256 amount) returns (bool)
envoie un montant donné de Wei à Address, renvoie
false
en cas d’échec, envoie 2300 de gaz, non réglable<address>.call(bytes memory) returns (bool, bytes memory)
émet un
CALL
de bas niveau avec la charge utile donnée, renvoie la condition de succès et les données de retour, transmet tous les gaz disponibles, ajustable<address>.delegatecall(bytes memory) returns (bool, bytes memory)
émet un
DELEGATECALL
de bas niveau avec la charge utile donnée, renvoie la condition de succès et les données de retour, transmet tous les gaz disponibles, réglable<address>.staticcall(bytes memory) returns (bool, bytes memory)
émet un
STATICCALL
de bas niveau avec la charge utile donnée, renvoie la condition de succès et les données de retour, transmet tous les gaz disponibles, réglable
Pour plus d’informations, consultez la section sur adress.
Avertissement
Vous devez éviter d’utiliser .call()
chaque fois que possible lors de l’exécution d’une autre fonction de contrat car elle contourne
la vérification de type le contrôle d’existence de la fonction et l’emballage des arguments.
Avertissement
Il y a quelques dangers à utiliser send
: Le transfert échoue si la profondeur de la pile d’appel est à 1024
(ceci peut toujours être forcé par l’appelant) et il échoue également si le destinataire tombe en panne sèche. Donc, afin de
de faire des transferts d’Ether sûrs, vérifiez toujours la valeur de retour de send
, utilisez transfer
ou encore mieux :
Utilisez un modèle où le destinataire retire l’argent.
Avertissement
En raison du fait que l’EVM considère qu’un appel à un contrat inexistant réussit toujours,
Solidity inclut une vérification supplémentaire en utilisant l’opcode extcodesize
lors des appels externes.
Cela garantit que le contrat qui est sur le point d’être appelé existe réellement (il contient du code)
soit une exception est levée.
Les appels de bas niveau qui opèrent sur des adresses plutôt que sur des instances de contrat (c’est-à-dire .call()
,
.delegatecall()
, .staticcall()
, .send()
et .transfer()
) n’incluent pas cette
vérification, ce qui les rend moins coûteux en termes de gaz mais aussi moins sûrs.
Note
Avant la version 0.5.0, Solidity permettait d’accéder aux membres adresse par une instance de contrat, par exemple this.balance
.
Ceci est maintenant interdit et une conversion explicite en adresse doit être faite : address(this).balance
.
Note
Si l’on accède à des variables d’état via un appel de délégué de bas niveau, la disposition de stockage des deux contrats doit s’aligner pour que le contrat appelé puisse accéder correctement aux variables de stockage du contrat appelant par leur nom. Ce n’est évidemment pas le cas si les pointeurs de stockage sont passés comme arguments de fonction, comme dans le cas des bibliothèques de haut niveau.
Note
Avant la version 0.5.0, .call
, .delegatecall
et .staticcall
retournaient uniquement la
condition de réussite et non les données de retour.
Note
Avant la version 0.5.0, il existait un membre appelé callcode`' avec une sémantique similaire mais légèrement différente de celle de ``deallcode
,
sémantique similaire mais légèrement différente de celle de delegatecall
.
Concernant les contrats
this
(le type du contrat actuel)le contrat actuel, explicitement convertible en Address.
selfdestruct(address payable recipient)
Détruit le contrat actuel, en envoyant ses fonds à l’adresse Address donnée et mettre fin à l’exécution. Notez que
selfdestruct
a quelques particularités héritées de l’EVM :la fonction de réception du contrat récepteur n’est pas exécutée.
le contrat n’est réellement détruit qu’à la fin de la transaction et les
revert
peuvent « annuler » la destruction.
En outre, toutes les fonctions du contrat en cours sont appelables directement, y compris la fonction en cours.
Note
Avant la version 0.5.0, il existait une fonction appelée suicide
ayant la même
sémantique que la fonction selfdestruct
.
Informations sur le type de produit
L’expression type(X)
peut être utilisée pour récupérer des informations sur le type
X
. Actuellement, la prise en charge de cette fonctionnalité est limitée (X
peut être soit
un contrat ou un type entier) mais elle pourrait être étendue dans le futur.
Les propriétés suivantes sont disponibles pour un type de contrat C
:
type(C).name
Le nom du contrat.
type(C).creationCode
Tableau d’octets en mémoire qui contient le bytecode de création du contrat. Ceci peut être utilisé dans l’assemblage en ligne pour construire des routines de création personnalisées, notamment en utilisant l’opcode
create2
. Cette propriété n’est pas accessible dans le contrat lui-même ou dans un contrat dérivé. Elle provoque l’inclusion du bytecode dans le bytecode du site d’appel et donc les références circulaires de ce genre ne sont pas possibles.type(C).runtimeCode
Tableau d’octets en mémoire qui contient le bytecode d’exécution du contrat. Il s’agit du code qui est généralement déployé par le constructeur de
C
. SiC
a un constructeur qui utilise l’assemblage en ligne, cela peut être différent du bytecode réellement déployé. Notez également que les bibliothèques modifient leur code d’exécution au moment du déploiement pour se prémunir contre les appels réguliers. Les mêmes restrictions que pour.creationCode
s’appliquent à cette propriété.
En plus des propriétés ci-dessus, les propriétés suivantes sont disponibles
pour une interface de type I
:
type(I).interfaceId
:Une valeur
bytes4
contenant le EIP-165 de l’interfaceI
donnée. Cet identificateur est défini comme étant leXOR
de tous les sélecteurs de fonctions définis dans l’interface elle-même - à l’exclusion de toutes les fonctions héritées.
Les propriétés suivantes sont disponibles pour un type entier T
:
type(T).min
La plus petite valeur représentable par le type
T
.type(T).max
La plus grande valeur représentable par le type
T
.