Please help - Invoke Error - Missing Payload

Cant run autotask for gassless minting

:computer: Environment
manually running the auto task to check it

:memo:Details
I am getting the following error
Logs
AUTOTASK START
END RequestId: 717223c4-d221-4838-9728-ddc898b79772
AUTOTASK COMPLETE
2022-10-14T10:30:35.380Z ERROR Invoke Error {"errorType":"Error","errorMessage":"Missing payload","stack":["Error: Missing payload"," at handler (/var/task/index.js:137:52)"," at Runtime.handler (/opt/nodejs/autotask-wrapper.js:28:26)"," at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1028:29)"]}.

:1234: Code to reproduce I was given this code from thirdweb.
const ethers = require("ethers");
const {
DefenderRelaySigner,
DefenderRelayProvider,
} = require("defender-relay-client/lib/ethers");

const speed = "fastest";

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 erc20PermitAbi = [
{
inputs: [
{
internalType: "address",
name: "owner",
type: "address",
},
{
internalType: "address",
name: "spender",
type: "address",
},
{
internalType: "uint256",
name: "value",
type: "uint256",
},
{
internalType: "uint256",
name: "deadline",
type: "uint256",
},
{
internalType: "uint8",
name: "v",
type: "uint8",
},
{
internalType: "bytes32",
name: "r",
type: "bytes32",
},
{
internalType: "bytes32",
name: "s",
type: "bytes32",
},
],
name: "permit",
outputs: ,
stateMutability: "nonpayable",
type: "function",
},
];

async function relayGeneric(forwarder, request, signature) {
// 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 = (parseInt(request.gas) + 50000).toString();
return await forwarder.execute(request, signature, { gasLimit });
}

async function relayTokenApproval(
permitContract,
permitMessage,
permitSignature
) {
// Tx args
const { owner, spender, value, deadline, v, r, s } = permitMessage;

// Send meta-tx through relayer to the forwarder contract
return await permitContract.permit(owner, spender, value, deadline, v, r, s);
}

async function handler(event) {
// Parse webhook payload
if (!event.request || !event.request.body) throw new Error(Missing payload);
const { type } = event.request.body;

console.log("Type", type);

// Initialize Relayer provider and signer, and forwarder contract
const credentials = { ...event };
const provider = new DefenderRelayProvider(credentials);
const signer = new DefenderRelaySigner(credentials, provider, {
speed,
});

let tx;

if (type == "permit") {
// ERC20 Permit
const { request, signature } = event.request.body;

// Initialize permitContract
const permitContract = new ethers.Contract(
  request.to,
  erc20PermitAbi,
  signer
);

tx = await relayTokenApproval(permitContract, request, signature);

} else if (type == "forward") {
// Gasless tx
const { request, signature, forwarderAddress } = event.request.body;
console.log(forwarderAddress);

// Initialize forwarder contract
const forwarder = new ethers.Contract(
  forwarderAddress,
  ForwarderAbi,
  signer
);

console.log(`Relaying`, request);
console.log(`Signature`, signature);

// fix ledger live where signature result in v = 0, 1.
const fixedSig = ethers.utils.joinSignature(ethers.utils.splitSignature(signature));

console.log(`Fixed Signature`, fixedSig);

tx = await relayGeneric(forwarder, request, fixedSig);

} else {
throw new Error(
Invalid gasless transaction type. Provide type 'permit' or 'forwarder'.
);
}

console.log(Sent meta-tx: ${tx.hash});
return { txHash: tx.hash, txResponse: tx };
}

module.exports = {
handler,
};

1 Like

Hi @Paulag and welcome to the community!

The missing payload error would come when the Autotask is triggered manually because the handler expects some information to be included when it is triggered (via webhook). Without the data, it throws the error as specified inside the handler (after the "Parse webhook payload" comment).

You could test the Autotask by sending a transaction however it is shaped via the webapp -- I'm actually not sure how the thirdweb template does that, but one way of testing is just to run the app locally and send a transaction that way. That way, it will supply the payload the Autotask expects so that it can trigger a meta-transaction.