@ew-did-registry/did-ethr-resolver
Version:
The package resolve CRUD operations on DID Documents
143 lines (130 loc) • 5.12 kB
text/typescript
import { Signer, providers, utils, Wallet } from 'ethers';
import { ProviderSettings } from '@ew-did-registry/did-resolver-interface';
import { Keys } from '@ew-did-registry/keys';
import { getProvider } from '../utils';
type EIP1193ProviderType =
| providers.ExternalProvider
| providers.JsonRpcFetchFunc;
/**
* A signer class that encapsulates the ethers Signer and ensures that publicKey is available.
* The public is necessary for verification of signatures made by the signer.
* The purpose of the ethers encapsulation is to allow consumers more flexiblity in ethers version.
*/
export class EwSigner extends Signer {
public readonly provider: providers.Provider;
public readonly publicKey: string;
/**
* A private constructor as this class uses factory method for instantiation API.
*/
private constructor(
public readonly signer: Signer,
publicKey: string,
public readonly privateKey?: string
) {
super();
if (!signer.provider) {
throw new Error(
'Signer is not connected to chain. Provider must be defined'
);
}
if (!publicKey) {
throw new Error('Public key should be a non-empty string');
}
const publicKeyWithoutHexPrefix =
publicKey.slice(0, 2) === '0x' ? publicKey.slice(2) : publicKey;
this.publicKey = new Keys({
publicKey: publicKeyWithoutHexPrefix,
}).publicKey;
this.provider = signer.provider;
}
getAddress(): Promise<string> {
return this.signer.getAddress();
}
sendTransaction(
transaction: providers.TransactionRequest
): Promise<providers.TransactionResponse> {
return this.signer.sendTransaction(transaction);
}
signMessage(message: string | utils.Bytes): Promise<string> {
return this.signer.signMessage(message);
}
signTransaction(transaction: providers.TransactionRequest): Promise<string> {
return this.signer.signTransaction(transaction);
}
connect(provider: providers.Provider): Signer {
return this.signer.connect(provider);
}
/**
* A factory method to create an EwSigner from a private key.
* ```typescript
* import {
* Operator,
* EwSigner
* } from '@ew-did-registry/did-ethr-resolver';
* import { Keys } from '@ew-did-registry/keys';
*
* const keys = new Keys();
* const providerSettings = { type: ProviderTypes.HTTP, };
* const signer = EwSigner.fromPrivateKey(keys.privateKey, providerSettings);
* const operator = new Operator(signer, registrySettings);
* ```
* @param privateKey a secp256k1 private key.
* @param providerSettings settings from which a web3 provider can be obtained
*/
public static fromPrivateKey(
privateKey: string,
providerSettings: ProviderSettings
): EwSigner {
const provider = getProvider(providerSettings);
const wallet = new Wallet(privateKey, provider);
const compressedPubKey = utils.computePublicKey(wallet.publicKey, true);
return new EwSigner(wallet, compressedPubKey, privateKey);
}
/**
* A factory method to create an EwSigner using an ethers library Signer.
* This is convenient if a suitable ethers signer is available.
* If instead an EIP1993 provider is available, see {@linkcode fromEIP1193}
* @param signer an ethers Signer connected to chain
* @param publicKey the publicKey of the signer associated with the provider
*/
public static fromEthersSigner(signer: Signer, publicKey: string): EwSigner {
return new EwSigner(signer, publicKey);
}
/**
* A factory method to create an EwSigner without needing a specific ethers object.
* Instead, any object which conforms to the necessary interface can be used.
* See https://docs.ethers.io/v5/api/providers/other/#Web3Provider for interface description.
*
* @example
* ```typescript
* import { Operator, EwSigner } from '@ew-did-registry/did-ethr-resolver';
* import detectMetamask from "@metamask/detect-provider";
*
* const web3Provider = await detectMetamask();
* const web3Signer = EwSigner.fromEIP1193(web3Provider, publicKey);
* const operator = new Operator(web3Signer, registrySettings);
* ```
* @param eip1993Provider an EIP1193 provider (https://docs.ethers.io/v5/api/providers/other/#Web3Provider)
* @param publicKey the publicKey of the signer associated with the provider
*/
// eslint-disable-next-line max-len
public static async fromEIP1193(
eip1993Provider: EIP1193ProviderType,
publicKey: string
): Promise<EwSigner> {
const provider = new providers.Web3Provider(eip1993Provider);
const signer = provider.getSigner();
try {
// Call getAddress() to check that signer has address
// Signer could be returned by not actually have an address
// Best to check now and "fail fast"
await signer.getAddress();
} catch (error) {
if (error instanceof Error) {
error.message = `Error instantiating EwSigner from ethers Provider. Provider must have signer with address. ${error.message}`;
throw new Error(error.message);
}
}
return new EwSigner(signer, publicKey);
}
}