Psychedelic / plug

Plug is a browser extension for users of the Internet Computer that allows you to access your ICP, Cycles, and other tokens as well as log into IC apps with one click.
GNU General Public License v3.0
166 stars 40 forks source link

TypeError: e is not a function #327

Open ghost opened 2 years ago

ghost commented 2 years ago

Dear team,

I've played with the Plug Wallet and tried to integrate it into my small app, but to no avail. I'm using version 0.4.4 with latest Firefox and here's my code almost without any modifications from your docs:

await window?.ic?.plug?.requestConnect({ host, });
const status = await window.ic.plug.isConnected();
console.log("connected:", status, canisterId, idlFactory);
const actor = await window.ic.plug.createActor({ canisterId, idlFactory });

The first 3 lines work as expected and I see a console output with status being true, my canister id and that the idlFunction is initialized. However, the execution of createAgent fails with an exception (see the screenshot).

Screenshot 2022-01-01 at 13 28 06

Since it's an internal exception and not an error returned from the actor constructor, I am a bit clueless about how to proceed.

Any help is appreciated!

tomiir commented 2 years ago

Hi! At first sight I can see that you are passing idlFactory when it's expecting interfaceFactory. Other than that the code seems fine I think. Let me know if this works or not. You can also always drop us a message in the discord channel (should get a quicker answer too!)

  public async createActor<T>({
    canisterId,
    interfaceFactory,
  }: CreateActor<T>): Promise<ActorSubclass<T>> 
ghost commented 2 years ago

@tomiir thanks so much, this was indeed the problem. After I started passing idlFactory as interfaceFactory I indeed could create the agent successfully:

        let status = await window.ic.plug.isConnected();
        if (status) {
            console.log(status, host, canisterId, idlFactory);
            const actor = await window.ic.plug.createActor({ host, canisterId, interfaceFactory: idlFactory });
            let result = await actor.popular_tags();
        }

However now I run into the next problem with this newly created agent. Whenever I call any function on it (eg popular_tags in the example above) I always get Uncaught (in promise) Error: No Agent could be found. I asked this question in #plug channel on discord, but didn't get useful hints. Do you have an idea maybe?

ghost commented 2 years ago

Btw, I figured out the issue - my flow reloaded the window after the connection and this destroyed the agent. I'm puzzled right now how to avoid reconnecting on every new app visit, but will consult the docs first. Sorry for the noise!

ghost commented 2 years ago

FYI, I decided to not integrate Plug for now. I managed to get it working, but I don't think the only workflow I found working is user friendly. Let me sketch the issues I encountered so that you can consider improving them in the future.

  1. TypeError: e is not a function: was caused by me misreading idlFactory as interfaceFactory. So it seems that interfaceFactory is a required parameter of the createActor constructor. This problem wouldn't be a problem if createActor would check all required arguments and return an error if one of them is missing.
  2. Uncaught (in promise) Error: No Agent could be found.: it turns out that for some unclear (to me) reason, even if await window.ic.plug.isConnected() returns true I still need to call await window.ic.plug.requestConnect({ host, whitelist: [canisterId] }) so that the agent gets initialized. Which effectively means there is no notion of a session and the Plug modal is shown on every single loading of the page. This makes no sense to me.
  3. Once I "fixed" the issue by requiring a connection on every load I ran into the next issue of failing to certify responses from the back end. I realized that it might has something to do with Plug using the NNS root key in local development mode, so with some googling and reading the dfinity forum I manager to overcome this problem using this code: if (process.env.DFX_NETWORK == "local") await window.ic.plug.agent.fetchRootKey(); But it really should be in the docs or even automated.
  4. The logout using await window.ic.plug.disconnect() is not working: it just hangs on that await for quite some time and then eventually I see the error Uncaught (in promise) Error: There was an error when this app/page tried to interact with your wallet in Plug. Please contact this project’s developers. I guess I could solve this as well somehow, but I decided to deprioritize the ingreation for now.

I help it helps during the future development!

rocky-fleek commented 2 years ago

Reopening this issue as it contains a lot of valid points and possible improvements.

rocky-fleek commented 2 years ago

Hi @TaggrX. Thanks for taking the time to debug and describe these issues so thoroughly and sorry for the late reply :pray: You make very valid points and I'll try to address them individually:

  1. You are right. We'll add parameter validation/sanitization on the provider interface methods. We use typescript but clearly this won't fail on JS code at all.
  2. Will review this point in particular, as the createActor method should be creating an agent if it's not present. The issue with the agent is that whenever a page refreshes, the inpage script in plug is re-executed, and the provider re-instantiated, causing the agent to be removed. We've had this issue for some time now and part of the reason we are trying to push the createActor approach (instead of creating actors with ic.plug.agent) is to ensure the agent is created at the time of execution and thus always available to the user.
  3. This fix is being added to the new version of plug. Probably coming out next week. (https://github.com/Psychedelic/plug-inpage-provider/pull/68)
  4. Will look into this as well. Might have to do with a refactor we did in the frontend regarding events and connection statuses.

We'll be scoping and planning these fixes next week and will let you know when they are released. Thanks again for the feedback and feel free to drop a message in our discord anytime! https://discord.gg/pFjDRhms

ghost commented 2 years ago

Thanks so much for addressing my feedback! I should have more time in a couple of weeks and would be very happy to try integrating Plug again!

riveign commented 2 years ago

Hi! @TaggrX wanted to do a follow up on this points

  1. This was released in 0.5 https://github.com/Psychedelic/plug-inpage-provider/pull/73
  2. This will be released in 0.6 (next version)
  3. This was released in 0.5 https://github.com/Psychedelic/plug-inpage-provider/pull/68
  4. This was released in the previous 0.4.7

Will keep the issue open till we release 0.6.

Thank you very much for all the feedback :D