I'm following this tutorial: https://docs.openzeppelin.com/learn/sending-gasless-transactions
But it doesn't really explain clearly how it works in details. A standard transaction is pretty simple to understand. An user signs a message, sends it, pays for it and it goes to blockchain.
If there is gasless transaction on mainnet or testnet like ropsten, user doesn't send transaction to the blockchain, instead he only signs it. What happens next? There must be something which grabs user's personal signed message (because as far as I know, this message is "private", it doesn't go to the global network) and puts it to the network and pays for it but how does exactly it work?
For a moment I was thinking that if I make a contract which extends GSNRecipient any user transaction will change into sign request and this contract will be making transactions to the network. So I recreated a simple Counter contract which extends GSNRecipientUpgradeSafe.
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
{
}
}
I deployed it and called start()
I didn't want to use any react scripts. I decided to use a normal web3js library and very basic simple 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>
I have checked a gsn demo: https://metacoin.opengsn.org/ After clicking "send metacoin" I'm getting sign message request. In the source code there is normal contract.methods......send(). So I decided to recreate it.
But unfortunately:
<button onclick="getCounterContract().methods.addValue().send({from:account})">click</button>
This simply calls a normal transaction instead of sign request.
web3.version: "1.2.6"
I'm pretty sure I misunderstood something or didn't understand properly. How can I make this working? Maybe there is something better than OpenZeppelin's GSN network code?
I'm using metamask.