Unidades y variables disponibles globalmente
Unidades de Ether
Un número literal puede tomar un sufijo de wei
, gwei
o ether
para especificar una subdenominación de Ether, donde números de Ether sin un postfix se supone que son Wei.
assert(1 wei == 1);
assert(1 gwei == 1e9);
assert(1 ether == 1e18);
El único efecto del sufijo subdenominación es una multiplicación por una potencia de diez.
Nota
Las denominaciones finney
y szabo
se han eliminado en la versión 0.7.0.
Unidades de tiempo
Sufijos como seconds
, minutes
, hours
, days
y weeks
después de números literales se pueden utilizar para especificar unidades de tiempo donde segundos son la unidad base y las unidades se consideran ingenuamente de la siguiente manera:
1 == 1 seconds
1 minutes == 60 seconds
1 hours == 60 minutes
1 days == 24 hours
1 weeks == 7 days
Tenga cuidado si realiza cálculos de calendario utilizando estas unidades, porque no todos los años equivalen a 365 días y ni siquiera todos los días tienen 24 horas debido a segundos bisiestos. Debido a que los segundos bisiestos no se pueden predecir, una librería de calendario exacta tiene que ser actualizado por un oráculo externo.
Nota
El sufijo years
se ha quitado en la versión 0.5.0 debido a las razones anteriores.
Estos sufijos no se pueden aplicar a las variables. Por ejemplo, si quieres interpretar un parámetro de función en días, puede hacerlo de las siguientes maneras:
function f(uint start, uint daysAfter) public {
if (block.timestamp >= start + daysAfter * 1 days) {
// ...
}
}
Variables y funciones especiales
Hay variables y funciones especiales que siempre existen en el espacio de nombres global y se utilizan principalmente para proporcionar información sobre el blockchain o son funciones de utilidad de uso general.
Propiedades de bloques y transacciones
blockhash(uint blockNumber) returns (bytes32)
: hash del bloque dado cuandoblocknumber
es uno de los 256 bloques más recientes; de lo contrario devuelve ceroblock.basefee
(uint
): tarifa base del bloque actual (EIP-3198 y EIP-1559)block.chainid
(uint
): ID de cadena actualblock.coinbase
(address payable
): dirección actual del minero del bloqueblock.difficulty
(uint
): dificultad del bloque actual. Para otras versiones de EVM se comporta como un alias obsoleto de
block.prevrandao
(EIP-4399 )
- block.gaslimit
(uint
): límite de gas del bloque actual
- block.number
(uint
): número de bloque actual
- block.timestamp
(uint
): marca de tiempo de bloque actual como segundos desde la época unix
- gasleft() returns (uint256)
: gas restante
- msg.data
(bytes calldata
): calldata completo
- msg.sender
(address
): remitente del mensaje (llamada actual)
- msg.sig
(bytes4
): primeros cuatro bytes de calldata (i.e. identificador de función)
- msg.value
(uint
): número de wei enviado con el mensaje
- tx.gasprice
(uint
): precio del gas de la transacción
- tx.origin
(address
): remitente de la transacción (cadena de llamadas completa)
Nota
Los valores de todos los miembros de msg
, incluyendo msg.sender
y
msg.value
pueden cambiar para cada llamada a una función externa.
Esto incluye llamadas a funciones de librería.
Nota
Cuando se evalúan los contratos fuera de la cadena en lugar de en contexto de una transacción incluido en un bloque, no debería asumir que block.*
y tx.*
se refieren a valores de cualquier bloque o transacción específica. Estos valores son proporcionados por la implementación de EVM que ejecuta el contrato y pueden ser arbitrarios.
Nota
No confíe en block.timestamp
o blockhash
como fuente de aleatoriedad,
a menos que sepas lo que estás haciendo.
Tanto la marca de tiempo y el hash de bloque pueden ser influenciados por los mineros hasta cierto punto. Malos actores en la comunidad minera pueden, por ejemplo, ejecutar una función de pago de casino en un hash elegido y simplemente reintentar un hash diferente si no recibieron dinero.
La marca de fecha del bloque actual debe ser estrictamente más grande que la marca de fecha del último bloque, pero la única garantía es que estará entre las marcas de fecha de dos bloques consecutivos en la cadena canónica.
Nota
Los hashes de bloque no están disponibles para todos los bloques por razones de escalabilidad. Solo puede acceder a los hashes de los 256 bloques más recientes, todos los demás valores serán cero.
Nota
La función blockhash
se conocía anteriormente como block.blockhash
, que quedó en desuso en la versión 0.4.22 y eliminado en la versión 0.5.0.
Nota
La función gasleft
se conocía anteriormente como msg.gas
, que quedó en desuso en la versión 0.4.21 y eliminado en la versión 0.5.0.
Nota
En versión 0.7.0, el alias now
(para block.timestamp
) se quitó.
Funciones de codificación y decodificación ABI
abi.decode(bytes memory encodedData, (...)) returns (...)
: ABI-decodifica los datos dados, mientras que los tipos se dan entre paréntesis como segundo argumento. Ejemplo:(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))
abi.encode(...) returns (bytes memory)
: ABI codifica los argumentos dadosabi.encodePacked(...) returns (bytes memory)
: Realiza packed encoding de los argumentos dados. ¡Tenga en cuenta que la codificación empaquetada puede ser ambigua!abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)
: ABI codifica los argumentos dados a partir del segundo y antepone el selector de cuatro bytes dadoabi.encodeWithSignature(string memory signature, ...) returns (bytes memory)
: Equivalente aabi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)
abi.encodeCall(function functionPointer, (...)) returns (bytes memory)
: ABI codifica una llamada afunctionPointer
con los argumentos encontrados en la tupla. Realiza una comprobación de tipo completa, garantizar que los tipos coincidan la firma de la función. El resultado es igual aabi.encodeWithSelector(functionPointer.selector, (...))
Nota
Estas funciones de codificación se pueden utilizar para crear datos para llamadas a funciones externas sin llamar realmente a una función externa. Además, keccak256(abi.encodePacked(a, b))
es una forma de calcular el hash de los datos estructurados (aunque tenga en cuenta que es posible crear una «colisión de hash» usando diferentes tipos de parámetros de función).
Consulte la documentación sobre la ABI y la codificación tightly packed para obtener más información sobre la codificación.
Miembros de bytes
bytes.concat(...) returns (bytes memory)
: Concatena el número de variable de bytes y bytes1, …, argumentos de bytes32 para una matriz de bytes
Miembros de cadena
string.concat(...) returns (string memory)
: Concatena el número variable de argumentos de cadena en una matriz de cadenas
Manejo de errores
Consulte la sección dedicada a assert y require para obtener más información sobre el control de errores y cuándo usar qué función.
assert(bool condition)
provoca un error de pánico y, por lo tanto, cambiar el estado de reversión si no se cumple la condición - para ser utilizado para errores internos.
require(bool condition)
se revierte si no se cumple la condición - para ser utilizado para errores en componentes internos o externos.
require(bool condition, string memory message)
se revierte si no se cumple la condición - para ser utilizado para errores en componentes internos o externos. También proporciona un mensaje de error.
revert()
anular la ejecución y revertir los cambios de estado
revert(string memory reason)
anular la ejecución y revertir los cambios de estado, proporcionar una cadena explicativa
Funciones matemáticas y criptográficas
addmod(uint x, uint y, uint k) returns (uint)
calcular
(x + y) % k
donde se realiza la adición con precisión arbitraria y no se envuelve en2**256
. Afirman quek != 0
a partir de la versión 0.5.0.mulmod(uint x, uint y, uint k) returns (uint)
calcular
(x * y) % k
donde se realiza la multiplicación con precisión arbitraria y no se envuelve en2**256
. Afirman quek != 0
a partir de la versión 0.5.0.keccak256(bytes memory) returns (bytes32)
computadora el hash Keccak-256 de la entrada
Nota
Solía haber un alias para keccak256
llamado sha3
, que se eliminó en la versión 0.5.0.
sha256(bytes memory) returns (bytes32)
computa el hash SHA-256 de la entrada
ripemd160(bytes memory) returns (bytes20)
computa el hash RIPEMD-160 de la entrada
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
recupera la dirección asociada con la clave pública de la firma de curva elíptica o devuelva cero en el error. Los parámetros de la función corresponden a los valores de ECDSA de la firma:
r
= primeros 32 bytes de firmas
= segundo 32 bytes of signaturev
= 1 byte final de firma
ecrecover
devuelve unaaddress
, y no unaaddress payable
. Ver dirección payable para la conversión, en caso de que necesite transferir fondos a la dirección recuperada.Para más detalles, lea ejemplo de uso.
Advertencia
Si utiliza ecrecover
, tenga en cuenta que una firma válida se puede convertir en una firma válida diferente sin requerir el conocimiento de la clave privada correspondiente. En la bifurcación dura de Homestead, este problema se ha corregido para las firmas de _transaction_ (see EIP-2), pero la función ecrecover permaneció sin cambios.
Por lo general, esto no es un problema a menos que requiera que las firmas sean únicas o utilícelos para identificar elementos. OpenZeppelin tiene una biblioteca auxiliar de ECDSA que puede usar como envoltorio para ecrecover
sin este problema.
Nota
Al ejecutar sha256
, ripemd160
o ecrecover
en un blockchain privado, es posible que se encuentre sin gas. Esto se debe a que estas funciones se implementan como «contratos precompilados» y solo existen realmente después de recibir el primer mensaje (aunque su código de contrato está codificado). Los mensajes a contratos inexistentes son más caros y, por lo tanto, la ejecución podría encontrarse con un error de falta de gas. Una solución para este problema es enviar primero Wei (1 por ejemplo) a cada uno de los contratos antes de utilizarlos en sus contratos reales. Esto no es un problema en la red principal o de prueba.
Miembros de tipos de direcciones
<address>.balance
(uint256
)balance de la dirección en Wei
<address>.code
(bytes memory
)código en la dirección (puede estar vacío)
<address>.codehash
(bytes32
)el codehash de la dirección
<address payable>.transfer(uint256 amount)
envía la cantidad dada de Wei a dirección, revierte en caso de error, adelanta 2300 estipendios de gas, no ajustable
<address payable>.send(uint256 amount) returns (bool)
envìa la cantidad dada de Wei a dirección, devuelve
false
en caso de error, adelanta 2300 estipendios de gas, no ajustable<address>.call(bytes memory) returns (bool, bytes memory)
emite
CALL
de bajo nivel con la carga útil dada, devuelve la condición de éxito y devuelve datos, reenvía todo el gas disponible, ajustable<address>.delegatecall(bytes memory) returns (bool, bytes memory)
emite
DELEGATECALL
de bajo nivel con la carga útil dada, devuelve la condición de éxito y devuelve datos, reenvía todo el gas disponible, ajustable<address>.staticcall(bytes memory) returns (bool, bytes memory)
emite
STATICCALL
de bajo nivel con la carga útil dada, devuelve la condición de éxito y devuelve datos, reenvía todo el gas disponible, ajustable
Para obtener más información, consulte la sección sobre dirección.
Advertencia
Debe evitar usar .call()
siempre que sea posible al ejecutar otra función de contrato, ya que omite la comprobación de tipo, comprobación de existencia de funciones y empaquetado de argumentos.
Advertencia
Hay algunos peligros en el uso de send
: La transferencia falla si la profundidad de la pila de llamadas está en 1024 (esto siempre puede ser forzado por el autor de la llamada) y también falla si el receptor se queda sin gasolina. Entonces,
para hacer transferencias seguras de Ether, compruebe siempre el valor devuelto de send
, usar transfer
o incluso mejor:
Use un patrón en el que el destinatario retire el dinero.
Advertencia
Debido a que la EVM considera que una llamada a un contrato inexistente siempre tiene éxito,
Solidity incluye una comprobación adicional utilizando el opcode extcodesize
al realizar llamadas externas.
Esto asegura que el contrato que está a punto de ser llamado realmente existe (contiene código)
o se genera una excepción.
Las llamadas de bajo nivel que operan en direcciones en lugar de instancias de contrato (i.e. .call()
,
.delegatecall()
, .staticcall()
, .send()
y .transfer()
) no incluya esta
comprobación, lo que los hace más baratos en términos de gas, pero también menos seguros.
Nota
Antes de la versión 0.5.0, Solidity permitió que se accediera a los miembros de la dirección mediante una instancia de contrato, por ejemplo this.balance
.
Esto ahora está prohibido y se debe hacer una conversión explícita a la dirección: address(this).balance
.
Nota
Si se accede a las variables de estado a través de una delegatecall de bajo nivel, el diseño de almacenamiento de los dos contratos debe alinearse para que el contrato llamado tenga acceso correctamente a las variables de almacenamiento del contrato de llamada por su nombre. Por supuesto, este no es el caso si los punteros de almacenamiento se pasan como argumentos de función como en el caso de las bibliotecas de alto nivel.
Nota
Antes de la versión 0.5.0, .call
, .delegatecall
y .staticcall
solo devolvieron la condición de éxito y no los datos de devolución.
Nota
Antes de la versión 0.5.0, había un miembro llamado callcode
con una semántica similar pero ligeramente diferente a la de delegatecall
.
Relacionados con el contrato
this
(tipo de contrato actual)el contrato actual, explícitamente convertible en dirección
selfdestruct(address payable recipient)
Destruir el contrato actual, enviando sus fondos a la dirección dada y finalizar la ejecución. Tenga en cuenta que
selfdestruct
tiene algunas peculiaridades heredadas del EVM:la función de recepción del contrato receptor no se ejecuta.
el contrato solo se destruye realmente al final de la transacción y
revert
podría «deshacer» la destrucción.
Además, todas las funciones del contrato actual son llamables directamente, incluida la función actual.
Advertencia
A partir de la versión 0.8.18, el uso de selfdestruct
tanto en Solidity como en Yul provocará una advertencia de obsoleto, ya que el opcode SELFDESTRUCT
sufrirá eventualmente cambios en su comportamiento.
deprecation warning, ya que el opcode SELFDESTRUCT
sufrirá eventualmente cambios en su comportamiento
como se indica en EIP-6049.
Nota
Antes de la versión 0.5.0, había una función llamada suicide
con la misma semántica que selfdestruct
.
Información de tipo
La expresión type(X)
se puede utilizar para recuperar información sobre el tipo
X
. Actualmente, la compatibilidad con esta característica es limitada (X
puede ser un contrato o un tipo entero) pero podría ampliarse en el futuro.
Las siguientes propiedades están disponibles para un tipo de contrato C
:
type(C).name
El nombre del contrato.
type(C).creationCode
Matriz de bytes de memoria que contiene el código de bytes de creación del contrato. Esto se puede utilizar en el ensamblaje en línea para crear rutinas de creación personalizadas, especialmente mediante el uso del opcode
create2
. No se puede acceder a esta propiedad en el propio contrato o en cualquier contrato derivado. Hace que el bytecode se incluya en el bytecode del sitio de la llamada y, por lo tanto, las referencias circulares como esa no son posibles.type(C).runtimeCode
Matriz de bytes de memoria que contiene el código de bytes en tiempo de ejecución del contrato. Este es el código que suele implementar el constructor de
C
. SiC
tiene un constructor que utiliza un conjunto en línea, esto podría ser diferente del bytecode realmente implementado. Tenga en cuenta también que las librerías modifican su bytecode en tiempo de ejecución en el momento de la implementación para protegerse contra las llamadas regulares. Las mismas restricciones que con.creationCode
también se aplican a esta propiedad.
Además de las propiedades anteriores, las siguientes propiedades están disponibles
para un tipo de interfaz I
:
type(I).interfaceId
:Un valor
bytes4
que contiene el EIP-165 identificador de interfaz de la interfaz dadaI
. Este identificador se define como elXOR
de todos los selectores de funciones definidos dentro de la propia interfaz - excluyendo todas las funciones heredadas.
Las siguientes propiedades están disponibles para un tipo entero T
:
type(T).min
El valor más pequeño representable por el tipo
T
.type(T).max
El valor más grande representable por el tipo
T
.
Palabras clave reservadas
Estas palabras clave están reservadas en Solidity. Podrían formar parte de la sintaxis en el futuro:
after
, alias
, apply
, auto
, byte
, case
, copyof
, default
,
define
, final
, implements
, in
, inline
, let
, macro
, match
,
mutable
, null
, of
, partial
, promise
, reference
, relocatable
,
sealed
, sizeof
, static
, supports
, switch
, typedef
, typeof
,
var
.