ethers.js/packages/providers/formatter.js
2019-05-14 18:48:48 -04:00

396 lines
15 KiB
JavaScript

"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var address_1 = require("@ethersproject/address");
var bignumber_1 = require("@ethersproject/bignumber");
var bytes_1 = require("@ethersproject/bytes");
var constants_1 = require("@ethersproject/constants");
var errors = __importStar(require("@ethersproject/errors"));
var properties_1 = require("@ethersproject/properties");
var transactions_1 = require("@ethersproject/transactions");
var Formatter = /** @class */ (function () {
function Formatter() {
var _newTarget = this.constructor;
errors.checkNew(_newTarget, Formatter);
this.formats = this.getDefaultFormats();
}
Formatter.prototype.getDefaultFormats = function () {
var _this = this;
var formats = ({});
var address = this.address.bind(this);
var bigNumber = this.bigNumber.bind(this);
var blockTag = this.blockTag.bind(this);
var data = this.data.bind(this);
var hash = this.hash.bind(this);
var hex = this.hex.bind(this);
var number = this.number.bind(this);
var strictData = function (v) { return _this.data(v, true); };
formats.transaction = {
hash: hash,
blockHash: Formatter.allowNull(hash, null),
blockNumber: Formatter.allowNull(number, null),
transactionIndex: Formatter.allowNull(number, null),
confirmations: Formatter.allowNull(number, null),
from: address,
gasPrice: bigNumber,
gasLimit: bigNumber,
to: Formatter.allowNull(address, null),
value: bigNumber,
nonce: number,
data: data,
r: Formatter.allowNull(this.uint256),
s: Formatter.allowNull(this.uint256),
v: Formatter.allowNull(number),
creates: Formatter.allowNull(address, null),
raw: Formatter.allowNull(data),
};
formats.transactionRequest = {
from: Formatter.allowNull(address),
nonce: Formatter.allowNull(number),
gasLimit: Formatter.allowNull(bigNumber),
gasPrice: Formatter.allowNull(bigNumber),
to: Formatter.allowNull(address),
value: Formatter.allowNull(bigNumber),
data: Formatter.allowNull(strictData),
};
formats.receiptLog = {
transactionLogIndex: Formatter.allowNull(number),
transactionIndex: number,
blockNumber: number,
transactionHash: hash,
address: address,
topics: Formatter.arrayOf(hash),
data: data,
logIndex: number,
blockHash: hash,
};
formats.receipt = {
to: Formatter.allowNull(this.address),
from: Formatter.allowNull(this.address),
contractAddress: Formatter.allowNull(address, null),
transactionIndex: number,
root: Formatter.allowNull(hash),
gasUsed: bigNumber,
logsBloom: Formatter.allowNull(data),
blockHash: hash,
transactionHash: hash,
logs: Formatter.arrayOf(this.receiptLog.bind(this)),
blockNumber: number,
confirmations: Formatter.allowNull(number, null),
cumulativeGasUsed: bigNumber,
status: Formatter.allowNull(number)
};
formats.block = {
hash: hash,
parentHash: hash,
number: number,
timestamp: number,
nonce: Formatter.allowNull(hex),
difficulty: this.difficulty.bind(this),
gasLimit: bigNumber,
gasUsed: bigNumber,
miner: address,
extraData: data,
transactions: Formatter.allowNull(Formatter.arrayOf(hash)),
};
formats.blockWithTransactions = properties_1.shallowCopy(formats.block);
formats.blockWithTransactions.transactions = Formatter.allowNull(Formatter.arrayOf(this.transactionResponse.bind(this)));
formats.filter = {
fromBlock: Formatter.allowNull(blockTag, undefined),
toBlock: Formatter.allowNull(blockTag, undefined),
blockHash: Formatter.allowNull(hash, undefined),
address: Formatter.allowNull(address, undefined),
topics: Formatter.allowNull(this.topics.bind(this), undefined),
};
formats.filterLog = {
blockNumber: Formatter.allowNull(number),
blockHash: Formatter.allowNull(hash),
transactionIndex: number,
removed: Formatter.allowNull(this.boolean.bind(this)),
address: address,
data: Formatter.allowFalsish(data, "0x"),
topics: Formatter.arrayOf(hash),
transactionHash: hash,
logIndex: number,
};
return formats;
};
// Requires a BigNumberish that is within the IEEE754 safe integer range; returns a number
// Strict! Used on input.
Formatter.prototype.number = function (number) {
return bignumber_1.BigNumber.from(number).toNumber();
};
// Strict! Used on input.
Formatter.prototype.bigNumber = function (value) {
return bignumber_1.BigNumber.from(value);
};
// Requires a boolean, "true" or "false"; returns a boolean
Formatter.prototype.boolean = function (value) {
if (typeof (value) === "boolean") {
return value;
}
if (typeof (value) === "string") {
value = value.toLowerCase();
if (value === "true") {
return true;
}
if (value === "false") {
return false;
}
}
throw new Error("invaid boolean - " + value);
};
Formatter.prototype.hex = function (value, strict) {
if (typeof (value) === "string") {
if (!strict && value.substring(0, 2) !== "0x") {
value = "0x" + value;
}
if (bytes_1.isHexString(value)) {
return value.toLowerCase();
}
}
return errors.throwError("invalid hash", errors.INVALID_ARGUMENT, {
argument: "value",
value: value
});
};
Formatter.prototype.data = function (value, strict) {
var result = this.hex(value, strict);
if ((result.length % 2) !== 0) {
throw new Error("invalid data; odd-length - " + value);
}
return result;
};
// Requires an address
// Strict! Used on input.
Formatter.prototype.address = function (value) {
return address_1.getAddress(value);
};
Formatter.prototype.callAddress = function (value) {
if (!bytes_1.isHexString(value, 32)) {
return null;
}
var address = address_1.getAddress(bytes_1.hexDataSlice(value, 12));
return (address === constants_1.AddressZero) ? null : address;
};
Formatter.prototype.contractAddress = function (value) {
return address_1.getContractAddress(value);
};
// Strict! Used on input.
Formatter.prototype.blockTag = function (blockTag) {
if (blockTag == null) {
return "latest";
}
if (blockTag === "earliest") {
return "0x0";
}
if (blockTag === "latest" || blockTag === "pending") {
return blockTag;
}
if (typeof (blockTag) === "number" || bytes_1.isHexString(blockTag)) {
return bytes_1.hexValue(blockTag);
}
throw new Error("invalid blockTag");
};
// Requires a hash, optionally requires 0x prefix; returns prefixed lowercase hash.
Formatter.prototype.hash = function (value, strict) {
var result = this.hex(value, strict);
if (bytes_1.hexDataLength(result) !== 32) {
return errors.throwError("invalid hash", errors.INVALID_ARGUMENT, {
argument: "value",
value: value
});
}
return result;
};
// Returns the difficulty as a number, or if too large (i.e. PoA network) null
Formatter.prototype.difficulty = function (value) {
var v = bignumber_1.BigNumber.from(value);
try {
return v.toNumber();
}
catch (error) { }
return null;
};
Formatter.prototype.uint256 = function (value) {
if (!bytes_1.isHexString(value)) {
throw new Error("invalid uint256");
}
return bytes_1.hexZeroPad(value, 32);
};
Formatter.prototype._block = function (value, format) {
if (value.author != null && value.miner == null) {
value.miner = value.author;
}
return Formatter.check(format, value);
};
Formatter.prototype.block = function (value) {
return this._block(value, this.formats.block);
};
Formatter.prototype.blockWithTransactions = function (value) {
return this._block(value, this.formats.blockWithTransactions);
};
// Strict! Used on input.
Formatter.prototype.transactionRequest = function (value) {
return Formatter.check(this.formats.transactionRequest, value);
};
Formatter.prototype.transactionResponse = function (transaction) {
// Rename gas to gasLimit
if (transaction.gas != null && transaction.gasLimit == null) {
transaction.gasLimit = transaction.gas;
}
// Some clients (TestRPC) do strange things like return 0x0 for the
// 0 address; correct this to be a real address
if (transaction.to && bignumber_1.BigNumber.from(transaction.to).isZero()) {
transaction.to = "0x0000000000000000000000000000000000000000";
}
// Rename input to data
if (transaction.input != null && transaction.data == null) {
transaction.data = transaction.input;
}
// If to and creates are empty, populate the creates from the transaction
if (transaction.to == null && transaction.creates == null) {
transaction.creates = this.contractAddress(transaction);
}
// @TODO: use transaction.serialize? Have to add support for including v, r, and s...
/*
if (!transaction.raw) {
// Very loose providers (e.g. TestRPC) do not provide a signature or raw
if (transaction.v && transaction.r && transaction.s) {
let raw = [
stripZeros(hexlify(transaction.nonce)),
stripZeros(hexlify(transaction.gasPrice)),
stripZeros(hexlify(transaction.gasLimit)),
(transaction.to || "0x"),
stripZeros(hexlify(transaction.value || "0x")),
hexlify(transaction.data || "0x"),
stripZeros(hexlify(transaction.v || "0x")),
stripZeros(hexlify(transaction.r)),
stripZeros(hexlify(transaction.s)),
];
transaction.raw = rlpEncode(raw);
}
}
*/
var result = Formatter.check(this.formats.transaction, transaction);
var networkId = transaction.networkId;
// geth-etc returns chainId
if (transaction.chainId != null && networkId == null && result.v == null) {
networkId = transaction.chainId;
}
if (bytes_1.isHexString(networkId)) {
networkId = bignumber_1.BigNumber.from(networkId).toNumber();
}
if (typeof (networkId) !== "number" && result.v != null) {
networkId = (result.v - 35) / 2;
if (networkId < 0) {
networkId = 0;
}
networkId = parseInt(networkId);
}
if (typeof (networkId) !== "number") {
networkId = 0;
}
result.networkId = networkId;
// 0x0000... should actually be null
if (result.blockHash && result.blockHash.replace(/0/g, "") === "x") {
result.blockHash = null;
}
return result;
};
Formatter.prototype.transaction = function (value) {
return transactions_1.parse(value);
};
Formatter.prototype.receiptLog = function (value) {
return Formatter.check(this.formats.receiptLog, value);
};
Formatter.prototype.receipt = function (value) {
//let status = transactionReceipt.status;
//let root = transactionReceipt.root;
var result = Formatter.check(this.formats.receipt, value);
result.logs.forEach(function (entry, index) {
if (entry.transactionLogIndex == null) {
entry.transactionLogIndex = index;
}
});
if (value.status != null) {
result.byzantium = true;
}
return result;
};
Formatter.prototype.topics = function (value) {
var _this = this;
if (Array.isArray(value)) {
return value.map(function (v) { return _this.topics(v); });
}
else if (value != null) {
return this.hash(value, true);
}
return null;
};
Formatter.prototype.filter = function (value) {
return Formatter.check(this.formats.filter, value);
};
Formatter.prototype.filterLog = function (value) {
return Formatter.check(this.formats.filterLog, value);
};
Formatter.check = function (format, object) {
var result = {};
for (var key in format) {
try {
var value = format[key](object[key]);
if (value !== undefined) {
result[key] = value;
}
}
catch (error) {
error.checkKey = key;
error.checkValue = object[key];
throw error;
}
}
return result;
};
// if value is null-ish, nullValue is returned
Formatter.allowNull = function (format, nullValue) {
return (function (value) {
if (value == null) {
return nullValue;
}
return format(value);
});
};
// If value is false-ish, replaceValue is returned
Formatter.allowFalsish = function (format, replaceValue) {
return (function (value) {
if (!value) {
return replaceValue;
}
return format(value);
});
};
// Requires an Array satisfying check
Formatter.arrayOf = function (format) {
return (function (array) {
if (!Array.isArray(array)) {
throw new Error("not an array");
}
var result = [];
array.forEach(function (value) {
result.push(format(value));
});
return result;
});
};
return Formatter;
}());
exports.Formatter = Formatter;