How to use ethers to query a contract from an autotask that is automatically connected to a relayer

Hey folks, running into some troubles while building an autotask.

I'm building an autotask automatically connected to a relayer. According to the docs, I should start the autotask with:

const { Relayer } = require('defender-relay-client');
exports.handler = async function(event) {
  const relayer = new Relayer(event);

  // ...
}  

This gives me access to my relayer without needing to handle credentials. So far so good.

But say that now I want to read from a view function in a deployed contract using the relayer's account. It seems I cannot simply do the following, because the relayer is not a valid provider for ethers.

const { Relayer } = require('defender-relay-client');
const { ethers } = require('ethers');

exports.handler = async function(event) {
  const relayer = new Relayer(event);
  // ...
  const contract = new ethers.Contract(
    contractAddress,
    contractAbi,
    relayer
  );
  // ...
}  

Fails with error invalid signer or provider.

So while troubleshooting the above, I came up with something a bit more convoluted:

const { Relayer } = require('defender-relay-client');
const { DefenderRelayProvider } = require('defender-relay-client/lib/ethers');
const { ethers } = require("ethers");

exports.handler = async function(event) {
  const relayer = new Relayer(event);
  
  // Get the credentials and instance a provider
  // First need to JSON.parse the credentials because they're stringified
  const { AccessKeyId, SecretAccessKey } = JSON.parse(event.credentials);
  const provider = new DefenderRelayProvider({
    apiKey: AccessKeyId,
    apiSecret: SecretAccessKey
  });
  
  const contract = new ethers.Contract(
    contractAddress,
    contractAbi,
    provider
  );
  // ...
}

But this doesn't work either - failing with

ERROR	Failed to get a token for the API key [redacted] {
  code: 'UserNotFoundException',
  name: 'UserNotFoundException',
  message: 'User does not exist.'
}

So the bottomline question is:

In an autotask that is automatically connected to a relayer, how should I use ethers to query a view function using the relayer account?

It feels like the answer should be fairly simple, but for some reason I cannot figure this out :frowning:
Thanks!

I was able to figure it out by following this example..

Essentially, instead of doing

const { Relayer } = require('defender-relay-client');
const { ethers } = require('ethers');

exports.handler = async function(event) {
  const relayer = new Relayer(event);
  // ...
  const contract = new ethers.Contract(
    contractAddress,
    contractAbi,
    relayer
  );
  // ...
}  

which fails, I'm now doing the following:

const { ethers } = require("ethers");
const {
  DefenderRelayProvider,
  DefenderRelaySigner
} = require('defender-relay-client/lib/ethers');

exports.handler = async function(event) {
  
  const provider = new DefenderRelayProvider(event);
  const signer = new DefenderRelaySigner(event, provider, { speed: 'fast' });
  
  const contract = new ethers.Contract(contract, contractAbi, provider);

  // ....
}

And now I can query the contract! :rocket:

I guess what originally confused me was this piece of documentation. Not sure if what's stated there is inaccurate or refers to a different use case. Anyway, the given example was clarifying.

Thanks for posting this, @tinchoabbate! I've amended the docs to include direct references to ethers and web3js setups. Do you think this change helps?

1 Like

yes! that looks better. I left a small comment in the PR.