Мультиподпись только в одной транзакции

Я кодирую контракт, в котором я хотел бы, чтобы некоторые функции вызывались только в том случае, если они одобрены двумя людьми (продавцом и покупателем).

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

Я не хочу, чтобы продавец действовал без одобрения покупателя, но проблема в том, что я не хочу, чтобы покупатель платил за газ.

Я думал каким-то образом сделать только одну транзакцию, отправленную продавцом (который, таким образом, будет платить за газ), но чтобы я мог проверить в своем смарт-контракте, что транзакция была подписана покупателем.

Есть ли у вас какие-либо советы о том, как лучше всего это реализовать?

Спасибо за ваши ответы

Ответы (2)

Вы можете использовать подход, аналогичный Balance Proofs в реализации Raiden каналов состояния . По сути, вы можете попросить клиента подписать подтверждение, которое мог подписать только клиент, а затем проверить эту подпись в контракте Solidity.

В вашем конкретном примере я бы подошел к этому так:

  1. Продавец хранит адрес покупателя в смарт-контракте.
  2. Клиент подписывает данные транзакции вне сети.
  3. Продавец отправляет транзакцию к договору с подписью покупателя.
  4. Смарт-контракт получает адрес из подписи и сопоставляет его с адресом клиента, сохраненным на шаге 1.

См. код использования Metamask для подписи данных здесь .

Вот еще один пример мультиподписи одной транзакции от Кристиана Лундквиста. Эта схема ближе к биткойн-мультиподписи, чем к мультиподписным контрактам с отслеживанием состояния.

https://medium.com/@ChrisLundkvist/exploring-simpler-ethereum-multisig-contracts-b71020c19037

Код:

pragma solidity 0.4.15;
contract SimpleMultiSig {

uint public nonce;                // (only) mutable state
uint public threshold;            // immutable state
mapping (address => bool) isOwner; // immutable state
address[] public ownersArr;        // immutable state

function SimpleMultiSig(uint threshold_, address[] owners_) {
  require(owners_.length <= 10 && threshold_ <= owners_.length && threshold_ != 0);

  address lastAdd = address(0); 
  for (uint i=0; i<owners_.length; i++) {
    require(owners_[i] > lastAdd);
    isOwner[owners_[i]] = true;
    lastAdd = owners_[i];
  }
  ownersArr = owners_;
  threshold = threshold_;
}

// Note that address recovered from signatures must be strictly increasing
function execute(uint8[] sigV, bytes32[] sigR, bytes32[] sigS, address destination, uint value, bytes data) {
  require(sigR.length == threshold);
  require(sigR.length == sigS.length && sigR.length == sigV.length);

  // Follows ERC191 signature scheme: https://github.com/ethereum/EIPs/issues/191
  bytes32 txHash = keccak256(byte(0x19), byte(0), this, destination, value, data, nonce);

  address lastAdd = address(0); // cannot have address(0) as an owner
  for (uint i = 0; i < threshold; i++) {
      address recovered = ecrecover(txHash, sigV[i], sigR[i], sigS[i]);
      require(recovered > lastAdd && isOwner[recovered]);
      lastAdd = recovered;
  }

  // If we make it here all signatures are accounted for
  nonce = nonce + 1;
  require(destination.call.value(value)(data));
}

function () payable {}

}