Skip to content

Commit

Permalink
feat: add ChainController (#4227)
Browse files Browse the repository at this point in the history
## Explanation

This new controller will be responsible of exposing Snaps that implement
the newly defined Chain API.

This controller also implements the chain API itself.

Reference: https://github.com/MetaMask/chain-api/

## Changelog

### `@metamask/chain-controller`

- **Added**: New `ChainController`: exposes/interacts with chain API
providers

## 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

---------

Co-authored-by: Elliot Winkler <[email protected]>
Co-authored-by: Gustavo Antunes <[email protected]>
  • Loading branch information
3 people authored May 20, 2024
1 parent e3929c9 commit 2752a88
Show file tree
Hide file tree
Showing 18 changed files with 934 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This repository contains the following packages [^fn1]:
- [`@metamask/assets-controllers`](packages/assets-controllers)
- [`@metamask/base-controller`](packages/base-controller)
- [`@metamask/build-utils`](packages/build-utils)
- [`@metamask/chain-controller`](packages/chain-controller)
- [`@metamask/composable-controller`](packages/composable-controller)
- [`@metamask/controller-utils`](packages/controller-utils)
- [`@metamask/ens-controller`](packages/ens-controller)
Expand Down Expand Up @@ -58,6 +59,7 @@ linkStyle default opacity:0.5
assets_controllers(["@metamask/assets-controllers"]);
base_controller(["@metamask/base-controller"]);
build_utils(["@metamask/build-utils"]);
chain_controller(["@metamask/chain-controller"]);
composable_controller(["@metamask/composable-controller"]);
controller_utils(["@metamask/controller-utils"]);
ens_controller(["@metamask/ens-controller"]);
Expand Down Expand Up @@ -97,6 +99,7 @@ linkStyle default opacity:0.5
assets_controllers --> network_controller;
assets_controllers --> polling_controller;
assets_controllers --> preferences_controller;
chain_controller --> base_controller;
composable_controller --> base_controller;
composable_controller --> json_rpc_engine;
ens_controller --> base_controller;
Expand Down
10 changes: 10 additions & 0 deletions packages/chain-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

[Unreleased]: https://github.com/MetaMask/core/
20 changes: 20 additions & 0 deletions packages/chain-controller/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
MIT License

Copyright (c) 2024 MetaMask

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
102 changes: 102 additions & 0 deletions packages/chain-controller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# `@metamask/chain-controller`

Manages chain-agnostic providers implementing the chain API.

## Installation

`yarn add @metamask/chain-controller`

or

`npm install @metamask/chain-controller`

## Contributing

This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).

## Description

This controller is responsible to "bridge" Snaps that implements the [Chain API] and a MetaMask
client.

The controller maps a "chain provider" to its CAIP-2 (chain id) identifier
(named `scope` in the [Chain API]).
The MetaMask client can then use an external source (outside for current controllers that
only support EVM networks) to fetch information from a non-EVM network.

The controller itself also implements the [Chain API]. Its uses the `scope` (that is always
required for any methods) to identify the chain provider and then forward the method call to this
provider.

The calls are dispatched through the `SnapsController:handleRequest`'s action.

Here's the high-level flow when invoking a [Chain API]'s method:

```mermaid
%%{init: {"flowchart": {"htmlLabels": false}}}%%
sequenceDiagram
autonumber
participant MetaMask
participant ChainController
participant Snap
box Metamask Client
participant MetaMask
participant ChainController
end
MetaMask -> Snap: Retrieves Snap ID
MetaMask ->> ChainController: registerProvider(scope, snapId)
note over MetaMask,Snap: Provider must be registered first
MetaMask ->> ChainController: chain_method(scope, ...)
activate MetaMask
alt If there is a chain client for this scope
ChainController ->> ChainController: client = getProviderClient(scope)
ChainController ->> Snap: client.chain_method(scope, ...)
Snap ->> Snap: Process Chain API request
Snap -->> ChainController: Chain API response
end
ChainController -->> MetaMask: Chain API Response
deactivate MetaMask
```

Clients and Snap interactions:

```mermaid
%%{init: {"flowchart": {"htmlLabels": false}}}%%
sequenceDiagram
autonumber
participant ChainController
participant SnapChainProviderClient
participant SnapHandlerClient
participant SnapsController
ChainController ->> SnapChainProviderClient: chain_method(scope, ...)
activate ChainController
note over SnapChainProviderClient: This client also implements the Chain API methods
SnapChainProviderClient ->> SnapHandlerClient: submitRequest({ snapId, origin, handler, request })
SnapHandlerClient ->> SnapsController: :handleRequest(...)
SnapsController -->> SnapHandlerClient: Response
SnapHandlerClient -->> SnapChainProviderClient: Response
SnapChainProviderClient -->> ChainController: Response
deactivate ChainController
```

## Resources

- [Chain API](https://github.com/MetaMask/chain-api/)
26 changes: 26 additions & 0 deletions packages/chain-controller/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* For a detailed explanation regarding each configuration property and type check, visit:
* https://jestjs.io/docs/configuration
*/

const merge = require('deepmerge');
const path = require('path');

const baseConfig = require('../../jest.config.packages');

const displayName = path.basename(__dirname);

module.exports = merge(baseConfig, {
// The display name when running multiple projects
displayName,

// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
});
71 changes: 71 additions & 0 deletions packages/chain-controller/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"name": "@metamask/chain-controller",
"version": "0.0.0",
"description": "Manages chain-agnostic providers",
"keywords": [
"MetaMask",
"Ethereum"
],
"homepage": "https://github.com/MetaMask/core/tree/main/packages/chain-controller#readme",
"bugs": {
"url": "https://github.com/MetaMask/core/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/core.git"
},
"license": "MIT",
"sideEffects": false,
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/types/index.d.ts"
},
"./package.json": "./package.json"
},
"main": "./dist/index.js",
"types": "./dist/types/index.d.ts",
"files": [
"dist/"
],
"scripts": {
"build": "tsup --config ../../tsup.config.ts --tsconfig ./tsconfig.build.json --clean",
"build:docs": "typedoc",
"changelog:update": "../../scripts/update-changelog.sh @metamask/chain-controller",
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/chain-controller",
"publish:preview": "yarn npm publish --tag preview",
"test": "jest --reporters=jest-silent-reporter",
"test:clean": "jest --clearCache",
"test:verbose": "jest --verbose",
"test:watch": "jest --watch"
},
"dependencies": {
"@metamask/base-controller": "^5.0.2",
"@metamask/chain-api": "^0.0.1",
"@metamask/keyring-api": "^6.1.1",
"@metamask/snaps-controllers": "^8.1.1",
"@metamask/snaps-sdk": "^4.2.0",
"@metamask/snaps-utils": "^7.4.0",
"@metamask/utils": "^8.3.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"@metamask/auto-changelog": "^3.4.4",
"@types/jest": "^27.4.1",
"@types/readable-stream": "^2.3.0",
"deepmerge": "^4.2.2",
"jest": "^27.5.1",
"ts-jest": "^27.1.4",
"typedoc": "^0.24.8",
"typedoc-plugin-missing-exports": "^2.0.0",
"typescript": "~4.9.5"
},
"engines": {
"node": ">=16.0.0"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
}
}
Loading

0 comments on commit 2752a88

Please sign in to comment.