¿Cómo hacer que otra persona pague por Gas?

Tengo entendido que msg.senderpaga la tarifa del gas. ¿Se puede escribir un contrato inteligente de tal manera que siempre sea el propietario del contrato quien pague las tarifas?

Como ejemplo, en un token ERC20, cuando alguien transfiere los tokens, paga la tarifa del gas, pero ¿qué sucede si el transferpropietario del contrato inteligente debe pagar la tarifa del gas para cada uno?

En una de las próximas actualizaciones de ethereum, podrá dejar que su contrato pague el gas.
@ Lo siento, estamos 3 años después de tu comentario, ¿ya llegó esa actualización?

Respuestas (5)

Hay 2 opciones con sus pros y sus contras:

  1. Usar firmas

    • Cada función en su contrato inteligente debe tener un signatureparámetro.
    • Las personas que deseen interactuar con el contrato inteligente deben firmar los parámetros de la función con la clave privada de su cuenta y enviarla al propietario del contrato inteligente (a través de cualquier canal de comunicación).
    • Luego, el propietario envía los parámetros junto con la firma a la cadena de bloques y paga la gasolina. La firma garantiza que el mensaje fue aprobado por el usuario.
  2. Reembolso del gas usado al final de la transacción. refundGasCostSe puede usar un modificador para esto (ver más abajo).

A continuación se presentan más detalles para cada opción:


Uso de firmas

Aquí hay un contrato simple ReceiverPaysque permite hacer que el receptor del pago pague el gas:

pragma solidity ^0.4.20;

contract ReceiverPays {
    address owner = msg.sender;

    mapping(uint256 => bool) usedNonces;

    // Funds are sent at deployment time.
    function ReceiverPays() public payable { }


    function claimPayment(uint256 amount, uint256 nonce, bytes sig) public {
        require(!usedNonces[nonce]);
        usedNonces[nonce] = true;

        // This recreates the message that was signed on the client.
        bytes32 message = prefixed(keccak256(msg.sender, amount, nonce, this));

        require(recoverSigner(message, sig) == owner);

        msg.sender.transfer(amount);
    }

    // Destroy contract and reclaim leftover funds.
    function kill() public {
        require(msg.sender == owner);
        selfdestruct(msg.sender);
    }


    // Signature methods

    function splitSignature(bytes sig)
        internal
        pure
        returns (uint8, bytes32, bytes32)
    {
        require(sig.length == 65);

        bytes32 r;
        bytes32 s;
        uint8 v;

        assembly {
            // first 32 bytes, after the length prefix
            r := mload(add(sig, 32))
            // second 32 bytes
            s := mload(add(sig, 64))
            // final byte (first byte of the next 32 bytes)
            v := byte(0, mload(add(sig, 96)))
        }

        return (v, r, s);
    }

    function recoverSigner(bytes32 message, bytes sig)
        internal
        pure
        returns (address)
    {
        uint8 v;
        bytes32 r;
        bytes32 s;

        (v, r, s) = splitSignature(sig);

        return ecrecover(message, v, r, s);
    }

    // Builds a prefixed hash to mimic the behavior of eth_sign.
    function prefixed(bytes32 hash) internal pure returns (bytes32) {
        return keccak256("\x19Ethereum Signed Message:\n32", hash);
    }
}

Se pueden encontrar más detalles en este artículo https://programtheblockchain.com/posts/2018/02/17/signing-and-verifying-messages-in-ethereum/

La limitación de este enfoque es que si su contrato inteligente necesita interactuar con otro contrato, entonces también deben implementar el mismo patrón agregando firmas a cada método.


Reembolso de gas usado al remitente de la transacción

No es una solución ideal, pero puede reembolsar el costo del combustible al remitente de la transacción. Puedes hacer esto con un modificador:

pragma solidity^0.4.11;

contract SomeContract {

    event SomeEvent(address sender);

    // Need to allow depositing ether to the contract
    function() public payable {
    }

    modifier refundGasCost()
    {
        uint remainingGasStart = msg.gas;

        _;

        uint remainingGasEnd = msg.gas;
        uint usedGas = remainingGasStart - remainingGasEnd;
        // Add intrinsic gas and transfer gas. Need to account for gas stipend as well.
        usedGas += 21000 + 9700;
        // Possibly need to check max gasprice and usedGas here to limit possibility for abuse.
        uint gasCost = usedGas * tx.gasprice;
        // Refund gas cost
        tx.origin.transfer(gasCost);
    }

    function doSomething() external refundGasCost {
        SomeEvent(msg.sender);  
    }
}

Reembolsar de esta manera implica algunos gastos generales: al menos 9700 de gas deben pagarse extra por el modificador transferinterno de llamada de función . También se debe agregar refundGasCostgas para otros códigos de operación en .refundGasCostusedGas

Además, el código anterior es potencialmente vulnerable a la reentrada y otros ataques. Lo proporcioné solo como un ejemplo y no lo probé a fondo.


https://github.com/ethereum/wiki/wiki/Design-Rationale

