Skip to content
This repository was archived by the owner on Feb 4, 2022. It is now read-only.

Commit 5c646cd

Browse files
authored
uses an empty array to represent a null filter parameter (#228)
* uses an empty array to represent a null filter parameter * Removes unnecesary imports * adds filters unit tests
1 parent fa276fa commit 5c646cd

File tree

6 files changed

+160
-3
lines changed

6 files changed

+160
-3
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# OS-specific files
2+
.DS_Store
3+
14
# Files and directories created by pub
25
.packages
36
.pub/

lib/src/browser/credentials.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'dart:typed_data';
66
import 'package:js/js.dart';
77
import 'package:web3dart/web3dart.dart';
88

9-
import '../../credentials.dart';
109
import '../../crypto.dart';
1110

1211
import 'dart_wrappers.dart';

lib/src/contracts/generated_contract.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'package:meta/meta.dart';
22

33
import '../../crypto.dart';
44
import '../../web3dart.dart';
5-
import 'deployed_contract.dart';
65

76
/// Base classes for generated contracts.
87
///

lib/src/core/filters.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,9 @@ class _EventFilter extends _Filter<FilterEvent> {
263263
encodedOptions['address'] = options.address?.hex;
264264
}
265265
if (options.topics != null) {
266-
encodedOptions['topics'] = options.topics;
266+
final topics = <dynamic>[];
267+
options.topics?.forEach((e) => topics.add(e.isEmpty ? null : e));
268+
encodedOptions['topics'] = topics;
267269
}
268270

269271
return encodedOptions;

test/core/event_filter_test.dart

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import 'package:test/test.dart';
2+
import 'package:web3dart/web3dart.dart';
3+
4+
import '../mock_client.dart';
5+
6+
void main() {
7+
const alice =
8+
'0x000000000000000000000000Dd611f2b2CaF539aC9e12CF84C09CB9bf81CA37F';
9+
const bob =
10+
'0x0000000000000000000000006c87E1a114C3379BEc929f6356c5263d62542C13';
11+
const contract = '0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d';
12+
13+
final testCases = [
14+
{
15+
'name': 'one topic',
16+
'input': [
17+
[alice]
18+
],
19+
'expected': [
20+
[alice]
21+
]
22+
},
23+
{
24+
'name': 'two topics one item',
25+
'input': [
26+
[alice, bob]
27+
],
28+
'expected': [
29+
[alice, bob]
30+
]
31+
},
32+
{
33+
'name': 'two topics two items',
34+
'input': [
35+
[alice],
36+
[bob]
37+
],
38+
'expected': [
39+
[alice],
40+
[bob]
41+
]
42+
},
43+
{
44+
'name': 'two topics first null',
45+
'input': [
46+
[],
47+
[bob]
48+
],
49+
'expected': [
50+
null,
51+
[bob]
52+
]
53+
},
54+
{
55+
'name': 'three topics first null',
56+
'input': [
57+
[],
58+
[alice],
59+
[bob]
60+
],
61+
'expected': [
62+
null,
63+
[alice],
64+
[bob]
65+
]
66+
},
67+
{
68+
'name': 'three topics second null',
69+
'input': [
70+
[alice],
71+
[],
72+
[bob]
73+
],
74+
'expected': [
75+
[alice],
76+
null,
77+
[bob]
78+
]
79+
}
80+
];
81+
82+
Future _runFilterTest(input, expected) async {
83+
final client = MockClient(expectAsync2((method, params) {
84+
expect(method, 'eth_getLogs');
85+
86+
// verify that the topics are sent to eth_getLogs in the correct format
87+
final actual = ((params as List)[0])['topics'];
88+
expect(actual, expected);
89+
90+
// return a valid response from eth_getLogs
91+
return [
92+
{'address': contract}
93+
];
94+
}));
95+
96+
final web3 = Web3Client('', client);
97+
addTearDown(web3.dispose);
98+
99+
// Dart typing will not allow an empty list to be added so when an empty
100+
// list is encountered, a list containing a single string is added and then
101+
// the single string in that list is removed.
102+
// The type is required to ensure `topics` is forced to List<List<String>>
103+
104+
// ignore: omit_local_variable_types
105+
final List<List<String>> topics = [];
106+
input.forEach((element) {
107+
if (element.length == 0) {
108+
topics.add(['dummy string element']);
109+
topics.last.remove('dummy string element');
110+
} else {
111+
topics.add(element as List<String>);
112+
}
113+
});
114+
115+
final filter = FilterOptions(
116+
fromBlock: const BlockNum.genesis(),
117+
toBlock: const BlockNum.current(),
118+
address: EthereumAddress.fromHex(contract),
119+
topics: topics);
120+
121+
await web3.getLogs(filter);
122+
}
123+
124+
// test each test case in the list of test cases
125+
for (final testCase in testCases) {
126+
test('filters test with ${testCase['name']}', () async {
127+
await _runFilterTest(testCase['input'], testCase['expected']);
128+
});
129+
}
130+
}

test/mock_client.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,30 @@ class MockClient extends BaseClient {
1111

1212
MockClient(this.handler);
1313

14+
@override
15+
Future<Response> post(Uri url,
16+
{Map<String, String>? headers, Object? body, Encoding? encoding}) async {
17+
if (body is! String) {
18+
fail('Invalid request, expected string as request body');
19+
}
20+
21+
final data = json.decode(body) as Map<String, dynamic>;
22+
if (data['jsonrpc'] != '2.0') {
23+
fail('Expected request to contain correct jsonrpc key');
24+
}
25+
26+
final id = data['id'];
27+
final method = data['method'] as String;
28+
final params = data['params'];
29+
final response = {
30+
'body': body,
31+
'id': id,
32+
'result': handler(method, params)
33+
};
34+
35+
return Response(json.encode(response), 200);
36+
}
37+
1438
@override
1539
Future<StreamedResponse> send(BaseRequest request) async {
1640
final data = await _jsonUtf8.decoder.bind(request.finalize()).first;

0 commit comments

Comments
 (0)