Hello! I am trying to create an autotask that links to a relayer for metatransactions. I am using my custom contract on the Mumbai testnet.
Environment
AutoTasks
Details
I am getting a an error saying my gas is unpredictable. The actual code looks like this:
cannot estimate gas; transaction may fail or may require manual gas limit
Here is my autotask code:
const ethers = require('ethers');
const { DefenderRelaySigner, DefenderRelayProvider } = require('defender-relay-client/lib/ethers');
const ForwarderAbi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct MinimalForwarder.ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct MinimalForwarder.ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}];
const ForwarderAddress = "0xf78A68a1Ec2950e995bbCdD7129B54e8a9213c74";
const ActiveBatchAddress = "0xd258cE5296C825bAb66E17c3D9CddB45C7fC102D";
async function relay(forwarder, request, signature, whitelist) {
// Decide if we want to relay this request based on a whitelist
const accepts = !whitelist || whitelist.includes(request.to);
if (!accepts) throw new Error(`Rejected request to ${request.to}`);
// Validate request on the forwarder contract
const valid = await forwarder.verify(request, signature);
if (!valid) throw new Error(`Invalid request`);
// Send meta-tx through relayer to the forwarder contract
const gasLimit = 8000000000;//(parseInt(request.gas)).toString();
return await forwarder.execute(request, signature, { gasLimit });
}
async function handler(event) {
// Parse webhook payload
if (!event.request || !event.request.body) throw new Error(`Missing payload`);
const { request, signature } = event.request.body;
console.log(`Relaying`, request);
// Initialize Relayer provider and signer, and forwarder contract
const credentials = { ... event };
const provider = new DefenderRelayProvider(credentials);
const signer = new DefenderRelaySigner(credentials, provider, { speed: 'fast' });
const forwarder = new ethers.Contract(ActiveBatchAddress, ForwarderAbi, signer);
// Relay transaction!
const tx = await relay(forwarder, request, signature);
console.log(`Sent meta-tx: ${tx.hash}`);
return { txHash: tx.hash };
}
module.exports = {
handler,
relay,
}
This is my custom contract, and im calling create function:
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/metatx/MinimalForwarder.sol";
import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
/**
* @title ERC1155Tradable
* ERC1155Tradable - ERC1155 contract that whitelists an operator address, has create and mint functionality, and supports useful standards from OpenZeppelin,
like _exists(), name(), symbol(), and totalSupply()
*/
contract ActiveBatch is ERC1155, Ownable, ERC2771Context {
using SafeMath for uint256;
uint256 private _currentTokenID = 0;
mapping(uint256 => uint256) private tokenSupply;
mapping(uint256 => uint256) private tokenBurnt;
string baseMetadataURI;
bool private mintFlag;
address private admin;
uint256 _storedInitialSuply;
event BurnedSupply(uint256 id); // will emit how much is burned so we can store in DB
function _msgSender()
internal
view
virtual
override(Context, ERC2771Context)
returns (address sender)
{
sender = ERC2771Context._msgSender();
}
function _msgData()
internal
view
virtual
override(Context, ERC2771Context)
returns (bytes calldata)
{
return ERC2771Context._msgData();
}
constructor(
string memory baseURI,
MinimalForwarder forwarder,
address _admin
) public ERC2771Context(address(forwarder)) ERC1155(baseURI) {
_setBaseMetadataURI(baseURI);
admin = _admin;
}
function _setBaseMetadataURI(string memory _newBaseMetadataURI) internal {
baseMetadataURI = _newBaseMetadataURI;
}
function uri(uint256 _tokenID)
public
view
override
returns (string memory)
{
string memory hexstringtokenID;
hexstringtokenID = Strings.toString(_tokenID);
return string(abi.encodePacked(baseMetadataURI, hexstringtokenID));
}
function totalSupply(uint256 _id) public view returns (uint256) {
return tokenSupply[_id];
}
function totalBurnt(uint256 _id) public view returns (uint256) {
return tokenBurnt[_id];
}
//this is to separate ownership transaction calls, our admin wallet will approve if it passes our bridge inspection
function approveMint(uint256 _initialSupply, bytes calldata _data)
external
{
require(
admin == _msgSender(),
"ActiveBatch#SenderIsAdmin: SENDER_IS_ADMIN"
);
mintFlag = true;
_storedInitialSuply = _initialSupply;
}
function create(address _initialOwner, bytes calldata _data)
external
onlyOwner
returns (uint256)
{
uint256 _id = _currentTokenID.add(1);
_currentTokenID++;
tokenSupply[_id] = _storedInitialSuply;
_mint(_initialOwner, _id, _storedInitialSuply, _data);
mintFlag = false;
return _id;
}
Is there any other way to set the gas price to a predictable limit? Thanks!
Code to reproduce