Requerir que los remitentes de transacciones paguen por el gas en lugar de contratos aumenta sustancialmente la usabilidad del desarrollador. Las versiones muy tempranas de Ethereum tenían contratos que pagaban el gas, pero esto llevó al problema bastante feo de que cada contrato tenía que implementar un código de "protección" que aseguraría que cada mensaje entrante compensara el contrato con suficiente éter para pagar el gas que consumado.

...

ORIGEN: el uso principal del código de operación ORIGEN, que proporciona el remitente de una transacción, es permitir que los contratos realicen pagos de reembolso por gas.

¡Gracias! Estaba buscando algo que no requiriera pagar gasolina por parte del usuario del contrato inteligente en primer lugar. Habiendo dicho eso, su solución es realmente interesante :)
Interesante. ¿Alguien ha probado eso?
Lo probé solo en Remix. El gas usado calculado no es exactamente igual al gas realmente usado, pero se acerca bastante.
No se recomienda confiar en tx.origin desde hace algún tiempo ethereum.stackexchange.com/a/200
@Ismael, ¿es un Vitalik Buterin real o un troll? No encontré que no se puede confiar en tx.origin (excepto que no se puede confiar para la autorización) en ningún lugar de los documentos oficiales.
@Ismael Curiosamente, acabo de encontrar esto en Racional de diseño: ORIGEN: el uso principal del código de operación ORIGEN, que proporciona el remitente de una transacción, es permitir que los contratos realicen pagos de reembolso por gas. github.com/ethereum/wiki/wiki/Design-Racional
@medvedev1088 Él es el verdadero. Hubo un exploit en el que un contrato malicioso puede atacar un contrato que se basa en tx.origin para hacerse pasar por un usuario desprevenido.

Acabo de publicar una pequeña biblioteca para agregar la capacidad de delegar la creación de transacciones (pago de tarifas): https://github.com/bitclave/Feeless

Solo necesitas:

  1. Herede su contrato inteligente del Feelesscontrato inteligente
  2. Agregue feelessmodificador para cualquier método que desee permitir llamar indirectamente
  3. Usar msgSenderen lugar de msg.senderen estos métodos y métodos llamados internamente por ellos

Y cualquiera podrá pagar cuotas por cualquier otro de forma totalmente desconfiada.

¡Muy elegante! Intente publicar su respuesta aquí también ethereum.stackexchange.com/questions/144/… . Puede tener más alcance.

La pregunta se hizo en febrero de 2018, parece una historia antigua en el espacio Etheruem.


Términos clave "metatransacciones" y "red de gasolineras":

Ejemplos recientes de envíos de tokens sin gas:

USDC

https://medium.com/centre-blog/centre-consortium-announces-release-of-usd-coin-version-2-0-37ee8b27e09b

USDC 2.0 presenta "envíos sin gas", que permiten a los desarrolladores de billeteras y aplicaciones abstraerse de la complejidad de las tarifas de gas (y la necesidad de que el cliente tenga un saldo de éter) y, en cambio, delegar el pago de las tarifas de gas a otra dirección. Esto permite a los desarrolladores proporcionar ese servicio ellos mismos o permite que un servicio de terceros pague las tarifas relacionadas.

ANTv2

https://aragon.org/blog/antv2

También ha habido otros desarrollos sorprendentes en el mundo de los tokens de Ethereum, incluidas las transferencias sin gas. Las transferencias sin gas permiten a los retransmisores u otros terceros subvencionar las transferencias de tokens para los usuarios

EIP-3009 que utilizan: https://eips.ethereum.org/EIPS/eip-3009

Desafortunadamente no, no es posible que otro usuario que no sea el usuario que originó la transacción pague por el gas. Acerca msg.senderde ver la edición a continuación.

Ha habido cierta discusión para abstraer la firma del protocolo y permitir luego tener contratos inteligentes de pago propio.

Sin embargo, esas fueron solo discusiones y esta característica ni siquiera está redactada en una implementación técnica.

Puede encontrar el comienzo de la discusión aquí y la continuación de la discusión actual allí .

EDITAR :

Para información, tenga en cuenta que msg.senderno es necesariamente el usuario que originó la transacción.

Tomemos dos contratos A y B e imaginemos que A llama a un método en el contrato B. Entonces El método llamado en B tendrá para msg.senderla dirección del contrato A.

La dirección original se refiere principalmente a tx.originla dirección que originó la transacción donde sea que apuntemos en la transacción.

También tenga en cuenta que al codificar un contrato inteligente no se recomienda usarlo tx.originpara determinar quién envió la transacción, sino usar un parámetro en la firma del método para identificar al usuario.

Echa un vistazo al proveedor de Fuel Web3 : https://github.com/ahmb84/fuel-web3-provider

"Fuel permite a los desarrolladores agregar un sistema de financiación a su Dapp y así hacer que las transacciones sean gratuitas para el usuario final".

Aquí hay una implementación de referencia: https://github.com/ahmb84/fuel-node-example