Enviar Ether (Transfer, Send y Call)

Transferir Ether entre contratos con Solidity

Alberto Lasa - Blockchain/Crypto
3 min readNov 10, 2021

Puedes enviar Ether a otra address (externa o de contrato) haciendo uso de:

  • transfer (Delega 2300 de Gas)
  • send (Delega 2300 de Gas)
  • call (Delega todo el Gas disponible o la cantidad que pongas en el código)

Cuando el beneficiario es otro contrato, este ejecuta alguna de las siguientes funciones:

  • receive()
  • fallback()

Video explicativo: https://www.youtube.com/watch?v=B62nrJ5Qmko

Cuando el objeto de la transacción interna (mensaje entre contratos) no tiene datos (“msg.data” está vacío) la ejecución recae en “receive()”, por ejemplo cuando se recibe desde “transfer” o “send”.

Por el contrario, cuando se envían datos sin especificar una función (o sin que haya una coincidencia con alguna del contrato) se ejecuta “fallback()”.

  • “receive()” no puede tener parámetros ni retornar nada. Aunque su ejecución sí puede modificar el estado del contrato. Debe marcarse siempre como “external” y “payable”.
  • “fallback()” no puede tener parámetros ni retornar nada. Aunque su ejecución sí puede modificar el estado del contrato. Debe marcarse siempre como “external”. Y para que pueda recibir Ether hay que marcarla como “payable”.
  • En ambas funciones no se antepone el palabra “function”.

Si queremos que nuestro contrato pueda recibir Ether sin que se ejecute una función concreta, al menos debe existir la función “fallback()”.

Si queremos enviar Ether entre contratos lo mejor es usar “transfer()”. Ya que “send” no revierte la transacción si se produce un error y puede degenerar en bugs. Sin embargo, hay una mejor opción.. “call”.

“call” retorna un valor booleano de éxito o fracaso, pero además ofrece la posibilidad de un retorno de datos desde la función receptora o beneficiaria. Aunque los datos estarán vacíos si se trata de las funciones “receive()” o “fallback()”. En cualquier caso, es importante resaltar que “call” no revierte la transacción en caso de error. Hay que gestionar el resultado evaluando su retorno.

¿Qué significa que estos métodos delegan Gas? Pues que “transfer” y “send” solo permiten gastar hasta un máximo de 2300 unidades de Gas a la función receptora, por lo tanto el contrato receptor/beneficiario no podrá llamar a otros contratos, o re-llamar al contrato emisor. Esto imposibilita ataques de reentrada ya que la función receptora no dispone del Gas necesario para ese ataque. Sin embargo, “call” delega todo el Gas que quede sin consumir en la transacción, salvo que especifiques una cantidad personalizada. Es por esta delegación de Gas que “call” puede facilitar un ataque de reentrada.

Medidas para prevenir un ataque de reentrada cuando usamos “call” :

  • Dentro de la función emisora hay que actualizar las variables de estado (si la función modifica alguna variable de estado) antes de llamar a “call”.
  • Estipular una cantidad limitada de Gas en “call”.

A una función:

=> someAddress.call({value: 1 ether, gas: 2300})(abi.encodeWithSignature(“someFunction(uint256)”, _arg1)) <=

Sin llamar a una función:

=> someAddress.call({value: 1 ether, gas: 2300})(“”) <=

Espero que te haya sido de utilidad este artículo, muchas gracias por tu lectura. Saludos. Aaaaa!!!!! Si te ha gustado dame un aplauso ;)

Sígueme también en:

  • YouTube:

https://www.youtube.com/channel/UCGArGu3QXNolrJ63qGSrw6w

  • Twitter:

https://twitter.com/LasaAlberto

--

--

Alberto Lasa - Blockchain/Crypto

Programación de Smart Contracts y Dapps sobre Ethereum: Solidity, Truffle, Web3.js, Node.js, Angular, React, JavaScript, TypeScript, Google Cloud, etc..