Skip to content
This repository has been archived by the owner on Nov 9, 2023. It is now read-only.

Introduce LegacyEthereumProvider interface #14

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

mcmire
Copy link
Contributor

@mcmire mcmire commented Jul 14, 2023

In some controller tests it's useful to create a fake provider that conforms to the same interface as a "real" provider but doesn't actually hit the network. To make such a fake provider, however, we must create a class that extends SafeEventEmitterProvider. This is unfortunate as it introduces the possibility that the network could be hit accidentally if not all of the methods in the interface are appropriately overridden.

This commit introduces an interface that allows us to implement the same interface without having to extend it.


For a real-world example of where an interface could be useful, see: https://github.com/MetaMask/core/blob/e506abc29fcddd74591ac32f32a3c2bb0712178e/packages/network-controller/tests/fake-provider.ts#L85

An alternative solution to MetaMask/core#1974.

In some controller tests it's useful to create a fake provider that
conforms to the same interface as a "real" provider but doesn't actually
hit the network. To make such a fake provider, however, we must create a
class that extends SafeEventEmitterProvider. This is unfortunate as it
introduces the possibility that the network could be hit accidentally if
not all of the methods in the interface are appropriately overridden.

This commit introduces an interface that allows us to _implement_ the
same interface without having to extend it.
@mcmire mcmire requested a review from a team as a code owner July 14, 2023 20:54
@Gudahtt
Copy link
Member

Gudahtt commented Jul 14, 2023

To make such a fake provider, however, we must create a class that extends SafeEventEmitterProvider.

It seems that we could already do this today just using the type. We can use that today without extending anything. I might be missing something though.

@mcmire
Copy link
Contributor Author

mcmire commented Jul 14, 2023

@Gudahtt Right, so in the case of FakeProvider, the reason why I don't think using the class as an interface will work is that SafeEventEmitterProvider must be instantiated with a JsonRpcEngine, but I don't want FakeProvider to take those arguments. So if I just replace extends SafeEventEmitterProvider with implements SafeEventEmitterProvider, then not only do I get an error because I can't call super() anymore, but I also get a general error. I believe this is the case because SafeEventEmitterProvider has private fields. This example on the TS playground sort of demonstrates the problem.

@Gudahtt
Copy link
Member

Gudahtt commented Jul 15, 2023

Oh I see. Hmm. In that case, it seems like we don't really want a SafeEventEmitterProvider type, but rather a Provider type. If we omit the event omitter methods and the constructor, what's left are the two provider methods.

Perhaps the name of this type could reflect that? That would let us drop the leading I as well, which is nice, as that seemed unconventional for us.

@mcmire
Copy link
Contributor Author

mcmire commented Jul 17, 2023

@Gudahtt Ah, right. We care about the event emitter part of the API — for instance, our provider in NetworkController needs to be properly typed so that we can pass it to swappable-obj-proxy — but Ethers doesn't care, and same goes for eth-query, now that I think about it. I'll rename it.

@mcmire
Copy link
Contributor Author

mcmire commented Jul 18, 2023

Alright, I've replaced SimpleEventEmitterProvider with JsonRpcProvider.

By the way I wasn't sure what to name this type. I didn't want to name it Provider because it could clash with other Provider types that we have defined elsewhere (currently we have three types across this repo, detect-provider, and providers). I noticed that we consistently call the provider an "Ethereum provider" in the JSDocs, so I guess that could make sense, although there's nothing about the interface that's Ethereum-specific. If anything it's a pre-EIP-1159 legacy JSON-RPC provider API that only MetaMask uses. That's kind of a mouthful though.

@mcmire mcmire changed the title Introduce SafeEventEmitterProvider interface Introduce JsonRpcProvider interface Jul 20, 2023
@Gudahtt
Copy link
Member

Gudahtt commented Jul 26, 2023

I'd consider it an Ethereum provider; the loose conventions that it follows are specific to the Ethereum ecosystem.

LegacyEthereumProvider maybe? 🤷 The name you chose seems OK too though.

Gudahtt
Gudahtt previously approved these changes Jul 26, 2023
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@mcmire
Copy link
Contributor Author

mcmire commented Jul 27, 2023

@Gudahtt I thought about it some more and I like LegacyEthereumProvider. I think it's important to remember that while using this interface.

@mcmire
Copy link
Contributor Author

mcmire commented Aug 22, 2023

Ah, I'd forgotten about this PR. I'll try to get this updated today.

@legobeat
Copy link
Contributor

Had completely forgot about the existence of this PR when making MetaMask/utils#140

Do I get this right?

@mcmire mcmire changed the title Introduce JsonRpcProvider interface Introduce LegacyEthereumProvider interface Oct 2, 2023
@jiexi
Copy link

jiexi commented Oct 3, 2023

I think LegacyEthereumProvider would match nicely with the other things we have prefixed with Legacy that are also provider related https://github.com/MetaMask/metamask-extension/blob/develop/app/scripts/contentscript.js#L42

Should we look back into phasing out send() and sendAsync()?

Looks like we tried to mark them deprecated at some point but ended up backing out MetaMask/providers#29

@mcmire
Copy link
Contributor Author

mcmire commented Oct 4, 2023

Should we look back into phasing out send() and sendAsync()?

Yes. Since we always control the provider anywhere it's used, ideally we should not be using a legacy provider anywhere, we should make our provider EIP-1193-compatible. From there, we can either modify eth-query/ethjs-query to support such a provider or even drop them altogether and use Ethers everywhere, or whatever we want to end up doing down the road.

