принятие эфира в смарт-контракт

Я пытаюсь создать простой смарт-контракт, чтобы изучить надежность и принцип работы Ethereum.

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

contract  AcceptEth {
    address public owner;
    uint public bal;
    uint public price;
    mapping (address => uint) balance;

    function AcceptEth() {
        // set owner as the address of the one who created the contract
        owner = msg.sender;
        // set the price to 2 ether
        price = 2 ether;
    }

    function accept() payable returns(bool success) {
        // deduct 2 ether from the one person who executed the contract
        balance[msg.sender] -= price;
        // send 2 ether to the owner of this contract
        balance[owner] += price;
        return true;
    }
}

Когда я взаимодействую с этим контрактом через ремикс, я получаю сообщение об ошибке «Исключение виртуальной машины при обработке транзакции: закончился газ», он создает транзакцию, и цена на газ составляла 21000000000, а значение было 0,00 ETH, когда я пытаюсь получить 2 эфира. от любого, кто использует этот метод.

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


person totalnoob    schedule 19.01.2018    source источник


Ответы (1)


Я думаю, что вы заблудились, так это то, что в контрактах есть встроенные механизмы для получения и хранения эфира. Например, если вы хотите сделать так, чтобы ваш метод accept() получал ровно 2 эфира (или то, что вы установили для price), вы должны сделать что-то вроде этого:

contract  AcceptEth {
    address public owner;
    uint public price;
    mapping (address => uint) balance;

    function AcceptEth() {
        // set owner as the address of the one who created the contract
        owner = msg.sender;
        // set the price to 2 ether
        price = 2 ether;
    }

    function accept() payable {
        // Error out if anything other than 2 ether is sent
        require(msg.value == price);

        // Track that calling account deposited ether
        balance[msg.sender] += msg.value;
    }
}

Теперь предположим, что у вас есть две учетные записи со следующими балансами:

0x01 = 50 эфиров

0x02 = 20 эфиров

И этот контракт развернут и имеет адрес 0xc0. Все адреса могут содержать эфир, поэтому даже в самом контракте есть баланс. Поскольку он был только что развернут (и не был развернут с каким-либо исходным эфиром), его баланс равен 0.

Теперь предположим, что 0x01 вызывает accept(), отправляя 2 эфира. Транзакция будет выполнена, и 3 адреса в нашем примере будут иметь следующие балансы:

0x01 = 48 эфиров

0x02 = 20 эфиров

0xc0 = 2 эфира

Теперь предположим, что 0x02 вызывает accept() ДВАЖДЫ, передавая 2 эфира оба раза:

0x01 = 48 эфиров

0x02 = 16 эфиров

0xc0 = 6 эфир

Контракт содержит весь отправленный ему эфир. Но ваш контракт также содержит состояние (карта balance, которую вы определили в коде), которая отслеживает, кто что депонировал. Итак, из этого сопоставления вы знаете, что 0x01 депонировал 2 эфира, а 0x02 депонировал 4 эфира. Если бы вы хотели ввести refund() метод, который отправляет эфир обратно, вы бы написали его так:

function refund(uint amountRequested) public {
  require(amountRequested > 0 && amountRequested <= balance[msg.sender]);

  balance[msg.sender] -= amountRequested;

  msg.sender.transfer(amountRequested); // contract transfers ether to msg.sender's address
}
person Adam Kipnis    schedule 20.01.2018
comment
спасибо за ответ, это действительно помогло лучше все понять. как и где я могу найти подходящее руководство по созданию вывода / перевода средств контракта только на адрес владельца контракта? - person totalnoob; 20.01.2018
comment
когда я взаимодействую с этим в remix, нет поля для указания значения при выполнении метода accept? - person totalnoob; 20.01.2018
comment
В документации Solidity есть все. solidity.readthedocs.io/en/develop - person Adam Kipnis; 20.01.2018
comment
Вкладка "Выполнить", вверху справа. Поле значения. В раскрывающемся списке вы можете указать, какой тип отправлять (эфир, вэй и т. Д.) - person Adam Kipnis; 20.01.2018
comment
Как сохранить баланс, чтобы его можно было преобразовать в настоящий эфир на уровне производства? - person Stuxen; 28.10.2019