-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow the developer to manually accept/reject an eth_requestAccounts …
…request (#15) * Refactor: make mock provider a class * Allow to set flag to request enable acceptance * Bump to v1 * Lint
- Loading branch information
1 parent
8a8d28d
commit b0679f6
Showing
4 changed files
with
167 additions
and
75 deletions.
There are no files selected for viewing
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
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 |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"name": "@rsksmart/mock-web3-provider", | ||
"version": "0.0.1", | ||
"version": "1.0.0", | ||
"main": "dist/index.js", | ||
"repository": "[email protected]:jessgusclark/mock-web3-provider.git", | ||
"author": "Jesse Clark <[email protected]>", | ||
|
@@ -13,6 +13,7 @@ | |
"build": "npx tsc --outDir ./dist", | ||
"build:watch": "npx tsc -w --outDir ./dist", | ||
"lint": "npx eslint ./src/*.ts", | ||
"lint:fix": "npx eslint ./src/*.ts --fix", | ||
"test": "npx jest", | ||
"test:ci": "npx jest --verbose --coverage --watchAll=false --coverageDirectory reports --maxWorkers=2", | ||
"test:watch": "npx jest --watch", | ||
|
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
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 |
---|---|---|
@@ -1,81 +1,129 @@ | ||
import { personalSign, decrypt } from 'eth-sig-util' | ||
|
||
interface ProviderSetup { | ||
address: string, | ||
privateKey: string, | ||
chainId: number, | ||
type ProviderSetup = { | ||
address: string | ||
privateKey: string | ||
networkVersion: number | ||
debug?: boolean | ||
manualConfirmEnable?: boolean | ||
} | ||
|
||
const provider = (startProps: ProviderSetup) => { | ||
const { | ||
address, privateKey, chainId, debug | ||
} = startProps | ||
interface IMockProvider { | ||
request(args: { method: 'eth_accounts'; params: string[] }): Promise<string[]> | ||
request(args: { method: 'eth_requestAccounts'; params: string[] }): Promise<string[]> | ||
|
||
request(args: { method: 'net_version' }): Promise<number> | ||
request(args: { method: 'eth_chainId'; params: string[] }): Promise<string> | ||
|
||
request(args: { method: 'personal_sign'; params: string[] }): Promise<string> | ||
request(args: { method: 'eth_decrypt'; params: string[] }): Promise<string> | ||
|
||
request(args: { method: string, params?: any[] }): Promise<any> | ||
} | ||
|
||
// eslint-disable-next-line import/prefer-default-export | ||
export class MockProvider implements IMockProvider { | ||
private setup: ProviderSetup | ||
|
||
private acceptEnable?: (value: unknown) => void | ||
|
||
private rejectEnable?: (value: unknown) => void | ||
|
||
constructor(setup: ProviderSetup) { | ||
this.setup = setup | ||
} | ||
|
||
/* Logging */ | ||
// eslint-disable-next-line no-console | ||
const log = (...args: (any | null)[]) => debug && console.log('🦄', ...args) | ||
|
||
const buildProvider = { | ||
isMetaMask: true, | ||
networkVersion: chainId, | ||
chainId: `0x${chainId.toString(16)}`, | ||
selectedAddress: address, | ||
|
||
request(props: { method: any; params: string[] }) { | ||
log(`request[${props.method}]`) | ||
switch (props.method) { | ||
case 'eth_requestAccounts': | ||
case 'eth_accounts': | ||
return Promise.resolve([this.selectedAddress]) | ||
case 'net_version': | ||
return Promise.resolve(this.networkVersion) | ||
case 'eth_chainId': | ||
return Promise.resolve(this.chainId) | ||
|
||
case 'personal_sign': { | ||
const privKey = Buffer.from(privateKey, 'hex'); | ||
const signed = personalSign(privKey, { data: props.params[0] }) | ||
log('signed', signed) | ||
return Promise.resolve(signed) | ||
} | ||
case 'eth_sendTransaction': { | ||
return Promise.reject(new Error('This service can not send transactions.')) | ||
} | ||
case 'eth_decrypt': { | ||
log('eth_decrypt', props) | ||
const stripped = props.params[0].substring(2) | ||
const buff = Buffer.from(stripped, 'hex'); | ||
const data = JSON.parse(buff.toString('utf8')); | ||
return Promise.resolve(decrypt(data, privateKey)) | ||
private log = (...args: (any | null)[]) => this.setup.debug && console.log('🦄', ...args) | ||
|
||
get selectedAddress(): string { | ||
return this.setup.address | ||
} | ||
|
||
get networkVersion(): number { | ||
return this.setup.networkVersion | ||
} | ||
|
||
get chainId(): string { | ||
return `0x${this.setup.networkVersion.toString(16)}` | ||
} | ||
|
||
answerEnable(acceptance: boolean) { | ||
if (acceptance) this.acceptEnable!('Accepted') | ||
else this.rejectEnable!('User rejected') | ||
} | ||
|
||
request({ method, params }: any): Promise<any> { | ||
this.log(`request[${method}]`) | ||
|
||
switch (method) { | ||
case 'eth_requestAccounts': | ||
case 'eth_accounts': | ||
if (this.setup.manualConfirmEnable) { | ||
return new Promise((resolve, reject) => { | ||
this.acceptEnable = resolve | ||
this.rejectEnable = reject | ||
}).then(() => [this.selectedAddress]) | ||
} | ||
default: | ||
log(`resquesting missing method ${props.method}`) | ||
// eslint-disable-next-line prefer-promise-reject-errors | ||
return Promise.reject(`The method ${props.method} is not implemented by the mock provider.`) | ||
return Promise.resolve([this.selectedAddress]) | ||
|
||
case 'net_version': | ||
return Promise.resolve(this.setup.networkVersion) | ||
|
||
case 'eth_chainId': | ||
return Promise.resolve(this.chainId) | ||
|
||
case 'personal_sign': { | ||
const privKey = Buffer.from(this.setup.privateKey, 'hex'); | ||
|
||
const signed: string = personalSign(privKey, { data: params[0] }) | ||
|
||
this.log('signed', signed) | ||
|
||
return Promise.resolve(signed) | ||
} | ||
}, | ||
|
||
sendAsync(props: { method: string }, cb: any) { | ||
switch (props.method) { | ||
case 'eth_accounts': | ||
cb(null, { result: [this.selectedAddress] }) | ||
break; | ||
case 'net_version': cb(null, { result: this.networkVersion }) | ||
break; | ||
default: log(`Method '${props.method}' is not supported yet.`) | ||
|
||
case 'eth_sendTransaction': { | ||
return Promise.reject(new Error('This service can not send transactions.')) | ||
} | ||
}, | ||
on(props: string) { | ||
log('registering event:', props) | ||
}, | ||
removeAllListeners() { | ||
log('removeAllListeners', null) | ||
}, | ||
|
||
case 'eth_decrypt': { | ||
this.log('eth_decrypt', { method, params }) | ||
|
||
const stripped = params[0].substring(2) | ||
const buff = Buffer.from(stripped, 'hex'); | ||
const data = JSON.parse(buff.toString('utf8')); | ||
|
||
const decrypted: string = decrypt(data, this.setup.privateKey) | ||
|
||
return Promise.resolve(decrypted) | ||
} | ||
|
||
default: | ||
this.log(`resquesting missing method ${method}`) | ||
// eslint-disable-next-line prefer-promise-reject-errors | ||
return Promise.reject(`The method ${method} is not implemented by the mock provider.`) | ||
} | ||
} | ||
|
||
log('Mock Provider ', buildProvider) | ||
return buildProvider; | ||
} | ||
sendAsync(props: { method: string }, cb: any) { | ||
switch (props.method) { | ||
case 'eth_accounts': | ||
cb(null, { result: [this.setup.address] }) | ||
break; | ||
|
||
case 'net_version': cb(null, { result: this.setup.networkVersion }) | ||
break; | ||
|
||
default: this.log(`Method '${props.method}' is not supported yet.`) | ||
} | ||
} | ||
|
||
on(props: string) { | ||
this.log('registering event:', props) | ||
} | ||
|
||
export default provider | ||
removeAllListeners() { | ||
this.log('removeAllListeners', null) | ||
} | ||
} |