Added initial support for EIP838, revert codes (#188).

This commit is contained in:
Richard Moore 2018-06-23 01:33:51 -04:00
parent cf16b0ffa9
commit 7949444612
No known key found for this signature in database
GPG Key ID: 525F70A6FCABC295
11 changed files with 97 additions and 43 deletions

View File

@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
var interface_1 = require("./interface"); var interface_1 = require("./interface");
var provider_1 = require("../providers/provider"); var provider_1 = require("../providers/provider");
var wallet_1 = require("../wallet/wallet"); var wallet_1 = require("../wallet/wallet");
var abi_coder_1 = require("../utils/abi-coder");
var address_1 = require("../utils/address"); var address_1 = require("../utils/address");
var bytes_1 = require("../utils/bytes"); var bytes_1 = require("../utils/bytes");
var bignumber_1 = require("../utils/bignumber"); var bignumber_1 = require("../utils/bignumber");
@ -93,6 +94,17 @@ function runMethod(contract, functionName, estimateOnly) {
tx.from = contract.signer.getAddress(); tx.from = contract.signer.getAddress();
} }
return contract.provider.call(tx).then(function (value) { return contract.provider.call(tx).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, {
address: contract.address,
method: method.signature,
args: params,
errorSignature: 'Error(string)',
errorArgs: [reason],
reason: reason
});
}
try { try {
var result = method.decode(value); var result = method.decode(value);
if (method.outputs.length === 1) { if (method.outputs.length === 1) {
@ -105,7 +117,7 @@ function runMethod(contract, functionName, estimateOnly) {
errors.throwError('call exception', errors.CALL_EXCEPTION, { errors.throwError('call exception', errors.CALL_EXCEPTION, {
address: contract.address, address: contract.address,
method: method.signature, method: method.signature,
value: params args: params
}); });
} }
throw error; throw error;

File diff suppressed because one or more lines are too long

44
dist/ethers.js vendored
View File

@ -9039,6 +9039,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
var interface_1 = require("./interface"); var interface_1 = require("./interface");
var provider_1 = require("../providers/provider"); var provider_1 = require("../providers/provider");
var wallet_1 = require("../wallet/wallet"); var wallet_1 = require("../wallet/wallet");
var abi_coder_1 = require("../utils/abi-coder");
var address_1 = require("../utils/address"); var address_1 = require("../utils/address");
var bytes_1 = require("../utils/bytes"); var bytes_1 = require("../utils/bytes");
var bignumber_1 = require("../utils/bignumber"); var bignumber_1 = require("../utils/bignumber");
@ -9122,6 +9123,17 @@ function runMethod(contract, functionName, estimateOnly) {
tx.from = contract.signer.getAddress(); tx.from = contract.signer.getAddress();
} }
return contract.provider.call(tx).then(function (value) { return contract.provider.call(tx).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, {
address: contract.address,
method: method.signature,
args: params,
errorSignature: 'Error(string)',
errorArgs: [reason],
reason: reason
});
}
try { try {
var result = method.decode(value); var result = method.decode(value);
if (method.outputs.length === 1) { if (method.outputs.length === 1) {
@ -9134,7 +9146,7 @@ function runMethod(contract, functionName, estimateOnly) {
errors.throwError('call exception', errors.CALL_EXCEPTION, { errors.throwError('call exception', errors.CALL_EXCEPTION, {
address: contract.address, address: contract.address,
method: method.signature, method: method.signature,
value: params args: params
}); });
} }
throw error; throw error;
@ -9339,7 +9351,7 @@ var Contract = /** @class */ (function () {
}()); }());
exports.Contract = Contract; exports.Contract = Contract;
},{"../providers/provider":57,"../utils/address":60,"../utils/bignumber":61,"../utils/bytes":62,"../utils/errors":63,"../utils/properties":67,"../wallet/wallet":80,"./interface":50}],49:[function(require,module,exports){ },{"../providers/provider":57,"../utils/abi-coder":59,"../utils/address":60,"../utils/bignumber":61,"../utils/bytes":62,"../utils/errors":63,"../utils/properties":67,"../wallet/wallet":80,"./interface":50}],49:[function(require,module,exports){
'use strict'; 'use strict';
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
var contract_1 = require("./contract"); var contract_1 = require("./contract");
@ -11362,11 +11374,7 @@ var Provider = /** @class */ (function () {
return _this.resolveName(addressOrName).then(function (address) { return _this.resolveName(addressOrName).then(function (address) {
var params = { address: address, blockTag: checkBlockTag(blockTag) }; var params = { address: address, blockTag: checkBlockTag(blockTag) };
return _this.perform('getTransactionCount', params).then(function (result) { return _this.perform('getTransactionCount', params).then(function (result) {
var value = parseInt(result); return bignumber_1.bigNumberify(result).toNumber();
if (value != result) {
throw new Error('invalid response - getTransactionCount');
}
return value;
}); });
}); });
}); });
@ -11431,10 +11439,11 @@ var Provider = /** @class */ (function () {
}; };
Provider.prototype.call = function (transaction) { Provider.prototype.call = function (transaction) {
var _this = this; var _this = this;
var tx = properties_1.shallowCopy(transaction);
return this.ready.then(function () { return this.ready.then(function () {
return properties_1.resolveProperties(transaction).then(function (transaction) { return properties_1.resolveProperties(tx).then(function (tx) {
return _this._resolveNames(transaction, ['to', 'from']).then(function (transaction) { return _this._resolveNames(tx, ['to', 'from']).then(function (tx) {
var params = { transaction: checkTransactionRequest(transaction) }; var params = { transaction: checkTransactionRequest(tx) };
return _this.perform('call', params).then(function (result) { return _this.perform('call', params).then(function (result) {
return bytes_1.hexlify(result); return bytes_1.hexlify(result);
}); });
@ -11444,10 +11453,15 @@ var Provider = /** @class */ (function () {
}; };
Provider.prototype.estimateGas = function (transaction) { Provider.prototype.estimateGas = function (transaction) {
var _this = this; var _this = this;
var tx = {
to: transaction.to,
from: transaction.from,
data: transaction.data
};
return this.ready.then(function () { return this.ready.then(function () {
return properties_1.resolveProperties(transaction).then(function (transaction) { return properties_1.resolveProperties(tx).then(function (tx) {
return _this._resolveNames(transaction, ['to', 'from']).then(function (transaction) { return _this._resolveNames(tx, ['to', 'from']).then(function (tx) {
var params = { transaction: checkTransactionRequest(transaction) }; var params = { transaction: checkTransactionRequest(tx) };
return _this.perform('estimateGas', params).then(function (result) { return _this.perform('estimateGas', params).then(function (result) {
return bignumber_1.bigNumberify(result); return bignumber_1.bigNumberify(result);
}); });
@ -13515,7 +13529,9 @@ function resolveProperties(object) {
Object.keys(object).forEach(function (key) { Object.keys(object).forEach(function (key) {
var value = object[key]; var value = object[key];
if (value instanceof Promise) { if (value instanceof Promise) {
promises.push(value.then(function (value) { result[key] = value; })); promises.push(value.then(function (value) {
result[key] = value;
}));
} }
else { else {
result[key] = value; result[key] = value;

2
dist/ethers.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -714,11 +714,7 @@ var Provider = /** @class */ (function () {
return _this.resolveName(addressOrName).then(function (address) { return _this.resolveName(addressOrName).then(function (address) {
var params = { address: address, blockTag: checkBlockTag(blockTag) }; var params = { address: address, blockTag: checkBlockTag(blockTag) };
return _this.perform('getTransactionCount', params).then(function (result) { return _this.perform('getTransactionCount', params).then(function (result) {
var value = parseInt(result); return bignumber_1.bigNumberify(result).toNumber();
if (value != result) {
throw new Error('invalid response - getTransactionCount');
}
return value;
}); });
}); });
}); });
@ -783,10 +779,11 @@ var Provider = /** @class */ (function () {
}; };
Provider.prototype.call = function (transaction) { Provider.prototype.call = function (transaction) {
var _this = this; var _this = this;
var tx = properties_1.shallowCopy(transaction);
return this.ready.then(function () { return this.ready.then(function () {
return properties_1.resolveProperties(transaction).then(function (transaction) { return properties_1.resolveProperties(tx).then(function (tx) {
return _this._resolveNames(transaction, ['to', 'from']).then(function (transaction) { return _this._resolveNames(tx, ['to', 'from']).then(function (tx) {
var params = { transaction: checkTransactionRequest(transaction) }; var params = { transaction: checkTransactionRequest(tx) };
return _this.perform('call', params).then(function (result) { return _this.perform('call', params).then(function (result) {
return bytes_1.hexlify(result); return bytes_1.hexlify(result);
}); });
@ -796,10 +793,15 @@ var Provider = /** @class */ (function () {
}; };
Provider.prototype.estimateGas = function (transaction) { Provider.prototype.estimateGas = function (transaction) {
var _this = this; var _this = this;
var tx = {
to: transaction.to,
from: transaction.from,
data: transaction.data
};
return this.ready.then(function () { return this.ready.then(function () {
return properties_1.resolveProperties(transaction).then(function (transaction) { return properties_1.resolveProperties(tx).then(function (tx) {
return _this._resolveNames(transaction, ['to', 'from']).then(function (transaction) { return _this._resolveNames(tx, ['to', 'from']).then(function (tx) {
var params = { transaction: checkTransactionRequest(transaction) }; var params = { transaction: checkTransactionRequest(tx) };
return _this.perform('estimateGas', params).then(function (result) { return _this.perform('estimateGas', params).then(function (result) {
return bignumber_1.bigNumberify(result); return bignumber_1.bigNumberify(result);
}); });

View File

@ -5,8 +5,9 @@ import { EventDescription, Interface } from './interface';
import { Provider, TransactionRequest, TransactionResponse } from '../providers/provider'; import { Provider, TransactionRequest, TransactionResponse } from '../providers/provider';
import { Signer } from '../wallet/wallet'; import { Signer } from '../wallet/wallet';
import { defaultAbiCoder } from '../utils/abi-coder';
import { getContractAddress } from '../utils/address'; import { getContractAddress } from '../utils/address';
import { isHexString } from '../utils/bytes'; import { hexDataLength, hexDataSlice, isHexString } from '../utils/bytes';
import { ParamType } from '../utils/abi-coder'; import { ParamType } from '../utils/abi-coder';
import { BigNumber, ConstantZero } from '../utils/bignumber'; import { BigNumber, ConstantZero } from '../utils/bignumber';
import { defineReadOnly, shallowCopy } from '../utils/properties'; import { defineReadOnly, shallowCopy } from '../utils/properties';
@ -105,6 +106,19 @@ function runMethod(contract: Contract, functionName: string, estimateOnly: boole
} }
return contract.provider.call(tx).then((value) => { return contract.provider.call(tx).then((value) => {
if ((hexDataLength(value) % 32) === 4 && hexDataSlice(value, 0, 4) === '0x08c379a0') {
let reason = defaultAbiCoder.decode([ 'string' ], hexDataSlice(value, 4));
errors.throwError('call revert exception', errors.CALL_EXCEPTION, {
address: contract.address,
method: method.signature,
args: params,
errorSignature: 'Error(string)',
errorArgs: [ reason ],
reason: reason
});
}
try { try {
let result = method.decode(value); let result = method.decode(value);
if (method.outputs.length === 1) { if (method.outputs.length === 1) {
@ -117,7 +131,7 @@ function runMethod(contract: Contract, functionName: string, estimateOnly: boole
errors.throwError('call exception', errors.CALL_EXCEPTION, { errors.throwError('call exception', errors.CALL_EXCEPTION, {
address: contract.address, address: contract.address,
method: method.signature, method: method.signature,
value: params args: params
}); });
} }
throw error; throw error;

View File

@ -877,9 +877,7 @@ export class Provider {
return this.resolveName(addressOrName).then((address) => { return this.resolveName(addressOrName).then((address) => {
var params = { address: address, blockTag: checkBlockTag(blockTag) }; var params = { address: address, blockTag: checkBlockTag(blockTag) };
return this.perform('getTransactionCount', params).then((result) => { return this.perform('getTransactionCount', params).then((result) => {
var value = parseInt(result); return bigNumberify(result).toNumber();
if (value != result) { throw new Error('invalid response - getTransactionCount'); }
return value;
}); });
}); });
}); });
@ -943,10 +941,11 @@ export class Provider {
call(transaction: TransactionRequest): Promise<string> { call(transaction: TransactionRequest): Promise<string> {
let tx: TransactionRequest = shallowCopy(transaction);
return this.ready.then(() => { return this.ready.then(() => {
return resolveProperties(transaction).then((transaction) => { return resolveProperties(tx).then((tx) => {
return this._resolveNames(transaction, [ 'to', 'from' ]).then((transaction) => { return this._resolveNames(tx, [ 'to', 'from' ]).then((tx) => {
var params = { transaction: checkTransactionRequest(transaction) }; var params = { transaction: checkTransactionRequest(tx) };
return this.perform('call', params).then((result) => { return this.perform('call', params).then((result) => {
return hexlify(result); return hexlify(result);
}); });
@ -956,10 +955,16 @@ export class Provider {
} }
estimateGas(transaction: TransactionRequest) { estimateGas(transaction: TransactionRequest) {
let tx: TransactionRequest = {
to: transaction.to,
from: transaction.from,
data: transaction.data
};
return this.ready.then(() => { return this.ready.then(() => {
return resolveProperties(transaction).then((transaction) => { return resolveProperties(tx).then((tx) => {
return this._resolveNames(transaction, [ 'to', 'from' ]).then((transaction) => { return this._resolveNames(tx, [ 'to', 'from' ]).then((tx) => {
var params = {transaction: checkTransactionRequest(transaction)}; var params = { transaction: checkTransactionRequest(tx) };
return this.perform('estimateGas', params).then((result) => { return this.perform('estimateGas', params).then((result) => {
return bigNumberify(result); return bigNumberify(result);
}); });

View File

@ -19,12 +19,14 @@ export function defineFrozen(object: any, name: string, value: any): void {
export function resolveProperties(object: any): Promise<any> { export function resolveProperties(object: any): Promise<any> {
let result: any = {}; let result: any = {};
let promises: Array<Promise<any>> = []; let promises: Array<Promise<void>> = [];
Object.keys(object).forEach((key) => { Object.keys(object).forEach((key) => {
let value = object[key]; let value = object[key];
if (value instanceof Promise) { if (value instanceof Promise) {
promises.push( promises.push(
value.then((value) => { result[key] = value; }) value.then((value) => {
result[key] = value;
})
); );
} else { } else {
result[key] = value; result[key] = value;

View File

@ -69,6 +69,7 @@ export class Wallet extends Signer {
} }
sign(transaction: TransactionRequest): Promise<string> { sign(transaction: TransactionRequest): Promise<string> {
return resolveProperties(transaction).then((tx) => { return resolveProperties(transaction).then((tx) => {
return signTransaction(tx, this.signingKey.signDigest.bind(this.signingKey)); return signTransaction(tx, this.signingKey.signDigest.bind(this.signingKey));
}); });

View File

@ -22,7 +22,9 @@ function resolveProperties(object) {
Object.keys(object).forEach(function (key) { Object.keys(object).forEach(function (key) {
var value = object[key]; var value = object[key];
if (value instanceof Promise) { if (value instanceof Promise) {
promises.push(value.then(function (value) { result[key] = value; })); promises.push(value.then(function (value) {
result[key] = value;
}));
} }
else { else {
result[key] = value; result[key] = value;