Signing calldata for execution

NOTE: We are using ethers v6.9for the senderSigner object.

Forward Transactions

When you receive the response from the migrate/forward-calldata it needs to be signed by the user before getting executed by the migrate/forward-calldata-trx.

To get the data signed and executed, go through the following steps:

  1. Generate the forward calldata.

const transferTokenDetails = [{
  tokenAddress: "0x0537a0f2e1373886a3d4f0e2b24c026ffa6f16f7";
  amount: "1000000";
}];
const requestBody = {
        chainId: "137",
        owner: await senderSigner.getAddress(),
        receiverAddress,
        tokensList: transferTokenDetails,
};
      
const forwardCallResponse = await sendRequest({
      url: GENERATE_FORWARD_CALL_DATA_ENDPOINT,
      method: HttpMethod.POST,
      headers: {
        "x-api-key": "AARC_API_KEY",
      },
      body: requestBody,
});
  • senderSigner is the signer object of the user.

  1. Get forwardCallDataResponse from the response in a variable.

const forwardTrxList = forwardCallResponse.forwardCallDataResponse;
  1. Run a loop to sign each item in the forwardTrxList

for (let index = 0; index < forwardTrxList.length; index++) {
          const element = forwardTrxList[index];
          if (element.txType === "PERMIT") {
            // Sign the EIP-712 message
            const eip712Struct = element.eip712Struct
            const { domain, types, value } = eip712Struct
            const signature = await senderSigner.signTypedData(domain, types, value);
            const dataSet = JSON.parse(element.data);
            dataSet.signature = signature;
            element.data = JSON.stringify(dataSet);
          } else if (element.txType === "PERMIT2_BATCH") {
            const eip712Struct = element.eip712Struct
            const { domain, types, value } = eip712Struct
            const signature = await senderSigner.signTypedData(domain, types, value);
            const dataSet = JSON.parse(element.data);
            dataSet.signature = signature;
            element.data = JSON.stringify(dataSet);
          }
        }
  • The if conditions are used to differentiate among the different Transaction Types involved in the transaction.

  • the signatures are generated for the eip712Struct present in the transaction item by signing it using the senderSigner.

At the end of the loop, this will edit and finalize the forwardTrxList.

  1. Pass the forwardTrxList and the txIndexes to the execution endpoint.

const txResponse: ExecuteCallDataResponse = await sendRequest({
  url: EXECUTE_FORWARD_CALL_DATA_ENDPOINT,
  method: HttpMethod.POST,
  headers: {
    "x-api-key": "AARC_API_KEY",
  },
  body: {
    chainId,
    trxList: forwardTrxList,
    txIndexes: forwardCallResponse.txIndexes,
  },
});

Voila! Your forward transaction is executed 🥳

Gasless Transactions

When you receive the response from the migrate/gasless-calldata it needs to be signed by the user before getting executed by the migrate/gasless-calldata-trx.

To get the data signed and executed, go through the following steps:

  1. Generate the gasless calldata.

const transferTokenDetails = [{
  tokenAddress: "0x0537a0f2e1373886a3d4f0e2b24c026ffa6f16f7";
  amount: "1000000";
}];
const requestBody = {
    chainId: this.chainId.toString(),
    owner: await senderSigner.getAddress(),
    receiverAddress,
    tokensList: transferTokenDetails,
};

const gaslessResponse = await sendRequest({
      url: GENERATE_GASLESS_CALL_DATA_ENDPOINT,
      method: HttpMethod.POST,
      headers: {
        "x-api-key": "AARC_API_KEY",
      },
      body: requestBody,
});
  • senderSigner is the signer object of the user.

  1. Get data from the response in a variable.

const resultSet = gaslessResponse.data;
  1. Initialize a variable to store the transactions which do not support Permit.

const non_permit_transactions = [];
  1. Run a loop to sign item in the resultSet

for (let index = 0; index < resultSet.length; index++) {
  const element = resultSet[index];
  if (element.txType === "PERMIT") {
    // Sign the EIP-712 message
    const eip712Struct = element.eip712Struct
    const { domain, types, value } = eip712Struct
    const signature = await senderSigner.signTypedData(domain, types, value);
    const dataSet = JSON.parse(element.data);
    dataSet.signature = signature;
    element.data = JSON.stringify(dataSet);
  }
  if (element.txType === "PERMIT2_SINGLE") {
    const eip712Struct = element.eip712Struct
    const { domain, types, value } = eip712Struct
    const signature = await senderSigner.signTypedData(domain, types, value);
    const dataSet = JSON.parse(element.data);
    dataSet.signature = signature;
    element.data = JSON.stringify(dataSet);
  }
  if (element.txType === "PERMIT2_BATCH") {
    const eip712Struct = element.eip712Struct
    const { domain, types, value } = eip712Struct
    const signature = await senderSigner.signTypedData(domain, types, value);
    const dataSet = JSON.parse(element.data);
    dataSet.signature = signature;
    element.data = JSON.stringify(dataSet);
  }
  if (element.txType === "NATIVE_TRANSFER") {
    non_permit_transactions.push({
      from: owner,
      to: receiverAddress,
      data: '0x',
      tokenAddress: element.tokenAddress[0],
      amount: element.amount,
      type: "dust",
    })
  }
  if (element.txType === "ERC20_TRANSFER") {
    non_permit_transactions.push({
      from: owner,
      data: element.data,
      to: receiverAddress,
      tokenAddress: element.tokenAddress[0],
      amount: element.amount,
      type: "cryptocurrency",
    })
  }
  if (element.txType === "NFT_TRANSFER") {
    non_permit_transactions.push({
      from: owner,
      to: receiverAddress,
      data: element.data,
      tokenAddress: element.tokenAddress[0],
      amount: '1',
      type: "cryptocurrency",
    })
  }
}
  • The if conditions are used to differentiate among the different Transaction Types involved in the transaction.

  • the signatures are generated for the eip712Struct present in the transaction item by signing it using the senderSigner.

  • transactions is populated with the transactions for tokens that don't support Permit.

At the end of the loop, this will edit and finalize the resultSet

  1. Execute the gasless transactions.

const txResponse = await sendRequest({
      url: EXECUTE_GASLESS_CALL_DATA_ENDPOINT,
      method: HttpMethod.POST,
      headers: {
        "x-api-key": "AARC_API_KEY",
      },
      body: { "137", trxList: resultSet},
});
  1. Execute the transactions for tokens that don't support Permit.

for (const tx of non_permit_transactions) {
    const trx = await senderSigner.sendTransaction({
        to: tx.tokenAddress,
        value: tx.type === "dust" ? tx.amount : '0x0',
        data: tx.data,
        gasLimit: BigInt(parseInt(Number(gasEstimated).toString()))
    });
}

Voila! Your gasless transaction is executed 🥳

Last updated