Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clients: Support Brave wallet default #411

Merged
merged 1 commit into from
Oct 31, 2024
Merged

Conversation

aefhm
Copy link
Contributor

@aefhm aefhm commented Sep 24, 2024

Description

Close #385 maybe.

Problem

Wagmi is concerned with bad implementations of EIP-1193 and wants to check that the removeListener function exists. However, the Brave wallet overrides ethereum properties and does not like the way we currently use Proxy objects, giving a typeerror upon a get call.

Our current implementation is a classic Proxy pattern in order to preserve this.

const proxy = new Proxy(aSecret, {
  get(target, prop, receiver) {
    const value = target[prop];
    if (value instanceof Function) {
      return function (...args) {
        return value.apply(this === receiver ? target : this, args);
      };
    }
    return value;
  },
});

simplified to:

return typeof value === 'function' ? value.bind(upstream) : value;

We can repro error via:

class Secret {
  #x = 1;
  x() {
    return this.#x;
  }
}

const aSecret = new Secret();
Object.defineProperties(aSecret, {
  removeListener: {
    value: function () {},
    writable: false,
  }
});
const proxy = new Proxy(aSecret, {
  get(target, prop, receiver) {
    const value = target[prop];
    if (value instanceof Function) {
      return function (...args) {
        return value.apply(this === receiver ? target : this, args);
      };
    }
    return value;
  },
});
console.log(proxy.removeListener);

One solution is to not forward context in order to maintain the function signature for Brave browsers as noted in this PR.

Copy link

netlify bot commented Sep 24, 2024

Deploy Preview for oasisprotocol-sapphire-paratime canceled.

Name Link
🔨 Latest commit 3cc95f8
🔍 Latest deploy log https://app.netlify.com/sites/oasisprotocol-sapphire-paratime/deploys/6722b98ef398b800083f2200

@aefhm aefhm self-assigned this Sep 24, 2024
@aefhm aefhm added p:1 Priority: high client javascript Pull requests that update JavaScript code bug integrations labels Sep 24, 2024
@aefhm aefhm requested a review from CedarMist September 24, 2024 04:59
@aefhm aefhm force-pushed the xz/fix-proxy-in-provider branch from de0f2ec to 60e355a Compare September 24, 2024 05:00
@aefhm aefhm force-pushed the xz/fix-proxy-in-provider branch from 60e355a to 9a0e4bf Compare October 6, 2024 17:45
@aefhm
Copy link
Contributor Author

aefhm commented Oct 6, 2024

One other solution mentioned would involve giving up the Proxy which currently prevents developers from accidentally double wrapping the provider. We ostensibly need that differentiation if but only for debugging purposes. Otherwise, I think creating a singleton factory would not necessarily be a clean solution, requiring a dev to continually reference the wrapped SapphireProvider.

@aefhm
Copy link
Contributor Author

aefhm commented Oct 6, 2024

Checking if @lukaw3d knows of a better magical JavaScript solution. 🙏🧙

@CedarMist
Copy link
Member

It should be possible to remove the proxy contract and use some kind of WeakRef singleton for providers instead?

Or... just don't do either.

As long as there's a test for using double-wrapped providers to make sure they don't mess up encryption & decryption.

@aefhm
Copy link
Contributor Author

aefhm commented Oct 7, 2024

Brave makes the upstream a Proxy. 😆

@CedarMist
Copy link
Member

CedarMist commented Oct 7, 2024

Can we do something like instead?

return (...args) => Reflect.apply(value, upstream, args)

Which will avoid the .bind call

@aefhm
Copy link
Contributor Author

aefhm commented Oct 7, 2024

Can we do something like instead?

return (...args) => Reflect.apply(value, upstream, args)

Which will avoid the .bind call

Uncaught (in promise) TypeError: 'get' on proxy: property 'removeListener' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected 'function(e,t){var n,r,i,o,s;if(u(t),void 0===(r=this._events))return this;if(void 0===(n=r[e]))return this;if(n...<omitted>...s}' but got '(...args) => Reflect.apply(value, upstream, args)')
...

😭

clients/js/src/provider.ts Outdated Show resolved Hide resolved
@aefhm
Copy link
Contributor Author

aefhm commented Oct 8, 2024

Can we do something like instead?

return (...args) => Reflect.apply(value, upstream, args)

Which will avoid the .bind call

Uncaught (in promise) TypeError: 'get' on proxy: property 'removeListener' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected 'function(e,t){var n,r,i,o,s;if(u(t),void 0===(r=this._events))return this;if(void 0===(n=r[e]))return this;if(n...<omitted>...s}' but got '(...args) => Reflect.apply(value, upstream, args)')
...

😭

Still generates typeerror.

Edit. I think the complication comes from the fact that upstream will sometimes be an Object, and sometimes a Proxy (Brave), so staying as a Proxy in our wrapper seems to be only path forward...

@aefhm aefhm force-pushed the xz/fix-proxy-in-provider branch from 9a0e4bf to 25a992d Compare October 8, 2024 11:20
@aefhm
Copy link
Contributor Author

aefhm commented Oct 13, 2024

I think maintaining the Proxy object is a reasonable for now in order to support Brave or any other upstream that hijacks the provider with their trap. What do you think @CedarMist?

@aefhm aefhm force-pushed the xz/fix-proxy-in-provider branch from 25a992d to 4fbd57c Compare October 22, 2024 14:31
@aefhm aefhm requested a review from lukaw3d October 22, 2024 22:16
@aefhm aefhm force-pushed the xz/fix-proxy-in-provider branch 3 times, most recently from 0fe5314 to e1d9092 Compare October 27, 2024 21:50
@aefhm aefhm force-pushed the xz/fix-proxy-in-provider branch from e1d9092 to 3cc95f8 Compare October 30, 2024 22:56
@CedarMist CedarMist added this to the clients-js-2.1.0 milestone Oct 30, 2024
@aefhm aefhm merged commit 88143e1 into main Oct 31, 2024
11 checks passed
@aefhm aefhm deleted the xz/fix-proxy-in-provider branch October 31, 2024 18:03
github-actions bot added a commit that referenced this pull request Oct 31, 2024
…z/fix-proxy-in-provider

clients: Support Brave wallet default 88143e1
github-actions bot added a commit that referenced this pull request Oct 31, 2024
…/fix-proxy-in-provider

clients: Support Brave wallet default 88143e1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug client integrations javascript Pull requests that update JavaScript code p:1 Priority: high
Projects
None yet
Development

Successfully merging this pull request may close these issues.

sapphire-viem-v2: ProxyObject throws error due to changed function signature
3 participants