¿Es posible que un contrato pague los gastos de gas (o parte de ellos) que resultan de la convocatoria del contrato? ¿O el remitente de un mensaje siempre paga los costos de gasolina resultantes sin importar qué?
Actualmente el usuario que inicia la transacción debe pagar la tarifa. Sin embargo, es probable que Serenity habilite esquemas de 'contrato paga'. (Vea la publicación del blog de Vitalik aquí ) Una posible solución es un contrato que reembolsa al remitente; sin embargo, esto aún requeriría que el usuario tenga algo de Ether y podría permitir que partes malintencionadas llamen repetidamente al contrato para agotar sus fondos.
No, un remitente con cero éter no puede "pedir" un contrato para pagar los costos del gas. Un remitente con cero éter ni siquiera puede enviar una transacción.
Más detalles: El remitente de una transacción debe tener suficiente gas para cubrir la ejecución de la transacción. Ese gas se requiere incluso antes de que se pueda llamar a un contrato. Una vez que se cumple el requisito de gas (para que la transacción se ejecute completamente sin quedarse sin gas), el contrato llamado puede enviar al remitente cualquier cantidad de fondos que tenga el contrato: el comportamiento neto es que el remitente puede terminar con más éter de lo que necesita. comenzó, pero eso es diferente del contrato que paga el gas.
Es como si pudieras conducir hasta el banco para obtener dinero, pero primero necesitas combustible para poder conducir hasta el banco: el banco no puede enviarte dinero para combustible antes de que manejes hasta el banco.
Hay una discusión en curso aquí para una versión futura (Serenity) que puede cambiar este comportamiento.
Solidity tiene gas()
sintaxis, como la siguiente mencionada en una de las respuestas aquí:
contract Gracious {
function runMe() {
this.realWork.gas(1000000)();
}
}
gas()
no significa usar el éter del contrato para pagar el gas. gas()
limita la cantidad de gas que recibe la subllamada ( realWork
). Si runMe
se proporciona con 3.000.000 de gas, entonces realWork
consumirá como máximo 1.000.000 de gas, por lo que runMe
se garantizará que cualquier función llamada cuando finalice tendrá 2.000.000 de gas. Si realWork
consume más de 1,000,000 de gas, se generará una excepción de inmediato, se pagarán los 3,000,000 de gas al minero y se revertirá la transacción.
Copiando mi respuesta de aquí ¿Cómo hacer que otra persona pague por Gas?
Hay 2 soluciones con sus pros y sus contras:
Usar firmas
signature
parámetro.Reembolso del gas usado al final de la transacción. Se 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 ReceiverPays
que 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 otros contratos, 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 transfer
interno de llamada de función . También se debe agregar refundGasCost
gas para otros códigos de operación en .refundGasCost
usedGas
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.
No todas las llamadas en un contrato necesitan gas. Es el llamado "ejecución en seco". https://github.com/ethereum/go-ethereum/wiki/Contratos-y-Transacciones#interactuando-con-contratos
Ahora todas las llamadas a funciones especificadas en abi están disponibles en la instancia del contrato. Simplemente puede llamar a esos métodos en la instancia del contrato y encadenar sendTransaction(3, {from: address}) o call(3) a él. La diferencia entre los dos es que call realiza una "ejecución en seco" localmente, en su computadora, mientras que sendTransaction en realidad enviaría su transacción para incluirla en la cadena de bloques y los resultados de su ejecución eventualmente se convertirán en parte del consenso global. En otras palabras, use call, si solo está interesado en el valor de retorno y use sendTransaction si solo le interesan los "efectos secundarios" en el estado del contrato.
Por lo tanto, es posible proporcionar un método en un contrato a los usuarios por costos de gas cero; en el ejemplo anterior, es la función de multiplicación.
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:
Feeless
contrato inteligentefeeless
modificador para cualquier método que desee permitir llamar indirectamentemsgSender
en lugar de msg.sender
en estos métodos y métodos llamados internamente por ellosY cualquiera podrá pagar cuotas por cualquier otro de forma totalmente desconfiada. Por ejemplo, el servicio puede pagar tarifas por transacciones de usuarios y compensar estas tarifas con tarifas de tokens propios.
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
Estas respuestas son buenas, pero noté que son un poco antiguas y hay una forma de enviar una transacción incluso cuando no tienen éter. Solo necesitan un poco de ayuda: https://medium.com/@andreafspeziale/understanding-ethereum-meta-transaction-d0d632da4eb2
Es complicado, pero no depende de una actualización de protocolo.
Un proceso groseramente resumido funciona así:
Espero eso ayude.
Actualmente no, pero actualmente se está discutiendo con un EIP. Gavin Wood dice que hay una manera de hacerlo actualmente, pero según tengo entendido, es algo así como un truco.
En primer lugar, quiero agradecer a @eth y @medvedev1088 por sus respuestas. @eth afirma que
Es como si pudieras conducir hasta el banco para obtener dinero, pero primero necesitas combustible para poder conducir hasta el banco: el banco no puede enviarte dinero para combustible antes de que manejes hasta el banco.
Creo que todos los que trabajan con tokens de utilidad se enfrentan a este problema inicial. Me importa como desarrollador porque no es fácil de usar preguntar a los usuarios que compran Ethereum en intercambios o locales. Por lo tanto, busco posibles soluciones que solucionen el "problema del primer token". La respuesta de @ medvedev1088 parece una solución a primera vista. No me di cuenta antes de probarlo, pero después de la prueba que he hecho, puedo decir fácilmente
El destinatario reclama su pago presentando el mensaje firmado en el contrato inteligente. El contrato inteligente verifica su autenticidad y luego libera los fondos.
de su blog es un poco engañoso. Porque cualquiera que quiera interactuar con un contrato inteligente por primera vez necesita gasolina.
Si tiene su propia red privada, puede probar con el siguiente código. (Antes de ejecutarlo, debe implementar un contrato de al menos 6 ether e implementarlo desde su cuenta de coinbase)
El código se puede encontrar en este violín .
Espero no haber entendido mal el primer enfoque de @ medvedev1088.
SCBuergel
david yu
shonjs