Uncaught (in promise) Error: Error: The relay hub address is set to zero in recipient

I’ve been trying to execute GSN tutorial. After npm run start and click the button(Increase Counter by 1) I get the following error in the browser console:

Uncaught (in promise) Error: Error: The relay hub address is set to zero in recipient at 0x5aa5142103cb6c6f01df5ccd5c3fd0cc545f78fe. Make sure it is a valid recipient contract.

The above address is Counter contract’s in the tutorial.

:computer: Environment
node 10.16.3 and npm 6.9.0
Truffle 5.0.36
Ganache 2.1

Counter contract and run-relayer(locally) deployed successfully and oz-gsn fund-recipient is OK. I confirmed the recipient balance.

Account 0x5aA5142103cb6c6f01df5CcD5C3fD0Cc545F78fe has a GSN balance of 5 ETH

:1234: Code to reproduce
Just followed the GSN tutorials.

Is it something I’ve missed? I got the local relay hub address after running the run-relayer but I don’t know how to use it(there is some configuration?)

1 Like

I found what I missed.
GSNRecipient should be initialized manually after deploying the contracts such as

foo@LAPTOP-HO37JSAG:~/sandbox/ozdapp$ oz send-tx --to 0x72BBA18033DCf231998aFC5143be15615B725D3A
Pick a network development
Select which function
❯ * initialize()

That calls the _upgradeRelayHub(0xD216153c06E857cD7f72665E0aF1d7D82172F494);
Looks like always same RelayHub address(in local or main/test network as doc says)

Finally tutorials works well. :joy:

One more thing I get some red message in the browser console from Metamask when sending a transaction but app works fine.

MetaMask - RPC Error: Internal JSON-RPC error. {code: -32603, message: "Internal JSON-RPC error.", data: {…}, stack: "Error: "message" must be a nonempty string.↵    at…eogaeaoehlefnkodbefgpgknn/background.js:1:1199541"}

My app.js(I changed to SimpleStorage.sol with “old” react) is

async componentDidMount() {
    const injectedWeb3Context = await fromInjected({gsn:{signKey: ephemeral()}});
    const { accounts, networkId, networkName, providerName, lib, connected } = injectedWeb3Context;

    const deployedNetwork = SimpleStorage.networks[networkId.toString()];
    const contract = new lib.eth.Contract(SimpleStorage.abi, deployedNetwork.address);

    this.setState({accounts, contract, networkId, lib});

    lib.eth.subscribe("logs", {address: contract._address})
        .on('data', (log) => {
        .on('error', (err) => console.log(err));

handleSendTx = async () => {

    const {accounts, contract} = this.state;

    if (this.state.val> 0) {
        this.setState({pending: !this.state.pending});

        try {
            await contract.methods.set(this.state.val).send({ from: accounts[0] });
        } catch (err) {
            this.setState({pending: false});

I hope this post is helpful for someone like me.

1 Like

Hi @swkim109

Which tutorial were you running?
Was it the following guide: https://docs.openzeppelin.com/sdk/2.5/gsn-dapp

The guide has a note that initialize needs to be called. How can the documentation be improved to save other people what you went through?

It is important that you remember to call the initialize() function when creating the contract, as this will be sure to get your contract ready to be used in the GSN.

Regarding the MetaMask messages, you could try using fromConnection rather than fromInjected and use Infura.

1 Like

Sorry, that is what I missed. I have 2 initialize functions(one is for GSN and the other is mine) and I called my initialize(). :sweat_smile:

1 Like

Hi @swkim109,

Let me know if the documentation on GSN can be improved.

Hopefully now you can update your initialize to also call the GSNRecipient.Initialize and also add the initializer modifier so that your initialize can only be called once.
See the documentation for details:

1 Like