Могут ли контракты оплачивать газ вместо отправителя сообщения?

Возможно ли, чтобы контракт оплачивал затраты на газ (или их часть), возникающие в результате отзыва контракта? Или отправитель сообщения всегда оплачивает получающиеся затраты на газ несмотря ни на что?

Вроде да - см. мой ответ здесь
> Только что опубликовал крошечную библиотеку, чтобы добавить возможность делегирования > создания транзакций (оплата комиссий): > github.com/bitclave/Feeless Как этот метод предотвращает двойные траты?
Прочтите эту ленивую миграцию с bitclave . Думал использовать это как часть механизма обновления, но не позволять пользователю платить. Я думаю, что ваша библиотека поможет.

Ответы (9)

В настоящее время пользователь, инициирующий транзакцию, должен оплатить комиссию. Однако Serenity, скорее всего, будет использовать схемы «оплаты по контракту». (См. сообщение в блоге Виталика здесь ) Возможный обходной путь — это контракт, который возвращает отправителю деньги, однако для этого все равно потребуется, чтобы пользователь удерживал некоторое количество эфира, и может позволить злоумышленникам неоднократно вызывать контракт, чтобы истощить его средства.

Тогда есть лучшие обходные пути. Я постараюсь опубликовать ответ, когда у меня будет шанс.
С нетерпением жду ваших обходных путей
У меня еще не было времени сделать это, поэтому вместо полного ответа я просто отмечу, что вы можете использовать механизм, похожий на будильник Ethereum, чтобы приложения могли отправлять свои транзакции случайным лицам, которые затем " одалживают им эфирную стоимость контракта и получают компенсацию за это по специальному контракту, финансируемому разработчиком целевого контракта. В результате получилось приложение, которое не требует от пользователей наличия эфира. Очевидно, что хотелось бы добавить в приложение какой-то элемент анти-сивиллы, чтобы предотвратить DoS. Одним из простых способов может быть небольшой PoW в приложении.
@JeffColeman немного запоздал с этим, но вы случайно не написали об этом больше подробностей? Было бы очень интересно получить полное представление о механизме, особенно о том, как будет работать самая первая часть.

Нет, отправитель с нулевым эфиром не может «попросить» контракт на оплату расходов на газ. Отправитель с нулевым эфиром не может даже отправить транзакцию.

Подробнее: у отправителя транзакции должно быть достаточно газа, чтобы покрыть выполнение транзакции. Этот газ требуется еще до того, как контракт может быть объявлен. Как только требование газа будет выполнено (чтобы транзакция прошла полностью без исчерпания газа), вызванный контракт может отправить отправителю любую сумму средств, которую содержит контракт: чистое поведение заключается в том, что отправитель может получить больше эфира, чем он начал с, но это отличается от контракта на оплату газа.

Это похоже на то, что вы можете доехать до банка, чтобы получить деньги, но сначала вам нужно топливо, чтобы иметь возможность доехать до банка: банк не может отправить вам деньги на топливо до того, как вы поедете в банк.

Здесь продолжается обсуждение будущей версии (Serenity), которая может изменить это поведение .


У Solidity есть gas()синтаксис, подобный следующему, упомянутому в одном из ответов здесь:

contract Gracious {
  function runMe() {
    this.realWork.gas(1000000)();
  }
}

gas()не означает использование эфира контракта для оплаты газа. gas()ограничивает количество газа, которое realWorkполучает подвызов ( ). Если runMeобеспечено 3 000 000 газа, то он realWorkбудет потреблять не более 1 000 000 газа, так что любые функции, вызываемые runMeпо завершении, будут гарантированно иметь 2 000 000 газа. Если realWorkпотребляет более 1 000 000 газа, то немедленно генерируется исключение, все 3 000 000 газа выплачиваются майнеру, а транзакция отменяется.

Копирую мой ответ отсюда Как заставить другого платить за газ?

Есть 2 обходных пути со своими плюсами и минусами:

  1. Используйте подписи

    • Каждая функция в вашем смарт-контракте должна иметь signatureпараметр.
    • Люди, которые хотят взаимодействовать со смарт-контрактом, должны подписать параметры функции закрытым ключом своей учетной записи и отправить его владельцу смарт-контракта (по любому каналу связи).
    • Затем владелец отправляет параметры вместе с подписью в блокчейн, оплачивая газ. Подпись гарантирует, что сообщение было одобрено пользователем.
  2. Возврат использованного газа по окончании сделки. Для этого можно использовать модификатор (см. ниже).

Ниже приведены более подробные сведения о каждом варианте:


Использование подписей

Вот простой 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/Дизайн-Обоснование

Требование к отправителям транзакций платить за газ вместо контрактов существенно повышает удобство использования для разработчиков. В очень ранних версиях Эфириума контракты оплачивали газ, но это привело к довольно уродливой проблеме, заключавшейся в том, что каждый контракт должен был реализовывать «защитный» код, который гарантировал бы, что каждое входящее сообщение компенсирует контракт достаточным количеством эфира для оплаты газа, который он потребляется.

...

ORIGIN: основное использование кода операции ORIGIN, который указывает отправителя транзакции, заключается в том, чтобы разрешить контрактам производить возврат платежей за газ.

