Насколько я понимаю, msg.sender
это оплата за газ. Можно ли написать смарт-контракт таким образом, чтобы комиссию всегда платил владелец контракта?
Например, в токене ERC20, когда кто-то передает токены, он платит комиссию за газ, но что, если плата за газ за каждого transfer
должна быть оплачена владельцем смарт-контракта?
Есть 2 варианта со своими плюсами и минусами:
Используйте подписи
signature
параметр.Возврат использованного газа в конце сделки. refundGasCost
Для этого можно использовать модификатор (см. ниже).
Ниже приведены более подробные сведения о каждом варианте:
Использование подписей
Вот простой ReceiverPays
договор, который позволяет заставить получателя платежа платить за газ:
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);
}
}
Более подробную информацию можно найти в этой статье https://programtheblockchain.com/posts/2018/02/17/signing-and-verifying-messages-in-ethereum/
Ограничение этого подхода заключается в том, что если ваш смарт-контракт должен взаимодействовать с другими контрактами, то они также должны реализовать один и тот же шаблон с добавлением подписей к каждому методу.
Возврат использованного газа отправителю транзакции
Это не идеальное решение, но вы можете возместить стоимость газа отправителю транзакции. Вы можете сделать это с помощью модификатора:
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);
}
}
Возврат таким образом подразумевает некоторые накладные расходы: как минимум 9700 газа нужно доплатить за transfer
вызов функции внутри refundGasCost
модификатора. refundGasCost
Также следует добавить газ для других опкодов в usedGas
.
Также приведенный выше код потенциально уязвим для повторного входа и других атак. Я привел его только в качестве примера и не проверял его полностью.
https://github.com/ethereum/wiki/wiki/Дизайн-Обоснование
Требование к отправителям транзакций платить за газ вместо контрактов существенно повышает удобство использования для разработчиков. В очень ранних версиях Ethereum контракты оплачивали газ, но это привело к довольно уродливой проблеме, заключавшейся в том, что каждый контракт должен был реализовывать «защитный» код, который гарантировал бы, что каждое входящее сообщение компенсирует контракт достаточным количеством эфира для оплаты газа, который он потребляется.
...
ORIGIN: основное использование кода операции ORIGIN, который указывает отправителя транзакции, заключается в том, чтобы разрешить контрактам производить возврат платежей за газ.
Только что опубликовал крошечную библиотеку, чтобы добавить возможность делегировать создание транзакций (оплата комиссий): https://github.com/bitclave/Feeless
Вам нужно всего лишь:
Feeless
смарт-контрактаfeeless
модификатор для любых методов, которые вы хотите разрешить косвенно вызывать.msgSender
вместо msg.sender
этих методов и методов, вызываемых ими внутриИ любой сможет оплачивать комиссию за любого другого совершенно ненадежным способом.
Вопрос был задан в феврале 2018 года, что похоже на древнюю историю пространства Etheruem.
Ключевые термины «метатранзакции» и «сеть АЗС»:
Недавние примеры отправки токенов без газа:
USDC 2.0 вводит «безгазовые отправки», которые позволяют разработчикам кошельков и приложений абстрагироваться от сложности платы за газ (и необходимости для клиента держать баланс эфира) и вместо этого делегировать оплату платы за газ на другой адрес. Это позволяет разработчикам либо предоставлять эту услугу самостоятельно, либо позволяет сторонней службе оплачивать соответствующие сборы.
В мире токенов Ethereum произошли и другие удивительные события, в том числе безгазовые переводы. Безгазовые переводы позволяют ретрансляторам или другим третьим сторонам субсидировать переводы токенов для пользователей.
EIP-3009, который они используют: https://eips.ethereum.org/EIPS/eip-3009 .
К сожалению, нет, другой пользователь, кроме пользователя, инициировавшего транзакцию, не может оплатить газ. О msg.sender
см. редактирование ниже.
Было некоторое обсуждение, чтобы абстрагировать подпись от протокола и позволить затем иметь самоокупаемые смарт-контракты.
Однако это были только обсуждения, и эта функция даже не заложена в техническую реализацию.
Вы можете найти начало обсуждения здесь и текущее продолжение обсуждения там .
РЕДАКТИРОВАТЬ :
Обратите внимание, что msg.sender
это не обязательно пользователь, инициировавший транзакцию.
Давайте возьмем два контракта A и B и представим, что A вызывает метод в контракте B. Тогда метод, вызванный в B, будет иметь msg.sender
адрес контракта A.
Первоначальный адрес в основном упоминается как tx.origin
адрес, который инициировал транзакцию, где бы мы ни указывали в транзакции.
Также обратите внимание, что при кодировании смарт-контракта не рекомендуется использовать tx.origin
для определения того, кто отправил транзакцию, а использовать параметр в подписи метода для идентификации пользователя.
Ознакомьтесь с провайдером Fuel Web3 : https://github.com/ahmb84/fuel-web3-provider .
«Fuel позволяет разработчикам добавить систему финансирования в свое Dapp и, таким образом, сделать транзакции бесплатными для конечного пользователя».
Вот эталонная реализация: https://github.com/ahmb84/fuel-node-example .
Орри
врвим