packages/interface-adapter/lib/adapter/web3/index.ts
import BN from "bn.js";
import { Web3Shim } from "../../shim";
import type {
InterfaceAdapter,
EvmBlockType,
Provider,
Transaction,
TransactionReceipt,
TransactionCostReport
} from "../types";
export interface Web3InterfaceAdapterOptions {
provider?: Provider;
networkType?: string;
}
export class Web3InterfaceAdapter implements InterfaceAdapter {
public web3: Web3Shim;
constructor({ provider, networkType }: Web3InterfaceAdapterOptions = {}) {
this.web3 = new Web3Shim({ provider, networkType });
}
public getNetworkId() {
return this.web3.eth.net.getId();
}
public getBlock(block: EvmBlockType) {
return this.web3.eth.getBlock(block);
}
public getTransaction(tx: string) {
return this.web3.eth.getTransaction(tx);
}
public getTransactionReceipt(tx: string) {
return this.web3.eth.getTransactionReceipt(tx);
}
public getBalance(address: string) {
return this.web3.eth.getBalance(address);
}
public getCode(address: string) {
return this.web3.eth.getCode(address);
}
public getAccounts() {
return this.web3.eth.getAccounts();
}
public async estimateGas(transactionConfig: Transaction, stacktrace = false) {
// web3 does not error gracefully when gas estimation fails due to a revert,
// so in cases where we want to get past this (debugging/stacktracing), we must
// catch the error and return null instead
if (stacktrace === true) {
try {
const gasEstimate = await this.web3.eth.estimateGas(transactionConfig);
return gasEstimate;
} catch {
return null;
}
} else {
return this.web3.eth.estimateGas(transactionConfig);
}
}
public getBlockNumber() {
return this.web3.eth.getBlockNumber();
}
public async getTransactionCostReport(
receipt: TransactionReceipt
): Promise<TransactionCostReport> {
const tx = await this.getTransaction(receipt.transactionHash);
const block = await this.getBlock(receipt.blockNumber);
if (!block) return null;
const balance = await this.getBalance(tx.from);
const gasPrice = new BN(tx.gasPrice);
const gas = new BN(receipt.gasUsed);
const value = new BN(tx.value);
const cost = gasPrice.mul(gas).add(value);
const timestamp =
typeof block.timestamp === "string"
? parseInt(block.timestamp)
: block.timestamp;
return {
timestamp,
from: tx.from,
balance: Web3Shim.utils.fromWei(balance, "ether"),
gasUnit: "gwei",
gasPrice: Web3Shim.utils.fromWei(gasPrice, "gwei"),
gas,
valueUnit: "ETH",
value: Web3Shim.utils.fromWei(value, "ether"),
cost
};
}
public displayCost(value: BN) {
return Web3Shim.utils.fromWei(value, "ether");
}
}