Skip to content

Commit

Permalink
Added optional blockTag to call; note that this may not behave as exp…
Browse files Browse the repository at this point in the history
…ected on all nodes (#226).
  • Loading branch information
ricmoo committed Oct 11, 2018
1 parent 84344ac commit 493273d
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 23 deletions.
15 changes: 11 additions & 4 deletions src.ts/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

///////////////////////////////
Expand Down Expand Up @@ -148,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);
}
Expand Down Expand Up @@ -202,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));
Expand Down
2 changes: 1 addition & 1 deletion src.ts/providers/abstract-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,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>;
Expand Down
6 changes: 3 additions & 3 deletions src.ts/providers/base-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -850,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);
});
Expand Down
22 changes: 13 additions & 9 deletions src.ts/providers/etherscan-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,15 @@ 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; }

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;
Expand Down Expand Up @@ -193,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';
Expand All @@ -227,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');
}
Expand Down
29 changes: 23 additions & 6 deletions src.ts/providers/json-rpc-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,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;

Expand Down Expand Up @@ -300,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) {
Expand Down Expand Up @@ -369,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) {
Expand All @@ -384,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;
}
Expand Down

0 comments on commit 493273d

Please sign in to comment.