GSN is bypassed during transaction


For some unknown reason, when I send a transaction that should be handled by GSN, it is done as normal. Meaning I paid gas fees and the “to” field of the transaction is not the forwarder but my own address.

Do you see any mistake there ?

const web3 = new Web3("");
const account = gsnWeb3.eth.accounts.wallet[0].address;

const gsnProvider = await RelayProvider.newProvider({
    provider: web3.currentProvider,
    config: {
        paymasterAddress: bscTestnetGsnPaymaster,

const gsnWeb3 = new Web3(gsnProvider);

const contract = new gsnWeb3.eth.Contract(Contract.abi, Contract.address);
await contract.methods.addLiquidity(poolId, liquidityAmount).send({ from: account, gas: 4000000, useGSN: true });

After diving into the @opengsn/provider codebase, I found the reason of this.

Sending transactions this way uses the “eth_sendRawTransaction” RPC method which doesn’t match the gsn library expectation, so it get bypassed.

The gsn library expects transactions with the “eth_sendTransaction” RPC method to forward it to the relayer, which is used when the private key is handle by the node which receives the transaction to broadcast.

If you don’t run your own node, the most straightforward way to achieve that is to use Metamask as the provider to create the RelayProvider. So you need to spin up a small web app to run this code.

PS: second issue I had is that there was no relayer reachable on BSC Testnet

  1. GSN hooks sendTransaction, which is a transaction that is ready to be sent - before it gets signed. when using Metamask (or equivalent provider) it is very clear: you don’t want to see the dialog to SEND the transaction, only a request to SIGN a message. sendRawTransaction is called after the used signed the transaction to send including its gas usage (with metamask, it will warn you if you don’t have gas. some is something you miss when signing with a wallet private key.
  2. I don’t understand what you mean by "you need to spin up a web app. " see the sample app