Gaslose Transaktionen - Transaktion senden statt Nachricht signieren. Wie funktioniert es?

Ich folge diesem Tutorial: https://docs.openzeppelin.com/learn/sending-gasless-transactions

Aber es erklärt nicht wirklich klar, wie es im Detail funktioniert. Eine Standardtransaktion ist ziemlich einfach zu verstehen. Ein Benutzer signiert eine Nachricht, sendet sie, bezahlt dafür und sie geht an die Blockchain.

Wenn es im Mainnet oder Testnet wie Ropsten eine gaslose Transaktion gibt, sendet der Benutzer keine Transaktion an die Blockchain, sondern signiert sie nur. Was passiert als nächstes? Es muss etwas geben, das die persönlich signierte Nachricht des Benutzers abgreift (denn soweit ich weiß, ist diese Nachricht "privat", sie geht nicht an das globale Netzwerk) und sie an das Netzwerk sendet und dafür bezahlt, aber wie genau funktioniert das? arbeiten?

Für einen Moment dachte ich, dass, wenn ich einen Vertrag abschließe, der GSNRecipient erweitert, jede Benutzertransaktion in eine Zeichenanforderung umgewandelt wird und dieser Vertrag Transaktionen mit dem Netzwerk durchführt. Also habe ich einen einfachen Zählervertrag neu erstellt, der GSNRecipientUpgradeSafe erweitert.

pragma solidity ^0.5.0;
import "./GSNRecipient.sol";
contract Counter is GSNRecipientUpgradeSafe
{
    int public value;
    
    function addValue()
        external
    {
        value++;
    }
    
    function start()
        external
    {
        __GSNRecipient_init();
    }
    
    function acceptRelayedCall(
        address relay,
        address from,
        bytes calldata encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes calldata approvalData,
        uint256 maxPossibleCharge
    )
        external
        view
        returns (uint256, bytes memory)
    {
        return _approveRelayedCall();
    }

    function _preRelayedCall(bytes memory context) internal returns (bytes32)
    {

    }

    function _postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) internal
    {
        
    }
}

Ich habe es bereitgestellt und start() aufgerufen

Ich wollte keine Reaktionsskripte verwenden. Ich entschied mich für eine normale web3js-Bibliothek und eine sehr einfache Website.

<span id="cnt">COUNTER</span>
<button onclick="getContract().methods.addValue().send({from:account})">click</button>
<script>
    let account;
    let web3;
    window.addEventListener('load', async () => {
        if(window.ethereum)
        {
            try
            {
                await ethereum.enable();
                web3 = new Web3(ethereum);
                web3.eth.defaultAccount = (await web3.eth.getAccounts())[0];
                account = web3.eth.defaultAccount;
                let c = getContract();
                $("#cnt").html(await c.methods.value().call());
                
            }
            catch(e)
            {
                console.log(e.toString());
            }
        }
    });
    
    function getContract()
    {
        return new web3.eth.Contract(abi, "0xaa9f0c1AC580EFA7A0e6d64d3eEBF62B4F970701");
    }
</script>

Ich habe eine gsn-Demo überprüft: https://metacoin.opengsn.org/ Nachdem ich auf „Metacoin senden“ geklickt habe, erhalte ich eine Anfrage zum Signieren einer Nachricht. Im Quellcode gibt es normale contract.methods......send(). Also beschloss ich, es nachzubauen.

Aber leider:

<button onclick="getCounterContract().methods.addValue().send({from:account})">click</button>

Dies ruft einfach eine normale Transaktion anstelle einer Signaturanforderung auf.

web3.version: "1.2.6"

Ich bin mir ziemlich sicher, dass ich etwas falsch oder nicht richtig verstanden habe. Wie kann ich das zum Laufen bringen? Vielleicht gibt es etwas Besseres als den GSN-Netzwerkcode von OpenZeppelin?

Ich verwende Metamaske.

Antworten (1)

Die Idee von "gaslosen" Transaktionen ist, dass ein Benutzer eine Nachricht signiert und diese Nachricht an einen Gas- Relayer sendet . Der Relayer ist eine separate Einheit, die die Nachrichten von den Benutzern sammelt und die Transaktionen sendet. Auf diese Weise muss der Benutzer nicht für die Transaktion bezahlen, sondern nur der Relayer. Anschließend kann der Benutzer optional Tokens oder andere Zahlungsmittel an den Relayer einzahlen.

Die Gelder der Benutzer werden in einem Smart Contract gespeichert, und nur mit einer gültigen Unterschrift des Benutzers können Gelder aus diesem Vertrag gesendet werden. In Ihrem Beispiel rufen Sie als Benutzer eine Funktion für einen Vertrag auf. Da alle tatsächlichen Transaktionen im Netzwerk Gas erfordern, wird eine Transaktion einfach direkt an den Vertrag gesendet, anstatt einen Gas-Relayer zu verwenden.

Um Transaktionen an das Tankstellennetz zu senden, können Sie beispielsweise deren JavaScript-Bibliotheken verwenden:

const { RelayProvider } = require('@opengsn/gsn')

const provider = new RelayProvider(web3.currentProvider, ...);
const web3 = new Web3(provider);

const counterContract = new web3.eth.Contract(abi, ...);
await counterContract.methods.addValue().send({ ... });

Dieser verwendet den , RelayProviderum die Transaktion zu signieren und an einen Gas-Relayer zu senden, der die Transaktion dann im Namen des Benutzers an Ihren Vertrag sendet.

Eine ausführlichere Anleitung zur Verwendung von OpenGSN finden Sie hier: https://docs.opengsn.org/gsn-provider/getting-started.html