2020-03-12 21:04:15 +03:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
import EventEmitter from "events";
|
|
|
|
|
|
|
|
import { ethers } from "ethers";
|
|
|
|
|
|
|
|
import { version } from "./_version";
|
|
|
|
|
|
|
|
const logger = new ethers.utils.Logger(version);
|
|
|
|
/*
|
|
|
|
function getBlockTag(tag) {
|
|
|
|
if (tag == null) { return "latest"; }
|
|
|
|
if (tag === "earliest" || tag === "latest" || tag === "pending") {
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
return ethers.utils.hexValue(tag)
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2021-04-18 09:40:26 +03:00
|
|
|
export class Eip1193Bridge extends EventEmitter {
|
2020-03-12 21:04:15 +03:00
|
|
|
readonly signer: ethers.Signer;
|
|
|
|
readonly provider: ethers.providers.Provider;
|
|
|
|
|
|
|
|
constructor(signer: ethers.Signer, provider?: ethers.providers.Provider) {
|
|
|
|
super();
|
|
|
|
ethers.utils.defineReadOnly(this, "signer", signer);
|
|
|
|
ethers.utils.defineReadOnly(this, "provider", provider || null);
|
|
|
|
}
|
|
|
|
|
2021-04-20 03:52:50 +03:00
|
|
|
request(request: { method: string, params?: Array<any>}): Promise<any> {
|
|
|
|
return this.send(request.method, request.params || []);
|
|
|
|
}
|
|
|
|
|
2020-03-12 21:04:15 +03:00
|
|
|
async send(method: string, params?: Array<any>): Promise<any> {
|
|
|
|
function throwUnsupported(message: string): never {
|
2021-04-20 03:52:50 +03:00
|
|
|
return logger.throwError(message, ethers.utils.Logger.errors.UNSUPPORTED_OPERATION, {
|
2020-03-12 21:04:15 +03:00
|
|
|
method: method,
|
|
|
|
params: params
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let coerce = (value: any) => value;
|
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case "eth_gasPrice": {
|
|
|
|
const result = await this.provider.getGasPrice();
|
|
|
|
return result.toHexString();
|
|
|
|
}
|
|
|
|
case "eth_accounts": {
|
|
|
|
const result = [ ];
|
|
|
|
if (this.signer) {
|
|
|
|
const address = await this.signer.getAddress();
|
|
|
|
result.push(address);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
case "eth_blockNumber": {
|
|
|
|
return await this.provider.getBlockNumber();
|
|
|
|
}
|
|
|
|
case "eth_chainId": {
|
|
|
|
const result = await this.provider.getNetwork();
|
2022-02-22 11:51:37 +03:00
|
|
|
return ethers.utils.hexValue(result.chainId);
|
2020-03-12 21:04:15 +03:00
|
|
|
}
|
|
|
|
case "eth_getBalance": {
|
|
|
|
const result = await this.provider.getBalance(params[0], params[1]);
|
|
|
|
return result.toHexString();
|
|
|
|
}
|
|
|
|
case "eth_getStorageAt": {
|
|
|
|
return this.provider.getStorageAt(params[0], params[1], params[2]);
|
|
|
|
}
|
|
|
|
case "eth_getTransactionCount": {
|
|
|
|
const result = await this.provider.getTransactionCount(params[0], params[1]);
|
|
|
|
return ethers.utils.hexValue(result);
|
|
|
|
}
|
|
|
|
case "eth_getBlockTransactionCountByHash":
|
|
|
|
case "eth_getBlockTransactionCountByNumber": {
|
|
|
|
const result = await this.provider.getBlock(params[0]);
|
|
|
|
return ethers.utils.hexValue(result.transactions.length);
|
|
|
|
}
|
|
|
|
case "eth_getCode": {
|
2022-07-14 04:55:56 +03:00
|
|
|
const result = await this.provider.getCode(params[0], params[1]);
|
2020-03-12 21:04:15 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
case "eth_sendRawTransaction": {
|
|
|
|
return await this.provider.sendTransaction(params[0]);
|
|
|
|
}
|
|
|
|
case "eth_call": {
|
|
|
|
const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(params[0]);
|
|
|
|
return await this.provider.call(req, params[1]);
|
|
|
|
}
|
|
|
|
case "estimateGas": {
|
|
|
|
if (params[1] && params[1] !== "latest") {
|
2020-04-22 09:42:25 +03:00
|
|
|
throwUnsupported("estimateGas does not support blockTag");
|
2020-03-12 21:04:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(params[0]);
|
|
|
|
const result = await this.provider.estimateGas(req);
|
|
|
|
return result.toHexString();
|
|
|
|
}
|
|
|
|
|
2021-10-04 18:46:24 +03:00
|
|
|
// @TODO: Transform? No uncles?
|
2020-03-12 21:04:15 +03:00
|
|
|
case "eth_getBlockByHash":
|
|
|
|
case "eth_getBlockByNumber": {
|
|
|
|
if (params[1]) {
|
|
|
|
return await this.provider.getBlockWithTransactions(params[0]);
|
|
|
|
} else {
|
|
|
|
return await this.provider.getBlock(params[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case "eth_getTransactionByHash": {
|
|
|
|
return await this.provider.getTransaction(params[0]);
|
|
|
|
}
|
|
|
|
case "eth_getTransactionReceipt": {
|
|
|
|
return await this.provider.getTransactionReceipt(params[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
case "eth_sign": {
|
|
|
|
if (!this.signer) {
|
|
|
|
return throwUnsupported("eth_sign requires an account");
|
|
|
|
}
|
|
|
|
|
|
|
|
const address = await this.signer.getAddress();
|
|
|
|
if (address !== ethers.utils.getAddress(params[0])) {
|
|
|
|
logger.throwArgumentError("account mismatch or account not found", "params[0]", params[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.signer.signMessage(ethers.utils.arrayify(params[1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
case "eth_sendTransaction": {
|
|
|
|
if (!this.signer) {
|
2021-04-20 03:52:50 +03:00
|
|
|
return throwUnsupported("eth_sendTransaction requires an account");
|
2020-03-12 21:04:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(params[0]);
|
|
|
|
const tx = await this.signer.sendTransaction(req);
|
|
|
|
return tx.hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
case "eth_getUncleCountByBlockHash":
|
|
|
|
case "eth_getUncleCountByBlockNumber":
|
|
|
|
{
|
|
|
|
coerce = ethers.utils.hexValue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case "eth_getTransactionByBlockHashAndIndex":
|
|
|
|
case "eth_getTransactionByBlockNumberAndIndex":
|
|
|
|
case "eth_getUncleByBlockHashAndIndex":
|
|
|
|
case "eth_getUncleByBlockNumberAndIndex":
|
|
|
|
case "eth_newFilter":
|
|
|
|
case "eth_newBlockFilter":
|
|
|
|
case "eth_newPendingTransactionFilter":
|
|
|
|
case "eth_uninstallFilter":
|
|
|
|
case "eth_getFilterChanges":
|
|
|
|
case "eth_getFilterLogs":
|
|
|
|
case "eth_getLogs":
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If our provider supports send, maybe it can do a better job?
|
|
|
|
if ((<any>(this.provider)).send) {
|
|
|
|
const result = await (<any>(this.provider)).send(method, params);
|
|
|
|
return coerce(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
return throwUnsupported(`unsupported method: ${ method }`);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|