MajorLift added a commit to MetaMask/core that referenced this pull request Oct 13, 2023
## Explanation

This PR implements the following incremental steps in the process for
migrating `eth-json-rpc-provider` into the core monorepo:

***

### Phase B: Staging from `merged-packages/`

#### 5. Port tags 
  - See: #1800
  
<details>  
  <summary>Push ported tags to core repo</summary>
  
- [x]
https://github.com/MetaMask/core/releases/tag/@metamask/eth-json-rpc-provider@2.2.0
- [x]
https://github.com/MetaMask/core/releases/tag/@metamask/eth-json-rpc-provider@2.1.0
- [x]
https://github.com/MetaMask/core/releases/tag/@metamask/eth-json-rpc-provider@2.0.0
- [x]
https://github.com/MetaMask/core/releases/tag/@metamask/eth-json-rpc-provider@1.0.1
- [x]
https://github.com/MetaMask/core/releases/tag/@metamask/eth-json-rpc-provider@1.0.0
</details>

<details>
<summary>Verify that the tag diff links in CHANGELOG are
working</summary>
  
- [x] **WONTFIX**:
https://github.com/MetaMask/core/compare/@metamask/eth-json-rpc-provider@2.2.0...HEAD
- [x]
https://github.com/MetaMask/core/compare/@metamask/eth-json-rpc-provider@2.1.0...@metamask/eth-json-rpc-provider@2.2.0
- [x]
https://github.com/MetaMask/core/compare/@metamask/eth-json-rpc-provider@2.0.0...@metamask/eth-json-rpc-provider@2.1.0
- [x]
https://github.com/MetaMask/core/compare/@metamask/eth-json-rpc-provider@1.0.1...@metamask/eth-json-rpc-provider@2.0.0
- [x]
https://github.com/MetaMask/core/compare/@metamask/eth-json-rpc-provider@1.0.0...@metamask/eth-json-rpc-provider@1.0.1
</details>

### Phase C: Integration into `packages/`

#### 1. The big leap
- [x] **Move migration target from `migrated-packages/` to
`packages/`.**
- [x] Run `yarn install` in the root directory.
- [x] Check that all tests are passing in migration target by running
`yarn workspace @metamask/<package-name> test`.

#### 2. Update downstream repos
- [x] Add tsconfig reference paths for migration target in downstream
packages and root.
- [x] Bump migration target version in downstream packages and root.

#### 3. Linter fixes
- [x] Apply yarn constraints fixes to migration target package.json
file: `yarn constraints --fix` (run twice).
- [x] Identify validator fixes for CHANGELOG using `yarn workspace
@metamask/<package-name> changelog:validate` and apply the diffs.

#### 4. Resolve downstream errors
- [x] #1653
  - If introducing the migration target breaks any downstream repos:
    - [x] Resolve simple errors
- [x] Mark and ignore complex errors using `@ts-expect-error TODO:`
annotations.
- [x] Create a separate issue for resolving the marked errors as soon as
the migration is completed.

#### 5. Finalize merge
- [x] Check that all tests are passing in all subpackages of core and
CI.
- [x] Merge `packages/<package-name>` directory into core main branch.

***

See #1551 (comment)
for an outline of the entire process.

## Next Steps

- The next PR(s) will implement the final steps of the migration process
(D-1 in the migration checklist).

## Blocked by
- Dependencies:
  - [x] typescript bump: #1718
- [x] `@metamask/utils` bump: #1639
- Downstream type errors:
  - [x] #1653
- [ ] MetaMask/eth-json-rpc-provider#14
(ignored)
  - [ ] MetaMask/utils#140 (ignored)
- Tag porting:
  - [x] #1802
- [x] "Unreleased" tag diff link shows entire history of core:
https://github.com/MetaMask/core/compare/@metamask/eth-json-rpc-provider@2.2.0...HEAD

## References

- Contributes to #1685
- Contributes to #1551

## Changelog

<!--
If you're making any consumer-facing changes, list those changes here as
if you were updating a changelog, using the template below as a guide.

(CATEGORY is one of BREAKING, ADDED, CHANGED, DEPRECATED, REMOVED, or
FIXED. For security-related issues, follow the Security Advisory
process.)

Please take care to name the exact pieces of the API you've added or
changed (e.g. types, interfaces, functions, or methods).

If there are any breaking changes, make sure to offer a solution for
consumers to follow once they upgrade to the changes.

Finally, if you're only making changes to development scripts or tests,
you may replace the template below with "None".
-->

### `@metamask/eth-json-rpc-provider`

- **ADDED**: Migrated into the core monorepo.

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've highlighted breaking changes using the "BREAKING" category
above as appropriate
@mcmire
Copy link
Contributor Author

mcmire commented Oct 16, 2023

I know we are working on creating unified types, but I think it would be worth it to have this type around in the meantime. My goal here isn't to unify anything, but merely to provide a lightweight version of the provider type that this package exports, so that if we want to make a fake provider in tests we can do so without having to subclass SafeEventEmitterProvider (which poses the risk that the network could actually be hit in tests).

So I'm proposing that we merge this PR first. Any thoughts on this? /cc @legobeat

@MetaMask MetaMask locked and limited conversation to collaborators Nov 1, 2023
@MajorLift
Copy link
Contributor

MajorLift commented Nov 1, 2023

This library has now been migrated into the core monorepo. This PR has been locked and this repo will be archived shortly. Going forward, any changes to this library will only be included in future releases if they are made in the core repo.

  • Please push this branch to core and open a new PR there.
  • Optionally, add a link pointing to the discussion here in the PR to provide context.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants