diff --git a/README.md b/README.md index a93ec4e..78ae79c 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,16 @@ This Web3.js plugin adds support for the following wallet-related RPC methods: - [wallet_addEthereumChain (EIP-3085)](https://eips.ethereum.org/EIPS/eip-3085) -- [wallet_updateEthereumChain (EIP-2015)](https://eips.ethereum.org/EIPS/eip-2015) - [wallet_switchEthereumChain (EIP-3326)](https://eips.ethereum.org/EIPS/eip-3326) -- [wallet_getOwnedAssets (EIP-2256)](https://eips.ethereum.org/EIPS/eip-2256) - [wallet_watchAsset (EIP-747)](https://eips.ethereum.org/EIPS/eip-747) - -Not implemented yet: - - [wallet_requestPermissions (EIP-2255)](https://eips.ethereum.org/EIPS/eip-2255) - [wallet_getPermissions (EIP-2255)](https://eips.ethereum.org/EIPS/eip-2255) +- [wallet_revokePermissions](https://docs.metamask.io/wallet/reference/json-rpc-methods/wallet_revokepermissions/) + +Experimental: + +- [wallet_updateEthereumChain (EIP-2015)](https://eips.ethereum.org/EIPS/eip-2015) +- [wallet_getOwnedAssets (EIP-2256)](https://eips.ethereum.org/EIPS/eip-2256) ## Installation @@ -62,6 +63,30 @@ await web3.walletRpc.addEthereumChain({ }); ``` +#### switchEthereumChain + +Invokes the `wallet_switchEthereumChain` method as defined in [EIP-3326](https://eips.ethereum.org/EIPS/eip-3326). + +```typescript +await web3.walletRpc.switchEthereumChain({ chainId: 5000 }); +``` + +#### watchAsset + +Invokes the `wallet_watchAsset` method as defined in [EIP-747](https://eips.ethereum.org/EIPS/eip-747). + +```typescript +await web3.walletRpc.watchAsset({ + type: "ERC20", + options: { + address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + symbol: "USDC", + }, +}); +``` + +### Experimental methods + #### updateEthereumChain Invokes the `wallet_updateEthereumChain` method as defined in [EIP-2015](https://eips.ethereum.org/EIPS/eip-2015). @@ -80,14 +105,6 @@ await web3.walletRpc.updateEthereumChain({ }); ``` -#### switchEthereumChain - -Invokes the `wallet_switchEthereumChain` method as defined in [EIP-3326](https://eips.ethereum.org/EIPS/eip-3326). - -```typescript -await web3.walletRpc.switchEthereumChain({ chainId: 5000 }); -``` - #### getOwnedAssets Invokes the `wallet_getOwnedAssets` method as defined in [EIP-2256](https://eips.ethereum.org/EIPS/eip-2256). @@ -98,20 +115,6 @@ const ownedAssets = await web3.walletRpc.getOwnedAssets({ }); ``` -#### watchAsset - -Invokes the `wallet_watchAsset` method as defined in [EIP-747](https://eips.ethereum.org/EIPS/eip-747). - -```typescript -await web3.walletRpc.watchAsset({ - type: "ERC20", - options: { - address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - symbol: "USDC", - }, -}); -``` - ## Contributing We welcome pull requests! For major changes, please open an issue first to discuss the proposed modifications. diff --git a/packages/web3-plugin-wallet-rpc/src/WalletRpcPlugin.ts b/packages/web3-plugin-wallet-rpc/src/WalletRpcPlugin.ts index 2fae980..9384a3d 100644 --- a/packages/web3-plugin-wallet-rpc/src/WalletRpcPlugin.ts +++ b/packages/web3-plugin-wallet-rpc/src/WalletRpcPlugin.ts @@ -5,6 +5,8 @@ import type { AddEthereumChainRequest, GetOwnedAssetsRequest, OwnedAsset, + Permission, + PermissionRequest, UpdateEthereumChainRequest, WatchAssetRequest, } from "./types"; @@ -16,6 +18,9 @@ type WalletRpcApi = { wallet_switchEthereumChain: (chainId: Numbers) => void; wallet_getOwnedAssets: (param: GetOwnedAssetsRequest) => OwnedAsset[]; wallet_watchAsset: (param: WatchAssetRequest) => boolean; + wallet_requestPermissions: (param: PermissionRequest) => Permission[]; + wallet_getPermissions: () => Permission[]; + wallet_revokePermissions: (param: PermissionRequest) => void; }; /** @@ -46,6 +51,20 @@ export class WalletRpcPlugin extends Web3PluginBase { * * @param param - Details of the chain to add * @returns a Promise that resolves if the request is successful + * + * @example + * await web3.walletRpc.addEthereumChain({ + * chainId: 5000, + * blockExplorerUrls: ["https://mantlescan.xyz"], + * chainName: "Mantle", + * iconUrls: ["https://icons.llamao.fi/icons/chains/rsz_mantle.jpg"], + * nativeCurrency: { + * name: "Mantle", + * symbol: "MNT", + * decimals: 18, + * }, + * rpcUrls: ["https://rpc.mantle.xyz"], + * }); */ public async addEthereumChain(param: AddEthereumChainRequest): Promise { return this.requestManager.send({ @@ -66,6 +85,7 @@ export class WalletRpcPlugin extends Web3PluginBase { * * @param param - Details of the chain to switch to and possibly add * @returns a Promise that resolves if the request is successful + * @experimental */ public async updateEthereumChain( param: UpdateEthereumChainRequest, @@ -88,6 +108,9 @@ export class WalletRpcPlugin extends Web3PluginBase { * * @param chainId - Chain ID of the chain to switch to * @returns a Promise that resolves if the request is successful + * + * @example + * await web3.walletRpc.switchEthereumChain({ chainId: 5000 }); */ public async switchEthereumChain(chainId: Numbers): Promise { return this.requestManager.send({ @@ -107,6 +130,7 @@ export class WalletRpcPlugin extends Web3PluginBase { * * @param param - Details of the request for owned assets * @returns a Promise that resolves to a list of owned assets + * @experimental */ public async getOwnedAssets( param: GetOwnedAssetsRequest, @@ -133,6 +157,15 @@ export class WalletRpcPlugin extends Web3PluginBase { * * @param param - Details of the asset to watch * @returns a Promise that resolves to `true` if the request is successful + * + * @example + * await web3.walletRpc.watchAsset({ + * type: "ERC20", + * options: { + * address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + * symbol: "USDC", + * }, + * }); */ public async watchAsset(param: WatchAssetRequest): Promise { return this.requestManager.send({ @@ -140,9 +173,65 @@ export class WalletRpcPlugin extends Web3PluginBase { params: [param], }); } + + /** + * Request permissions for a dApp. + * + * See [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255) for more details. + * + * @param param - Details of the permission request + * @returns a Promise that resolves to an array of granted permissions + * + * @example + * const permissions = await web3.walletRpc.requestPermissions({ + * eth_accounts: {} + * }); + */ + public async requestPermissions( + param: PermissionRequest, + ): Promise { + return this.requestManager.send({ + method: "wallet_requestPermissions", + params: [param], + }); + } + + /** + * Retrieve the list of permissions granted to the dApp. + * + * See [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255) for more details. + * + * @returns a Promise that resolves to an array of granted permissions + * + * @example + * const permissions = await web3.walletRpc.getPermissions(); + */ + public async getPermissions(): Promise { + return this.requestManager.send({ + method: "wallet_getPermissions", + params: [], + }); + } + + /** + * Revoke permissions granted to the dApp. + * + * @param param - Details of the permissions to revoke + * @returns a Promise that resolves if the request is successful + * + * @example + * await web3.walletRpc.revokePermissions({ + * eth_accounts: {} + * }); + */ + public async revokePermissions(param: PermissionRequest): Promise { + return this.requestManager.send({ + method: "wallet_revokePermissions", + params: [param], + }); + } } -// Module Augmentation declare module "web3" { interface Web3Context { walletRpc: WalletRpcPlugin; diff --git a/packages/web3-plugin-wallet-rpc/src/types.ts b/packages/web3-plugin-wallet-rpc/src/types.ts index 5ab36b9..74c683c 100644 --- a/packages/web3-plugin-wallet-rpc/src/types.ts +++ b/packages/web3-plugin-wallet-rpc/src/types.ts @@ -141,3 +141,59 @@ export type WatchAssetRequest = { image?: string; }; }; + +/** + * Request or revoke permissions. + * + * See [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255) for more details. + */ +export type PermissionRequest = Record; + +/** + * Specific restrictions applied to the permitted method + * + * See [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255) for more details. + */ +export type Caveat = { + /** + * The type of the Caveat. + */ + type: string; + + /** + * An arbitrary JSON value. The value of a Caveat is only meaningful in the context of the type of the Caveat. + */ + value: any; +}; + +/** + * Permission granted to a dApp. + * + * See [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255) for more details. + */ +export type Permission = { + /** + * The permission ID. + */ + id: string; + + /** + * A URI of the dapp being granted this permission. + */ + invoker: string; + + /** + * The method that is being permitted (e.g. eth_accounts). + */ + parentCapability: string; + + /** + * A list of restrictions applied to the method. + */ + caveats: Caveat[]; + + /** + * The date is the timestamp of the request, in Unix time, and is optional. + */ + date?: number; +}; diff --git a/packages/web3-plugin-wallet-rpc/test/wallet_getPermissions.test.ts b/packages/web3-plugin-wallet-rpc/test/wallet_getPermissions.test.ts new file mode 100644 index 0000000..f681cad --- /dev/null +++ b/packages/web3-plugin-wallet-rpc/test/wallet_getPermissions.test.ts @@ -0,0 +1,26 @@ +import { Web3 } from "web3"; + +import { WalletRpcPlugin } from "../src"; + +describe("WalletRpcPlugin", () => { + describe("wallet_getPermissions", () => { + const web3 = new Web3("http://127.0.0.1:8545"); + web3.registerPlugin(new WalletRpcPlugin()); + + const requestManagerSendSpy = jest.fn(); + web3.requestManager.send = requestManagerSendSpy; + + afterEach(() => { + requestManagerSendSpy.mockClear(); + }); + + it("should call the method with expected params", async () => { + await web3.walletRpc.getPermissions(); + + expect(requestManagerSendSpy).toHaveBeenCalledWith({ + method: "wallet_getPermissions", + params: [], + }); + }); + }); +}); diff --git a/packages/web3-plugin-wallet-rpc/test/wallet_requestPermissions.test.ts b/packages/web3-plugin-wallet-rpc/test/wallet_requestPermissions.test.ts new file mode 100644 index 0000000..c8f8d94 --- /dev/null +++ b/packages/web3-plugin-wallet-rpc/test/wallet_requestPermissions.test.ts @@ -0,0 +1,30 @@ +import { Web3 } from "web3"; + +import { WalletRpcPlugin } from "../src"; + +describe("WalletRpcPlugin", () => { + describe("wallet_requestPermissions", () => { + const web3 = new Web3("http://127.0.0.1:8545"); + web3.registerPlugin(new WalletRpcPlugin()); + + const requestManagerSendSpy = jest.fn(); + web3.requestManager.send = requestManagerSendSpy; + + afterEach(() => { + requestManagerSendSpy.mockClear(); + }); + + it("should call the method with expected params", async () => { + const request = { + eth_accounts: {}, + }; + + await web3.walletRpc.requestPermissions(request); + + expect(requestManagerSendSpy).toHaveBeenCalledWith({ + method: "wallet_requestPermissions", + params: [request], + }); + }); + }); +}); diff --git a/packages/web3-plugin-wallet-rpc/test/wallet_revokePermissions.test.ts b/packages/web3-plugin-wallet-rpc/test/wallet_revokePermissions.test.ts new file mode 100644 index 0000000..2d23506 --- /dev/null +++ b/packages/web3-plugin-wallet-rpc/test/wallet_revokePermissions.test.ts @@ -0,0 +1,30 @@ +import { Web3 } from "web3"; + +import { WalletRpcPlugin } from "../src"; + +describe("WalletRpcPlugin", () => { + describe("wallet_revokePermissions", () => { + const web3 = new Web3("http://127.0.0.1:8545"); + web3.registerPlugin(new WalletRpcPlugin()); + + const requestManagerSendSpy = jest.fn(); + web3.requestManager.send = requestManagerSendSpy; + + afterEach(() => { + requestManagerSendSpy.mockClear(); + }); + + it("should call the method with expected params", async () => { + const request = { + eth_accounts: {}, + }; + + await web3.walletRpc.revokePermissions(request); + + expect(requestManagerSendSpy).toHaveBeenCalledWith({ + method: "wallet_revokePermissions", + params: [request], + }); + }); + }); +});