За это следует больше голосовать, так как в настоящее время это единственный способ оплатить сборы для вызывающего абонента.

Не всем звонкам по контракту нужен газ. Это так называемый «сухой ход». https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions#interacting-with-contracts

Теперь все вызовы функций, указанные в abi, доступны в экземпляре контракта. Вы можете просто вызвать эти методы в экземпляре контракта и связать с ним sendTransaction(3, {from: address}) или call(3). Разница между ними заключается в том, что вызов выполняет «пробный прогон» локально, на вашем компьютере, в то время как sendTransaction фактически отправляет вашу транзакцию для включения в цепочку блоков, и результаты ее выполнения в конечном итоге станут частью глобального консенсуса. Другими словами, используйте вызов, если вас интересует только возвращаемое значение, и используйте sendTransaction, если вас интересуют только "побочные эффекты" состояния контракта.

Таким образом, можно предоставить пользователям в контракте метод нулевой стоимости газа — в приведенном выше примере это функция умножения.

Вы правы, это пробный запуск, и в вопросе используется «отправитель сообщения» вместо «отправитель транзакции», что было бы более точным.

Только что опубликовал крошечную библиотеку, чтобы добавить возможность делегировать создание транзакций (оплата комиссий): https://github.com/bitclave/Feeless

Вам нужно всего лишь:

  1. Наследуйте свой смарт-контракт от Feelessсмарт-контракта
  2. Добавьте feelessмодификатор для любых методов, которые вы хотите разрешить косвенно вызывать.
  3. Используйте msgSenderвместо msg.senderэтих методов и методов, вызываемых ими внутри

И любой сможет оплачивать комиссию за любого другого совершенно ненадежным способом. Например, сервис может платить комиссию за транзакции пользователей и компенсировать эту комиссию собственными токенами.

Просто для ясности, это работает путем возмещения абонентской платы? Я просмотрел ваш код, и мне трудно понять, где это происходит. Строки 24-28 проверяют подпись и нонс, строка 30 вызывает нужную функцию, а где происходит расчет суммы окупаемости и сама окупаемость?
Этот контракт позволяет создавать субконтракты, где каждый может выполнить что-то для кого угодно на основе проверки подписи. Кажется, GSN построен на том же подходе.

Ознакомьтесь с провайдером Fuel Web3 : https://github.com/ahmb84/fuel-web3-provider .

«Fuel позволяет разработчикам добавить систему финансирования в свое Dapp и, таким образом, сделать транзакции бесплатными для конечного пользователя».

Вот эталонная реализация: https://github.com/ahmb84/fuel-node-example .

Как это работает? Я не могу сказать с сайта github.

Эти ответы хороши, но я заметил, что они немного устарели, и есть способ отправить транзакцию, даже если у них нет эфира. Им просто нужна небольшая помощь: https://medium.com/@andreafspeziale/understanding-ethereum-meta-transaction-d0d632da4eb2

Это сложно, но это не зависит от обновления протокола.

В общих чертах процесс работает следующим образом:

  1. Подписывающая подписывает транзакцию для контракта/блокчейна, но не отправляет ее обычным способом. Это будет стоить газа.
  2. Подписавшаяся сторона пересылает сообщение (вне цепочки) ретранслятору. Реле — это сервер где-то, который платит за газ. У него есть подписанное сообщение, которое было бы действительным, если бы оно было отправлено в Ethereum.
  3. Реле отправляет подписанную транзакцию и оплачивает газ.

Надеюсь, поможет.

В настоящее время нет, но в настоящее время обсуждается с EIP. Гэвин Вуд говорит, что в настоящее время есть способ сделать это, но, насколько я понимаю, это что-то вроде взлома.

Любые указатели на EIP?

Во-первых, я хочу поблагодарить @eth и @medvedev1088 за их ответы. @eth утверждает, что

Это похоже на то, что вы можете доехать до банка, чтобы получить деньги, но сначала вам нужно топливо, чтобы иметь возможность доехать до банка: банк не может отправить вам деньги на топливо до того, как вы поедете в банк.

Я думаю, что с этой изначальной проблемой сталкиваются все, кто работает с утилити-токенами. Меня как разработчика это волнует, потому что неудобно просить пользователей покупать Эфириум на биржах или у местных жителей. Поэтому я ищу возможные решения, которые обходят «проблему с первым токеном». Ответ @ medvedev1088 на первый взгляд кажется решением. Я не осознавал это до тестирования, но после того, как я провел тест, я могу легко сказать

Получатель требует свой платеж, представляя подписанное сообщение смарт-контракту. Смарт-контракт проверяет свою подлинность, а затем выпускает средства.

из его блога немного вводит в заблуждение. Потому что любому, кто хочет взаимодействовать со смарт-контрактом в первый раз, нужен газ.

Если у вас есть собственная частная сеть, вы можете протестировать ее с помощью приведенного ниже кода. (Перед его выполнением вам необходимо развернуть контракт как минимум на 6 эфиров и развернуть его со своей учетной записи coinbase)

Код можно найти в этой скрипке

Надеюсь, я правильно понял первый подход @medvedev1088.