ethers.js/src/providers/json-rpc-provider.js

313 lines
12 KiB
JavaScript
Raw Normal View History

2018-06-13 22:39:39 +03:00
'use strict';
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
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 });
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC
var networks_1 = require("./networks");
var provider_js_1 = require("./provider.js");
var address_1 = require("../utils/address");
var convert_1 = require("../utils/convert");
var utf8_1 = require("../utils/utf8");
var web_1 = require("../utils/web");
var errors = __importStar(require("../utils/errors"));
function timer(timeout) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve();
}, timeout);
});
}
function getResult(payload) {
if (payload.error) {
// @TODO: not any
var error = new Error(payload.error.message);
error.code = payload.error.code;
error.data = payload.error.data;
throw error;
}
return payload.result;
}
// Convert an ethers.js transaction into a JSON-RPC transaction
// - gasLimit => gas
// - All values hexlified
// - All numeric values zero-striped
function hexlifyTransaction(transaction) {
var result = {};
// Some nodes (INFURA ropsten; INFURA mainnet is fine) don't like extra zeros.
['gasLimit', 'gasPrice', 'nonce', 'value'].forEach(function (key) {
if (transaction[key] == null) {
return;
}
var value = convert_1.hexStripZeros(convert_1.hexlify(transaction[key]));
if (key === 'gasLimit') {
key = 'gas';
}
result[key] = value;
});
['from', 'to', 'data'].forEach(function (key) {
if (transaction[key] == null) {
return;
}
result[key] = convert_1.hexlify(transaction[key]);
});
return result;
}
exports.hexlifyTransaction = hexlifyTransaction;
function getLowerCase(value) {
if (value) {
return value.toLowerCase();
}
return value;
}
var JsonRpcSigner = /** @class */ (function () {
// private _syncAddress: boolean;
function JsonRpcSigner(provider, address) {
//errors.checkNew(this, JsonRpcSigner);
this.provider = provider;
// Statically attach to a given address
if (address) {
this._address = address;
//this._syncAddress = true;
}
}
Object.defineProperty(JsonRpcSigner.prototype, "address", {
get: function () {
if (!this._address) {
errors.throwError('no sync sync address available; use getAddress', errors.UNSUPPORTED_OPERATION, { operation: 'address' });
}
return this._address;
},
enumerable: true,
configurable: true
});
JsonRpcSigner.prototype.getAddress = function () {
if (this._address) {
return Promise.resolve(this._address);
}
return this.provider.send('eth_accounts', []).then(function (accounts) {
if (accounts.length === 0) {
errors.throwError('no accounts', errors.UNSUPPORTED_OPERATION, { operation: 'getAddress' });
}
return address_1.getAddress(accounts[0]);
});
};
JsonRpcSigner.prototype.getBalance = function (blockTag) {
var _this = this;
return this.getAddress().then(function (address) {
return _this.provider.getBalance(address, blockTag);
});
};
JsonRpcSigner.prototype.getTransactionCount = function (blockTag) {
var _this = this;
return this.getAddress().then(function (address) {
return _this.provider.getTransactionCount(address, blockTag);
});
};
// @TODO:
//sendTransaction(transaction: TransactionRequest): Promise<TransactionResponse> {
JsonRpcSigner.prototype.sendTransaction = function (transaction) {
var _this = this;
transaction = hexlifyTransaction(transaction);
return this.getAddress().then(function (address) {
transaction.from = address.toLowerCase();
return _this.provider.send('eth_sendTransaction', [transaction]).then(function (hash) {
// @TODO: Use secp256k1 to fill this in instead...
return new Promise(function (resolve, reject) {
function check() {
this.provider.getTransaction(hash).then(function (transaction) {
if (!transaction) {
setTimeout(check, 1000);
return;
}
transaction.wait = function (timeout) {
return this.provider.waitForTransaction(hash, timeout);
};
resolve(transaction);
});
}
check();
});
});
});
};
JsonRpcSigner.prototype.signMessage = function (message) {
var _this = this;
var data = ((typeof (message) === 'string') ? utf8_1.toUtf8Bytes(message) : message);
return this.getAddress().then(function (address) {
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
return _this.provider.send('eth_sign', [address.toLowerCase(), convert_1.hexlify(data)]);
});
};
JsonRpcSigner.prototype.unlock = function (password) {
var provider = this.provider;
return this.getAddress().then(function (address) {
return provider.send('personal_unlockAccount', [address.toLowerCase(), password, null]);
});
};
return JsonRpcSigner;
}());
exports.JsonRpcSigner = JsonRpcSigner;
var JsonRpcProvider = /** @class */ (function (_super) {
__extends(JsonRpcProvider, _super);
function JsonRpcProvider(url, network) {
//errors.checkNew(this, JsonRpcProvider);
var _this = this;
// One parameter, but it is a network name, so swap it with the URL
if (typeof (url) === 'string') {
if (network === null && networks_1.getNetwork(url)) {
network = url;
url = null;
}
}
_this = _super.call(this, network) || this;
// Default URL
if (!url) {
url = 'http://localhost:8545';
}
if (typeof (url) === 'string') {
_this.connection = {
url: url
};
}
else {
_this.connection = url;
}
// The network is unknown, query the JSON-RPC for it
if (!_this.network) {
_this.ready = new Promise(function (resolve, reject) {
setTimeout(function () {
_this.send('net_version', []).then(function (result) {
var chainId = parseInt(result);
var network = networks_1.getNetwork(chainId);
if (network) {
return resolve(network);
}
resolve({
name: 'custom',
chainId: chainId
});
});
});
});
}
return _this;
}
JsonRpcProvider.prototype.getSigner = function (address) {
return new JsonRpcSigner(this, address);
};
JsonRpcProvider.prototype.listAccounts = function () {
return this.send('eth_accounts', []).then(function (accounts) {
return accounts.map(function (a) { return address_1.getAddress(a); });
});
};
JsonRpcProvider.prototype.send = function (method, params) {
var request = {
method: method,
params: params,
id: 42,
jsonrpc: "2.0"
};
return web_1.fetchJson(this.connection, JSON.stringify(request), getResult);
};
JsonRpcProvider.prototype.perform = function (method, params) {
switch (method) {
case 'getBlockNumber':
return this.send('eth_blockNumber', []);
case 'getGasPrice':
return this.send('eth_gasPrice', []);
case 'getBalance':
return this.send('eth_getBalance', [getLowerCase(params.address), params.blockTag]);
case 'getTransactionCount':
return this.send('eth_getTransactionCount', [getLowerCase(params.address), params.blockTag]);
case 'getCode':
return this.send('eth_getCode', [getLowerCase(params.address), params.blockTag]);
case 'getStorageAt':
return this.send('eth_getStorageAt', [getLowerCase(params.address), params.position, params.blockTag]);
case 'sendTransaction':
return this.send('eth_sendRawTransaction', [params.signedTransaction]);
case 'getBlock':
if (params.blockTag) {
return this.send('eth_getBlockByNumber', [params.blockTag, false]);
}
else if (params.blockHash) {
return this.send('eth_getBlockByHash', [params.blockHash, false]);
}
return Promise.reject(new Error('invalid block tag or block hash'));
case 'getTransaction':
return this.send('eth_getTransactionByHash', [params.transactionHash]);
case 'getTransactionReceipt':
return this.send('eth_getTransactionReceipt', [params.transactionHash]);
case 'call':
return this.send('eth_call', [hexlifyTransaction(params.transaction), 'latest']);
case 'estimateGas':
return this.send('eth_estimateGas', [hexlifyTransaction(params.transaction)]);
case 'getLogs':
if (params.filter && params.filter.address != null) {
params.filter.address = getLowerCase(params.filter.address);
}
return this.send('eth_getLogs', [params.filter]);
default:
break;
}
errors.throwError(method + ' not implemented', errors.NOT_IMPLEMENTED, { operation: method });
return null;
};
JsonRpcProvider.prototype._startPending = function () {
if (this._pendingFilter != null) {
return;
}
var self = this;
var pendingFilter = this.send('eth_newPendingTransactionFilter', []);
this._pendingFilter = pendingFilter;
pendingFilter.then(function (filterId) {
function poll() {
self.send('eth_getFilterChanges', [filterId]).then(function (hashes) {
if (self._pendingFilter != pendingFilter) {
return null;
}
var seq = Promise.resolve();
hashes.forEach(function (hash) {
self._emitted['t:' + hash.toLowerCase()] = 'pending';
seq = seq.then(function () {
return self.getTransaction(hash).then(function (tx) {
self.emit('pending', tx);
});
});
});
return seq.then(function () {
return timer(1000);
});
}).then(function () {
if (self._pendingFilter != pendingFilter) {
self.send('eth_uninstallFilter', [filterId]);
return;
}
setTimeout(function () { poll(); }, 0);
});
}
poll();
return filterId;
});
};
JsonRpcProvider.prototype._stopPending = function () {
this._pendingFilter = null;
};
return JsonRpcProvider;
}(provider_js_1.Provider));
exports.JsonRpcProvider = JsonRpcProvider;