-
Notifications
You must be signed in to change notification settings - Fork 236
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1778 from Web3Auth/feat/mpc-signingProvider
fix: mpc-signing provider
- Loading branch information
Showing
19 changed files
with
1,167 additions
and
522 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Web3Auth Ethereum MPC Provider | ||
|
||
[![npm version](https://img.shields.io/npm/v/@web3auth-mpc/ethereum-provider?label=%22%22)](https://www.npmjs.com/package/@web3auth-mpc/ethereum-provider/v/latest) | ||
[![minzip](https://img.shields.io/bundlephobia/minzip/@web3auth-mpc/ethereum-provider?label=%22%22)](https://bundlephobia.com/result?p=@web3auth-mpc/ethereum-provider@latest) | ||
|
||
> Web3Auth is where passwordless auth meets non-custodial key infrastructure for Web3 apps and wallets. By aggregating OAuth (Google, Twitter, Discord) logins, different wallets and innovative Multi Party Computation (MPC) - Web3Auth provides a seamless login experience to every user on your application. | ||
Web3Auth Ethereum Provider can be used to interact with wallet or connected EVM compatible chain using RPC calls. This is an EIP-1193 compatible JRPC provider. This package exposes a class `EthereumPrivateKeyProvider`, which accepts a `secp251k1` private key and returns `EIP1193` compatible provider, which can be used with various wallet sdks. | ||
|
||
## 📖 Documentation | ||
|
||
Read more about Web3Auth Ethereum Provider in the [official Web3Auth Documentation](https://web3auth.io/docs/sdk/web/providers/evm#getting-a-provider-from-any-secp256k1-private-key). | ||
|
||
## 💡 Features | ||
- Plug and Play, OAuth based Web3 Authentication Service | ||
- Fully decentralized, non-custodial key infrastructure | ||
- End to end Whitelabelable solution | ||
- Threshold Cryptography based Key Reconstruction | ||
- Multi Factor Authentication Setup & Recovery (Includes password, backup phrase, device factor editing/deletion etc) | ||
- Support for WebAuthn & Passwordless Login | ||
- Support for connecting to multiple wallets | ||
- DApp Active Session Management | ||
|
||
...and a lot more | ||
|
||
## 🔗 Installation | ||
|
||
```shell | ||
npm install --save @web3auth/ethereum-mpc-provider | ||
``` | ||
|
||
## 🩹 Example | ||
|
||
```ts | ||
import { EthereumPrivateKeyProvider } from "@web3auth/ethereum-mpc-provider"; | ||
import type { SafeEventEmitterProvider } from "@web3auth/base"; | ||
const signEthMessage = async (provider: SafeEventEmitterProvider): Promise<string> => { | ||
const web3 = new Web3(provider as any); | ||
const accounts = await web3.eth.getAccounts(); | ||
// hex message | ||
const message = "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"; | ||
const signature = await web3.eth.sign(message, accounts[0]); | ||
return signature; | ||
}; | ||
|
||
(async () => { | ||
const provider = await EthereumPrivateKeyProvider.getProviderInstance({ | ||
chainConfig: { | ||
rpcTarget: "https://polygon-rpc.com", | ||
chainId: "0x89", // hex chain id | ||
networkName: "matic", | ||
ticker: "matic", | ||
tickerName: "matic", | ||
}, | ||
privKey: "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318", | ||
}); | ||
const signedMessage = await signEthMessage(provider); | ||
})(); | ||
``` | ||
|
||
Checkout the examples for your preferred blockchain and platform in our [examples repository](https://github.com/Web3Auth/examples/) | ||
|
||
## 🌐 Demo | ||
|
||
Checkout the [Web3Auth Demo](https://demo-app.web3auth.io/) to see how Web3Auth can be used in your application. | ||
|
||
## 💬 Troubleshooting and Support | ||
|
||
- Have a look at our [Community Portal](https://community.web3auth.io/) to see if anyone has any questions or issues you might be having. Feel free to reate new topics and we'll help you out as soon as possible. | ||
- Checkout our [Troubleshooting Documentation Page](https://web3auth.io/docs/troubleshooting) to know the common issues and solutions. | ||
- For Priority Support, please have a look at our [Pricing Page](https://web3auth.io/pricing.html) for the plan that suits your needs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
{ | ||
"name": "@web3auth/ethereum-mpc-provider", | ||
"version": "8.1.0", | ||
"homepage": "https://github.com/Web3Auth/Web3Auth#readme", | ||
"license": "ISC", | ||
"main": "dist/ethereumMpcProvider.cjs.js", | ||
"module": "dist/ethereumMpcProvider.esm.js", | ||
"unpkg": "dist/ethereumMpcProvider.umd.min.js", | ||
"jsdelivr": "dist/ethereumMpcProvider.umd.min.js", | ||
"types": "dist/types/index.d.ts", | ||
"author": "Torus Labs", | ||
"scripts": { | ||
"test": "mocha --config ../../.mocharc.json test/**.ts", | ||
"test-debugger": "mocha --config ../../.mocharc.json --inspect-brk test/**.ts", | ||
"dev": "torus-scripts start", | ||
"build": "torus-scripts build", | ||
"lint": "eslint --fix 'src/**/*.ts'", | ||
"prepack": "npm run build", | ||
"pre-commit": "lint-staged --cwd ." | ||
}, | ||
"dependencies": { | ||
"@ethereumjs/common": "^4.3.0", | ||
"@ethereumjs/tx": "^5.3.0", | ||
"@ethereumjs/util": "^9.0.3", | ||
"@metamask/eth-sig-util": "^7.0.1", | ||
"@metamask/rpc-errors": "^6.2.1", | ||
"@toruslabs/base-controllers": "^5.5.5", | ||
"@toruslabs/http-helpers": "^6.1.1", | ||
"@toruslabs/openlogin-jrpc": "^8.1.0", | ||
"@web3auth/base": "^8.1.0", | ||
"@web3auth/base-provider": "^8.1.0", | ||
"@web3auth/ethereum-provider": "^8.1.0" | ||
}, | ||
"peerDependencies": { | ||
"@babel/runtime": "7.x" | ||
}, | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"lint-staged": { | ||
"!(*d).ts": [ | ||
"eslint --cache --fix", | ||
"prettier --write" | ||
] | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/Web3Auth/Web3Auth.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/Web3Auth/Web3Auth/issues" | ||
}, | ||
"keywords": [], | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"engines": { | ||
"node": ">=18.x", | ||
"npm": ">=9.x" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./providers"; |
1 change: 1 addition & 0 deletions
1
packages/providers/ethereum-mpc-provider/src/providers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./signingProviders"; |
184 changes: 184 additions & 0 deletions
184
...providers/ethereum-mpc-provider/src/providers/signingProviders/EthereumSigningProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import { providerErrors, rpcErrors } from "@metamask/rpc-errors"; | ||
import { JRPCEngine, JRPCMiddleware, providerFromEngine } from "@toruslabs/openlogin-jrpc"; | ||
import { CHAIN_NAMESPACES, CustomChainConfig, WalletInitializationError } from "@web3auth/base"; | ||
import { BaseProvider, BaseProviderConfig, BaseProviderState } from "@web3auth/base-provider"; | ||
import { | ||
AddEthereumChainParameter, | ||
createChainSwitchMiddleware, | ||
createEthMiddleware, | ||
createJsonRpcClient, | ||
IChainSwitchHandlers, | ||
TransactionFormatter, | ||
} from "@web3auth/ethereum-provider"; | ||
|
||
import { createAccountMiddleware } from "../../rpc/ethRpcMiddlewares"; | ||
import { IAccountHandlers } from "../../rpc/interfaces"; | ||
import { getProviderHandlers } from "./signingUtils"; | ||
|
||
export interface EthereumSigningProviderConfig extends BaseProviderConfig { | ||
chainConfig: CustomChainConfig; | ||
} | ||
|
||
export interface EthereumSigningProviderState extends BaseProviderState { | ||
signMethods?: { | ||
sign: (msgHash: Buffer, rawMsg?: Buffer) => Promise<{ v: number; r: Buffer; s: Buffer }>; | ||
getPublic: () => Promise<Buffer>; | ||
}; | ||
} | ||
export class EthereumSigningProvider extends BaseProvider< | ||
BaseProviderConfig, | ||
EthereumSigningProviderState, | ||
{ | ||
sign: (msgHash: Buffer, rawMsg?: Buffer) => Promise<{ v: number; r: Buffer; s: Buffer }>; | ||
getPublic: () => Promise<Buffer>; | ||
} | ||
> { | ||
readonly PROVIDER_CHAIN_NAMESPACE = CHAIN_NAMESPACES.EIP155; | ||
|
||
constructor({ config, state }: { config: EthereumSigningProviderConfig; state?: EthereumSigningProviderState }) { | ||
super({ config: { chainConfig: { ...config.chainConfig, chainNamespace: CHAIN_NAMESPACES.EIP155 } }, state }); | ||
} | ||
|
||
public static getProviderInstance = async (params: { | ||
signMethods: { | ||
sign: (msgHash: Buffer, rawMsg?: Buffer) => Promise<{ v: number; r: Buffer; s: Buffer }>; | ||
getPublic: () => Promise<Buffer>; | ||
}; | ||
chainConfig: CustomChainConfig; | ||
}): Promise<EthereumSigningProvider> => { | ||
const providerFactory = new EthereumSigningProvider({ config: { chainConfig: params.chainConfig } }); | ||
await providerFactory.setupProvider(params.signMethods); | ||
return providerFactory; | ||
}; | ||
|
||
public async enable(): Promise<string[]> { | ||
if (!this.state.signMethods) | ||
throw providerErrors.custom({ message: "signMethods are not found in state, plz pass it in constructor state param", code: 4902 }); | ||
await this.setupProvider(this.state.signMethods); | ||
return this._providerEngineProxy.request({ method: "eth_accounts" }); | ||
} | ||
|
||
public async setupProvider({ | ||
sign, | ||
getPublic, | ||
}: { | ||
sign: (msgHash: Buffer, rawMsg?: Buffer) => Promise<{ v: number; r: Buffer; s: Buffer }>; | ||
getPublic: () => Promise<Buffer>; | ||
}): Promise<void> { | ||
const { chainNamespace } = this.config.chainConfig; | ||
if (chainNamespace !== this.PROVIDER_CHAIN_NAMESPACE) throw WalletInitializationError.incompatibleChainNameSpace("Invalid chain namespace"); | ||
const txFormatter = new TransactionFormatter({ | ||
getProviderEngineProxy: this.getProviderEngineProxy.bind(this), | ||
}); | ||
const providerHandlers = getProviderHandlers({ | ||
txFormatter, | ||
sign, | ||
getPublic, | ||
getProviderEngineProxy: this.getProviderEngineProxy.bind(this), | ||
}); | ||
const ethMiddleware = createEthMiddleware(providerHandlers); | ||
const chainSwitchMiddleware = this.getChainSwitchMiddleware(); | ||
const engine = new JRPCEngine(); | ||
// Not a partial anymore because of checks in ctor | ||
const { networkMiddleware } = createJsonRpcClient(this.config.chainConfig as CustomChainConfig); | ||
engine.push(ethMiddleware); | ||
engine.push(chainSwitchMiddleware); | ||
engine.push(this.getAccountMiddleware()); | ||
engine.push(networkMiddleware); | ||
const provider = providerFromEngine(engine); | ||
this.updateProviderEngineProxy(provider); | ||
await txFormatter.init(); | ||
await this.lookupNetwork(); | ||
} | ||
|
||
public async updateAccount(params: { | ||
signMethods: { | ||
sign: (msgHash: Buffer, rawMsg?: Buffer) => Promise<{ v: number; r: Buffer; s: Buffer }>; | ||
getPublic: () => Promise<Buffer>; | ||
}; | ||
}): Promise<void> { | ||
if (!this._providerEngineProxy) throw providerErrors.custom({ message: "Provider is not initialized", code: 4902 }); | ||
const currentSignMethods = this.state.signMethods; | ||
if (!currentSignMethods) { | ||
throw providerErrors.custom({ message: "signing methods are unavailable ", code: 4092 }); | ||
} | ||
const currentPubKey = (await currentSignMethods.getPublic()).toString("hex"); | ||
const updatePubKey = (await params.signMethods.getPublic()).toString("hex"); | ||
if (currentPubKey !== updatePubKey) { | ||
await this.setupProvider(params.signMethods); | ||
this._providerEngineProxy.emit("accountsChanged", { | ||
accounts: await this._providerEngineProxy.request<unknown, string[]>({ method: "eth_accounts" }), | ||
}); | ||
} | ||
} | ||
|
||
public async switchChain(params: { chainId: string }): Promise<void> { | ||
if (!this._providerEngineProxy) throw providerErrors.custom({ message: "Provider is not initialized", code: 4902 }); | ||
const chainConfig = this.getChainConfig(params.chainId); | ||
this.update({ | ||
chainId: "loading", | ||
}); | ||
this.configure({ chainConfig }); | ||
if (!this.state.signMethods) { | ||
throw providerErrors.custom({ message: "sign methods are undefined", code: 4902 }); | ||
} | ||
await this.setupProvider(this.state.signMethods); | ||
} | ||
|
||
protected async lookupNetwork(): Promise<string> { | ||
if (!this._providerEngineProxy) throw providerErrors.custom({ message: "Provider is not initialized", code: 4902 }); | ||
const { chainId } = this.config.chainConfig; | ||
if (!chainId) throw rpcErrors.invalidParams("chainId is required while lookupNetwork"); | ||
const network = await this._providerEngineProxy.request<string[], string>({ | ||
method: "net_version", | ||
params: [], | ||
}); | ||
|
||
if (parseInt(chainId, 16) !== parseInt(network, 10)) throw providerErrors.chainDisconnected(`Invalid network, net_version is: ${network}`); | ||
if (this.state.chainId !== chainId) { | ||
this.emit("chainChanged", chainId); | ||
this.emit("connect", { chainId }); | ||
} | ||
this.update({ chainId }); | ||
return network; | ||
} | ||
|
||
private getChainSwitchMiddleware(): JRPCMiddleware<unknown, unknown> { | ||
const chainSwitchHandlers: IChainSwitchHandlers = { | ||
addChain: async (params: AddEthereumChainParameter): Promise<void> => { | ||
const { chainId, chainName, rpcUrls, blockExplorerUrls, nativeCurrency, iconUrls } = params; | ||
this.addChain({ | ||
chainNamespace: CHAIN_NAMESPACES.EIP155, | ||
chainId, | ||
ticker: nativeCurrency?.symbol || "ETH", | ||
tickerName: nativeCurrency?.name || "Ether", | ||
displayName: chainName, | ||
rpcTarget: rpcUrls[0], | ||
blockExplorerUrl: blockExplorerUrls?.[0] || "", | ||
decimals: nativeCurrency?.decimals || 18, | ||
logo: iconUrls?.[0] || "https://images.toruswallet.io/eth.svg", | ||
}); | ||
}, | ||
switchChain: async (params: { chainId: string }): Promise<void> => { | ||
const { chainId } = params; | ||
await this.switchChain({ chainId }); | ||
}, | ||
}; | ||
const chainSwitchMiddleware = createChainSwitchMiddleware(chainSwitchHandlers); | ||
return chainSwitchMiddleware; | ||
} | ||
|
||
private getAccountMiddleware(): JRPCMiddleware<unknown, unknown> { | ||
const accountHandlers: IAccountHandlers = { | ||
updateSignMethods: async (params: { | ||
signMethods: { | ||
sign: (msgHash: Buffer, rawMsg?: Buffer) => Promise<{ v: number; r: Buffer; s: Buffer }>; | ||
getPublic: () => Promise<Buffer>; | ||
}; | ||
}): Promise<void> => { | ||
await this.updateAccount(params); | ||
}, | ||
}; | ||
return createAccountMiddleware(accountHandlers); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
packages/providers/ethereum-mpc-provider/src/providers/signingProviders/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./EthereumSigningProvider"; |
Oops, something went wrong.