Tengo entendido que msg.sender
paga 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 transfer
propietario del contrato inteligente debe pagar la tarifa del gas para cada uno?
Hay 2 opciones con sus pros y sus contras:
Usar firmas
signature
parámetro.Reembolso del gas usado al final de la transacción. refundGasCost
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 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 transfer
interno de llamada de función . También se debe agregar refundGasCost
gas para otros códigos de operación en .refundGasCost
usedGas
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.
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.
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 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.
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.sender
de 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.sender
no 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.sender
la dirección del contrato A.
La dirección original se refiere principalmente a tx.origin
la 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.origin
para 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
orry
vrwim