Skip to content

Commit a4e768e

Browse files
committed
Added pending transaction event for providers that support it.
1 parent 2d4fb37 commit a4e768e

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

providers/infura-provider.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,11 @@ function InfuraProvider(network, apiAccessToken) {
4242
}
4343
JsonRpcProvider.inherits(InfuraProvider);
4444

45+
utils.defineProperty(InfuraProvider.prototype, '_startPending', function() {
46+
console.log('WARNING: INFURA does not support pending filters');
47+
});
48+
49+
utils.defineProperty(InfuraProvider.prototype, '_stopPending', function() {
50+
});
51+
4552
module.exports = InfuraProvider;

providers/json-rpc-provider.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ var utils = (function() {
1414
}
1515
})();
1616

17+
// @TODO: Move this to utils
18+
function timer(timeout) {
19+
return new Promise(function(resolve) {
20+
setTimeout(function() {
21+
resolve();
22+
}, timeout);
23+
});
24+
}
25+
1726
function getResult(payload) {
1827
if (payload.error) {
1928
var error = new Error(payload.error.message);
@@ -157,4 +166,46 @@ utils.defineProperty(JsonRpcProvider.prototype, 'perform', function(method, para
157166
return Promise.reject(new Error('not implemented - ' + method));
158167
});
159168

169+
utils.defineProperty(JsonRpcProvider.prototype, '_startPending', function() {
170+
if (this._pendingFilter != null) { return; }
171+
var self = this;
172+
173+
var pendingFilter = this.send('eth_newPendingTransactionFilter', []);
174+
this._pendingFilter = pendingFilter;
175+
176+
pendingFilter.then(function(filterId) {
177+
function poll() {
178+
self.send('eth_getFilterChanges', [ filterId ]).then(function(hashes) {
179+
if (self._pendingFilter != pendingFilter) { return; }
180+
181+
var seq = Promise.resolve();
182+
hashes.forEach(function(hash) {
183+
seq = seq.then(function() {
184+
return self.getTransaction(hash).then(function(tx) {
185+
self.emit('pending', tx);
186+
});
187+
});
188+
});
189+
190+
return seq.then(function() {
191+
return timer(1000);
192+
});
193+
}).then(function() {
194+
if (self._pendingFilter != pendingFilter) {
195+
self.send('eth_uninstallFilter', [ filterIf ]);
196+
return;
197+
}
198+
setTimeout(function() { poll(); }, 0);
199+
});
200+
}
201+
poll();
202+
203+
return filterId;
204+
});
205+
});
206+
207+
utils.defineProperty(JsonRpcProvider.prototype, '_stopPending', function() {
208+
this._pendingFilter = null;
209+
});
210+
160211
module.exports = JsonRpcProvider;

providers/provider.js

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ function checkTransaction(transaction) {
215215
}
216216

217217
if (!transaction.raw) {
218-
219218
// Very loose providers (e.g. TestRPC) don't provide a signature or raw
220219
if (transaction.v && transaction.r && transaction.s) {
221220
var raw = [
@@ -718,7 +717,7 @@ utils.defineProperty(Provider.prototype, 'sendTransaction', function(signedTrans
718717

719718
utils.defineProperty(Provider.prototype, 'call', function(transaction) {
720719
var self = this;
721-
return this._resolveNames(transaction, ['to', 'from']).then(function(transaction) {
720+
return this._resolveNames(transaction, [ 'to', 'from' ]).then(function(transaction) {
722721
var params = { transaction: checkTransactionRequest(transaction) };
723722
return self.perform('call', params).then(function(result) {
724723
return utils.hexlify(result);
@@ -728,7 +727,7 @@ utils.defineProperty(Provider.prototype, 'call', function(transaction) {
728727

729728
utils.defineProperty(Provider.prototype, 'estimateGas', function(transaction) {
730729
var self = this;
731-
return this._resolveNames(transaction, ['to', 'from']).then(function(transaction) {
730+
return this._resolveNames(transaction, [ 'to', 'from' ]).then(function(transaction) {
732731
var params = {transaction: checkTransactionRequest(transaction)};
733732
return self.perform('estimateGas', params).then(function(result) {
734733
return utils.bigNumberify(result);
@@ -934,6 +933,9 @@ function getEventString(object) {
934933
if (object === 'block') {
935934
return 'block';
936935

936+
} else if (object === 'pending') {
937+
return 'pending';
938+
937939
} else if (utils.isHexString(object)) {
938940
if (object.length === 66) {
939941
return 'tx:' + object;
@@ -961,6 +963,9 @@ function parseEventString(string) {
961963
} else if (string === 'block') {
962964
return {type: 'block'};
963965

966+
} else if (string === 'pending') {
967+
return {type: 'pending'};
968+
964969
} else if (string.substring(0, 8) === 'address:') {
965970
return {type: 'address', address: string.substring(8)};
966971

@@ -980,17 +985,26 @@ function parseEventString(string) {
980985
throw new Error('invalid event string');
981986
}
982987

988+
utils.defineProperty(Provider.prototype, '_startPending', function() {
989+
console.log('WARNING: this provider does not support pending events');
990+
});
991+
992+
utils.defineProperty(Provider.prototype, '_stopPending', function() {
993+
});
994+
983995
utils.defineProperty(Provider.prototype, 'on', function(eventName, listener) {
984996
var key = getEventString(eventName);
985997
if (!this._events[key]) { this._events[key] = []; }
986998
this._events[key].push({eventName: eventName, listener: listener, type: 'on'});
999+
if (key === 'pending') { this._startPending(); }
9871000
this.polling = true;
9881001
});
9891002

9901003
utils.defineProperty(Provider.prototype, 'once', function(eventName, listener) {
9911004
var key = getEventString(eventName);
9921005
if (!this._events[key]) { this._events[key] = []; }
9931006
this._events[key].push({eventName: eventName, listener: listener, type: 'once'});
1007+
if (key === 'pending') { this._startPending(); }
9941008
this.polling = true;
9951009
});
9961010

@@ -1015,7 +1029,11 @@ utils.defineProperty(Provider.prototype, 'emit', function(eventName) {
10151029
}
10161030
}
10171031

1018-
if (listeners.length === 0) { delete this._events[key]; }
1032+
if (listeners.length === 0) {
1033+
delete this._events[key];
1034+
if (key === 'pending') { this._stopPending(); }
1035+
}
1036+
10191037
if (this.listenerCount() === 0) { this.polling = false; }
10201038
});
10211039

@@ -1060,4 +1078,8 @@ utils.defineProperty(Provider.prototype, 'removeListener', function(eventName, l
10601078
if (this.listenerCount() === 0) { this.polling = false; }
10611079
});
10621080

1081+
utils.defineProperty(Provider, '_formatters', {
1082+
checkTransactionResponse: checkTransaction
1083+
});
1084+
10631085
module.exports = Provider;

0 commit comments

Comments
 (0)