From ef3f5c108deaacd99dc0bf945821896c1025c854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9?= Date: Thu, 27 Oct 2022 16:23:30 -0400 Subject: [PATCH] Metamask signing support (#69) * Support for payable contract methods * Metamask signing support --- README.md | 47 +++++++++++++++++++++++++++++++ src/index.ts | 1 + src/interfaces.ts | 19 ++++++++++++- src/providers/index.ts | 1 + src/providers/metamaskProvider.ts | 20 +++++++++++++ src/wallets/key.ts | 10 +------ 6 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 src/providers/index.ts create mode 100644 src/providers/metamaskProvider.ts diff --git a/README.md b/README.md index c6b1d71..e37b6ec 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,21 @@ const key = new HDKey(new WSProvider(HARMONY_RPC_WS), options) const key = new HDKey(HarmonyShards.SHARD_0, options) ``` +## Metamask Provider + +Implementation a subclass of HttpProvider that takes window.ethereum as a parameter, each method of HttpProvider is implemented by this subclass by cascading the request appropriately to window.ethereum + +```ts +import detectEthereumProvider from '@metamask/detect-provider' +import { MetamaskProvider } from 'harmony-marketplace-sdk' + +const provider = await detectEthereumProvider() + +// Using a MetamaskProvider with window or a detected provider. +const key = new Key(new MetamaskProvider(window.ethereum || provider)) + +``` + ## Base Token The `BaseToken` is an extension over a regular [Contract](https://github.com/harmony-one/sdk/tree/master/packages/harmony-contract) which is the Harmony recomendation for interact with smart contracts. This abstract class contains the core functionality for interact with Harmony Smart Contracts. @@ -1365,6 +1380,38 @@ const { addr, receiptId } = await bridge.sendToken( ) ``` +## Development + +Install all the dependencies: + +```sh +npmn ci +``` + +Copy the `.env.sample` file to `.env` + +```sh +cp .env.sample .env +``` + +In the project directory, you can run: + +### `npm run test` + +Running the unit tests. + +### `npm run test:cov` + +Running the test coverage. + +### `npm run test:e2e` + +Running the end to end test. + +### `npm run test:lint` + +Running the lint. + ## Change Log See [Changelog](CHANGELOG.md) for more information. diff --git a/src/index.ts b/src/index.ts index cbaa7a6..5df28fc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export * from './wallets' export * from './constants' export * from './interfaces' export * from './utils' +export * from './providers' diff --git a/src/interfaces.ts b/src/interfaces.ts index be33638..daf4e21 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -3,6 +3,7 @@ import { Arrayish } from '@harmony-js/crypto' import { HttpProvider, WSProvider } from '@harmony-js/network' import { ChainID, ChainType } from '@harmony-js/utils' import BN from 'bn.js' +import { MetamaskProvider } from './providers' import { Key, MnemonicKey, PrivateKey } from './wallets' export type BNish = BN | Arrayish | bigint | number @@ -34,7 +35,7 @@ export enum HarmonyShards { SHARD_0_DEVNET = 'SHARD_0_DEVNET', } -export type RpcProviderType = string | HttpProvider | WSProvider | HarmonyShards +export type RpcProviderType = string | HttpProvider | WSProvider | MetamaskProvider | HarmonyShards export type ContractProviderType = Wallet | Key | PrivateKey | MnemonicKey @@ -92,3 +93,19 @@ export interface BridgeResponse { export interface ChainId { [key: number]: string } + +interface ProviderRequestArguments { + readonly method: string + readonly params?: readonly unknown[] | object +} + +export interface MetaMaskEthereumProvider { + isMetaMask?: boolean + once(eventName: string | symbol, listener: (...args: any[]) => void): this + on(eventName: string | symbol, listener: (...args: any[]) => void): this + off(eventName: string | symbol, listener: (...args: any[]) => void): this + addListener(eventName: string | symbol, listener: (...args: any[]) => void): this + removeListener(eventName: string | symbol, listener: (...args: any[]) => void): this + removeAllListeners(event?: string | symbol): this + request(args: ProviderRequestArguments): Promise +} diff --git a/src/providers/index.ts b/src/providers/index.ts new file mode 100644 index 0000000..1121181 --- /dev/null +++ b/src/providers/index.ts @@ -0,0 +1 @@ +export * from './metamaskProvider' diff --git a/src/providers/metamaskProvider.ts b/src/providers/metamaskProvider.ts new file mode 100644 index 0000000..1af7d4f --- /dev/null +++ b/src/providers/metamaskProvider.ts @@ -0,0 +1,20 @@ +import { HttpProvider, RPCRequestPayload } from '@harmony-js/network' +import { MetaMaskEthereumProvider } from '../interfaces' + +export class MetamaskProvider extends HttpProvider { + private readonly provider: MetaMaskEthereumProvider + + constructor(provider?: MetaMaskEthereumProvider) { + super('') + + if (!provider) { + throw new Error('Invalid MetaMask provider!') + } + + this.provider = provider + } + + requestFunc({ payload }: { payload: RPCRequestPayload }): Promise { + return this.provider.request({ method: payload.method, params: payload.params }) + } +} diff --git a/src/wallets/key.ts b/src/wallets/key.ts index 6df2c40..ac82112 100644 --- a/src/wallets/key.ts +++ b/src/wallets/key.ts @@ -1,7 +1,7 @@ import { Wallet } from '@harmony-js/account' import { Messenger, HttpProvider, WSProvider } from '@harmony-js/network' import { ChainID, ChainType, isWs } from '@harmony-js/utils' -import { HARMONY_SHARDS, CHAINS_ID } from '../constants' +import { HARMONY_SHARDS } from '../constants' import { HarmonyRpcConfig, HarmonyShards, RpcProviderType } from '../interfaces' /** @@ -21,14 +21,6 @@ export class Key extends Wallet { provider = url } else if (typeof url === 'string') { provider = isWs(url) ? new WSProvider(url) : new HttpProvider(url) - } else if (url['isMetaMask']) { - const _chain = Number(url['networkVersion']) - const rpc_url = CHAINS_ID[_chain] - - if (!rpc_url) throw new Error('Invalid metamask harmony chain.') - - provider = new HttpProvider(rpc_url) - chain = _chain } else { throw new Error('Invalid url param.') }