forked from tornado-packages/ethers.js
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ac2d923b7 | ||
|
|
6996dd86f4 | ||
|
|
493273d698 | ||
|
|
84344ac4c2 | ||
|
|
9b118af304 | ||
|
|
e39e2ed718 | ||
|
|
71f781d542 | ||
|
|
b2db10e216 | ||
|
|
3736a15714 | ||
|
|
248158130e | ||
|
|
f5c7ccbb80 | ||
|
|
24335d0dd7 | ||
|
|
908c2c1096 | ||
|
|
9797b36186 | ||
|
|
731f189010 | ||
|
|
cc5b157231 | ||
|
|
99fed75202 | ||
|
|
cb5f9f576a | ||
|
|
aeac2cdb86 | ||
|
|
0dafd83033 | ||
|
|
f6d946cf68 |
2
_version.d.ts
vendored
2
_version.d.ts
vendored
@@ -1 +1 @@
|
||||
export declare const version = "4.0.1";
|
||||
export declare const version = "4.0.5";
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.version = "4.0.1";
|
||||
exports.version = "4.0.5";
|
||||
|
||||
6
contract.d.ts
vendored
6
contract.d.ts
vendored
@@ -21,6 +21,12 @@ export interface Event extends Log {
|
||||
getTransaction: () => Promise<TransactionResponse>;
|
||||
getTransactionReceipt: () => Promise<TransactionReceipt>;
|
||||
}
|
||||
export interface ContractReceipt extends TransactionReceipt {
|
||||
events?: Array<Event>;
|
||||
}
|
||||
export interface ContractTransaction extends TransactionResponse {
|
||||
wait(confirmations?: number): Promise<ContractReceipt>;
|
||||
}
|
||||
export declare class VoidSigner extends Signer {
|
||||
readonly address: string;
|
||||
constructor(address: string, provider: Provider);
|
||||
|
||||
39
contract.js
39
contract.js
@@ -106,14 +106,20 @@ function resolveAddresses(provider, value, paramType) {
|
||||
function runMethod(contract, functionName, estimateOnly) {
|
||||
var method = contract.interface.functions[functionName];
|
||||
return function () {
|
||||
var _this = this;
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
var tx = {};
|
||||
var blockTag = null;
|
||||
// If 1 extra parameter was passed in, it contains overrides
|
||||
if (params.length === method.inputs.length + 1 && typeof (params[params.length - 1]) === 'object') {
|
||||
tx = properties_1.shallowCopy(params.pop());
|
||||
if (tx.blockTag != null) {
|
||||
blockTag = tx.blockTag;
|
||||
delete tx.blockTag;
|
||||
}
|
||||
// Check for unexpected keys (e.g. using "gas" instead of "gasLimit")
|
||||
for (var key in tx) {
|
||||
if (!allowedTransactionKeys[key]) {
|
||||
@@ -153,7 +159,7 @@ function runMethod(contract, functionName, estimateOnly) {
|
||||
if (tx.from == null && contract.signer) {
|
||||
tx.from = contract.signer.getAddress();
|
||||
}
|
||||
return contract.provider.call(tx).then(function (value) {
|
||||
return contract.provider.call(tx, blockTag).then(function (value) {
|
||||
if ((bytes_1.hexDataLength(value) % 32) === 4 && bytes_1.hexDataSlice(value, 0, 4) === '0x08c379a0') {
|
||||
var reason = abi_coder_1.defaultAbiCoder.decode(['string'], bytes_1.hexDataSlice(value, 4));
|
||||
errors.throwError('call revert exception', errors.CALL_EXCEPTION, {
|
||||
@@ -206,7 +212,36 @@ function runMethod(contract, functionName, estimateOnly) {
|
||||
if (tx.from != null) {
|
||||
errors.throwError('cannot override from in a transaction', errors.UNSUPPORTED_OPERATION, { operation: 'sendTransaction' });
|
||||
}
|
||||
return contract.signer.sendTransaction(tx);
|
||||
return contract.signer.sendTransaction(tx).then(function (tx) {
|
||||
var wait = tx.wait.bind(tx);
|
||||
tx.wait = function (confirmations) {
|
||||
return wait(confirmations).then(function (receipt) {
|
||||
receipt.events = receipt.logs.map(function (log) {
|
||||
var event = properties_1.deepCopy(log);
|
||||
var parsed = _this.interface.parseLog(log);
|
||||
if (parsed) {
|
||||
event.args = parsed.values;
|
||||
event.decode = parsed.decode;
|
||||
event.event = parsed.name;
|
||||
event.eventSignature = parsed.signature;
|
||||
}
|
||||
event.removeListener = function () { return _this.provider; };
|
||||
event.getBlock = function () {
|
||||
return _this.provider.getBlock(receipt.blockHash);
|
||||
};
|
||||
event.getTransaction = function () {
|
||||
return _this.provider.getTransaction(receipt.transactionHash);
|
||||
};
|
||||
event.getTransactionReceipt = function () {
|
||||
return Promise.resolve(receipt);
|
||||
};
|
||||
return event;
|
||||
});
|
||||
return receipt;
|
||||
});
|
||||
};
|
||||
return tx;
|
||||
});
|
||||
}
|
||||
throw new Error('invalid type - ' + method.type);
|
||||
return null;
|
||||
|
||||
288
dist/ethers.js
vendored
288
dist/ethers.js
vendored
@@ -1,7 +1,7 @@
|
||||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ethers = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.version = "4.0.1";
|
||||
exports.version = "4.0.5";
|
||||
|
||||
},{}],2:[function(require,module,exports){
|
||||
"use strict";
|
||||
@@ -154,14 +154,20 @@ function resolveAddresses(provider, value, paramType) {
|
||||
function runMethod(contract, functionName, estimateOnly) {
|
||||
var method = contract.interface.functions[functionName];
|
||||
return function () {
|
||||
var _this = this;
|
||||
var params = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
params[_i] = arguments[_i];
|
||||
}
|
||||
var tx = {};
|
||||
var blockTag = null;
|
||||
// If 1 extra parameter was passed in, it contains overrides
|
||||
if (params.length === method.inputs.length + 1 && typeof (params[params.length - 1]) === 'object') {
|
||||
tx = properties_1.shallowCopy(params.pop());
|
||||
if (tx.blockTag != null) {
|
||||
blockTag = tx.blockTag;
|
||||
delete tx.blockTag;
|
||||
}
|
||||
// Check for unexpected keys (e.g. using "gas" instead of "gasLimit")
|
||||
for (var key in tx) {
|
||||
if (!allowedTransactionKeys[key]) {
|
||||
@@ -201,7 +207,7 @@ function runMethod(contract, functionName, estimateOnly) {
|
||||
if (tx.from == null && contract.signer) {
|
||||
tx.from = contract.signer.getAddress();
|
||||
}
|
||||
return contract.provider.call(tx).then(function (value) {
|
||||
return contract.provider.call(tx, blockTag).then(function (value) {
|
||||
if ((bytes_1.hexDataLength(value) % 32) === 4 && bytes_1.hexDataSlice(value, 0, 4) === '0x08c379a0') {
|
||||
var reason = abi_coder_1.defaultAbiCoder.decode(['string'], bytes_1.hexDataSlice(value, 4));
|
||||
errors.throwError('call revert exception', errors.CALL_EXCEPTION, {
|
||||
@@ -254,7 +260,36 @@ function runMethod(contract, functionName, estimateOnly) {
|
||||
if (tx.from != null) {
|
||||
errors.throwError('cannot override from in a transaction', errors.UNSUPPORTED_OPERATION, { operation: 'sendTransaction' });
|
||||
}
|
||||
return contract.signer.sendTransaction(tx);
|
||||
return contract.signer.sendTransaction(tx).then(function (tx) {
|
||||
var wait = tx.wait.bind(tx);
|
||||
tx.wait = function (confirmations) {
|
||||
return wait(confirmations).then(function (receipt) {
|
||||
receipt.events = receipt.logs.map(function (log) {
|
||||
var event = properties_1.deepCopy(log);
|
||||
var parsed = _this.interface.parseLog(log);
|
||||
if (parsed) {
|
||||
event.args = parsed.values;
|
||||
event.decode = parsed.decode;
|
||||
event.event = parsed.name;
|
||||
event.eventSignature = parsed.signature;
|
||||
}
|
||||
event.removeListener = function () { return _this.provider; };
|
||||
event.getBlock = function () {
|
||||
return _this.provider.getBlock(receipt.blockHash);
|
||||
};
|
||||
event.getTransaction = function () {
|
||||
return _this.provider.getTransaction(receipt.transactionHash);
|
||||
};
|
||||
event.getTransactionReceipt = function () {
|
||||
return Promise.resolve(receipt);
|
||||
};
|
||||
return event;
|
||||
});
|
||||
return receipt;
|
||||
});
|
||||
};
|
||||
return tx;
|
||||
});
|
||||
}
|
||||
throw new Error('invalid type - ' + method.type);
|
||||
return null;
|
||||
@@ -718,6 +753,7 @@ exports.ContractFactory = ContractFactory;
|
||||
},{"./abstract-signer":2,"./constants":3,"./errors":5,"./providers/abstract-provider":49,"./utils/abi-coder":58,"./utils/address":59,"./utils/bignumber":61,"./utils/bytes":62,"./utils/interface":67,"./utils/properties":72}],5:[function(require,module,exports){
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var _version_1 = require("./_version");
|
||||
// Unknown Error
|
||||
exports.UNKNOWN_ERROR = 'UNKNOWN_ERROR';
|
||||
// Not implemented
|
||||
@@ -784,6 +820,7 @@ function throwError(message, code, params) {
|
||||
messageDetails.push(key + '=' + JSON.stringify(params[key].toString()));
|
||||
}
|
||||
});
|
||||
messageDetails.push("version=" + _version_1.version);
|
||||
var reason = message;
|
||||
if (messageDetails.length) {
|
||||
message += ' (' + messageDetails.join(', ') + ')';
|
||||
@@ -825,7 +862,7 @@ function setCensorship(censorship, permanent) {
|
||||
}
|
||||
exports.setCensorship = setCensorship;
|
||||
|
||||
},{}],6:[function(require,module,exports){
|
||||
},{"./_version":1}],6:[function(require,module,exports){
|
||||
'use strict';
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
@@ -9192,10 +9229,12 @@ module.exports = { browser: true };
|
||||
if (!checkBufferish(password)) {
|
||||
throw new Error('password must be an array or buffer');
|
||||
}
|
||||
password = Array.prototype.slice.call(password);
|
||||
|
||||
if (!checkBufferish(salt)) {
|
||||
throw new Error('salt must be an array or buffer');
|
||||
}
|
||||
salt = Array.prototype.slice.call(salt);
|
||||
|
||||
var b = PBKDF2_HMAC_SHA256_OneIter(password, salt, p * 128 * r);
|
||||
var B = new Uint32Array(p * 32 * r)
|
||||
@@ -9954,6 +9993,7 @@ var formatTransaction = {
|
||||
blockHash: allowNull(checkHash, null),
|
||||
blockNumber: allowNull(checkNumber, null),
|
||||
transactionIndex: allowNull(checkNumber, null),
|
||||
confirmations: allowNull(checkNumber, null),
|
||||
from: address_1.getAddress,
|
||||
gasPrice: bignumber_1.bigNumberify,
|
||||
gasLimit: bignumber_1.bigNumberify,
|
||||
@@ -10082,6 +10122,7 @@ var formatTransactionReceipt = {
|
||||
transactionHash: checkHash,
|
||||
logs: arrayOf(checkTransactionReceiptLog),
|
||||
blockNumber: checkNumber,
|
||||
confirmations: allowNull(checkNumber, null),
|
||||
cumulativeGasUsed: bignumber_1.bigNumberify,
|
||||
status: allowNull(checkNumber)
|
||||
};
|
||||
@@ -10192,6 +10233,11 @@ function getEventTag(eventName) {
|
||||
}
|
||||
throw new Error('invalid event - ' + eventName);
|
||||
}
|
||||
//////////////////////////////
|
||||
// Helper Object
|
||||
function getTime() {
|
||||
return (new Date()).getTime();
|
||||
}
|
||||
var BaseProvider = /** @class */ (function (_super) {
|
||||
__extends(BaseProvider, _super);
|
||||
function BaseProvider(network) {
|
||||
@@ -10224,11 +10270,13 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
// until we get a response. This provides devs with a consistent view. Similarly for
|
||||
// transaction hashes.
|
||||
_this._emitted = { block: _this._lastBlockNumber };
|
||||
_this._fastQueryDate = 0;
|
||||
return _this;
|
||||
}
|
||||
BaseProvider.prototype._doPoll = function () {
|
||||
var _this = this;
|
||||
this.getBlockNumber().then(function (blockNumber) {
|
||||
_this._setFastBlockNumber(blockNumber);
|
||||
// If the block hasn't changed, meh.
|
||||
if (blockNumber === _this._lastBlockNumber) {
|
||||
return;
|
||||
@@ -10378,13 +10426,44 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
BaseProvider.prototype._getFastBlockNumber = function () {
|
||||
var _this = this;
|
||||
var now = getTime();
|
||||
// Stale block number, request a newer value
|
||||
if ((now - this._fastQueryDate) > 2 * this._pollingInterval) {
|
||||
this._fastQueryDate = now;
|
||||
this._fastBlockNumberPromise = this.getBlockNumber().then(function (blockNumber) {
|
||||
if (_this._fastBlockNumber == null || blockNumber > _this._fastBlockNumber) {
|
||||
_this._fastBlockNumber = blockNumber;
|
||||
}
|
||||
return _this._fastBlockNumber;
|
||||
});
|
||||
}
|
||||
return this._fastBlockNumberPromise;
|
||||
};
|
||||
BaseProvider.prototype._setFastBlockNumber = function (blockNumber) {
|
||||
// Older block, maybe a stale request
|
||||
if (this._fastBlockNumber != null && blockNumber < this._fastBlockNumber) {
|
||||
return;
|
||||
}
|
||||
// Update the time we updated the blocknumber
|
||||
this._fastQueryDate = getTime();
|
||||
// Newer block number, use it
|
||||
if (this._fastBlockNumber == null || blockNumber > this._fastBlockNumber) {
|
||||
this._fastBlockNumber = blockNumber;
|
||||
this._fastBlockNumberPromise = Promise.resolve(blockNumber);
|
||||
}
|
||||
};
|
||||
// @TODO: Add .poller which must be an event emitter with a 'start', 'stop' and 'block' event;
|
||||
// this will be used once we move to the WebSocket or other alternatives to polling
|
||||
BaseProvider.prototype.waitForTransaction = function (transactionHash, timeout) {
|
||||
BaseProvider.prototype.waitForTransaction = function (transactionHash, confirmations) {
|
||||
var _this = this;
|
||||
if (!confirmations) {
|
||||
confirmations = 1;
|
||||
}
|
||||
return web_1.poll(function () {
|
||||
return _this.getTransactionReceipt(transactionHash).then(function (receipt) {
|
||||
if (receipt == null) {
|
||||
if (receipt == null || receipt.confirmations < confirmations) {
|
||||
return undefined;
|
||||
}
|
||||
return receipt;
|
||||
@@ -10399,6 +10478,7 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
if (value != result) {
|
||||
throw new Error('invalid response - getBlockNumber');
|
||||
}
|
||||
_this._setFastBlockNumber(value);
|
||||
return value;
|
||||
});
|
||||
});
|
||||
@@ -10492,7 +10572,7 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
// This should be called by any subclass wrapping a TransactionResponse
|
||||
BaseProvider.prototype._wrapTransaction = function (tx, hash) {
|
||||
var _this = this;
|
||||
if (bytes_1.hexDataLength(hash) !== 32) {
|
||||
if (hash != null && bytes_1.hexDataLength(hash) !== 32) {
|
||||
throw new Error('invalid response - sendTransaction');
|
||||
}
|
||||
var result = tx;
|
||||
@@ -10502,11 +10582,11 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
}
|
||||
this._emitted['t:' + tx.hash] = 'pending';
|
||||
// @TODO: (confirmations? number, timeout? number)
|
||||
result.wait = function () {
|
||||
return _this.waitForTransaction(hash).then(function (receipt) {
|
||||
result.wait = function (confirmations) {
|
||||
return _this.waitForTransaction(tx.hash, confirmations).then(function (receipt) {
|
||||
if (receipt.status === 0) {
|
||||
errors.throwError('transaction failed', errors.CALL_EXCEPTION, {
|
||||
transactionHash: hash,
|
||||
transactionHash: tx.hash,
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
@@ -10515,13 +10595,14 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
};
|
||||
return result;
|
||||
};
|
||||
BaseProvider.prototype.call = function (transaction) {
|
||||
BaseProvider.prototype.call = function (transaction, blockTag) {
|
||||
var _this = this;
|
||||
var tx = properties_1.shallowCopy(transaction);
|
||||
return this.ready.then(function () {
|
||||
return properties_1.resolveProperties(tx).then(function (tx) {
|
||||
return properties_1.resolveProperties({ blockTag: blockTag, tx: tx }).then(function (_a) {
|
||||
var blockTag = _a.blockTag, tx = _a.tx;
|
||||
return _this._resolveNames(tx, ['to', 'from']).then(function (tx) {
|
||||
var params = { transaction: checkTransactionRequest(tx) };
|
||||
var params = { blockTag: checkBlockTag(blockTag), transaction: checkTransactionRequest(tx) };
|
||||
return _this.perform('call', params).then(function (result) {
|
||||
return bytes_1.hexlify(result);
|
||||
});
|
||||
@@ -10608,7 +10689,22 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return BaseProvider.checkTransactionResponse(result);
|
||||
var tx = BaseProvider.checkTransactionResponse(result);
|
||||
if (tx.blockNumber == null) {
|
||||
tx.confirmations = 0;
|
||||
}
|
||||
else if (tx.confirmations == null) {
|
||||
return _this._getFastBlockNumber().then(function (blockNumber) {
|
||||
// Add the confirmations using the fast block number (pessimistic)
|
||||
var confirmations = (blockNumber - tx.blockNumber) + 1;
|
||||
if (confirmations <= 0) {
|
||||
confirmations = 1;
|
||||
}
|
||||
tx.confirmations = confirmations;
|
||||
return _this._wrapTransaction(tx);
|
||||
});
|
||||
}
|
||||
return _this._wrapTransaction(tx);
|
||||
});
|
||||
}, { onceBlock: _this });
|
||||
});
|
||||
@@ -10628,7 +10724,26 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return checkTransactionReceipt(result);
|
||||
// "geth-etc" returns receipts before they are ready
|
||||
if (result.blockHash == null) {
|
||||
return undefined;
|
||||
}
|
||||
var receipt = checkTransactionReceipt(result);
|
||||
if (receipt.blockNumber == null) {
|
||||
receipt.confirmations = 0;
|
||||
}
|
||||
else if (receipt.confirmations == null) {
|
||||
return _this._getFastBlockNumber().then(function (blockNumber) {
|
||||
// Add the confirmations using the fast block number (pessimistic)
|
||||
var confirmations = (blockNumber - receipt.blockNumber) + 1;
|
||||
if (confirmations <= 0) {
|
||||
confirmations = 1;
|
||||
}
|
||||
receipt.confirmations = confirmations;
|
||||
return receipt;
|
||||
});
|
||||
}
|
||||
return receipt;
|
||||
});
|
||||
}, { onceBlock: _this });
|
||||
});
|
||||
@@ -10996,7 +11111,6 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
return _this;
|
||||
}
|
||||
EtherscanProvider.prototype.perform = function (method, params) {
|
||||
//if (!params) { params = {}; }
|
||||
var url = this.baseUrl;
|
||||
var apiKey = '';
|
||||
if (this.apiKey) {
|
||||
@@ -11031,17 +11145,19 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
url += '/api?module=proxy&action=eth_sendRawTransaction&hex=' + params.signedTransaction;
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult).catch(function (error) {
|
||||
// "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 21464000000000 and got: 0"
|
||||
if (error.responseText.toLowerCase().indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "Transaction with the same hash was already imported."
|
||||
if (error.responseText.indexOf('same hash was already imported') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce."
|
||||
if (error.responseText.indexOf('another transaction with same nonce') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
if (error.responseText) {
|
||||
// "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 21464000000000 and got: 0"
|
||||
if (error.responseText.toLowerCase().indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "Transaction with the same hash was already imported."
|
||||
if (error.responseText.indexOf('same hash was already imported') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce."
|
||||
if (error.responseText.indexOf('another transaction with same nonce') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -11066,15 +11182,20 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
url += '/api?module=proxy&action=eth_getTransactionReceipt&txhash=' + params.transactionHash;
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult);
|
||||
case 'call':
|
||||
case 'call': {
|
||||
var transaction = getTransactionString(params.transaction);
|
||||
if (transaction) {
|
||||
transaction = '&' + transaction;
|
||||
}
|
||||
url += '/api?module=proxy&action=eth_call' + transaction;
|
||||
//url += '&tag=' + params.blockTag + apiKey;
|
||||
if (params.blockTag !== 'latest') {
|
||||
throw new Error('EtherscanProvider does not support blockTag for call');
|
||||
}
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult);
|
||||
case 'estimateGas':
|
||||
}
|
||||
case 'estimateGas': {
|
||||
var transaction = getTransactionString(params.transaction);
|
||||
if (transaction) {
|
||||
transaction = '&' + transaction;
|
||||
@@ -11082,6 +11203,7 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
url += '/api?module=proxy&action=eth_estimateGas&' + transaction;
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult);
|
||||
}
|
||||
case 'getLogs':
|
||||
url += '/api?module=logs&action=getLogs';
|
||||
try {
|
||||
@@ -11528,21 +11650,23 @@ var JsonRpcSigner = /** @class */ (function (_super) {
|
||||
throw error;
|
||||
});
|
||||
}, function (error) {
|
||||
// See: JsonRpcProvider.sendTransaction (@TODO: Expose a ._throwError??)
|
||||
if (error.responseText.indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('nonce too low') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {
|
||||
transaction: tx
|
||||
});
|
||||
if (error.responseText) {
|
||||
// See: JsonRpcProvider.sendTransaction (@TODO: Expose a ._throwError??)
|
||||
if (error.responseText.indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('nonce too low') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -11565,6 +11689,9 @@ var JsonRpcSigner = /** @class */ (function (_super) {
|
||||
return JsonRpcSigner;
|
||||
}(abstract_signer_1.Signer));
|
||||
exports.JsonRpcSigner = JsonRpcSigner;
|
||||
var allowedTransactionKeys = {
|
||||
chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, value: true
|
||||
};
|
||||
var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
__extends(JsonRpcProvider, _super);
|
||||
function JsonRpcProvider(url, network) {
|
||||
@@ -11641,17 +11768,19 @@ var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
return this.send('eth_getStorageAt', [getLowerCase(params.address), params.position, params.blockTag]);
|
||||
case 'sendTransaction':
|
||||
return this.send('eth_sendRawTransaction', [params.signedTransaction]).catch(function (error) {
|
||||
// "insufficient funds for gas * price + value"
|
||||
if (error.responseText.indexOf('insufficient funds') > 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "nonce too low"
|
||||
if (error.responseText.indexOf('nonce too low') > 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "replacement transaction underpriced"
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') > 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
if (error.responseText) {
|
||||
// "insufficient funds for gas * price + value"
|
||||
if (error.responseText.indexOf('insufficient funds') > 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "nonce too low"
|
||||
if (error.responseText.indexOf('nonce too low') > 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "replacement transaction underpriced"
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') > 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -11668,9 +11797,9 @@ var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
case 'getTransactionReceipt':
|
||||
return this.send('eth_getTransactionReceipt', [params.transactionHash]);
|
||||
case 'call':
|
||||
return this.send('eth_call', [JsonRpcProvider.hexlifyTransaction(params.transaction), 'latest']);
|
||||
return this.send('eth_call', [JsonRpcProvider.hexlifyTransaction(params.transaction, { from: true }), params.blockTag]);
|
||||
case 'estimateGas':
|
||||
return this.send('eth_estimateGas', [JsonRpcProvider.hexlifyTransaction(params.transaction)]);
|
||||
return this.send('eth_estimateGas', [JsonRpcProvider.hexlifyTransaction(params.transaction, { from: true })]);
|
||||
case 'getLogs':
|
||||
if (params.filter && params.filter.address != null) {
|
||||
params.filter.address = getLowerCase(params.filter.address);
|
||||
@@ -11728,8 +11857,21 @@ var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
// - gasLimit => gas
|
||||
// - All values hexlified
|
||||
// - All numeric values zero-striped
|
||||
// @TODO: Not any, a dictionary of string to strings
|
||||
JsonRpcProvider.hexlifyTransaction = function (transaction) {
|
||||
// NOTE: This allows a TransactionRequest, but all values should be resolved
|
||||
// before this is called
|
||||
JsonRpcProvider.hexlifyTransaction = function (transaction, allowExtra) {
|
||||
if (!allowExtra) {
|
||||
allowExtra = {};
|
||||
}
|
||||
for (var key in transaction) {
|
||||
if (!allowedTransactionKeys[key] && !allowExtra[key]) {
|
||||
errors.throwError('invalid key - ' + key, errors.INVALID_ARGUMENT, {
|
||||
argument: 'transaction',
|
||||
value: transaction,
|
||||
key: key
|
||||
});
|
||||
}
|
||||
}
|
||||
var result = {};
|
||||
// Some nodes (INFURA ropsten; INFURA mainnet is fine) don't like extra zeros.
|
||||
['gasLimit', 'gasPrice', 'nonce', 'value'].forEach(function (key) {
|
||||
@@ -13043,6 +13185,9 @@ var BigNumber = /** @class */ (function () {
|
||||
else if (value.toHexString) {
|
||||
properties_1.defineReadOnly(this, '_hex', toHex(toBN(value.toHexString())));
|
||||
}
|
||||
else if (value._hex && bytes_1.isHexString(value._hex)) {
|
||||
properties_1.defineReadOnly(this, '_hex', value._hex);
|
||||
}
|
||||
else if (bytes_1.isArrayish(value)) {
|
||||
properties_1.defineReadOnly(this, '_hex', toHex(new bn_js_1.default.BN(bytes_1.hexlify(value).substring(2), 16)));
|
||||
}
|
||||
@@ -13497,6 +13642,7 @@ var HDNode = /** @class */ (function () {
|
||||
properties_1.defineReadOnly(this, 'keyPair', new secp256k1_1.KeyPair(privateKey));
|
||||
properties_1.defineReadOnly(this, 'privateKey', this.keyPair.privateKey);
|
||||
properties_1.defineReadOnly(this, 'publicKey', this.keyPair.compressedPublicKey);
|
||||
properties_1.defineReadOnly(this, 'address', secp256k1_1.computeAddress(this.publicKey));
|
||||
properties_1.defineReadOnly(this, 'chainCode', bytes_1.hexlify(chainCode));
|
||||
properties_1.defineReadOnly(this, 'index', index);
|
||||
properties_1.defineReadOnly(this, 'depth', depth);
|
||||
@@ -15957,6 +16103,9 @@ function fetchJson(connection, json, processFunc) {
|
||||
// @TODO: not any!
|
||||
var error = new Error('invalid response - ' + request.status);
|
||||
error.statusCode = request.status;
|
||||
if (request.responseText) {
|
||||
error.responseText = request.responseText;
|
||||
}
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
@@ -16173,6 +16322,9 @@ var transaction_1 = require("./utils/transaction");
|
||||
var abstract_signer_1 = require("./abstract-signer");
|
||||
var abstract_provider_1 = require("./providers/abstract-provider");
|
||||
var errors = __importStar(require("./errors"));
|
||||
var allowedTransactionKeys = {
|
||||
chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, value: true
|
||||
};
|
||||
var Wallet = /** @class */ (function (_super) {
|
||||
__extends(Wallet, _super);
|
||||
function Wallet(privateKey, provider) {
|
||||
@@ -16222,6 +16374,15 @@ var Wallet = /** @class */ (function (_super) {
|
||||
};
|
||||
Wallet.prototype.sign = function (transaction) {
|
||||
var _this = this;
|
||||
for (var key in transaction) {
|
||||
if (!allowedTransactionKeys[key]) {
|
||||
errors.throwError('unsupported transaction property - ' + key, errors.INVALID_ARGUMENT, {
|
||||
argument: 'transaction',
|
||||
value: transaction,
|
||||
key: key
|
||||
});
|
||||
}
|
||||
}
|
||||
return properties_1.resolveProperties(transaction).then(function (tx) {
|
||||
var rawTx = transaction_1.serialize(tx);
|
||||
var signature = _this.signingKey.signDigest(keccak256_1.keccak256(rawTx));
|
||||
@@ -16254,16 +16415,17 @@ var Wallet = /** @class */ (function (_super) {
|
||||
if (tx.to != null) {
|
||||
tx.to = this.provider.resolveName(tx.to);
|
||||
}
|
||||
if (tx.gasLimit == null) {
|
||||
tx.from = this.getAddress();
|
||||
tx.gasLimit = this.provider.estimateGas(tx);
|
||||
}
|
||||
if (tx.gasPrice == null) {
|
||||
tx.gasPrice = this.provider.getGasPrice();
|
||||
}
|
||||
if (tx.nonce == null) {
|
||||
tx.nonce = this.getTransactionCount();
|
||||
}
|
||||
if (tx.gasLimit == null) {
|
||||
var estimate = properties_1.shallowCopy(tx);
|
||||
estimate.from = this.getAddress();
|
||||
tx.gasLimit = this.provider.estimateGas(estimate);
|
||||
}
|
||||
if (tx.chainId == null) {
|
||||
tx.chainId = this.provider.getNetwork().then(function (network) { return network.chainId; });
|
||||
}
|
||||
|
||||
2
dist/ethers.min.js
vendored
2
dist/ethers.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/ethers.min.js.map
vendored
2
dist/ethers.min.js.map
vendored
File diff suppressed because one or more lines are too long
39
dist/ethers.types.txt
vendored
39
dist/ethers.types.txt
vendored
@@ -17,9 +17,9 @@ declare module 'ethers/ethers' {
|
||||
import * as wordlists from 'ethers/wordlists';
|
||||
import { platform } from 'ethers/utils/shims';
|
||||
import { version } from 'ethers/_version';
|
||||
import { ContractFunction, Event, EventFilter } from 'ethers/contract';
|
||||
import { ContractFunction, ContractTransaction, Event, EventFilter } from 'ethers/contract';
|
||||
function getDefaultProvider(network?: utils.Network | string): providers.BaseProvider;
|
||||
export { Signer, Wallet, VoidSigner, getDefaultProvider, providers, Contract, ContractFactory, constants, errors, utils, wordlists, platform, version, ContractFunction, Event, EventFilter };
|
||||
export { Signer, Wallet, VoidSigner, getDefaultProvider, providers, Contract, ContractFactory, constants, errors, utils, wordlists, platform, version, ContractFunction, ContractTransaction, Event, EventFilter };
|
||||
}
|
||||
|
||||
declare module 'ethers/contract' {
|
||||
@@ -46,6 +46,12 @@ declare module 'ethers/contract' {
|
||||
getTransaction: () => Promise<TransactionResponse>;
|
||||
getTransactionReceipt: () => Promise<TransactionReceipt>;
|
||||
}
|
||||
export interface ContractReceipt extends TransactionReceipt {
|
||||
events?: Array<Event>;
|
||||
}
|
||||
export interface ContractTransaction extends TransactionResponse {
|
||||
wait(confirmations?: number): Promise<ContractReceipt>;
|
||||
}
|
||||
export class VoidSigner extends Signer {
|
||||
readonly address: string;
|
||||
constructor(address: string, provider: Provider);
|
||||
@@ -146,7 +152,7 @@ declare module 'ethers/wallet' {
|
||||
* Static methods to create Wallet instances.
|
||||
*/
|
||||
static createRandom(options?: any): Wallet;
|
||||
static fromEncryptedJson(json: string, password: Arrayish, progressCallback: ProgressCallback): Promise<Wallet>;
|
||||
static fromEncryptedJson(json: string, password: Arrayish, progressCallback?: ProgressCallback): Promise<Wallet>;
|
||||
static fromMnemonic(mnemonic: string, path?: string, wordlist?: Wordlist): Wallet;
|
||||
}
|
||||
}
|
||||
@@ -238,13 +244,15 @@ declare module 'ethers/utils' {
|
||||
declare module 'ethers/wordlists' {
|
||||
import { Wordlist } from 'ethers/utils/wordlist';
|
||||
const en: Wordlist;
|
||||
const ko: Wordlist;
|
||||
const es: Wordlist;
|
||||
const fr: Wordlist;
|
||||
const it: Wordlist;
|
||||
const ja: Wordlist;
|
||||
const ko: Wordlist;
|
||||
const zh: Wordlist;
|
||||
const zh_cn: Wordlist;
|
||||
const zh_tw: Wordlist;
|
||||
export { en, it, ja, ko, zh, zh_cn, zh_tw };
|
||||
export { en, es, fr, it, ja, ko, zh, zh_cn, zh_tw };
|
||||
}
|
||||
|
||||
declare module 'ethers/utils/shims' {
|
||||
@@ -252,7 +260,7 @@ declare module 'ethers/utils/shims' {
|
||||
}
|
||||
|
||||
declare module 'ethers/_version' {
|
||||
export const version = "4.0.1";
|
||||
export const version = "4.0.5";
|
||||
}
|
||||
|
||||
declare module 'ethers/utils/bignumber' {
|
||||
@@ -480,6 +488,7 @@ declare module 'ethers/providers/abstract-provider' {
|
||||
transactionHash?: string;
|
||||
logs?: Array<Log>;
|
||||
blockNumber?: number;
|
||||
confirmations?: number;
|
||||
cumulativeGasUsed?: BigNumber;
|
||||
byzantium: boolean;
|
||||
status?: number;
|
||||
@@ -498,9 +507,10 @@ declare module 'ethers/providers/abstract-provider' {
|
||||
blockNumber?: number;
|
||||
blockHash?: string;
|
||||
timestamp?: number;
|
||||
confirmations: number;
|
||||
from: string;
|
||||
raw?: string;
|
||||
wait: (timeout?: number) => Promise<TransactionReceipt>;
|
||||
wait: (confirmations?: number) => Promise<TransactionReceipt>;
|
||||
}
|
||||
export type EventType = string | Array<string> | Filter;
|
||||
export type Listener = (...args: Array<any>) => void;
|
||||
@@ -513,7 +523,7 @@ declare module 'ethers/providers/abstract-provider' {
|
||||
abstract getCode(addressOrName: string | Promise<string>, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
abstract getStorageAt(addressOrName: string | Promise<string>, position: BigNumberish | Promise<BigNumberish>, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
abstract sendTransaction(signedTransaction: string | Promise<string>): Promise<TransactionResponse>;
|
||||
abstract call(transaction: TransactionRequest): Promise<string>;
|
||||
abstract call(transaction: TransactionRequest, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
abstract estimateGas(transaction: TransactionRequest): Promise<BigNumber>;
|
||||
abstract getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
abstract getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
@@ -612,6 +622,7 @@ declare module 'ethers/utils/hdnode' {
|
||||
export class HDNode {
|
||||
readonly privateKey: string;
|
||||
readonly publicKey: string;
|
||||
readonly address: string;
|
||||
readonly mnemonic: string;
|
||||
readonly path: string;
|
||||
readonly chainCode: string;
|
||||
@@ -719,7 +730,9 @@ declare module 'ethers/providers/base-provider' {
|
||||
readonly blockNumber: number;
|
||||
polling: boolean;
|
||||
pollingInterval: number;
|
||||
waitForTransaction(transactionHash: string, timeout?: number): Promise<TransactionReceipt>;
|
||||
_getFastBlockNumber(): Promise<number>;
|
||||
_setFastBlockNumber(blockNumber: number): void;
|
||||
waitForTransaction(transactionHash: string, confirmations?: number): Promise<TransactionReceipt>;
|
||||
getBlockNumber(): Promise<number>;
|
||||
getGasPrice(): Promise<BigNumber>;
|
||||
getBalance(addressOrName: string | Promise<string>, blockTag?: BlockTag | Promise<BlockTag>): Promise<BigNumber>;
|
||||
@@ -728,7 +741,7 @@ declare module 'ethers/providers/base-provider' {
|
||||
getStorageAt(addressOrName: string | Promise<string>, position: BigNumberish | Promise<BigNumberish>, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
sendTransaction(signedTransaction: string | Promise<string>): Promise<TransactionResponse>;
|
||||
_wrapTransaction(tx: Transaction, hash?: string): TransactionResponse;
|
||||
call(transaction: TransactionRequest): Promise<string>;
|
||||
call(transaction: TransactionRequest, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
estimateGas(transaction: TransactionRequest): Promise<BigNumber>;
|
||||
getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
@@ -826,7 +839,11 @@ declare module 'ethers/providers/json-rpc-provider' {
|
||||
perform(method: string, params: any): Promise<any>;
|
||||
protected _startPending(): void;
|
||||
protected _stopPending(): void;
|
||||
static hexlifyTransaction(transaction: TransactionRequest): any;
|
||||
static hexlifyTransaction(transaction: TransactionRequest, allowExtra?: {
|
||||
[key: string]: boolean;
|
||||
}): {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
dist/wordlist-es.js
vendored
2
dist/wordlist-es.js
vendored
File diff suppressed because one or more lines are too long
2
dist/wordlist-fr.js
vendored
2
dist/wordlist-fr.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var _version_1 = require("./_version");
|
||||
// Unknown Error
|
||||
exports.UNKNOWN_ERROR = 'UNKNOWN_ERROR';
|
||||
// Not implemented
|
||||
@@ -66,6 +67,7 @@ function throwError(message, code, params) {
|
||||
messageDetails.push(key + '=' + JSON.stringify(params[key].toString()));
|
||||
}
|
||||
});
|
||||
messageDetails.push("version=" + _version_1.version);
|
||||
var reason = message;
|
||||
if (messageDetails.length) {
|
||||
message += ' (' + messageDetails.join(', ') + ')';
|
||||
|
||||
4
ethers.d.ts
vendored
4
ethers.d.ts
vendored
@@ -8,6 +8,6 @@ import * as utils from './utils';
|
||||
import * as wordlists from './wordlists';
|
||||
import { platform } from './utils/shims';
|
||||
import { version } from './_version';
|
||||
import { ContractFunction, Event, EventFilter } from './contract';
|
||||
import { ContractFunction, ContractTransaction, Event, EventFilter } from './contract';
|
||||
declare function getDefaultProvider(network?: utils.Network | string): providers.BaseProvider;
|
||||
export { Signer, Wallet, VoidSigner, getDefaultProvider, providers, Contract, ContractFactory, constants, errors, utils, wordlists, platform, version, ContractFunction, Event, EventFilter };
|
||||
export { Signer, Wallet, VoidSigner, getDefaultProvider, providers, Contract, ContractFactory, constants, errors, utils, wordlists, platform, version, ContractFunction, ContractTransaction, Event, EventFilter };
|
||||
|
||||
8
package-lock.json
generated
8
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ethers",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.5",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -5838,9 +5838,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"scrypt-js": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz",
|
||||
"integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q="
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz",
|
||||
"integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw=="
|
||||
},
|
||||
"secp256k1": {
|
||||
"version": "3.5.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ethers",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.5",
|
||||
"description": "Ethereum wallet library.",
|
||||
"main": "./index.js",
|
||||
"types": "./index.d.ts",
|
||||
|
||||
6
providers/abstract-provider.d.ts
vendored
6
providers/abstract-provider.d.ts
vendored
@@ -46,6 +46,7 @@ export interface TransactionReceipt {
|
||||
transactionHash?: string;
|
||||
logs?: Array<Log>;
|
||||
blockNumber?: number;
|
||||
confirmations?: number;
|
||||
cumulativeGasUsed?: BigNumber;
|
||||
byzantium: boolean;
|
||||
status?: number;
|
||||
@@ -64,9 +65,10 @@ export interface TransactionResponse extends Transaction {
|
||||
blockNumber?: number;
|
||||
blockHash?: string;
|
||||
timestamp?: number;
|
||||
confirmations: number;
|
||||
from: string;
|
||||
raw?: string;
|
||||
wait: (timeout?: number) => Promise<TransactionReceipt>;
|
||||
wait: (confirmations?: number) => Promise<TransactionReceipt>;
|
||||
}
|
||||
export declare type EventType = string | Array<string> | Filter;
|
||||
export declare type Listener = (...args: Array<any>) => void;
|
||||
@@ -79,7 +81,7 @@ export declare abstract class Provider implements OnceBlockable {
|
||||
abstract getCode(addressOrName: string | Promise<string>, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
abstract getStorageAt(addressOrName: string | Promise<string>, position: BigNumberish | Promise<BigNumberish>, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
abstract sendTransaction(signedTransaction: string | Promise<string>): Promise<TransactionResponse>;
|
||||
abstract call(transaction: TransactionRequest): Promise<string>;
|
||||
abstract call(transaction: TransactionRequest, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
abstract estimateGas(transaction: TransactionRequest): Promise<BigNumber>;
|
||||
abstract getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
abstract getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
|
||||
9
providers/base-provider.d.ts
vendored
9
providers/base-provider.d.ts
vendored
@@ -12,6 +12,9 @@ export declare class BaseProvider extends Provider {
|
||||
private _poller;
|
||||
private _lastBlockNumber;
|
||||
private _balances;
|
||||
private _fastBlockNumber;
|
||||
private _fastBlockNumberPromise;
|
||||
private _fastQueryDate;
|
||||
/**
|
||||
* ready
|
||||
*
|
||||
@@ -30,7 +33,9 @@ export declare class BaseProvider extends Provider {
|
||||
readonly blockNumber: number;
|
||||
polling: boolean;
|
||||
pollingInterval: number;
|
||||
waitForTransaction(transactionHash: string, timeout?: number): Promise<TransactionReceipt>;
|
||||
_getFastBlockNumber(): Promise<number>;
|
||||
_setFastBlockNumber(blockNumber: number): void;
|
||||
waitForTransaction(transactionHash: string, confirmations?: number): Promise<TransactionReceipt>;
|
||||
getBlockNumber(): Promise<number>;
|
||||
getGasPrice(): Promise<BigNumber>;
|
||||
getBalance(addressOrName: string | Promise<string>, blockTag?: BlockTag | Promise<BlockTag>): Promise<BigNumber>;
|
||||
@@ -39,7 +44,7 @@ export declare class BaseProvider extends Provider {
|
||||
getStorageAt(addressOrName: string | Promise<string>, position: BigNumberish | Promise<BigNumberish>, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
sendTransaction(signedTransaction: string | Promise<string>): Promise<TransactionResponse>;
|
||||
_wrapTransaction(tx: Transaction, hash?: string): TransactionResponse;
|
||||
call(transaction: TransactionRequest): Promise<string>;
|
||||
call(transaction: TransactionRequest, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
estimateGas(transaction: TransactionRequest): Promise<BigNumber>;
|
||||
getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
||||
|
||||
@@ -150,6 +150,7 @@ var formatTransaction = {
|
||||
blockHash: allowNull(checkHash, null),
|
||||
blockNumber: allowNull(checkNumber, null),
|
||||
transactionIndex: allowNull(checkNumber, null),
|
||||
confirmations: allowNull(checkNumber, null),
|
||||
from: address_1.getAddress,
|
||||
gasPrice: bignumber_1.bigNumberify,
|
||||
gasLimit: bignumber_1.bigNumberify,
|
||||
@@ -278,6 +279,7 @@ var formatTransactionReceipt = {
|
||||
transactionHash: checkHash,
|
||||
logs: arrayOf(checkTransactionReceiptLog),
|
||||
blockNumber: checkNumber,
|
||||
confirmations: allowNull(checkNumber, null),
|
||||
cumulativeGasUsed: bignumber_1.bigNumberify,
|
||||
status: allowNull(checkNumber)
|
||||
};
|
||||
@@ -388,6 +390,11 @@ function getEventTag(eventName) {
|
||||
}
|
||||
throw new Error('invalid event - ' + eventName);
|
||||
}
|
||||
//////////////////////////////
|
||||
// Helper Object
|
||||
function getTime() {
|
||||
return (new Date()).getTime();
|
||||
}
|
||||
var BaseProvider = /** @class */ (function (_super) {
|
||||
__extends(BaseProvider, _super);
|
||||
function BaseProvider(network) {
|
||||
@@ -420,11 +427,13 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
// until we get a response. This provides devs with a consistent view. Similarly for
|
||||
// transaction hashes.
|
||||
_this._emitted = { block: _this._lastBlockNumber };
|
||||
_this._fastQueryDate = 0;
|
||||
return _this;
|
||||
}
|
||||
BaseProvider.prototype._doPoll = function () {
|
||||
var _this = this;
|
||||
this.getBlockNumber().then(function (blockNumber) {
|
||||
_this._setFastBlockNumber(blockNumber);
|
||||
// If the block hasn't changed, meh.
|
||||
if (blockNumber === _this._lastBlockNumber) {
|
||||
return;
|
||||
@@ -574,13 +583,44 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
BaseProvider.prototype._getFastBlockNumber = function () {
|
||||
var _this = this;
|
||||
var now = getTime();
|
||||
// Stale block number, request a newer value
|
||||
if ((now - this._fastQueryDate) > 2 * this._pollingInterval) {
|
||||
this._fastQueryDate = now;
|
||||
this._fastBlockNumberPromise = this.getBlockNumber().then(function (blockNumber) {
|
||||
if (_this._fastBlockNumber == null || blockNumber > _this._fastBlockNumber) {
|
||||
_this._fastBlockNumber = blockNumber;
|
||||
}
|
||||
return _this._fastBlockNumber;
|
||||
});
|
||||
}
|
||||
return this._fastBlockNumberPromise;
|
||||
};
|
||||
BaseProvider.prototype._setFastBlockNumber = function (blockNumber) {
|
||||
// Older block, maybe a stale request
|
||||
if (this._fastBlockNumber != null && blockNumber < this._fastBlockNumber) {
|
||||
return;
|
||||
}
|
||||
// Update the time we updated the blocknumber
|
||||
this._fastQueryDate = getTime();
|
||||
// Newer block number, use it
|
||||
if (this._fastBlockNumber == null || blockNumber > this._fastBlockNumber) {
|
||||
this._fastBlockNumber = blockNumber;
|
||||
this._fastBlockNumberPromise = Promise.resolve(blockNumber);
|
||||
}
|
||||
};
|
||||
// @TODO: Add .poller which must be an event emitter with a 'start', 'stop' and 'block' event;
|
||||
// this will be used once we move to the WebSocket or other alternatives to polling
|
||||
BaseProvider.prototype.waitForTransaction = function (transactionHash, timeout) {
|
||||
BaseProvider.prototype.waitForTransaction = function (transactionHash, confirmations) {
|
||||
var _this = this;
|
||||
if (!confirmations) {
|
||||
confirmations = 1;
|
||||
}
|
||||
return web_1.poll(function () {
|
||||
return _this.getTransactionReceipt(transactionHash).then(function (receipt) {
|
||||
if (receipt == null) {
|
||||
if (receipt == null || receipt.confirmations < confirmations) {
|
||||
return undefined;
|
||||
}
|
||||
return receipt;
|
||||
@@ -595,6 +635,7 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
if (value != result) {
|
||||
throw new Error('invalid response - getBlockNumber');
|
||||
}
|
||||
_this._setFastBlockNumber(value);
|
||||
return value;
|
||||
});
|
||||
});
|
||||
@@ -688,7 +729,7 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
// This should be called by any subclass wrapping a TransactionResponse
|
||||
BaseProvider.prototype._wrapTransaction = function (tx, hash) {
|
||||
var _this = this;
|
||||
if (bytes_1.hexDataLength(hash) !== 32) {
|
||||
if (hash != null && bytes_1.hexDataLength(hash) !== 32) {
|
||||
throw new Error('invalid response - sendTransaction');
|
||||
}
|
||||
var result = tx;
|
||||
@@ -698,11 +739,11 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
}
|
||||
this._emitted['t:' + tx.hash] = 'pending';
|
||||
// @TODO: (confirmations? number, timeout? number)
|
||||
result.wait = function () {
|
||||
return _this.waitForTransaction(hash).then(function (receipt) {
|
||||
result.wait = function (confirmations) {
|
||||
return _this.waitForTransaction(tx.hash, confirmations).then(function (receipt) {
|
||||
if (receipt.status === 0) {
|
||||
errors.throwError('transaction failed', errors.CALL_EXCEPTION, {
|
||||
transactionHash: hash,
|
||||
transactionHash: tx.hash,
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
@@ -711,13 +752,14 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
};
|
||||
return result;
|
||||
};
|
||||
BaseProvider.prototype.call = function (transaction) {
|
||||
BaseProvider.prototype.call = function (transaction, blockTag) {
|
||||
var _this = this;
|
||||
var tx = properties_1.shallowCopy(transaction);
|
||||
return this.ready.then(function () {
|
||||
return properties_1.resolveProperties(tx).then(function (tx) {
|
||||
return properties_1.resolveProperties({ blockTag: blockTag, tx: tx }).then(function (_a) {
|
||||
var blockTag = _a.blockTag, tx = _a.tx;
|
||||
return _this._resolveNames(tx, ['to', 'from']).then(function (tx) {
|
||||
var params = { transaction: checkTransactionRequest(tx) };
|
||||
var params = { blockTag: checkBlockTag(blockTag), transaction: checkTransactionRequest(tx) };
|
||||
return _this.perform('call', params).then(function (result) {
|
||||
return bytes_1.hexlify(result);
|
||||
});
|
||||
@@ -804,7 +846,22 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return BaseProvider.checkTransactionResponse(result);
|
||||
var tx = BaseProvider.checkTransactionResponse(result);
|
||||
if (tx.blockNumber == null) {
|
||||
tx.confirmations = 0;
|
||||
}
|
||||
else if (tx.confirmations == null) {
|
||||
return _this._getFastBlockNumber().then(function (blockNumber) {
|
||||
// Add the confirmations using the fast block number (pessimistic)
|
||||
var confirmations = (blockNumber - tx.blockNumber) + 1;
|
||||
if (confirmations <= 0) {
|
||||
confirmations = 1;
|
||||
}
|
||||
tx.confirmations = confirmations;
|
||||
return _this._wrapTransaction(tx);
|
||||
});
|
||||
}
|
||||
return _this._wrapTransaction(tx);
|
||||
});
|
||||
}, { onceBlock: _this });
|
||||
});
|
||||
@@ -824,7 +881,26 @@ var BaseProvider = /** @class */ (function (_super) {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return checkTransactionReceipt(result);
|
||||
// "geth-etc" returns receipts before they are ready
|
||||
if (result.blockHash == null) {
|
||||
return undefined;
|
||||
}
|
||||
var receipt = checkTransactionReceipt(result);
|
||||
if (receipt.blockNumber == null) {
|
||||
receipt.confirmations = 0;
|
||||
}
|
||||
else if (receipt.confirmations == null) {
|
||||
return _this._getFastBlockNumber().then(function (blockNumber) {
|
||||
// Add the confirmations using the fast block number (pessimistic)
|
||||
var confirmations = (blockNumber - receipt.blockNumber) + 1;
|
||||
if (confirmations <= 0) {
|
||||
confirmations = 1;
|
||||
}
|
||||
receipt.confirmations = confirmations;
|
||||
return receipt;
|
||||
});
|
||||
}
|
||||
return receipt;
|
||||
});
|
||||
}, { onceBlock: _this });
|
||||
});
|
||||
|
||||
@@ -112,7 +112,6 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
return _this;
|
||||
}
|
||||
EtherscanProvider.prototype.perform = function (method, params) {
|
||||
//if (!params) { params = {}; }
|
||||
var url = this.baseUrl;
|
||||
var apiKey = '';
|
||||
if (this.apiKey) {
|
||||
@@ -147,17 +146,19 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
url += '/api?module=proxy&action=eth_sendRawTransaction&hex=' + params.signedTransaction;
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult).catch(function (error) {
|
||||
// "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 21464000000000 and got: 0"
|
||||
if (error.responseText.toLowerCase().indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "Transaction with the same hash was already imported."
|
||||
if (error.responseText.indexOf('same hash was already imported') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce."
|
||||
if (error.responseText.indexOf('another transaction with same nonce') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
if (error.responseText) {
|
||||
// "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 21464000000000 and got: 0"
|
||||
if (error.responseText.toLowerCase().indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "Transaction with the same hash was already imported."
|
||||
if (error.responseText.indexOf('same hash was already imported') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce."
|
||||
if (error.responseText.indexOf('another transaction with same nonce') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -182,15 +183,20 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
url += '/api?module=proxy&action=eth_getTransactionReceipt&txhash=' + params.transactionHash;
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult);
|
||||
case 'call':
|
||||
case 'call': {
|
||||
var transaction = getTransactionString(params.transaction);
|
||||
if (transaction) {
|
||||
transaction = '&' + transaction;
|
||||
}
|
||||
url += '/api?module=proxy&action=eth_call' + transaction;
|
||||
//url += '&tag=' + params.blockTag + apiKey;
|
||||
if (params.blockTag !== 'latest') {
|
||||
throw new Error('EtherscanProvider does not support blockTag for call');
|
||||
}
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult);
|
||||
case 'estimateGas':
|
||||
}
|
||||
case 'estimateGas': {
|
||||
var transaction = getTransactionString(params.transaction);
|
||||
if (transaction) {
|
||||
transaction = '&' + transaction;
|
||||
@@ -198,6 +204,7 @@ var EtherscanProvider = /** @class */ (function (_super) {
|
||||
url += '/api?module=proxy&action=eth_estimateGas&' + transaction;
|
||||
url += apiKey;
|
||||
return web_1.fetchJson(url, null, getJsonResult);
|
||||
}
|
||||
case 'getLogs':
|
||||
url += '/api?module=logs&action=getLogs';
|
||||
try {
|
||||
|
||||
6
providers/json-rpc-provider.d.ts
vendored
6
providers/json-rpc-provider.d.ts
vendored
@@ -27,5 +27,9 @@ export declare class JsonRpcProvider extends BaseProvider {
|
||||
perform(method: string, params: any): Promise<any>;
|
||||
protected _startPending(): void;
|
||||
protected _stopPending(): void;
|
||||
static hexlifyTransaction(transaction: TransactionRequest): any;
|
||||
static hexlifyTransaction(transaction: TransactionRequest, allowExtra?: {
|
||||
[key: string]: boolean;
|
||||
}): {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -132,21 +132,23 @@ var JsonRpcSigner = /** @class */ (function (_super) {
|
||||
throw error;
|
||||
});
|
||||
}, function (error) {
|
||||
// See: JsonRpcProvider.sendTransaction (@TODO: Expose a ._throwError??)
|
||||
if (error.responseText.indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('nonce too low') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {
|
||||
transaction: tx
|
||||
});
|
||||
if (error.responseText) {
|
||||
// See: JsonRpcProvider.sendTransaction (@TODO: Expose a ._throwError??)
|
||||
if (error.responseText.indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('nonce too low') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -169,6 +171,9 @@ var JsonRpcSigner = /** @class */ (function (_super) {
|
||||
return JsonRpcSigner;
|
||||
}(abstract_signer_1.Signer));
|
||||
exports.JsonRpcSigner = JsonRpcSigner;
|
||||
var allowedTransactionKeys = {
|
||||
chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, value: true
|
||||
};
|
||||
var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
__extends(JsonRpcProvider, _super);
|
||||
function JsonRpcProvider(url, network) {
|
||||
@@ -245,17 +250,19 @@ var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
return this.send('eth_getStorageAt', [getLowerCase(params.address), params.position, params.blockTag]);
|
||||
case 'sendTransaction':
|
||||
return this.send('eth_sendRawTransaction', [params.signedTransaction]).catch(function (error) {
|
||||
// "insufficient funds for gas * price + value"
|
||||
if (error.responseText.indexOf('insufficient funds') > 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "nonce too low"
|
||||
if (error.responseText.indexOf('nonce too low') > 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "replacement transaction underpriced"
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') > 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
if (error.responseText) {
|
||||
// "insufficient funds for gas * price + value"
|
||||
if (error.responseText.indexOf('insufficient funds') > 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {});
|
||||
}
|
||||
// "nonce too low"
|
||||
if (error.responseText.indexOf('nonce too low') > 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {});
|
||||
}
|
||||
// "replacement transaction underpriced"
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') > 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -272,9 +279,9 @@ var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
case 'getTransactionReceipt':
|
||||
return this.send('eth_getTransactionReceipt', [params.transactionHash]);
|
||||
case 'call':
|
||||
return this.send('eth_call', [JsonRpcProvider.hexlifyTransaction(params.transaction), 'latest']);
|
||||
return this.send('eth_call', [JsonRpcProvider.hexlifyTransaction(params.transaction, { from: true }), params.blockTag]);
|
||||
case 'estimateGas':
|
||||
return this.send('eth_estimateGas', [JsonRpcProvider.hexlifyTransaction(params.transaction)]);
|
||||
return this.send('eth_estimateGas', [JsonRpcProvider.hexlifyTransaction(params.transaction, { from: true })]);
|
||||
case 'getLogs':
|
||||
if (params.filter && params.filter.address != null) {
|
||||
params.filter.address = getLowerCase(params.filter.address);
|
||||
@@ -332,8 +339,21 @@ var JsonRpcProvider = /** @class */ (function (_super) {
|
||||
// - gasLimit => gas
|
||||
// - All values hexlified
|
||||
// - All numeric values zero-striped
|
||||
// @TODO: Not any, a dictionary of string to strings
|
||||
JsonRpcProvider.hexlifyTransaction = function (transaction) {
|
||||
// NOTE: This allows a TransactionRequest, but all values should be resolved
|
||||
// before this is called
|
||||
JsonRpcProvider.hexlifyTransaction = function (transaction, allowExtra) {
|
||||
if (!allowExtra) {
|
||||
allowExtra = {};
|
||||
}
|
||||
for (var key in transaction) {
|
||||
if (!allowedTransactionKeys[key] && !allowExtra[key]) {
|
||||
errors.throwError('invalid key - ' + key, errors.INVALID_ARGUMENT, {
|
||||
argument: 'transaction',
|
||||
value: transaction,
|
||||
key: key
|
||||
});
|
||||
}
|
||||
}
|
||||
var result = {};
|
||||
// Some nodes (INFURA ropsten; INFURA mainnet is fine) don't like extra zeros.
|
||||
['gasLimit', 'gasPrice', 'nonce', 'value'].forEach(function (key) {
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const version = "4.0.1";
|
||||
export const version = "4.0.5";
|
||||
|
||||
@@ -16,7 +16,7 @@ import { UnsignedTransaction } from './utils/transaction';
|
||||
///////////////////////////////
|
||||
// Imported Abstracts
|
||||
|
||||
import { Provider } from './providers/abstract-provider';
|
||||
import { BlockTag, Provider } from './providers/abstract-provider';
|
||||
import { Signer } from './abstract-signer';
|
||||
|
||||
///////////////////////////////
|
||||
@@ -53,6 +53,14 @@ export interface Event extends Log {
|
||||
getTransactionReceipt: () => Promise<TransactionReceipt>;
|
||||
}
|
||||
|
||||
export interface ContractReceipt extends TransactionReceipt {
|
||||
events?: Array<Event>;
|
||||
}
|
||||
|
||||
export interface ContractTransaction extends TransactionResponse {
|
||||
wait(confirmations?: number): Promise<ContractReceipt>;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
|
||||
export class VoidSigner extends Signer {
|
||||
@@ -140,14 +148,21 @@ type RunFunction = (...params: Array<any>) => Promise<any>;
|
||||
function runMethod(contract: Contract, functionName: string, estimateOnly: boolean): RunFunction {
|
||||
let method = contract.interface.functions[functionName];
|
||||
return function(...params): Promise<any> {
|
||||
var tx: any = {}
|
||||
let tx: any = {}
|
||||
|
||||
let blockTag: BlockTag = null;
|
||||
|
||||
// If 1 extra parameter was passed in, it contains overrides
|
||||
if (params.length === method.inputs.length + 1 && typeof(params[params.length - 1]) === 'object') {
|
||||
tx = shallowCopy(params.pop());
|
||||
|
||||
if (tx.blockTag != null) {
|
||||
blockTag = tx.blockTag;
|
||||
delete tx.blockTag;
|
||||
}
|
||||
|
||||
// Check for unexpected keys (e.g. using "gas" instead of "gasLimit")
|
||||
for (var key in tx) {
|
||||
for (let key in tx) {
|
||||
if (!allowedTransactionKeys[key]) {
|
||||
throw new Error('unknown transaction override ' + key);
|
||||
}
|
||||
@@ -194,7 +209,7 @@ function runMethod(contract: Contract, functionName: string, estimateOnly: boole
|
||||
tx.from = contract.signer.getAddress()
|
||||
}
|
||||
|
||||
return contract.provider.call(tx).then((value) => {
|
||||
return contract.provider.call(tx, blockTag).then((value) => {
|
||||
|
||||
if ((hexDataLength(value) % 32) === 4 && hexDataSlice(value, 0, 4) === '0x08c379a0') {
|
||||
let reason = defaultAbiCoder.decode([ 'string' ], hexDataSlice(value, 4));
|
||||
@@ -256,7 +271,42 @@ function runMethod(contract: Contract, functionName: string, estimateOnly: boole
|
||||
errors.throwError('cannot override from in a transaction', errors.UNSUPPORTED_OPERATION, { operation: 'sendTransaction' })
|
||||
}
|
||||
|
||||
return contract.signer.sendTransaction(tx);
|
||||
return contract.signer.sendTransaction(tx).then((tx) => {
|
||||
let wait = tx.wait.bind(tx);
|
||||
|
||||
tx.wait = (confirmations?: number) => {
|
||||
return wait(confirmations).then((receipt: ContractReceipt) => {
|
||||
receipt.events = receipt.logs.map((log) => {
|
||||
let event: Event = (<Event>deepCopy(log));
|
||||
|
||||
let parsed = this.interface.parseLog(log);
|
||||
if (parsed) {
|
||||
event.args = parsed.values;
|
||||
event.decode = parsed.decode;
|
||||
event.event = parsed.name;
|
||||
event.eventSignature = parsed.signature;
|
||||
}
|
||||
|
||||
event.removeListener = () => { return this.provider; }
|
||||
event.getBlock = () => {
|
||||
return this.provider.getBlock(receipt.blockHash);
|
||||
}
|
||||
event.getTransaction = () => {
|
||||
return this.provider.getTransaction(receipt.transactionHash);
|
||||
}
|
||||
event.getTransactionReceipt = () => {
|
||||
return Promise.resolve(receipt);
|
||||
}
|
||||
|
||||
return event;
|
||||
});
|
||||
|
||||
return receipt;
|
||||
});
|
||||
};
|
||||
|
||||
return tx;
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error('invalid type - ' + method.type);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
import { version } from './_version';
|
||||
|
||||
// Unknown Error
|
||||
export const UNKNOWN_ERROR = 'UNKNOWN_ERROR';
|
||||
|
||||
@@ -69,21 +71,23 @@ export function throwError(message: string, code: string, params: any): never {
|
||||
if (!code) { code = UNKNOWN_ERROR; }
|
||||
if (!params) { params = {}; }
|
||||
|
||||
var messageDetails: Array<string> = [];
|
||||
Object.keys(params).forEach(function(key) {
|
||||
let messageDetails: Array<string> = [];
|
||||
Object.keys(params).forEach((key) => {
|
||||
try {
|
||||
messageDetails.push(key + '=' + JSON.stringify(params[key]));
|
||||
} catch (error) {
|
||||
messageDetails.push(key + '=' + JSON.stringify(params[key].toString()));
|
||||
}
|
||||
});
|
||||
var reason = message;
|
||||
messageDetails.push("version=" + version);
|
||||
|
||||
let reason = message;
|
||||
if (messageDetails.length) {
|
||||
message += ' (' + messageDetails.join(', ') + ')';
|
||||
}
|
||||
|
||||
// @TODO: Any??
|
||||
var error: any = new Error(message);
|
||||
let error: any = new Error(message);
|
||||
error.reason = reason;
|
||||
error.code = code
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import { version } from './_version';
|
||||
////////////////////////
|
||||
// Types
|
||||
|
||||
import { ContractFunction, Event, EventFilter } from './contract';
|
||||
import { ContractFunction, ContractTransaction, Event, EventFilter } from './contract';
|
||||
|
||||
|
||||
////////////////////////
|
||||
@@ -72,6 +72,7 @@ export {
|
||||
// Types
|
||||
|
||||
ContractFunction,
|
||||
ContractTransaction,
|
||||
Event,
|
||||
EventFilter
|
||||
};
|
||||
|
||||
@@ -69,6 +69,7 @@ export interface TransactionReceipt {
|
||||
transactionHash?: string,
|
||||
logs?: Array<Log>,
|
||||
blockNumber?: number,
|
||||
confirmations?: number,
|
||||
cumulativeGasUsed?: BigNumber,
|
||||
byzantium: boolean,
|
||||
status?: number
|
||||
@@ -93,6 +94,8 @@ export interface TransactionResponse extends Transaction {
|
||||
blockHash?: string,
|
||||
timestamp?: number,
|
||||
|
||||
confirmations: number,
|
||||
|
||||
// Not optional (as it is in Transaction)
|
||||
from: string;
|
||||
|
||||
@@ -100,7 +103,7 @@ export interface TransactionResponse extends Transaction {
|
||||
raw?: string,
|
||||
|
||||
// This function waits until the transaction has been mined
|
||||
wait: (timeout?: number) => Promise<TransactionReceipt>
|
||||
wait: (confirmations?: number) => Promise<TransactionReceipt>
|
||||
};
|
||||
|
||||
export type EventType = string | Array<string> | Filter;
|
||||
@@ -122,7 +125,7 @@ export abstract class Provider implements OnceBlockable {
|
||||
abstract getStorageAt(addressOrName: string | Promise<string>, position: BigNumberish | Promise<BigNumberish>, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
|
||||
abstract sendTransaction(signedTransaction: string | Promise<string>): Promise<TransactionResponse>;
|
||||
abstract call(transaction: TransactionRequest): Promise<string>;
|
||||
abstract call(transaction: TransactionRequest, blockTag?: BlockTag | Promise<BlockTag>): Promise<string>;
|
||||
abstract estimateGas(transaction: TransactionRequest): Promise<BigNumber>;
|
||||
|
||||
abstract getBlock(blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>, includeTransactions?: boolean): Promise<Block>;
|
||||
|
||||
@@ -156,6 +156,8 @@ const formatTransaction = {
|
||||
blockNumber: allowNull(checkNumber, null),
|
||||
transactionIndex: allowNull(checkNumber, null),
|
||||
|
||||
confirmations: allowNull(checkNumber, null),
|
||||
|
||||
from: getAddress,
|
||||
|
||||
gasPrice: bigNumberify,
|
||||
@@ -236,7 +238,7 @@ function checkTransactionResponse(transaction: any): TransactionResponse {
|
||||
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;
|
||||
@@ -313,6 +315,7 @@ const formatTransactionReceipt = {
|
||||
transactionHash: checkHash,
|
||||
logs: arrayOf(checkTransactionReceiptLog),
|
||||
blockNumber: checkNumber,
|
||||
confirmations: allowNull(checkNumber, null),
|
||||
cumulativeGasUsed: bigNumberify,
|
||||
status: allowNull(checkNumber)
|
||||
};
|
||||
@@ -377,6 +380,7 @@ function checkLog(log: any): any {
|
||||
return check(formatLog, log);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Event Serializeing
|
||||
|
||||
@@ -438,6 +442,13 @@ function getEventTag(eventName: EventType): string {
|
||||
throw new Error('invalid event - ' + eventName);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// Helper Object
|
||||
|
||||
function getTime() {
|
||||
return (new Date()).getTime();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// Provider Object
|
||||
|
||||
@@ -473,6 +484,10 @@ export class BaseProvider extends Provider {
|
||||
// string => BigNumber
|
||||
private _balances: any;
|
||||
|
||||
private _fastBlockNumber: number;
|
||||
private _fastBlockNumberPromise: Promise<number>;
|
||||
private _fastQueryDate: number;
|
||||
|
||||
|
||||
/**
|
||||
* ready
|
||||
@@ -521,10 +536,13 @@ export class BaseProvider extends Provider {
|
||||
// until we get a response. This provides devs with a consistent view. Similarly for
|
||||
// transaction hashes.
|
||||
this._emitted = { block: this._lastBlockNumber };
|
||||
|
||||
this._fastQueryDate = 0;
|
||||
}
|
||||
|
||||
private _doPoll(): void {
|
||||
this.getBlockNumber().then((blockNumber) => {
|
||||
this._setFastBlockNumber(blockNumber);
|
||||
|
||||
// If the block hasn't changed, meh.
|
||||
if (blockNumber === this._lastBlockNumber) { return; }
|
||||
@@ -665,13 +683,45 @@ export class BaseProvider extends Provider {
|
||||
}
|
||||
}
|
||||
|
||||
_getFastBlockNumber(): Promise<number> {
|
||||
let now = getTime();
|
||||
|
||||
// Stale block number, request a newer value
|
||||
if ((now - this._fastQueryDate) > 2 * this._pollingInterval) {
|
||||
this._fastQueryDate = now;
|
||||
this._fastBlockNumberPromise = this.getBlockNumber().then((blockNumber) => {
|
||||
if (this._fastBlockNumber == null || blockNumber > this._fastBlockNumber) {
|
||||
this._fastBlockNumber = blockNumber;
|
||||
}
|
||||
return this._fastBlockNumber;
|
||||
});
|
||||
}
|
||||
|
||||
return this._fastBlockNumberPromise;
|
||||
}
|
||||
|
||||
_setFastBlockNumber(blockNumber: number): void {
|
||||
// Older block, maybe a stale request
|
||||
if (this._fastBlockNumber != null && blockNumber < this._fastBlockNumber) { return; }
|
||||
|
||||
// Update the time we updated the blocknumber
|
||||
this._fastQueryDate = getTime();
|
||||
|
||||
// Newer block number, use it
|
||||
if (this._fastBlockNumber == null || blockNumber > this._fastBlockNumber) {
|
||||
this._fastBlockNumber = blockNumber;
|
||||
this._fastBlockNumberPromise = Promise.resolve(blockNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: Add .poller which must be an event emitter with a 'start', 'stop' and 'block' event;
|
||||
// this will be used once we move to the WebSocket or other alternatives to polling
|
||||
|
||||
waitForTransaction(transactionHash: string, timeout?: number): Promise<TransactionReceipt> {
|
||||
waitForTransaction(transactionHash: string, confirmations?: number): Promise<TransactionReceipt> {
|
||||
if (!confirmations) { confirmations = 1; }
|
||||
return poll(() => {
|
||||
return this.getTransactionReceipt(transactionHash).then((receipt) => {
|
||||
if (receipt == null) { return undefined; }
|
||||
if (receipt == null || receipt.confirmations < confirmations) { return undefined; }
|
||||
return receipt;
|
||||
});
|
||||
}, { onceBlock: this });
|
||||
@@ -680,8 +730,9 @@ export class BaseProvider extends Provider {
|
||||
getBlockNumber(): Promise<number> {
|
||||
return this.ready.then(() => {
|
||||
return this.perform('getBlockNumber', { }).then((result) => {
|
||||
var value = parseInt(result);
|
||||
let value = parseInt(result);
|
||||
if (value != result) { throw new Error('invalid response - getBlockNumber'); }
|
||||
this._setFastBlockNumber(value);
|
||||
return value;
|
||||
});
|
||||
});
|
||||
@@ -771,7 +822,7 @@ export class BaseProvider extends Provider {
|
||||
|
||||
// This should be called by any subclass wrapping a TransactionResponse
|
||||
_wrapTransaction(tx: Transaction, hash?: string): TransactionResponse {
|
||||
if (hexDataLength(hash) !== 32) { throw new Error('invalid response - sendTransaction'); }
|
||||
if (hash != null && hexDataLength(hash) !== 32) { throw new Error('invalid response - sendTransaction'); }
|
||||
|
||||
let result: TransactionResponse = <TransactionResponse>tx;
|
||||
|
||||
@@ -781,12 +832,13 @@ export class BaseProvider extends Provider {
|
||||
}
|
||||
|
||||
this._emitted['t:' + tx.hash] = 'pending';
|
||||
|
||||
// @TODO: (confirmations? number, timeout? number)
|
||||
result.wait = () => {
|
||||
return this.waitForTransaction(hash).then((receipt) => {
|
||||
result.wait = (confirmations?: number) => {
|
||||
return this.waitForTransaction(tx.hash, confirmations).then((receipt) => {
|
||||
if (receipt.status === 0) {
|
||||
errors.throwError('transaction failed', errors.CALL_EXCEPTION, {
|
||||
transactionHash: hash,
|
||||
transactionHash: tx.hash,
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
@@ -798,12 +850,12 @@ export class BaseProvider extends Provider {
|
||||
}
|
||||
|
||||
|
||||
call(transaction: TransactionRequest): Promise<string> {
|
||||
call(transaction: TransactionRequest, blockTag?: BlockTag | Promise<BlockTag>): Promise<string> {
|
||||
let tx: TransactionRequest = shallowCopy(transaction);
|
||||
return this.ready.then(() => {
|
||||
return resolveProperties(tx).then((tx) => {
|
||||
return resolveProperties({ blockTag: blockTag, tx: tx }).then(({ blockTag, tx }) => {
|
||||
return this._resolveNames(tx, [ 'to', 'from' ]).then((tx) => {
|
||||
var params = { transaction: checkTransactionRequest(tx) };
|
||||
let params = { blockTag: checkBlockTag(blockTag), transaction: checkTransactionRequest(tx) };
|
||||
return this.perform('call', params).then((result) => {
|
||||
return hexlify(result);
|
||||
});
|
||||
@@ -883,7 +935,7 @@ export class BaseProvider extends Provider {
|
||||
getTransaction(transactionHash: string): Promise<TransactionResponse> {
|
||||
return this.ready.then(() => {
|
||||
return resolveProperties({ transactionHash: transactionHash }).then(({ transactionHash }) => {
|
||||
var params = { transactionHash: checkHash(transactionHash) };
|
||||
let params = { transactionHash: checkHash(transactionHash) };
|
||||
return poll(() => {
|
||||
return this.perform('getTransaction', params).then((result) => {
|
||||
if (result == null) {
|
||||
@@ -892,7 +944,25 @@ export class BaseProvider extends Provider {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return BaseProvider.checkTransactionResponse(result);
|
||||
|
||||
let tx = BaseProvider.checkTransactionResponse(result);
|
||||
|
||||
if (tx.blockNumber == null) {
|
||||
tx.confirmations = 0;
|
||||
|
||||
} else if (tx.confirmations == null) {
|
||||
return this._getFastBlockNumber().then((blockNumber) => {
|
||||
|
||||
// Add the confirmations using the fast block number (pessimistic)
|
||||
let confirmations = (blockNumber - tx.blockNumber) + 1;
|
||||
if (confirmations <= 0) { confirmations = 1; }
|
||||
tx.confirmations = confirmations;
|
||||
|
||||
return this._wrapTransaction(tx);
|
||||
});
|
||||
}
|
||||
|
||||
return this._wrapTransaction(tx);
|
||||
});
|
||||
}, { onceBlock: this });
|
||||
});
|
||||
@@ -902,7 +972,7 @@ export class BaseProvider extends Provider {
|
||||
getTransactionReceipt(transactionHash: string): Promise<TransactionReceipt> {
|
||||
return this.ready.then(() => {
|
||||
return resolveProperties({ transactionHash: transactionHash }).then(({ transactionHash }) => {
|
||||
var params = { transactionHash: checkHash(transactionHash) };
|
||||
let params = { transactionHash: checkHash(transactionHash) };
|
||||
return poll(() => {
|
||||
return this.perform('getTransactionReceipt', params).then((result) => {
|
||||
if (result == null) {
|
||||
@@ -911,7 +981,28 @@ export class BaseProvider extends Provider {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return checkTransactionReceipt(result);
|
||||
|
||||
// "geth-etc" returns receipts before they are ready
|
||||
if (result.blockHash == null) { return undefined; }
|
||||
|
||||
let receipt = checkTransactionReceipt(result);
|
||||
|
||||
if (receipt.blockNumber == null) {
|
||||
receipt.confirmations = 0;
|
||||
|
||||
} else if (receipt.confirmations == null) {
|
||||
return this._getFastBlockNumber().then((blockNumber) => {
|
||||
|
||||
// Add the confirmations using the fast block number (pessimistic)
|
||||
let confirmations = (blockNumber - receipt.blockNumber) + 1;
|
||||
if (confirmations <= 0) { confirmations = 1; }
|
||||
receipt.confirmations = confirmations;
|
||||
|
||||
return receipt;
|
||||
});
|
||||
}
|
||||
|
||||
return receipt;
|
||||
});
|
||||
}, { onceBlock: this });
|
||||
});
|
||||
|
||||
@@ -108,9 +108,7 @@ export class EtherscanProvider extends BaseProvider{
|
||||
|
||||
|
||||
perform(method: string, params: any) {
|
||||
//if (!params) { params = {}; }
|
||||
|
||||
var url = this.baseUrl;
|
||||
let url = this.baseUrl;
|
||||
|
||||
let apiKey = '';
|
||||
if (this.apiKey) { apiKey += '&apikey=' + this.apiKey; }
|
||||
@@ -118,7 +116,7 @@ export class EtherscanProvider extends BaseProvider{
|
||||
switch (method) {
|
||||
case 'getBlockNumber':
|
||||
url += '/api?module=proxy&action=eth_blockNumber' + apiKey;
|
||||
return fetchJson(url, null, getJsonResult);
|
||||
return fetchJson(url, null, getJsonResult);
|
||||
|
||||
case 'getGasPrice':
|
||||
url += '/api?module=proxy&action=eth_gasPrice' + apiKey;
|
||||
@@ -152,17 +150,19 @@ export class EtherscanProvider extends BaseProvider{
|
||||
url += '/api?module=proxy&action=eth_sendRawTransaction&hex=' + params.signedTransaction;
|
||||
url += apiKey;
|
||||
return fetchJson(url, null, getJsonResult).catch((error) => {
|
||||
// "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 21464000000000 and got: 0"
|
||||
if (error.responseText.toLowerCase().indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, { });
|
||||
}
|
||||
// "Transaction with the same hash was already imported."
|
||||
if (error.responseText.indexOf('same hash was already imported') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, { });
|
||||
}
|
||||
// "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce."
|
||||
if (error.responseText.indexOf('another transaction with same nonce') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, { });
|
||||
if (error.responseText) {
|
||||
// "Insufficient funds. The account you tried to send transaction from does not have enough funds. Required 21464000000000 and got: 0"
|
||||
if (error.responseText.toLowerCase().indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, { });
|
||||
}
|
||||
// "Transaction with the same hash was already imported."
|
||||
if (error.responseText.indexOf('same hash was already imported') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, { });
|
||||
}
|
||||
// "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce."
|
||||
if (error.responseText.indexOf('another transaction with same nonce') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, { });
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -191,19 +191,25 @@ export class EtherscanProvider extends BaseProvider{
|
||||
return fetchJson(url, null, getJsonResult);
|
||||
|
||||
|
||||
case 'call':
|
||||
var transaction = getTransactionString(params.transaction);
|
||||
case 'call': {
|
||||
let transaction = getTransactionString(params.transaction);
|
||||
if (transaction) { transaction = '&' + transaction; }
|
||||
url += '/api?module=proxy&action=eth_call' + transaction;
|
||||
//url += '&tag=' + params.blockTag + apiKey;
|
||||
if (params.blockTag !== 'latest') {
|
||||
throw new Error('EtherscanProvider does not support blockTag for call');
|
||||
}
|
||||
url += apiKey;
|
||||
return fetchJson(url, null, getJsonResult);
|
||||
}
|
||||
|
||||
case 'estimateGas':
|
||||
var transaction = getTransactionString(params.transaction);
|
||||
case 'estimateGas': {
|
||||
let transaction = getTransactionString(params.transaction);
|
||||
if (transaction) { transaction = '&' + transaction; }
|
||||
url += '/api?module=proxy&action=eth_estimateGas&' + transaction;
|
||||
url += apiKey;
|
||||
return fetchJson(url, null, getJsonResult);
|
||||
}
|
||||
|
||||
case 'getLogs':
|
||||
url += '/api?module=logs&action=getLogs';
|
||||
@@ -225,7 +231,7 @@ export class EtherscanProvider extends BaseProvider{
|
||||
if (params.filter.topics.length > 1) {
|
||||
throw new Error('unsupported topic format');
|
||||
}
|
||||
var topic0 = params.filter.topics[0];
|
||||
let topic0 = params.filter.topics[0];
|
||||
if (typeof(topic0) !== 'string' || topic0.length !== 66) {
|
||||
throw new Error('unsupported topic0 format');
|
||||
}
|
||||
|
||||
@@ -135,21 +135,23 @@ export class JsonRpcSigner extends Signer {
|
||||
throw error;
|
||||
});
|
||||
}, (error) => {
|
||||
// See: JsonRpcProvider.sendTransaction (@TODO: Expose a ._throwError??)
|
||||
if (error.responseText.indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('nonce too low') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {
|
||||
transaction: tx
|
||||
});
|
||||
if (error.responseText) {
|
||||
// See: JsonRpcProvider.sendTransaction (@TODO: Expose a ._throwError??)
|
||||
if (error.responseText.indexOf('insufficient funds') >= 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('nonce too low') >= 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') >= 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, {
|
||||
transaction: tx
|
||||
});
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -174,6 +176,10 @@ export class JsonRpcSigner extends Signer {
|
||||
}
|
||||
}
|
||||
|
||||
const allowedTransactionKeys: { [ key: string ]: boolean } = {
|
||||
chainId: true, data: true, gasLimit: true, gasPrice:true, nonce: true, to: true, value: true
|
||||
}
|
||||
|
||||
export class JsonRpcProvider extends BaseProvider {
|
||||
readonly connection: ConnectionInfo;
|
||||
|
||||
@@ -266,17 +272,19 @@ export class JsonRpcProvider extends BaseProvider {
|
||||
|
||||
case 'sendTransaction':
|
||||
return this.send('eth_sendRawTransaction', [ params.signedTransaction ]).catch((error) => {
|
||||
// "insufficient funds for gas * price + value"
|
||||
if (error.responseText.indexOf('insufficient funds') > 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, { });
|
||||
}
|
||||
// "nonce too low"
|
||||
if (error.responseText.indexOf('nonce too low') > 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, { });
|
||||
}
|
||||
// "replacement transaction underpriced"
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') > 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, { });
|
||||
if (error.responseText) {
|
||||
// "insufficient funds for gas * price + value"
|
||||
if (error.responseText.indexOf('insufficient funds') > 0) {
|
||||
errors.throwError('insufficient funds', errors.INSUFFICIENT_FUNDS, { });
|
||||
}
|
||||
// "nonce too low"
|
||||
if (error.responseText.indexOf('nonce too low') > 0) {
|
||||
errors.throwError('nonce has already been used', errors.NONCE_EXPIRED, { });
|
||||
}
|
||||
// "replacement transaction underpriced"
|
||||
if (error.responseText.indexOf('replacement transaction underpriced') > 0) {
|
||||
errors.throwError('replacement fee too low', errors.REPLACEMENT_UNDERPRICED, { });
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
@@ -296,10 +304,10 @@ export class JsonRpcProvider extends BaseProvider {
|
||||
return this.send('eth_getTransactionReceipt', [ params.transactionHash ]);
|
||||
|
||||
case 'call':
|
||||
return this.send('eth_call', [ JsonRpcProvider.hexlifyTransaction(params.transaction), 'latest' ]);
|
||||
return this.send('eth_call', [ JsonRpcProvider.hexlifyTransaction(params.transaction, { from: true }), params.blockTag ]);
|
||||
|
||||
case 'estimateGas':
|
||||
return this.send('eth_estimateGas', [ JsonRpcProvider.hexlifyTransaction(params.transaction) ]);
|
||||
return this.send('eth_estimateGas', [ JsonRpcProvider.hexlifyTransaction(params.transaction, { from: true }) ]);
|
||||
|
||||
case 'getLogs':
|
||||
if (params.filter && params.filter.address != null) {
|
||||
@@ -365,9 +373,22 @@ export class JsonRpcProvider extends BaseProvider {
|
||||
// - gasLimit => gas
|
||||
// - All values hexlified
|
||||
// - All numeric values zero-striped
|
||||
// @TODO: Not any, a dictionary of string to strings
|
||||
static hexlifyTransaction(transaction: TransactionRequest): any {
|
||||
var result: any = {};
|
||||
// NOTE: This allows a TransactionRequest, but all values should be resolved
|
||||
// before this is called
|
||||
static hexlifyTransaction(transaction: TransactionRequest, allowExtra?: { [key: string]: boolean }): { [key: string]: string } {
|
||||
if (!allowExtra) { allowExtra = {}; }
|
||||
|
||||
for (let key in transaction) {
|
||||
if (!allowedTransactionKeys[key] && !allowExtra[key]) {
|
||||
errors.throwError('invalid key - ' + key, errors.INVALID_ARGUMENT, {
|
||||
argument: 'transaction',
|
||||
value: transaction,
|
||||
key: key
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let result: { [key: string]: string } = {};
|
||||
|
||||
// Some nodes (INFURA ropsten; INFURA mainnet is fine) don't like extra zeros.
|
||||
['gasLimit', 'gasPrice', 'nonce', 'value'].forEach(function(key) {
|
||||
@@ -380,7 +401,7 @@ export class JsonRpcProvider extends BaseProvider {
|
||||
['from', 'to', 'data'].forEach(function(key) {
|
||||
if ((<any>transaction)[key] == null) { return; }
|
||||
result[key] = hexlify((<any>transaction)[key]);
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { toUtf8Bytes, UnicodeNormalizationForm } from './utf8';
|
||||
import { pbkdf2 } from './pbkdf2';
|
||||
import { computeHmac, SupportedAlgorithms } from './hmac';
|
||||
import { defineReadOnly, isType, setType } from './properties';
|
||||
import { KeyPair } from './secp256k1';
|
||||
import { computeAddress, KeyPair } from './secp256k1';
|
||||
import { sha256 } from './sha2';
|
||||
|
||||
const N = bigNumberify("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
|
||||
@@ -54,6 +54,8 @@ export class HDNode {
|
||||
readonly privateKey: string;
|
||||
readonly publicKey: string;
|
||||
|
||||
readonly address: string;
|
||||
|
||||
readonly mnemonic: string;
|
||||
readonly path: string;
|
||||
|
||||
@@ -81,6 +83,8 @@ export class HDNode {
|
||||
defineReadOnly(this, 'privateKey', this.keyPair.privateKey);
|
||||
defineReadOnly(this, 'publicKey', this.keyPair.compressedPublicKey);
|
||||
|
||||
defineReadOnly(this, 'address', computeAddress(this.publicKey));
|
||||
|
||||
defineReadOnly(this, 'chainCode', hexlify(chainCode));
|
||||
|
||||
defineReadOnly(this, 'index', index);
|
||||
|
||||
@@ -182,19 +182,21 @@ class _EventDescription extends Description implements EventDescription {
|
||||
|
||||
let topics: Array<string> = [];
|
||||
if (!this.anonymous) { topics.push(this.topic); }
|
||||
|
||||
params.forEach((arg, index) => {
|
||||
if (arg === null) {
|
||||
topics.push(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let param = this.inputs[index];
|
||||
|
||||
if (!param.indexed) {
|
||||
errors.throwError('cannot filter non-indexed parameters; must be null', errors.INVALID_ARGUMENT, { argument: (param.name || index), value: arg });
|
||||
if (arg != null) {
|
||||
errors.throwError('cannot filter non-indexed parameters; must be null', errors.INVALID_ARGUMENT, { argument: (param.name || index), value: arg });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (param.type === 'string') {
|
||||
if (arg == null) {
|
||||
topics.push(null);
|
||||
} else if (param.type === 'string') {
|
||||
topics.push(id(arg));
|
||||
} else if (param.type === 'bytes') {
|
||||
topics.push(keccak256(arg));
|
||||
|
||||
@@ -118,6 +118,9 @@ export function fetchJson(connection: string | ConnectionInfo, json: string, pro
|
||||
// @TODO: not any!
|
||||
let error: any = new Error('invalid response - ' + request.status);
|
||||
error.statusCode = request.status;
|
||||
if (request.responseText) {
|
||||
error.responseText = request.responseText;
|
||||
}
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ import { BlockTag, TransactionRequest, TransactionResponse } from './providers/a
|
||||
|
||||
import * as errors from './errors';
|
||||
|
||||
const allowedTransactionKeys: { [ key: string ]: boolean } = {
|
||||
chainId: true, data: true, gasLimit: true, gasPrice:true, nonce: true, to: true, value: true
|
||||
}
|
||||
|
||||
export class Wallet extends AbstractSigner {
|
||||
|
||||
@@ -69,6 +72,15 @@ export class Wallet extends AbstractSigner {
|
||||
}
|
||||
|
||||
sign(transaction: TransactionRequest): Promise<string> {
|
||||
for (let key in transaction) {
|
||||
if (!allowedTransactionKeys[key]) {
|
||||
errors.throwError('unsupported transaction property - ' + key, errors.INVALID_ARGUMENT, {
|
||||
argument: 'transaction',
|
||||
value: transaction,
|
||||
key: key
|
||||
});
|
||||
}
|
||||
}
|
||||
return resolveProperties(transaction).then((tx) => {
|
||||
let rawTx = serializeTransaction(tx);
|
||||
let signature = this.signingKey.signDigest(keccak256(rawTx));
|
||||
@@ -98,17 +110,12 @@ export class Wallet extends AbstractSigner {
|
||||
throw new Error('invalid transaction object');
|
||||
}
|
||||
|
||||
var tx = shallowCopy(transaction);
|
||||
let tx = shallowCopy(transaction);
|
||||
|
||||
if (tx.to != null) {
|
||||
tx.to = this.provider.resolveName(tx.to);
|
||||
}
|
||||
|
||||
if (tx.gasLimit == null) {
|
||||
tx.from = this.getAddress();
|
||||
tx.gasLimit = this.provider.estimateGas(tx);
|
||||
}
|
||||
|
||||
if (tx.gasPrice == null) {
|
||||
tx.gasPrice = this.provider.getGasPrice();
|
||||
}
|
||||
@@ -117,6 +124,12 @@ export class Wallet extends AbstractSigner {
|
||||
tx.nonce = this.getTransactionCount();
|
||||
}
|
||||
|
||||
if (tx.gasLimit == null) {
|
||||
let estimate = shallowCopy(tx);
|
||||
estimate.from = this.getAddress();
|
||||
tx.gasLimit = this.provider.estimateGas(estimate);
|
||||
}
|
||||
|
||||
if (tx.chainId == null) {
|
||||
tx.chainId = this.provider.getNetwork().then((network) => network.chainId);
|
||||
}
|
||||
@@ -165,7 +178,7 @@ export class Wallet extends AbstractSigner {
|
||||
return Wallet.fromMnemonic(mnemonic, options.path, options.locale);
|
||||
}
|
||||
|
||||
static fromEncryptedJson(json: string, password: Arrayish, progressCallback: ProgressCallback): Promise<Wallet> {
|
||||
static fromEncryptedJson(json: string, password: Arrayish, progressCallback?: ProgressCallback): Promise<Wallet> {
|
||||
if (isCrowdsaleWallet(json)) {
|
||||
try {
|
||||
if (progressCallback) { progressCallback(0); }
|
||||
|
||||
@@ -9,19 +9,14 @@ let lookup: { [word: string]: number } = {};
|
||||
let wordlist: Array<string> = null;
|
||||
|
||||
function dropDiacritic(word: string): string {
|
||||
let output: Array<number> = [];
|
||||
toUtf8Bytes(word.normalize('NFD').toLowerCase()).forEach((c) => {
|
||||
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 123)) {
|
||||
output.push(c);
|
||||
}
|
||||
});
|
||||
return toUtf8String(output);
|
||||
return toUtf8String(Array.prototype.filter.call(toUtf8Bytes(word.normalize('NFD').toLowerCase()), (c: number) => {
|
||||
return ((c >= 65 && c <= 90) || (c >= 97 && c <= 123));
|
||||
}));
|
||||
}
|
||||
|
||||
function expand(word: string): string {
|
||||
let output: Array<number> = [];
|
||||
|
||||
toUtf8Bytes(word).forEach((c) => {
|
||||
Array.prototype.forEach.call(toUtf8Bytes(word), (c: number) => {
|
||||
// Acute accent
|
||||
if (c === 47) {
|
||||
output.push(204);
|
||||
|
||||
@@ -9,19 +9,15 @@ let wordlist: Array<string> = null;
|
||||
let lookup: { [word: string]: number } = { }
|
||||
|
||||
function dropDiacritic(word: string): string {
|
||||
let output: Array<number> = [];
|
||||
toUtf8Bytes(word.normalize('NFD').toLowerCase()).forEach((c) => {
|
||||
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 123)) {
|
||||
output.push(c);
|
||||
}
|
||||
});
|
||||
return toUtf8String(output);
|
||||
return toUtf8String(Array.prototype.filter.call(toUtf8Bytes(word.normalize('NFD').toLowerCase()), (c: number) => {
|
||||
return ((c >= 65 && c <= 90) || (c >= 97 && c <= 123));
|
||||
}));
|
||||
}
|
||||
|
||||
function expand(word: string): string {
|
||||
let output: Array<number> = [];
|
||||
|
||||
toUtf8Bytes(word).forEach((c) => {
|
||||
Array.prototype.forEach.call(toUtf8Bytes(word), (c: number) => {
|
||||
// Acute accent
|
||||
if (c === 47) {
|
||||
output.push(204);
|
||||
|
||||
@@ -9,6 +9,7 @@ var ethers = utils.getEthers(__filename);
|
||||
describe("Package Version", function() {
|
||||
var url = "http://registry.npmjs.org/ethers"
|
||||
it("is not already published", function() {
|
||||
this.timeout(20000);
|
||||
return ethers.utils.fetchJson(url).then(function(data) {
|
||||
assert.ok(Object.keys(data.versions).indexOf(ethers.version) === -1);
|
||||
});
|
||||
|
||||
@@ -22,6 +22,8 @@ describe('Test HD Node Derivation', function(test) {
|
||||
var wallet = new ethers.Wallet(node.privateKey);
|
||||
assert.equal(wallet.address.toLowerCase(), nodeTest.address,
|
||||
'Generates address - ' + nodeTest.privateKey);
|
||||
|
||||
assert.equal(node.address, (new ethers.Wallet(node)).address, 'HDNode address matches - ' + nodeTest.privateKey);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -64,6 +66,8 @@ function testEasySeed(lang, locale) {
|
||||
}
|
||||
|
||||
testEasySeed(ethers.wordlists.en, 'en');
|
||||
testEasySeed(ethers.wordlists.es, 'es');
|
||||
testEasySeed(ethers.wordlists.fr, 'fr');
|
||||
testEasySeed(ethers.wordlists.ja, 'ja');
|
||||
testEasySeed(ethers.wordlists.zh_cn, 'zh_cn');
|
||||
testEasySeed(ethers.wordlists.zh_tw, 'zh_tw');
|
||||
|
||||
@@ -302,6 +302,11 @@ function testProvider(providerName, networkName) {
|
||||
function testTransactionReceipt(expected) {
|
||||
var title = ('Receipt ' + expected.transactionHash.substring(0, 10) + ' - ');
|
||||
return provider.getTransactionReceipt(expected.transactionHash).then(function(receipt) {
|
||||
|
||||
// This changes with every block
|
||||
assert.equal(typeof(receipt.confirmations), 'number', 'confirmations is a number');
|
||||
delete receipt.confirmations;
|
||||
|
||||
for (var key in receipt) {
|
||||
equals((title + key), receipt[key], expected[key]);
|
||||
}
|
||||
@@ -326,6 +331,14 @@ function testProvider(providerName, networkName) {
|
||||
function testTransaction(expected) {
|
||||
var title = ('Transaction ' + expected.hash.substring(0, 10) + ' - ');
|
||||
return provider.getTransaction(expected.hash).then(function(tx) {
|
||||
|
||||
// This changes with every block
|
||||
assert.equal(typeof(tx.confirmations), 'number', 'confirmations is a number');
|
||||
delete tx.confirmations;
|
||||
|
||||
assert.equal(typeof(tx.wait), 'function', 'wait is a function');
|
||||
delete tx.wait
|
||||
|
||||
for (var key in tx) {
|
||||
equals((title + key), tx[key], expected[key]);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
|
||||
<!-- Load the browser dist ethers package -->
|
||||
<script type="text/javascript" src="../dist/ethers.min.js"></script>
|
||||
<script type="text/javascript" src="../dist/wordlist-es.js"></script>
|
||||
<script type="text/javascript" src="../dist/wordlist-fr.js"></script>
|
||||
<script type="text/javascript" src="../dist/wordlist-it.js"></script>
|
||||
<script type="text/javascript" src="../dist/wordlist-ja.js"></script>
|
||||
<script type="text/javascript" src="../dist/wordlist-ko.js"></script>
|
||||
|
||||
@@ -89,6 +89,9 @@ var BigNumber = /** @class */ (function () {
|
||||
else if (value.toHexString) {
|
||||
properties_1.defineReadOnly(this, '_hex', toHex(toBN(value.toHexString())));
|
||||
}
|
||||
else if (value._hex && bytes_1.isHexString(value._hex)) {
|
||||
properties_1.defineReadOnly(this, '_hex', value._hex);
|
||||
}
|
||||
else if (bytes_1.isArrayish(value)) {
|
||||
properties_1.defineReadOnly(this, '_hex', toHex(new bn_js_1.default.BN(bytes_1.hexlify(value).substring(2), 16)));
|
||||
}
|
||||
|
||||
1
utils/hdnode.d.ts
vendored
1
utils/hdnode.d.ts
vendored
@@ -5,6 +5,7 @@ export declare class HDNode {
|
||||
private readonly keyPair;
|
||||
readonly privateKey: string;
|
||||
readonly publicKey: string;
|
||||
readonly address: string;
|
||||
readonly mnemonic: string;
|
||||
readonly path: string;
|
||||
readonly chainCode: string;
|
||||
|
||||
@@ -54,6 +54,7 @@ var HDNode = /** @class */ (function () {
|
||||
properties_1.defineReadOnly(this, 'keyPair', new secp256k1_1.KeyPair(privateKey));
|
||||
properties_1.defineReadOnly(this, 'privateKey', this.keyPair.privateKey);
|
||||
properties_1.defineReadOnly(this, 'publicKey', this.keyPair.compressedPublicKey);
|
||||
properties_1.defineReadOnly(this, 'address', secp256k1_1.computeAddress(this.publicKey));
|
||||
properties_1.defineReadOnly(this, 'chainCode', bytes_1.hexlify(chainCode));
|
||||
properties_1.defineReadOnly(this, 'index', index);
|
||||
properties_1.defineReadOnly(this, 'depth', depth);
|
||||
|
||||
@@ -82,6 +82,9 @@ function fetchJson(connection, json, processFunc) {
|
||||
// @TODO: not any!
|
||||
var error = new Error('invalid response - ' + request.status);
|
||||
error.statusCode = request.status;
|
||||
if (request.responseText) {
|
||||
error.responseText = request.responseText;
|
||||
}
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
2
wallet.d.ts
vendored
2
wallet.d.ts
vendored
@@ -30,6 +30,6 @@ export declare class Wallet extends AbstractSigner {
|
||||
* Static methods to create Wallet instances.
|
||||
*/
|
||||
static createRandom(options?: any): Wallet;
|
||||
static fromEncryptedJson(json: string, password: Arrayish, progressCallback: ProgressCallback): Promise<Wallet>;
|
||||
static fromEncryptedJson(json: string, password: Arrayish, progressCallback?: ProgressCallback): Promise<Wallet>;
|
||||
static fromMnemonic(mnemonic: string, path?: string, wordlist?: Wordlist): Wallet;
|
||||
}
|
||||
|
||||
21
wallet.js
21
wallet.js
@@ -31,6 +31,9 @@ var transaction_1 = require("./utils/transaction");
|
||||
var abstract_signer_1 = require("./abstract-signer");
|
||||
var abstract_provider_1 = require("./providers/abstract-provider");
|
||||
var errors = __importStar(require("./errors"));
|
||||
var allowedTransactionKeys = {
|
||||
chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, value: true
|
||||
};
|
||||
var Wallet = /** @class */ (function (_super) {
|
||||
__extends(Wallet, _super);
|
||||
function Wallet(privateKey, provider) {
|
||||
@@ -80,6 +83,15 @@ var Wallet = /** @class */ (function (_super) {
|
||||
};
|
||||
Wallet.prototype.sign = function (transaction) {
|
||||
var _this = this;
|
||||
for (var key in transaction) {
|
||||
if (!allowedTransactionKeys[key]) {
|
||||
errors.throwError('unsupported transaction property - ' + key, errors.INVALID_ARGUMENT, {
|
||||
argument: 'transaction',
|
||||
value: transaction,
|
||||
key: key
|
||||
});
|
||||
}
|
||||
}
|
||||
return properties_1.resolveProperties(transaction).then(function (tx) {
|
||||
var rawTx = transaction_1.serialize(tx);
|
||||
var signature = _this.signingKey.signDigest(keccak256_1.keccak256(rawTx));
|
||||
@@ -112,16 +124,17 @@ var Wallet = /** @class */ (function (_super) {
|
||||
if (tx.to != null) {
|
||||
tx.to = this.provider.resolveName(tx.to);
|
||||
}
|
||||
if (tx.gasLimit == null) {
|
||||
tx.from = this.getAddress();
|
||||
tx.gasLimit = this.provider.estimateGas(tx);
|
||||
}
|
||||
if (tx.gasPrice == null) {
|
||||
tx.gasPrice = this.provider.getGasPrice();
|
||||
}
|
||||
if (tx.nonce == null) {
|
||||
tx.nonce = this.getTransactionCount();
|
||||
}
|
||||
if (tx.gasLimit == null) {
|
||||
var estimate = properties_1.shallowCopy(tx);
|
||||
estimate.from = this.getAddress();
|
||||
tx.gasLimit = this.provider.estimateGas(estimate);
|
||||
}
|
||||
if (tx.chainId == null) {
|
||||
tx.chainId = this.provider.getNetwork().then(function (network) { return network.chainId; });
|
||||
}
|
||||
|
||||
@@ -16,17 +16,13 @@ var words = "A/bacoAbdomenAbejaAbiertoAbogadoAbonoAbortoAbrazoAbrirAbueloAbusoAc
|
||||
var lookup = {};
|
||||
var wordlist = null;
|
||||
function dropDiacritic(word) {
|
||||
var output = [];
|
||||
utf8_1.toUtf8Bytes(word.normalize('NFD').toLowerCase()).forEach(function (c) {
|
||||
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 123)) {
|
||||
output.push(c);
|
||||
}
|
||||
});
|
||||
return utf8_1.toUtf8String(output);
|
||||
return utf8_1.toUtf8String(Array.prototype.filter.call(utf8_1.toUtf8Bytes(word.normalize('NFD').toLowerCase()), function (c) {
|
||||
return ((c >= 65 && c <= 90) || (c >= 97 && c <= 123));
|
||||
}));
|
||||
}
|
||||
function expand(word) {
|
||||
var output = [];
|
||||
utf8_1.toUtf8Bytes(word).forEach(function (c) {
|
||||
Array.prototype.forEach.call(utf8_1.toUtf8Bytes(word), function (c) {
|
||||
// Acute accent
|
||||
if (c === 47) {
|
||||
output.push(204);
|
||||
|
||||
@@ -16,17 +16,13 @@ var words = "AbaisserAbandonAbdiquerAbeilleAbolirAborderAboutirAboyerAbrasifAbre
|
||||
var wordlist = null;
|
||||
var lookup = {};
|
||||
function dropDiacritic(word) {
|
||||
var output = [];
|
||||
utf8_1.toUtf8Bytes(word.normalize('NFD').toLowerCase()).forEach(function (c) {
|
||||
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 123)) {
|
||||
output.push(c);
|
||||
}
|
||||
});
|
||||
return utf8_1.toUtf8String(output);
|
||||
return utf8_1.toUtf8String(Array.prototype.filter.call(utf8_1.toUtf8Bytes(word.normalize('NFD').toLowerCase()), function (c) {
|
||||
return ((c >= 65 && c <= 90) || (c >= 97 && c <= 123));
|
||||
}));
|
||||
}
|
||||
function expand(word) {
|
||||
var output = [];
|
||||
utf8_1.toUtf8Bytes(word).forEach(function (c) {
|
||||
Array.prototype.forEach.call(utf8_1.toUtf8Bytes(word), function (c) {
|
||||
// Acute accent
|
||||
if (c === 47) {
|
||||
output.push(204);
|
||||
|
||||
Reference in New Issue
Block a user