Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Argument of type 'EthereumProvider' is not assignable to parameter of type 'ExternalProvider | JsonRpcFetchFunc'. #3455

Open
gluax opened this issue Jul 29, 2022 · 10 comments

Comments

@gluax
Copy link

gluax commented Jul 29, 2022

Hey all.

I would love for there to be more typescript examples and more programmatic examples.

I'm trying to programmatically spin up a local blockchain with a contract for fuzz testing. I.e. I need the ability to randomly create addresses with funds and etc on demand. I do see a lot of the functions I need available, however, it's quite a struggle to figure out how to get access to what I need to call. So some more examples would really be appreciated for the programmatic side.

However, I'm blocked right at the start trying to create an ethers Web3Provider with the error, Argument of type 'EthereumProvider' is not assignable to parameter of type 'ExternalProvider | JsonRpcFetchFunc'.

The code is as follows:

import { ethers } from "ethers";
import Ganache from "ganache";

export function start_private_chain(): ethers.providers.Web3Provider {
  const provider = Ganache.provider();
  return new ethers.providers.Web3Provider(provider);
}

Would appreciate any help here. Thanks.

@davidmurdoch
Copy link
Member

Are you able to find and post the type for ExternalProvider?

@gluax
Copy link
Author

gluax commented Jul 29, 2022

From ethers lib .

@davidmurdoch
Copy link
Member

My hunch is that this is due to strictFunctionTypes enabled in your tsconfig.json (see also: strict).

Ganache's provider types are very strict, which let's us offer type hints like:

image

possible rpc methods

and:

image

an rpc method's specific allowed params.

The problem is that Ethers' expected provider function signature's method: string is not strictly assignable to Ganache's method: "eth_estimateGas" | "eth_sendTransaction" | ... .

This isn't really an Ether's problem though, nor is it a bug in Ganache. But it does make for a bad UX!

Additionally, Ether's omits the jsonrpc and id types from their send and sendAsync function signatures (I suspect this is a bug in Ether's types and this may need to be updated).

Possible fixes:

Ethers could relax its ExternalProvider type so that sendAsync, send, and request accept any for the method param.

  • downside is the types would now be too loose.

Ganache could relax its types on sendAsync, send, and request to accept string for the method param.

  • downside is that we loose detailed type checking

Ethers could use Generics:

export type ExternalProvider<T extends string> = {
    isMetaMask?: boolean;
    isStatus?: boolean;
    host?: string;
    path?: string;
    request?: (request: { method: T, params?: Array<any> }) => Promise<any>
}

export type JsonRpcFetchFunc<T extends string> = (method: T, params?: Array<any>) => Promise<any>;

export class Web3Provider<T extends string> extends JsonRpcProvider {
    readonly provider: ExternalProvider<T> | null = null;
    readonly jsonRpcFetchFunc: JsonRpcFetchFunc<T> | null = null;

    constructor(provider: ExternalProvider<T> | JsonRpcFetchFunc<T>, network?: Networkish) {
      //...
    }
    // ...
}

Something similar to the above would allow for the best of both worlds. It even opens up the possibility for Ethers to flow the strict type checking offered by Ganache (and maybe others?) in its own methods, like send. /cc @ricmoo

That said, there may be some other issues with the types, but the problems are only with the types, not with the run-time provider. You should be able to use it as you have now, but you'll need to cast it with as any or (as unknown as ExternalProvider).

Let's keep this open so the team here can discuss options and other potential solutions I haven't thought of.

Re: docs for programmatic use... you are right; we are lacking in that department... docs are in the works! (cc @MicaiahReid)

@davidmurdoch davidmurdoch moved this to Inbox in Ganache Aug 2, 2022
@gluax
Copy link
Author

gluax commented Aug 2, 2022

Hey, all I'm trying to create the provider as stated above, however, it seems the network is never set.

I'm trying to do the following essentially:

const options = {
      chain: {
        networkId: 5777,
        chainId: 5777,
      }
    };
    const server = Ganache.server(options);
    const provider = new ethers.providers.Web3Provider(this.server.provider as unknown as ethers.providers.ExternalProvider);
     await this.server.listen(8888, 'localhost');

However, await provider.getNetwork() provides a name of unknown for the network. I didn't see any ways to configure this either in the documentation. Can I get some advice here please?

@davidmurdoch
Copy link
Member

What do you expect the network name to be?

@gluax
Copy link
Author

gluax commented Aug 3, 2022

Something just like "evm" or "ganache" or other standard network names, but as it is now, sending transactions to a deployed contract results in

Error: could not detect network (event="noNetwork", code=NETWORK_ERROR, version=providers/5.6.8)
    at Logger.makeError (C:\Users\galu\Documents\work\Flux\fpo-node-fuzzer\node_modules\@ethersproject\logger\lib\index.js:233:21)
    at Logger.throwError (C:\Users\galu\Documents\work\Flux\fpo-node-fuzzer\node_modules\@ethersproject\logger\lib\index.js:242:20)
    at JsonRpcProvider.<anonymous> (C:\Users\galu\Documents\work\Flux\fpo-node-fuzzer\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:561:54)
    at step (C:\Users\galu\Documents\work\Flux\fpo-node-fuzzer\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:48:23)
    at Object.throw (C:\Users\galu\Documents\work\Flux\fpo-node-fuzzer\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:29:53)
    at rejected (C:\Users\galu\Documents\work\Flux\fpo-node-fuzzer\node_modules\@ethersproject\providers\lib\json-rpc-provider.js:21:65)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  reason: 'could not detect network',
  code: 'NETWORK_ERROR',
  event: 'noNetwork'
}

because there is no network set.

@gluax
Copy link
Author

gluax commented Aug 3, 2022

Update: My network error was resolved by specifying 0.0.0.0 as the server IP to start on rather than localhost. This is interesting to me considering I'm making no outbound calls. But writing it here for anyone else with a similar issue!

@davidmurdoch
Copy link
Member

@gluax Ether's has no way of knowing that the network you created only milliseconds ago should have a name ("ganache" isn't a unique network, and all Ethereum networks use "evm"). That said, I wonder if chainId and networkId of 1337 would show as "devnet" or something similar.

@gluax Did you try server.listen(8888, "127.0.0.1")? The Ganache server might not be binding to a hostname of "localhost" as expected. If 127.0.0.1 does work for you can you open a new issue about accepting "localhost" as a hostname?

@gluax
Copy link
Author

gluax commented Aug 3, 2022

@davidmurdoch ah that makes more sense. I'm out for lunch at the moment but will try the actual address for localhost when I get back and open an issue if that is the problem.

@gluax
Copy link
Author

gluax commented Aug 3, 2022

Correct 127.0.0.1 works however specifying localhost does not. See issue #3491.

@davidmurdoch davidmurdoch moved this from Inbox to Backlog in Ganache Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
Status: Backlog
Development

No branches or pull requests

2 participants