Solidity: Vulnerabilidades Con Llamadas Externas#
Un contrato inteligente no solo puede recibir transacciones de un usuario, tambi茅n puede ser otro contrato inteligente el que realice el llamado. Veamos vulnerabilidades que puede ser explotada si se hace mal uso de los llamados entre contratos.
Diferencias entre las funciones Call y DelegateCall#
La funci贸n call
es utilizada para hacer llamadas a otro contrato inteligente a trav茅s de su address y enviar ETH o configurar el uso del gas.
addressToSend.call{value: msg.value, gas: 10000}("");
Otra funci贸n similar es delegatecall
, pero solo puede hacer llamados y no enviar ETH.
addressToSend.delegatecall("");
Adem谩s de que call
sea payable
y delegatecall
no lo es, tienen otra importante diferencia que es el contexto en donde se ejecutan. Cuando utilizas call
para llamar a otro contrato, el c贸digo que ejecutar谩 pertenece a otro contexto. Es el comportamiento m谩s l贸gico que uno quiere y puede esperar, ya que es otro contrato, posiblemente desarrollado por otra persona y no nos interesa lo que haga. Esto no es as铆 con delegatecall
.
delegatecall
no posee contexto de ejecuci贸n propio. Al usar esta funci贸n, la l贸gica y los cambios de estado se realizan en el contrato principal que origin贸 la llamada con call
. En otras palabras, el Contrato A sede su estado, valores de variables y dem谩s, a un Contrato B y este tendr谩 acceso total al primer contrato y su contexto.
No es recomendable la utilizaci贸n de delegatecall
salvo escasas excepciones como llamar a una librer铆a externa o solo utilizarlo para funciones puras que no modifique el estado del contrato.
Validaci贸n de llamadas a contratos externos#
A veces el comportamiento de nuestro contrato depende del resultado de una llamada externa a otro contrato. Esto lo debemos verificar correctamente y no confiarnos de que las cosas en el otro contrato fueron exitosas.
Si realizas una llamada a otro contrato, con excepci贸n de que realmente no nos interese el resultado, haz la validaci贸n necesaria para saber qu茅 sucedi贸 en la llamada.
uint llamadasExitosas;
function incrementarLlamadas(address direccion) public {
direccion.call(abi.encodedPacked("algunaFuncion()"));
// Si la llamada tuvo un problema, no se est谩 realizando la verificaci贸n y estamos incrementando la variable de todos modos
llamadasExitosas++;
}
Es una buena pr谩ctica utilizar la funci贸n revert()
para revertir las operaciones realizadas en caso de un error.
uint llamadasExitosas;
function incrementarLlamadas(address direccion) public {
(bool resultado) = direccion.call(abi.encodedPacked("algunaFuncion()"));
if (!resultado) revert();
if (resultado) llamadasExitosas++;
}
El otro contrato puede haberse quedado sin gas o haber alg煤n tipo de problema en la llamada como para que la misma no se haya concretado correctamente. Asegura el c贸digo de tu contrato antes de continuar luego de llamados externos y evitar gastos innecesarios.
Hacer una llamada a otro contrato inteligente no deja de ser similar al consumo de una API de un tercero. Debemos actuar de una manera u otra dependiendo el resultado satisfactorio o no de la misma.
Conclusi贸n#
Las llamadas externas en Solidity presentan riesgos importantes si no se manejan con cuidado. Es fundamental validar los resultados de las interacciones con otros contratos y evitar el uso innecesario de funciones como delegatecall
, que puede comprometer el estado del contrato llamante. Implementar buenas pr谩cticas de seguridad minimiza errores y protege la l贸gica de los contratos inteligentes.
Post creado en colaboraci贸n con el Curso de Seguridad de Smart Contracts de Platzi.