2018-06-13 22:39:39 +03:00
'use strict' ;
2018-06-18 12:42:41 +03:00
var _ _extends = ( this && this . _ _extends ) || ( function ( ) {
var extendStatics = Object . setPrototypeOf ||
( { _ _proto _ _ : [ ] } instanceof Array && function ( d , b ) { d . _ _proto _ _ = b ; } ) ||
function ( d , b ) { for ( var p in b ) if ( b . hasOwnProperty ( p ) ) d [ p ] = b [ p ] ; } ;
return function ( d , b ) {
extendStatics ( d , b ) ;
function _ _ ( ) { this . constructor = d ; }
d . prototype = b === null ? Object . create ( b ) : ( _ _ . prototype = b . prototype , new _ _ ( ) ) ;
} ;
} ) ( ) ;
2018-06-13 22:39:39 +03:00
var _ _importStar = ( this && this . _ _importStar ) || function ( mod ) {
if ( mod && mod . _ _esModule ) return mod ;
var result = { } ;
if ( mod != null ) for ( var k in mod ) if ( Object . hasOwnProperty . call ( mod , k ) ) result [ k ] = mod [ k ] ;
result [ "default" ] = mod ;
return result ;
} ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
//import inherits = require('inherits');
2018-06-18 12:42:41 +03:00
var wallet _1 = require ( "../wallet/wallet" ) ;
2018-06-13 22:39:39 +03:00
var address _1 = require ( "../utils/address" ) ;
var bignumber _1 = require ( "../utils/bignumber" ) ;
2018-06-17 23:47:28 +03:00
var bytes _1 = require ( "../utils/bytes" ) ;
2018-06-13 22:39:39 +03:00
var utf8 _1 = require ( "../utils/utf8" ) ;
var rlp _1 = require ( "../utils/rlp" ) ;
2018-06-18 12:42:41 +03:00
var hash _1 = require ( "../utils/hash" ) ;
2018-06-13 22:39:39 +03:00
var networks _1 = require ( "./networks" ) ;
var properties _1 = require ( "../utils/properties" ) ;
2018-06-17 23:32:57 +03:00
var transaction _1 = require ( "../utils/transaction" ) ;
2018-06-13 22:39:39 +03:00
var errors = _ _importStar ( require ( "../utils/errors" ) ) ;
2018-06-17 23:32:57 +03:00
;
;
2018-06-13 22:39:39 +03:00
//////////////////////////////
// Request and Response Checking
// @TODO: not any?
function check ( format , object ) {
var result = { } ;
for ( var key in format ) {
try {
var value = format [ key ] ( object [ key ] ) ;
if ( value !== undefined ) {
result [ key ] = value ;
}
}
catch ( error ) {
error . checkKey = key ;
error . checkValue = object [ key ] ;
throw error ;
}
}
return result ;
}
function allowNull ( check , nullValue ) {
return ( function ( value ) {
if ( value == null ) {
return nullValue ;
}
return check ( value ) ;
} ) ;
}
function allowFalsish ( check , replaceValue ) {
return ( function ( value ) {
if ( ! value ) {
return replaceValue ;
}
return check ( value ) ;
} ) ;
}
function arrayOf ( check ) {
return ( function ( array ) {
if ( ! Array . isArray ( array ) ) {
throw new Error ( 'not an array' ) ;
}
var result = [ ] ;
array . forEach ( function ( value ) {
result . push ( check ( value ) ) ;
} ) ;
return result ;
} ) ;
}
function checkHash ( hash ) {
2018-06-17 23:47:28 +03:00
if ( typeof ( hash ) === 'string' && bytes _1 . hexDataLength ( hash ) === 32 ) {
2018-06-13 22:39:39 +03:00
return hash ;
}
errors . throwError ( 'invalid hash' , errors . INVALID _ARGUMENT , { arg : 'hash' , value : hash } ) ;
return null ;
}
function checkNumber ( number ) {
return bignumber _1 . bigNumberify ( number ) . toNumber ( ) ;
}
// Returns the difficulty as a number, or if too large (i.e. PoA network) null
function checkDifficulty ( value ) {
var v = bignumber _1 . bigNumberify ( value ) ;
try {
return v . toNumber ( ) ;
}
catch ( error ) { }
return null ;
}
function checkBoolean ( value ) {
if ( typeof ( value ) === 'boolean' ) {
return value ;
}
if ( typeof ( value ) === 'string' ) {
if ( value === 'true' ) {
return true ;
}
if ( value === 'false' ) {
return false ;
}
}
throw new Error ( 'invaid boolean - ' + value ) ;
}
function checkUint256 ( uint256 ) {
2018-06-17 23:47:28 +03:00
if ( ! bytes _1 . isHexString ( uint256 ) ) {
2018-06-13 22:39:39 +03:00
throw new Error ( 'invalid uint256' ) ;
}
while ( uint256 . length < 66 ) {
uint256 = '0x0' + uint256 . substring ( 2 ) ;
}
return uint256 ;
}
/ *
function checkString ( string ) {
if ( typeof ( string ) !== 'string' ) { throw new Error ( 'invalid string' ) ; }
return string ;
}
* /
function checkBlockTag ( blockTag ) {
if ( blockTag == null ) {
return 'latest' ;
}
if ( blockTag === 'earliest' ) {
return '0x0' ;
}
if ( blockTag === 'latest' || blockTag === 'pending' ) {
return blockTag ;
}
if ( typeof ( blockTag ) === 'number' ) {
2018-06-17 23:47:28 +03:00
return bytes _1 . hexStripZeros ( bytes _1 . hexlify ( blockTag ) ) ;
2018-06-13 22:39:39 +03:00
}
2018-06-17 23:47:28 +03:00
if ( bytes _1 . isHexString ( blockTag ) ) {
return bytes _1 . hexStripZeros ( blockTag ) ;
2018-06-13 22:39:39 +03:00
}
throw new Error ( 'invalid blockTag' ) ;
}
var formatBlock = {
hash : checkHash ,
parentHash : checkHash ,
number : checkNumber ,
timestamp : checkNumber ,
2018-06-17 23:47:28 +03:00
nonce : allowNull ( bytes _1 . hexlify ) ,
2018-06-13 22:39:39 +03:00
difficulty : checkDifficulty ,
gasLimit : bignumber _1 . bigNumberify ,
gasUsed : bignumber _1 . bigNumberify ,
miner : address _1 . getAddress ,
2018-06-17 23:47:28 +03:00
extraData : bytes _1 . hexlify ,
2018-06-13 22:39:39 +03:00
//transactions: allowNull(arrayOf(checkTransaction)),
transactions : allowNull ( arrayOf ( checkHash ) ) ,
} ;
function checkBlock ( block ) {
if ( block . author != null && block . miner == null ) {
block . miner = block . author ;
}
return check ( formatBlock , block ) ;
}
var formatTransaction = {
hash : checkHash ,
blockHash : allowNull ( checkHash , null ) ,
blockNumber : allowNull ( checkNumber , null ) ,
transactionIndex : allowNull ( checkNumber , null ) ,
from : address _1 . getAddress ,
gasPrice : bignumber _1 . bigNumberify ,
gasLimit : bignumber _1 . bigNumberify ,
to : allowNull ( address _1 . getAddress , null ) ,
value : bignumber _1 . bigNumberify ,
nonce : checkNumber ,
2018-06-17 23:47:28 +03:00
data : bytes _1 . hexlify ,
2018-06-13 22:39:39 +03:00
r : allowNull ( checkUint256 ) ,
s : allowNull ( checkUint256 ) ,
v : allowNull ( checkNumber ) ,
creates : allowNull ( address _1 . getAddress , null ) ,
2018-06-17 23:47:28 +03:00
raw : allowNull ( bytes _1 . hexlify ) ,
2018-06-13 22:39:39 +03:00
} ;
function checkTransactionResponse ( transaction ) {
// Rename gas to gasLimit
if ( transaction . gas != null && transaction . gasLimit == null ) {
transaction . gasLimit = transaction . gas ;
}
// Some clients (TestRPC) do strange things like return 0x0 for the
// 0 address; correct this to be a real address
if ( transaction . to && bignumber _1 . bigNumberify ( transaction . to ) . isZero ( ) ) {
transaction . to = '0x0000000000000000000000000000000000000000' ;
}
// Rename input to data
if ( transaction . input != null && transaction . data == null ) {
transaction . data = transaction . input ;
}
// If to and creates are empty, populate the creates from the transaction
if ( transaction . to == null && transaction . creates == null ) {
2018-06-14 04:10:41 +03:00
transaction . creates = address _1 . getContractAddress ( transaction ) ;
2018-06-13 22:39:39 +03:00
}
if ( ! transaction . raw ) {
// Very loose providers (e.g. TestRPC) don't provide a signature or raw
if ( transaction . v && transaction . r && transaction . s ) {
var raw = [
2018-06-17 23:47:28 +03:00
bytes _1 . stripZeros ( bytes _1 . hexlify ( transaction . nonce ) ) ,
bytes _1 . stripZeros ( bytes _1 . hexlify ( transaction . gasPrice ) ) ,
bytes _1 . stripZeros ( bytes _1 . hexlify ( transaction . gasLimit ) ) ,
2018-06-13 22:39:39 +03:00
( transaction . to || "0x" ) ,
2018-06-17 23:47:28 +03:00
bytes _1 . stripZeros ( bytes _1 . hexlify ( transaction . value || '0x' ) ) ,
bytes _1 . hexlify ( transaction . data || '0x' ) ,
bytes _1 . stripZeros ( bytes _1 . hexlify ( transaction . v || '0x' ) ) ,
bytes _1 . stripZeros ( bytes _1 . hexlify ( transaction . r ) ) ,
bytes _1 . stripZeros ( bytes _1 . hexlify ( transaction . s ) ) ,
2018-06-13 22:39:39 +03:00
] ;
transaction . raw = rlp _1 . encode ( raw ) ;
}
}
var result = check ( formatTransaction , transaction ) ;
var networkId = transaction . networkId ;
2018-06-17 23:47:28 +03:00
if ( bytes _1 . isHexString ( networkId ) ) {
2018-06-13 22:39:39 +03:00
networkId = bignumber _1 . bigNumberify ( networkId ) . toNumber ( ) ;
}
if ( typeof ( networkId ) !== 'number' && result . v != null ) {
networkId = ( result . v - 35 ) / 2 ;
if ( networkId < 0 ) {
networkId = 0 ;
}
networkId = parseInt ( networkId ) ;
}
if ( typeof ( networkId ) !== 'number' ) {
networkId = 0 ;
}
result . networkId = networkId ;
// 0x0000... should actually be null
if ( result . blockHash && result . blockHash . replace ( /0/g , '' ) === 'x' ) {
result . blockHash = null ;
}
return result ;
}
exports . checkTransactionResponse = checkTransactionResponse ;
var formatTransactionRequest = {
from : allowNull ( address _1 . getAddress ) ,
nonce : allowNull ( checkNumber ) ,
gasLimit : allowNull ( bignumber _1 . bigNumberify ) ,
gasPrice : allowNull ( bignumber _1 . bigNumberify ) ,
to : allowNull ( address _1 . getAddress ) ,
value : allowNull ( bignumber _1 . bigNumberify ) ,
2018-06-17 23:47:28 +03:00
data : allowNull ( bytes _1 . hexlify ) ,
2018-06-13 22:39:39 +03:00
} ;
function checkTransactionRequest ( transaction ) {
return check ( formatTransactionRequest , transaction ) ;
}
var formatTransactionReceiptLog = {
transactionLogIndex : allowNull ( checkNumber ) ,
transactionIndex : checkNumber ,
blockNumber : checkNumber ,
transactionHash : checkHash ,
address : address _1 . getAddress ,
topics : arrayOf ( checkHash ) ,
2018-06-17 23:47:28 +03:00
data : bytes _1 . hexlify ,
2018-06-13 22:39:39 +03:00
logIndex : checkNumber ,
blockHash : checkHash ,
} ;
function checkTransactionReceiptLog ( log ) {
return check ( formatTransactionReceiptLog , log ) ;
}
var formatTransactionReceipt = {
contractAddress : allowNull ( address _1 . getAddress , null ) ,
transactionIndex : checkNumber ,
root : allowNull ( checkHash ) ,
gasUsed : bignumber _1 . bigNumberify ,
2018-06-17 23:47:28 +03:00
logsBloom : allowNull ( bytes _1 . hexlify ) ,
2018-06-13 22:39:39 +03:00
blockHash : checkHash ,
transactionHash : checkHash ,
logs : arrayOf ( checkTransactionReceiptLog ) ,
blockNumber : checkNumber ,
cumulativeGasUsed : bignumber _1 . bigNumberify ,
status : allowNull ( checkNumber )
} ;
function checkTransactionReceipt ( transactionReceipt ) {
//var status = transactionReceipt.status;
//var root = transactionReceipt.root;
var result = check ( formatTransactionReceipt , transactionReceipt ) ;
result . logs . forEach ( function ( entry , index ) {
if ( entry . transactionLogIndex == null ) {
entry . transactionLogIndex = index ;
}
} ) ;
if ( transactionReceipt . status != null ) {
result . byzantium = true ;
}
return result ;
}
function checkTopics ( topics ) {
if ( Array . isArray ( topics ) ) {
topics . forEach ( function ( topic ) {
checkTopics ( topic ) ;
} ) ;
}
else if ( topics != null ) {
checkHash ( topics ) ;
}
return topics ;
}
var formatFilter = {
fromBlock : allowNull ( checkBlockTag , undefined ) ,
toBlock : allowNull ( checkBlockTag , undefined ) ,
address : allowNull ( address _1 . getAddress , undefined ) ,
topics : allowNull ( checkTopics , undefined ) ,
} ;
function checkFilter ( filter ) {
return check ( formatFilter , filter ) ;
}
var formatLog = {
blockNumber : allowNull ( checkNumber ) ,
blockHash : allowNull ( checkHash ) ,
transactionIndex : checkNumber ,
removed : allowNull ( checkBoolean ) ,
address : address _1 . getAddress ,
2018-06-17 23:47:28 +03:00
data : allowFalsish ( bytes _1 . hexlify , '0x' ) ,
2018-06-13 22:39:39 +03:00
topics : arrayOf ( checkHash ) ,
transactionHash : checkHash ,
logIndex : checkNumber ,
} ;
function checkLog ( log ) {
return check ( formatLog , log ) ;
}
function stallPromise ( allowNullFunc , executeFunc ) {
return new Promise ( function ( resolve , reject ) {
var attempt = 0 ;
function check ( ) {
executeFunc ( ) . then ( function ( result ) {
// If we have a result, or are allowed null then we're done
if ( result || allowNullFunc ( ) ) {
resolve ( result ) ;
// Otherwise, exponential back-off (up to 10s) our next request
}
else {
attempt ++ ;
2018-06-23 03:30:50 +03:00
var timeout = 500 + 250 * parseInt ( String ( Math . random ( ) * ( 1 << attempt ) ) ) ;
2018-06-13 22:39:39 +03:00
if ( timeout > 10000 ) {
timeout = 10000 ;
}
setTimeout ( check , timeout ) ;
}
} , function ( error ) {
reject ( error ) ;
} ) ;
}
check ( ) ;
} ) ;
}
//////////////////////////////
// Event Serializeing
function recurse ( object , convertFunc ) {
if ( Array . isArray ( object ) ) {
var result = [ ] ;
object . forEach ( function ( object ) {
result . push ( recurse ( object , convertFunc ) ) ;
} ) ;
return result ;
}
return convertFunc ( object ) ;
}
function getEventString ( object ) {
try {
return 'address:' + address _1 . getAddress ( object ) ;
}
catch ( error ) { }
2018-06-23 03:30:50 +03:00
if ( object === 'block' || object === 'pending' || object === 'error' ) {
return object ;
2018-06-13 22:39:39 +03:00
}
2018-06-17 23:47:28 +03:00
else if ( bytes _1 . hexDataLength ( object ) === 32 ) {
2018-06-17 23:32:57 +03:00
return 'tx:' + object ;
2018-06-13 22:39:39 +03:00
}
else if ( Array . isArray ( object ) ) {
2018-06-23 03:30:50 +03:00
// Replace null in the structure with '0x'
var stringified = recurse ( object , function ( object ) {
2018-06-13 22:39:39 +03:00
if ( object == null ) {
object = '0x' ;
}
return object ;
} ) ;
try {
2018-06-23 03:30:50 +03:00
return 'topic:' + rlp _1 . encode ( stringified ) ;
2018-06-13 22:39:39 +03:00
}
catch ( error ) {
console . log ( error ) ;
}
}
2018-06-18 12:42:41 +03:00
try {
throw new Error ( ) ;
}
catch ( e ) {
console . log ( e . stack ) ;
}
2018-06-13 22:39:39 +03:00
throw new Error ( 'invalid event - ' + object ) ;
}
2018-06-23 03:30:50 +03:00
function parseEventString ( event ) {
if ( event . substring ( 0 , 3 ) === 'tx:' ) {
return { type : 'transaction' , hash : event . substring ( 3 ) } ;
2018-06-13 22:39:39 +03:00
}
2018-06-23 03:30:50 +03:00
else if ( event === 'block' || event === 'pending' || event === 'error' ) {
return { type : event } ;
2018-06-13 22:39:39 +03:00
}
2018-06-23 03:30:50 +03:00
else if ( event . substring ( 0 , 8 ) === 'address:' ) {
return { type : 'address' , address : event . substring ( 8 ) } ;
2018-06-13 22:39:39 +03:00
}
2018-06-23 03:30:50 +03:00
else if ( event . substring ( 0 , 6 ) === 'topic:' ) {
2018-06-13 22:39:39 +03:00
try {
2018-06-23 03:30:50 +03:00
var object = recurse ( rlp _1 . decode ( event . substring ( 6 ) ) , function ( object ) {
2018-06-13 22:39:39 +03:00
if ( object === '0x' ) {
object = null ;
}
return object ;
} ) ;
return { type : 'topic' , topic : object } ;
}
catch ( error ) {
console . log ( error ) ;
}
}
throw new Error ( 'invalid event string' ) ;
}
//////////////////////////////
// Provider Object
/ * @ T O D O :
type Event = {
eventName : string ,
listener : any , // @TODO: Function any: any
type : string ,
}
* /
2018-06-18 12:42:41 +03:00
// @TODO: Perhaps allow a SignDigestAsyncFunc?
// Enable a simple signing function and provider to provide a full Signer
var ProviderSigner = /** @class */ ( function ( _super ) {
_ _extends ( ProviderSigner , _super ) ;
function ProviderSigner ( address , signDigest , provider ) {
var _this = _super . call ( this ) || this ;
errors . checkNew ( _this , ProviderSigner ) ;
properties _1 . defineReadOnly ( _this , '_addressPromise' , Promise . resolve ( address ) ) ;
properties _1 . defineReadOnly ( _this , 'signDigest' , signDigest ) ;
properties _1 . defineReadOnly ( _this , 'provider' , provider ) ;
return _this ;
}
ProviderSigner . prototype . getAddress = function ( ) {
return this . _addressPromise ;
} ;
ProviderSigner . prototype . signMessage = function ( message ) {
return Promise . resolve ( bytes _1 . joinSignature ( this . signDigest ( hash _1 . hashMessage ( message ) ) ) ) ;
} ;
ProviderSigner . prototype . sendTransaction = function ( transaction ) {
var _this = this ;
transaction = properties _1 . shallowCopy ( transaction ) ;
if ( transaction . chainId == null ) {
transaction . chainId = this . provider . getNetwork ( ) . then ( function ( network ) {
return network . chainId ;
} ) ;
}
if ( transaction . from == null ) {
transaction . from = this . getAddress ( ) ;
}
if ( transaction . gasLimit == null ) {
transaction . gasLimit = this . provider . estimateGas ( transaction ) ;
}
if ( transaction . gasPrice == null ) {
transaction . gasPrice = this . provider . getGasPrice ( ) ;
}
return properties _1 . resolveProperties ( transaction ) . then ( function ( tx ) {
var signedTx = transaction _1 . sign ( tx , _this . signDigest ) ;
return _this . _addressPromise . then ( function ( address ) {
if ( transaction _1 . parse ( signedTx ) . from !== address ) {
errors . throwError ( 'signing address does not match expected address' , errors . UNKNOWN _ERROR , { address : transaction _1 . parse ( signedTx ) . from , expectedAddress : address , signedTransaction : signedTx } ) ;
}
return _this . provider . sendTransaction ( signedTx ) ;
} ) ;
} ) ;
} ;
return ProviderSigner ;
} ( wallet _1 . Signer ) ) ;
exports . ProviderSigner = ProviderSigner ;
2018-06-13 22:39:39 +03:00
var Provider = /** @class */ ( function ( ) {
function Provider ( network ) {
2018-06-18 12:42:41 +03:00
var _this = this ;
2018-06-14 04:10:41 +03:00
errors . checkNew ( this , Provider ) ;
2018-06-18 12:42:41 +03:00
if ( network instanceof Promise ) {
properties _1 . defineReadOnly ( this , 'ready' , network . then ( function ( network ) {
properties _1 . defineReadOnly ( _this , '_network' , network ) ;
return network ;
} ) ) ;
2018-06-13 22:39:39 +03:00
}
else {
2018-06-18 12:42:41 +03:00
var knownNetwork = networks _1 . getNetwork ( ( network == null ) ? 'homestead' : network ) ;
if ( knownNetwork ) {
properties _1 . defineReadOnly ( this , '_network' , knownNetwork ) ;
properties _1 . defineReadOnly ( this , 'ready' , Promise . resolve ( this . _network ) ) ;
}
else {
errors . throwError ( 'invalid network' , errors . INVALID _ARGUMENT , { arg : 'network' , value : network } ) ;
}
2018-06-13 22:39:39 +03:00
}
this . _lastBlockNumber = - 2 ;
// Balances being watched for changes
this . _balances = { } ;
// Events being listened to
this . _events = { } ;
this . _pollingInterval = 4000 ;
// We use this to track recent emitted events; for example, if we emit a "block" of 100
// and we get a `getBlock(100)` request which would result in null, we should retry
// until we get a response. This provides devs with a consistent view. Similarly for
// transaction hashes.
this . _emitted = { block : this . _lastBlockNumber } ;
}
Provider . prototype . _doPoll = function ( ) {
var _this = this ;
this . getBlockNumber ( ) . then ( function ( blockNumber ) {
// If the block hasn't changed, meh.
if ( blockNumber === _this . _lastBlockNumber ) {
return ;
}
if ( _this . _lastBlockNumber === - 2 ) {
_this . _lastBlockNumber = blockNumber - 1 ;
}
// Notify all listener for each block that has passed
for ( var i = _this . _lastBlockNumber + 1 ; i <= blockNumber ; i ++ ) {
if ( _this . _emitted . block < i ) {
_this . _emitted . block = i ;
// Evict any transaction hashes or block hashes over 12 blocks
// old, since they should not return null anyways
Object . keys ( _this . _emitted ) . forEach ( function ( key ) {
if ( key === 'block' ) {
return ;
}
if ( _this . _emitted [ key ] > i + 12 ) {
delete _this . _emitted [ key ] ;
}
} ) ;
}
_this . emit ( 'block' , i ) ;
}
// Sweep balances and remove addresses we no longer have events for
var newBalances = { } ;
// Find all transaction hashes we are waiting on
Object . keys ( _this . _events ) . forEach ( function ( eventName ) {
var event = parseEventString ( eventName ) ;
if ( event . type === 'transaction' ) {
_this . getTransaction ( event . hash ) . then ( function ( transaction ) {
if ( ! transaction || transaction . blockNumber == null ) {
return ;
}
_this . _emitted [ 't:' + transaction . hash . toLowerCase ( ) ] = transaction . blockNumber ;
_this . emit ( event . hash , transaction ) ;
} ) ;
}
else if ( event . type === 'address' ) {
if ( _this . _balances [ event . address ] ) {
newBalances [ event . address ] = _this . _balances [ event . address ] ;
}
_this . getBalance ( event . address , 'latest' ) . then ( function ( balance ) {
var lastBalance = this . _balances [ event . address ] ;
if ( lastBalance && balance . eq ( lastBalance ) ) {
return ;
}
this . _balances [ event . address ] = balance ;
this . emit ( event . address , balance ) ;
} ) ;
}
else if ( event . type === 'topic' ) {
_this . getLogs ( {
fromBlock : _this . _lastBlockNumber + 1 ,
toBlock : blockNumber ,
topics : event . topic
} ) . then ( function ( logs ) {
if ( logs . length === 0 ) {
return ;
}
logs . forEach ( function ( log ) {
_this . _emitted [ 'b:' + log . blockHash . toLowerCase ( ) ] = log . blockNumber ;
_this . _emitted [ 't:' + log . transactionHash . toLowerCase ( ) ] = log . blockNumber ;
_this . emit ( event . topic , log ) ;
} ) ;
} ) ;
}
} ) ;
_this . _lastBlockNumber = blockNumber ;
_this . _balances = newBalances ;
} ) ;
this . doPoll ( ) ;
} ;
Provider . prototype . resetEventsBlock = function ( blockNumber ) {
this . _lastBlockNumber = this . blockNumber ;
this . _doPoll ( ) ;
} ;
Object . defineProperty ( Provider . prototype , "network" , {
get : function ( ) {
return this . _network ;
} ,
enumerable : true ,
configurable : true
} ) ;
Provider . prototype . getNetwork = function ( ) {
return this . ready ;
} ;
Object . defineProperty ( Provider . prototype , "blockNumber" , {
get : function ( ) {
if ( this . _lastBlockNumber < 0 ) {
return null ;
}
return this . _lastBlockNumber ;
} ,
enumerable : true ,
configurable : true
} ) ;
Object . defineProperty ( Provider . prototype , "polling" , {
get : function ( ) {
return ( this . _poller != null ) ;
} ,
set : function ( value ) {
var _this = this ;
setTimeout ( function ( ) {
if ( value && ! _this . _poller ) {
_this . _poller = setInterval ( _this . _doPoll . bind ( _this ) , _this . pollingInterval ) ;
}
else if ( ! value && _this . _poller ) {
clearInterval ( _this . _poller ) ;
_this . _poller = null ;
}
} , 0 ) ;
} ,
enumerable : true ,
configurable : true
} ) ;
Object . defineProperty ( Provider . prototype , "pollingInterval" , {
get : function ( ) {
return this . _pollingInterval ;
} ,
set : function ( value ) {
var _this = this ;
2018-06-23 03:30:50 +03:00
if ( typeof ( value ) !== 'number' || value <= 0 || parseInt ( String ( value ) ) != value ) {
2018-06-13 22:39:39 +03:00
throw new Error ( 'invalid polling interval' ) ;
}
this . _pollingInterval = value ;
if ( this . _poller ) {
clearInterval ( this . _poller ) ;
this . _poller = setInterval ( function ( ) { _this . _doPoll ( ) ; } , this . _pollingInterval ) ;
}
} ,
enumerable : true ,
configurable : true
} ) ;
// @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
Provider . prototype . waitForTransaction = function ( transactionHash , timeout ) {
var self = this ;
return new Promise ( function ( resolve , reject ) {
var timer = null ;
function complete ( transaction ) {
if ( timer ) {
clearTimeout ( timer ) ;
}
resolve ( transaction ) ;
}
self . once ( transactionHash , complete ) ;
if ( typeof ( timeout ) === 'number' && timeout > 0 ) {
timer = setTimeout ( function ( ) {
self . removeListener ( transactionHash , complete ) ;
reject ( new Error ( 'timeout' ) ) ;
} , timeout ) ;
}
} ) ;
} ;
Provider . prototype . getBlockNumber = function ( ) {
var _this = this ;
return this . ready . then ( function ( ) {
return _this . perform ( 'getBlockNumber' , { } ) . then ( function ( result ) {
2018-06-23 03:30:50 +03:00
var value = parseInt ( result ) ;
2018-06-13 22:39:39 +03:00
if ( value != result ) {
throw new Error ( 'invalid response - getBlockNumber' ) ;
}
return value ;
} ) ;
} ) ;
} ;
Provider . prototype . getGasPrice = function ( ) {
var _this = this ;
return this . ready . then ( function ( ) {
return _this . perform ( 'getGasPrice' , { } ) . then ( function ( result ) {
return bignumber _1 . bigNumberify ( result ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getBalance = function ( addressOrName , blockTag ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { addressOrName : addressOrName , blockTag : blockTag } ) . then ( function ( _a ) {
var addressOrName = _a . addressOrName , blockTag = _a . blockTag ;
return _this . resolveName ( addressOrName ) . then ( function ( address ) {
var params = { address : address , blockTag : checkBlockTag ( blockTag ) } ;
return _this . perform ( 'getBalance' , params ) . then ( function ( result ) {
return bignumber _1 . bigNumberify ( result ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getTransactionCount = function ( addressOrName , blockTag ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { addressOrName : addressOrName , blockTag : blockTag } ) . then ( function ( _a ) {
var addressOrName = _a . addressOrName , blockTag = _a . blockTag ;
return _this . resolveName ( addressOrName ) . then ( function ( address ) {
var params = { address : address , blockTag : checkBlockTag ( blockTag ) } ;
return _this . perform ( 'getTransactionCount' , params ) . then ( function ( result ) {
var value = parseInt ( result ) ;
if ( value != result ) {
throw new Error ( 'invalid response - getTransactionCount' ) ;
}
return value ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getCode = function ( addressOrName , blockTag ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { addressOrName : addressOrName , blockTag : blockTag } ) . then ( function ( _a ) {
var addressOrName = _a . addressOrName , blockTag = _a . blockTag ;
return _this . resolveName ( addressOrName ) . then ( function ( address ) {
var params = { address : address , blockTag : checkBlockTag ( blockTag ) } ;
return _this . perform ( 'getCode' , params ) . then ( function ( result ) {
2018-06-17 23:47:28 +03:00
return bytes _1 . hexlify ( result ) ;
2018-06-13 22:39:39 +03:00
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getStorageAt = function ( addressOrName , position , blockTag ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { addressOrName : addressOrName , position : position , blockTag : blockTag } ) . then ( function ( _a ) {
var addressOrName = _a . addressOrName , position = _a . position , blockTag = _a . blockTag ;
return _this . resolveName ( addressOrName ) . then ( function ( address ) {
var params = {
address : address ,
blockTag : checkBlockTag ( blockTag ) ,
2018-06-17 23:47:28 +03:00
position : bytes _1 . hexStripZeros ( bytes _1 . hexlify ( position ) ) ,
2018-06-13 22:39:39 +03:00
} ;
return _this . perform ( 'getStorageAt' , params ) . then ( function ( result ) {
2018-06-17 23:47:28 +03:00
return bytes _1 . hexlify ( result ) ;
2018-06-13 22:39:39 +03:00
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . sendTransaction = function ( signedTransaction ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { signedTransaction : signedTransaction } ) . then ( function ( _a ) {
var signedTransaction = _a . signedTransaction ;
2018-06-17 23:47:28 +03:00
var params = { signedTransaction : bytes _1 . hexlify ( signedTransaction ) } ;
2018-06-17 23:32:57 +03:00
return _this . perform ( 'sendTransaction' , params ) . then ( function ( hash ) {
2018-06-17 23:47:28 +03:00
if ( bytes _1 . hexDataLength ( hash ) !== 32 ) {
2018-06-13 22:39:39 +03:00
throw new Error ( 'invalid response - sendTransaction' ) ;
}
2018-06-17 23:32:57 +03:00
// A signed transaction always has a from (and we add wait below)
var tx = transaction _1 . parse ( signedTransaction ) ;
// Check the hash we expect is the same as the hash the server reported
if ( tx . hash !== hash ) {
errors . throwError ( 'Transaction hash mismatch from Proivder.sendTransaction.' , errors . UNKNOWN _ERROR , { expectedHash : tx . hash , returnedHash : hash } ) ;
}
_this . _emitted [ 't:' + tx . hash . toLowerCase ( ) ] = 'pending' ;
tx . wait = function ( timeout ) {
return _this . waitForTransaction ( hash , timeout ) ;
} ;
return tx ;
2018-06-13 22:39:39 +03:00
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . call = function ( transaction ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( transaction ) . then ( function ( transaction ) {
return _this . _resolveNames ( transaction , [ 'to' , 'from' ] ) . then ( function ( transaction ) {
var params = { transaction : checkTransactionRequest ( transaction ) } ;
return _this . perform ( 'call' , params ) . then ( function ( result ) {
2018-06-17 23:47:28 +03:00
return bytes _1 . hexlify ( result ) ;
2018-06-13 22:39:39 +03:00
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . estimateGas = function ( transaction ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( transaction ) . then ( function ( transaction ) {
return _this . _resolveNames ( transaction , [ 'to' , 'from' ] ) . then ( function ( transaction ) {
var params = { transaction : checkTransactionRequest ( transaction ) } ;
return _this . perform ( 'estimateGas' , params ) . then ( function ( result ) {
return bignumber _1 . bigNumberify ( result ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getBlock = function ( blockHashOrBlockTag ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { blockHashOrBlockTag : blockHashOrBlockTag } ) . then ( function ( _a ) {
var blockHashOrBlockTag = _a . blockHashOrBlockTag ;
try {
2018-06-17 23:47:28 +03:00
var blockHash = bytes _1 . hexlify ( blockHashOrBlockTag ) ;
if ( bytes _1 . hexDataLength ( blockHash ) === 32 ) {
2018-06-13 22:39:39 +03:00
return stallPromise ( function ( ) {
return ( _this . _emitted [ 'b:' + blockHash . toLowerCase ( ) ] == null ) ;
} , function ( ) {
return _this . perform ( 'getBlock' , { blockHash : blockHash } ) . then ( function ( block ) {
if ( block == null ) {
return null ;
}
return checkBlock ( block ) ;
} ) ;
} ) ;
}
}
catch ( error ) { }
try {
var blockTag = checkBlockTag ( blockHashOrBlockTag ) ;
return stallPromise ( function ( ) {
2018-06-17 23:47:28 +03:00
if ( bytes _1 . isHexString ( blockTag ) ) {
2018-06-13 22:39:39 +03:00
var blockNumber = parseInt ( blockTag . substring ( 2 ) , 16 ) ;
return blockNumber > _this . _emitted . block ;
}
return true ;
} , function ( ) {
return _this . perform ( 'getBlock' , { blockTag : blockTag } ) . then ( function ( block ) {
if ( block == null ) {
return null ;
}
return checkBlock ( block ) ;
} ) ;
} ) ;
}
catch ( error ) { }
throw new Error ( 'invalid block hash or block tag' ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getTransaction = function ( transactionHash ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { transactionHash : transactionHash } ) . then ( function ( _a ) {
var transactionHash = _a . transactionHash ;
var params = { transactionHash : checkHash ( transactionHash ) } ;
return stallPromise ( function ( ) {
return ( _this . _emitted [ 't:' + transactionHash . toLowerCase ( ) ] == null ) ;
} , function ( ) {
return _this . perform ( 'getTransaction' , params ) . then ( function ( result ) {
if ( result != null ) {
result = checkTransactionResponse ( result ) ;
}
return result ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getTransactionReceipt = function ( transactionHash ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( { transactionHash : transactionHash } ) . then ( function ( _a ) {
var transactionHash = _a . transactionHash ;
var params = { transactionHash : checkHash ( transactionHash ) } ;
return stallPromise ( function ( ) {
return ( _this . _emitted [ 't:' + transactionHash . toLowerCase ( ) ] == null ) ;
} , function ( ) {
return _this . perform ( 'getTransactionReceipt' , params ) . then ( function ( result ) {
if ( result != null ) {
result = checkTransactionReceipt ( result ) ;
}
return result ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getLogs = function ( filter ) {
var _this = this ;
return this . ready . then ( function ( ) {
return properties _1 . resolveProperties ( filter ) . then ( function ( filter ) {
return _this . _resolveNames ( filter , [ 'address' ] ) . then ( function ( filter ) {
var params = { filter : checkFilter ( filter ) } ;
return _this . perform ( 'getLogs' , params ) . then ( function ( result ) {
return arrayOf ( checkLog ) ( result ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
Provider . prototype . getEtherPrice = function ( ) {
var _this = this ;
return this . ready . then ( function ( ) {
return _this . perform ( 'getEtherPrice' , { } ) . then ( function ( result ) {
// @TODO: Check valid float
return result ;
} ) ;
} ) ;
} ;
2018-06-22 09:18:19 +03:00
// @TODO: Could probably use resolveProperties instead?
2018-06-13 22:39:39 +03:00
Provider . prototype . _resolveNames = function ( object , keys ) {
var promises = [ ] ;
2018-06-23 03:30:50 +03:00
var result = properties _1 . shallowCopy ( object ) ;
2018-06-13 22:39:39 +03:00
keys . forEach ( function ( key ) {
if ( result [ key ] === undefined ) {
return ;
}
promises . push ( this . resolveName ( result [ key ] ) . then ( function ( address ) {
result [ key ] = address ;
} ) ) ;
} , this ) ;
return Promise . all ( promises ) . then ( function ( ) { return result ; } ) ;
} ;
Provider . prototype . _getResolver = function ( name ) {
var _this = this ;
// Get the resolver from the blockchain
return this . getNetwork ( ) . then ( function ( network ) {
// No ENS...
if ( ! network . ensAddress ) {
errors . throwError ( 'network does support ENS' , errors . UNSUPPORTED _OPERATION , { operation : 'ENS' , network : network . name } ) ;
}
// keccak256('resolver(bytes32)')
2018-06-18 12:42:41 +03:00
var data = '0x0178b8bf' + hash _1 . namehash ( name ) . substring ( 2 ) ;
2018-06-13 22:39:39 +03:00
var transaction = { to : network . ensAddress , data : data } ;
return _this . call ( transaction ) . then ( function ( data ) {
// extract the address from the data
2018-06-17 23:47:28 +03:00
if ( bytes _1 . hexDataLength ( data ) !== 32 ) {
2018-06-13 22:39:39 +03:00
return null ;
}
2018-06-17 23:47:28 +03:00
return address _1 . getAddress ( bytes _1 . hexDataSlice ( data , 12 ) ) ;
2018-06-13 22:39:39 +03:00
} ) ;
} ) ;
} ;
Provider . prototype . resolveName = function ( name ) {
var _this = this ;
// If it is a promise, resolve it then recurse
if ( name instanceof Promise ) {
return name . then ( function ( addressOrName ) {
return _this . resolveName ( addressOrName ) ;
} ) ;
}
// If it is already an address, nothing to resolve
try {
return Promise . resolve ( address _1 . getAddress ( name ) ) ;
}
catch ( error ) { }
var self = this ;
2018-06-18 12:42:41 +03:00
var nodeHash = hash _1 . namehash ( name ) ;
2018-06-13 22:39:39 +03:00
// Get the addr from the resovler
return this . _getResolver ( name ) . then ( function ( resolverAddress ) {
// keccak256('addr(bytes32)')
var data = '0x3b3b57de' + nodeHash . substring ( 2 ) ;
var transaction = { to : resolverAddress , data : data } ;
return self . call ( transaction ) ;
// extract the address from the data
} ) . then ( function ( data ) {
2018-06-17 23:47:28 +03:00
if ( bytes _1 . hexDataLength ( data ) !== 32 ) {
2018-06-13 22:39:39 +03:00
return null ;
}
2018-06-17 23:47:28 +03:00
var address = address _1 . getAddress ( bytes _1 . hexDataSlice ( data , 12 ) ) ;
2018-06-13 22:39:39 +03:00
if ( address === '0x0000000000000000000000000000000000000000' ) {
return null ;
}
return address ;
} ) ;
} ;
Provider . prototype . lookupAddress = function ( address ) {
var _this = this ;
if ( address instanceof Promise ) {
return address . then ( function ( address ) {
return _this . lookupAddress ( address ) ;
} ) ;
}
address = address _1 . getAddress ( address ) ;
var name = address . substring ( 2 ) + '.addr.reverse' ;
2018-06-18 12:42:41 +03:00
var nodehash = hash _1 . namehash ( name ) ;
2018-06-13 22:39:39 +03:00
var self = this ;
return this . _getResolver ( name ) . then ( function ( resolverAddress ) {
if ( ! resolverAddress ) {
return null ;
}
// keccak('name(bytes32)')
var data = '0x691f3431' + nodehash . substring ( 2 ) ;
var transaction = { to : resolverAddress , data : data } ;
return self . call ( transaction ) ;
} ) . then ( function ( data ) {
// Strip off the "0x"
data = data . substring ( 2 ) ;
// Strip off the dynamic string pointer (0x20)
if ( data . length < 64 ) {
return null ;
}
data = data . substring ( 64 ) ;
if ( data . length < 64 ) {
return null ;
}
var length = bignumber _1 . bigNumberify ( '0x' + data . substring ( 0 , 64 ) ) . toNumber ( ) ;
data = data . substring ( 64 ) ;
if ( 2 * length > data . length ) {
return null ;
}
var name = utf8 _1 . toUtf8String ( '0x' + data . substring ( 0 , 2 * length ) ) ;
// Make sure the reverse record matches the foward record
return self . resolveName ( name ) . then ( function ( addr ) {
if ( addr != address ) {
return null ;
}
return name ;
} ) ;
} ) ;
} ;
Provider . prototype . doPoll = function ( ) {
} ;
Provider . prototype . perform = function ( method , params ) {
errors . throwError ( method + ' not implemented' , errors . NOT _IMPLEMENTED , { operation : method } ) ;
return null ;
} ;
Provider . prototype . _startPending = function ( ) {
console . log ( 'WARNING: this provider does not support pending events' ) ;
} ;
Provider . prototype . _stopPending = function ( ) {
} ;
Provider . prototype . on = function ( eventName , listener ) {
var key = getEventString ( eventName ) ;
if ( ! this . _events [ key ] ) {
this . _events [ key ] = [ ] ;
}
this . _events [ key ] . push ( { eventName : eventName , listener : listener , type : 'on' } ) ;
if ( key === 'pending' ) {
this . _startPending ( ) ;
}
this . polling = true ;
return this ;
} ;
Provider . prototype . once = function ( eventName , listener ) {
var key = getEventString ( eventName ) ;
if ( ! this . _events [ key ] ) {
this . _events [ key ] = [ ] ;
}
this . _events [ key ] . push ( { eventName : eventName , listener : listener , type : 'once' } ) ;
if ( key === 'pending' ) {
this . _startPending ( ) ;
}
this . polling = true ;
return this ;
} ;
Provider . prototype . emit = function ( eventName ) {
var args = [ ] ;
for ( var _i = 1 ; _i < arguments . length ; _i ++ ) {
args [ _i - 1 ] = arguments [ _i ] ;
}
var result = false ;
var key = getEventString ( eventName ) ;
//var args = Array.prototype.slice.call(arguments, 1);
var listeners = this . _events [ key ] ;
if ( ! listeners ) {
return result ;
}
for ( var i = 0 ; i < listeners . length ; i ++ ) {
var listener = listeners [ i ] ;
if ( listener . type === 'once' ) {
listeners . splice ( i , 1 ) ;
i -- ;
}
try {
listener . listener . apply ( this , args ) ;
result = true ;
}
catch ( error ) {
console . log ( 'Event Listener Error: ' + error . message ) ;
}
}
if ( listeners . length === 0 ) {
delete this . _events [ key ] ;
if ( key === 'pending' ) {
this . _stopPending ( ) ;
}
}
if ( this . listenerCount ( ) === 0 ) {
this . polling = false ;
}
return result ;
} ;
// @TODO: type EventName
Provider . prototype . listenerCount = function ( eventName ) {
if ( ! eventName ) {
var result = 0 ;
for ( var key in this . _events ) {
result += this . _events [ key ] . length ;
}
return result ;
}
var listeners = this . _events [ getEventString ( eventName ) ] ;
if ( ! listeners ) {
return 0 ;
}
return listeners . length ;
} ;
Provider . prototype . listeners = function ( eventName ) {
var listeners = this . _events [ getEventString ( eventName ) ] ;
if ( ! listeners ) {
return [ ] ;
}
var result = [ ] ;
for ( var i = 0 ; i < listeners . length ; i ++ ) {
result . push ( listeners [ i ] . listener ) ;
}
return result ;
} ;
Provider . prototype . removeAllListeners = function ( eventName ) {
delete this . _events [ getEventString ( eventName ) ] ;
if ( this . listenerCount ( ) === 0 ) {
this . polling = false ;
}
return this ;
} ;
Provider . prototype . removeListener = function ( eventName , listener ) {
var eventNameString = getEventString ( eventName ) ;
var listeners = this . _events [ eventNameString ] ;
if ( ! listeners ) {
return this ;
}
for ( var i = 0 ; i < listeners . length ; i ++ ) {
if ( listeners [ i ] . listener === listener ) {
listeners . splice ( i , 1 ) ;
break ;
}
}
if ( listeners . length === 0 ) {
this . removeAllListeners ( eventName ) ;
}
return this ;
} ;
return Provider ;
} ( ) ) ;
exports . Provider = Provider ;