Я следую этому руководству: https://docs.openzeppelin.com/learn/sending-gasless-transactions
Но на самом деле это не объясняет четко, как это работает в деталях. Стандартная транзакция довольно проста для понимания. Пользователь подписывает сообщение, отправляет его, оплачивает и оно отправляется в блокчейн.
Если в основной сети или тестовой сети есть безгазовая транзакция, такая как ropsten, пользователь не отправляет транзакцию в блокчейн, а только подписывает ее. Что будет дальше? Должно быть что-то, что захватывает личное подписанное сообщение пользователя (потому что, насколько я знаю, это сообщение "частное", оно не выходит в глобальную сеть) и помещает его в сеть и платит за это, но как именно это происходит? работа?
На мгновение я подумал, что если я создам контракт, расширяющий GSNRecipient, любая пользовательская транзакция превратится в запрос подписи, и этот контракт будет выполнять транзакции в сети. Поэтому я воссоздал простой контракт Counter, который расширяет 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
{
}
}
Я развернул его и вызвал start()
Я не хотел использовать какие-либо сценарии реагирования. Я решил использовать обычную библиотеку web3js и очень простой простой веб-сайт.
<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>
Я проверил демонстрацию gsn: https://metacoin.opengsn.org/ После нажатия «отправить метакойн» я получаю запрос на подписание сообщения. В исходном коде есть обычные contract.methods......send(). Поэтому я решил воссоздать его.
Но, к сожалению:
<button onclick="getCounterContract().methods.addValue().send({from:account})">click</button>
Это просто вызывает обычную транзакцию вместо запроса на подпись.
web3.версия: "1.2.6"
Я почти уверен, что я что-то неправильно понял или не понял правильно. Как я могу заставить это работать? Может быть, есть что-то лучше, чем сетевой код OpenZeppelin GSN?
Я использую метамаску.
Идея «безгазовых» транзакций заключается в том, что пользователь подписывает сообщение и отправляет это сообщение ретранслятору газа . Ретранслятор — это отдельный объект, который собирает сообщения от пользователей и отправляет транзакции. Таким образом, пользователю не нужно платить за транзакцию, это делает только ретранслятор. Затем, при желании, пользователь может заплатить ретранслятору токенами или другими платежными средствами.
Средства пользователей хранятся в смарт-контракте, и только при наличии действительной подписи, предоставленной пользователем, средства могут быть отправлены из этого контракта. В вашем примере вы вызываете функцию контракта как пользователь. Поскольку для всех фактических транзакций в сети требуется газ, это просто отправит транзакцию непосредственно в контракт, а не через ретранслятор газа.
Для отправки транзакций в сеть АЗС можно использовать их библиотеки JavaScript, например:
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({ ... });
Это позволит RelayProvider
подписать транзакцию и отправить ее ретранслятору газа, который затем отправит транзакцию в ваш контракт от имени пользователя.
Более подробное руководство по использованию OpenGSN можно найти здесь: https://docs.opengsn.org/gsn-provider/getting-started.html.