Line data Source code
1 : /*
2 : * Package : Ethereum
3 : * Author : S. Hamblett <steve.hamblett@linux.com>
4 : * Date : 06/011/2017
5 : * Copyright : S.Hamblett
6 : *
7 : * The Ethereum client package
8 : */
9 :
10 : part of ethereum;
11 :
12 : /// The Ethereum JSON-RPC client class.
13 : /// Further details of this interface and its API specification can be found at
14 : /// https://github.com/ethereum/wiki/wiki/JSON-RPC#web3_clientversion.
15 : /// The API calls return null if an ethereum error occurred.
16 : class Ethereum {
17 1 : Ethereum(this._networkAdapter) {
18 3 : rpcClient = new EthereumRpcClient(_networkAdapter);
19 : }
20 :
21 : Ethereum.withConnectionParameters(EthereumINetworkAdapter adapter,
22 : String hostname, String scheme,
23 : [port = defaultHttpPort])
24 1 : : _networkAdapter = adapter {
25 3 : rpcClient = new EthereumRpcClient(_networkAdapter);
26 1 : connectParameters(scheme, hostname, port);
27 : }
28 :
29 : /// Constants
30 : static const String rpcHttpScheme = 'http';
31 : static const String rpcWsScheme = 'ws';
32 :
33 : /// Defaults
34 : static const int defaultHttpPort = 8545;
35 : static const int defaultWsPort = 8546;
36 :
37 : /// Connection parameters
38 : int port = defaultHttpPort;
39 : String host;
40 : Uri _uri;
41 :
42 0 : Uri get uri => _uri;
43 :
44 : /// HTTP Adapter
45 : EthereumINetworkAdapter _networkAdapter;
46 :
47 0 : set httpAdapter(EthereumINetworkAdapter adapter) => _networkAdapter = adapter;
48 :
49 : /// Json RPC client
50 : EthereumRpcClient rpcClient;
51 :
52 : /// Last error
53 : EthereumError lastError = new EthereumError();
54 :
55 : /// Transmission id
56 2 : set id(int value) => rpcClient.resetTransmissionId(value);
57 :
58 4 : int get id => rpcClient.id;
59 :
60 : /// Connection methods
61 :
62 : //// Connect using a host string of the form http://thehost.com:1234,
63 : /// port is optional. Scheme must be http or ws
64 : void connectString(String hostname) {
65 : if (hostname == null) {
66 1 : throw new ArgumentError.notNull("Ethereum::connectString - hostname");
67 : }
68 1 : final Uri uri = Uri.parse(hostname);
69 1 : _validateUri(uri);
70 : }
71 :
72 : /// Connect using a URI, port is optional
73 : void connectUri(Uri uri) {
74 : if (uri == null) {
75 1 : throw new ArgumentError.notNull("Ethereum::connectUri - uri");
76 : }
77 1 : _validateUri(uri);
78 : }
79 :
80 : /// Connect by explicitly setting the connection parameters.
81 : /// Scheme must be either rpcScheme or rpcWsScheme
82 : void connectParameters(String scheme, String hostname, [int port]) {
83 : if (hostname == null) {
84 1 : throw new ArgumentError.notNull("Ethereum::connectParameters - hostname");
85 : }
86 3 : if ((scheme != rpcHttpScheme) && (scheme != rpcWsScheme)) {
87 1 : throw new FormatException(
88 1 : "Ethereum::connectParameters - invalid scheme $scheme");
89 : }
90 : int uriPort;
91 : if (port != null) {
92 : uriPort = port;
93 : }
94 2 : final Uri uri = new Uri(scheme: scheme, host: hostname, port: uriPort);
95 2 : _validateUri(uri);
96 : }
97 :
98 : void _validateUri(Uri puri) {
99 : // Must have a valid scheme which must be http, host and port
100 6 : if (puri.hasAuthority && (puri.host.isNotEmpty)) {
101 4 : host = puri.host;
102 : } else {
103 0 : throw new ArgumentError.value(
104 0 : puri.host, "Ethereum::_validateUri - invalid host");
105 : }
106 : Uri newUri = puri;
107 2 : if (!puri.hasPort) {
108 4 : if (puri.scheme == rpcHttpScheme) {
109 2 : newUri = puri.replace(port: defaultHttpPort);
110 : } else {
111 1 : newUri = puri.replace(port: defaultWsPort);
112 : }
113 : }
114 4 : port = newUri.port;
115 2 : _uri = newUri;
116 6 : rpcClient.uri = _uri;
117 : }
118 :
119 : /// Print errors, default is off
120 : bool printError = false;
121 :
122 : /// Error processing helper
123 : void _processError(String method, Map res) {
124 1 : final Map error = res[ethErrorKey];
125 6 : lastError.updateError(error['code'], error['message'], rpcClient.id);
126 1 : if (printError) {
127 4 : print("ERROR::$method - ${lastError.toString()}");
128 : }
129 : }
130 :
131 : /// API methods
132 :
133 : //// Client version
134 : Future<String> clientVersion() async {
135 : final String method = EthereumRpcMethods.web3ClientVersion;
136 3 : final res = await rpcClient.request(method);
137 1 : if (res.containsKey(ethResultKey)) {
138 1 : return res[ethResultKey];
139 : }
140 0 : _processError(method, res);
141 : return null;
142 0 : }
143 :
144 : /// Returns Keccak-256 (not the standardized SHA3-256) of the given data.
145 : Future<BigInteger> sha3(BigInteger data) async {
146 : if (data == null) {
147 1 : throw new ArgumentError.notNull("Ethereum::sha3 - data");
148 : }
149 : final String method = EthereumRpcMethods.web3Sha3;
150 2 : final List params = [EthereumUtilities.bigIntegerToHex(data)];
151 3 : final res = await rpcClient.request(method, params);
152 1 : if (res.containsKey(ethResultKey)) {
153 2 : return new BigInteger(res[ethResultKey]);
154 : }
155 0 : _processError(method, res);
156 : return null;
157 1 : }
158 :
159 : /// Net version
160 : Future<String> netVersion() async {
161 : final String method = EthereumRpcMethods.netVersion;
162 3 : final res = await rpcClient.request(method);
163 1 : if (res.containsKey(ethResultKey)) {
164 1 : return res[ethResultKey];
165 : }
166 0 : _processError(method, res);
167 : return null;
168 0 : }
169 :
170 : /// Net listening, true when listening
171 : Future<bool> netListening() async {
172 : final String method = EthereumRpcMethods.netListening;
173 3 : final res = await rpcClient.request(method);
174 1 : if (res.containsKey(ethResultKey)) {
175 1 : return res[ethResultKey];
176 : }
177 0 : _processError(method, res);
178 : return null;
179 0 : }
180 :
181 : /// Net peer count,
182 : Future<int> netPeerCount() async {
183 : final String method = EthereumRpcMethods.netPeerCount;
184 3 : final res = await rpcClient.request(method);
185 1 : if (res.containsKey(ethResultKey)) {
186 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
187 : }
188 0 : _processError(method, res);
189 : return null;
190 0 : }
191 :
192 : /// Protocol version
193 : Future<String> protocolVersion() async {
194 : final String method = EthereumRpcMethods.protocolVersion;
195 3 : final res = await rpcClient.request(method);
196 1 : if (res.containsKey(ethResultKey)) {
197 1 : return res[ethResultKey];
198 : }
199 0 : _processError(method, res);
200 : return null;
201 0 : }
202 :
203 : /// Sync status, an object with data about the sync status if syncing or false if not.
204 : Future<EthereumSyncStatus> syncStatus() async {
205 : final String method = EthereumRpcMethods.syncing;
206 3 : final res = await rpcClient.request(method);
207 1 : if (res.containsKey(ethResultKey)) {
208 1 : return new EthereumSyncStatus.fromMap(res);
209 : }
210 0 : _processError(method, res);
211 : return null;
212 0 : }
213 :
214 : /// The client coinbase address.
215 : Future<BigInteger> coinbaseAddress() async {
216 : final String method = EthereumRpcMethods.coinbaseAddress;
217 3 : final res = await rpcClient.request(method);
218 1 : if (res.containsKey(ethResultKey)) {
219 2 : return new BigInteger(res[ethResultKey]);
220 : }
221 0 : _processError(method, res);
222 : return null;
223 0 : }
224 :
225 : /// Mining, true when mining
226 : Future<bool> mining() async {
227 : final String method = EthereumRpcMethods.mining;
228 3 : final res = await rpcClient.request(method);
229 1 : if (res.containsKey(ethResultKey)) {
230 1 : return res[ethResultKey];
231 : }
232 0 : _processError(method, res);
233 : return null;
234 0 : }
235 :
236 : /// Hashrate, returns the number of hashes per second that the node is mining with.
237 : Future<int> hashrate() async {
238 : final String method = EthereumRpcMethods.hashrate;
239 3 : final res = await rpcClient.request(method);
240 1 : if (res.containsKey(ethResultKey)) {
241 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
242 : }
243 0 : _processError(method, res);
244 : return null;
245 0 : }
246 :
247 : /// The current price per gas in wei.
248 : Future<int> gasPrice() async {
249 : final String method = EthereumRpcMethods.gasPrice;
250 3 : final res = await rpcClient.request(method);
251 1 : if (res.containsKey(ethResultKey)) {
252 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
253 : }
254 0 : _processError(method, res);
255 : return null;
256 0 : }
257 :
258 : /// Accounts, a list of addresses owned by client.
259 : Future<List<BigInteger>> accounts() async {
260 : final String method = EthereumRpcMethods.accounts;
261 3 : final res = await rpcClient.request(method);
262 1 : if (res.containsKey(ethResultKey)) {
263 2 : return EthereumUtilities.hexToBigIntegerList(res[ethResultKey]);
264 : }
265 0 : _processError(method, res);
266 : return null;
267 0 : }
268 :
269 : /// Block number, the number of most recent block.
270 : Future<int> blockNumber() async {
271 : final String method = EthereumRpcMethods.blockNumber;
272 3 : final res = await rpcClient.request(method);
273 1 : if (res.containsKey(ethResultKey)) {
274 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
275 : }
276 0 : _processError(method, res);
277 : return null;
278 0 : }
279 :
280 : /// Get balance, the balance of the account of the given address.
281 : Future<int> getBalance(BigInteger accountNumber,
282 : EthereumDefaultBlock block) async {
283 : if (accountNumber == null) {
284 1 : throw new ArgumentError.notNull("Ethereum::getBalance - accountNumber");
285 : }
286 : if (block == null) {
287 1 : throw new ArgumentError.notNull("Ethereum::getBalance - block");
288 : }
289 : final String method = EthereumRpcMethods.balance;
290 1 : final String blockString = block.getSelection();
291 1 : final List params = [
292 1 : EthereumUtilities.bigIntegerToHex(accountNumber),
293 : blockString
294 : ];
295 3 : final res = await rpcClient.request(method, params);
296 1 : if (res.containsKey(ethResultKey)) {
297 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
298 : }
299 0 : _processError(method, res);
300 : return null;
301 1 : }
302 :
303 : /// Get Storage at, the value from a storage position at a given address.
304 : /// Parameters are the address of the storage, the integer position of the storage and
305 : // the default block parameter.
306 : Future<BigInteger> getStorageAt(BigInteger address, int pos,
307 : EthereumDefaultBlock block) async {
308 : if (address == null) {
309 1 : throw new ArgumentError.notNull("Ethereum::getStorageAt - address");
310 : }
311 : if (pos == null) {
312 1 : throw new ArgumentError.notNull("Ethereum::getStorageAt - pos");
313 : }
314 : if (block == null) {
315 1 : throw new ArgumentError.notNull("Ethereum::getStorageAt - block");
316 : }
317 : final String method = EthereumRpcMethods.storageAt;
318 1 : final String blockString = block.getSelection();
319 1 : final List params = [
320 1 : EthereumUtilities.bigIntegerToHex(address),
321 1 : EthereumUtilities.intToHex(pos),
322 : blockString
323 : ];
324 3 : final res = await rpcClient.request(method, params);
325 1 : if (res.containsKey(ethResultKey)) {
326 2 : return new BigInteger(res[ethResultKey]);
327 : }
328 1 : _processError(method, res);
329 : return null;
330 1 : }
331 :
332 : /// Transaction count, returns the number of transactions sent from an address.
333 : Future<int> getTransactionCount(int address,
334 : EthereumDefaultBlock block) async {
335 : if (address == null) {
336 1 : throw new ArgumentError.notNull(
337 : "Ethereum::getTransactionCount - address");
338 : }
339 : if (block == null) {
340 1 : throw new ArgumentError.notNull("Ethereum::getTransactionCount - block");
341 : }
342 : final String method = EthereumRpcMethods.transactionCount;
343 1 : final String blockString = block.getSelection();
344 2 : final List params = [EthereumUtilities.intToHex(address), blockString];
345 3 : final res = await rpcClient.request(method, params);
346 1 : if (res.containsKey(ethResultKey)) {
347 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
348 : }
349 0 : _processError(method, res);
350 : return null;
351 1 : }
352 :
353 : /// Block Transaction Count By Hash
354 : /// The number of transactions in a block from a block matching the given block hash.
355 : /// If the method returns null a count of 0 is returned, this is to distinguish between
356 : /// this and an error.
357 : Future<int> getBlockTransactionCountByHash(int blockHash) async {
358 : if (blockHash == null) {
359 1 : throw new ArgumentError.notNull(
360 : "Ethereum::getBlockTransactionCountByHash - blockHash");
361 : }
362 : final String method = EthereumRpcMethods.blockTransactionCountByHash;
363 2 : final List params = [EthereumUtilities.intToHex(blockHash)];
364 3 : final res = await rpcClient.request(method, params);
365 1 : if (res.containsKey(ethResultKey)) {
366 1 : if (res[ethResultKey] != null) {
367 0 : return EthereumUtilities.hexToInt(res[ethResultKey]);
368 : } else {
369 : return 0;
370 : }
371 : }
372 0 : _processError(method, res);
373 : return null;
374 1 : }
375 :
376 : /// Block Transaction Count By Number
377 : /// The number of transactions in a block matching the given block number.
378 : /// If the method returns null a count of 0 is returned, this is to distinguish between
379 : /// this and an error.
380 : Future<int> getBlockTransactionCountByNumber(
381 : EthereumDefaultBlock blockNumber) async {
382 : if (blockNumber == null) {
383 1 : throw new ArgumentError.notNull(
384 : "Ethereum::getBlockTransactionCountByNumber - blockNumber");
385 : }
386 : final String method = EthereumRpcMethods.blockTransactionCountByNumber;
387 1 : final String blockString = blockNumber.getSelection();
388 1 : final List params = [blockString];
389 3 : final res = await rpcClient.request(method, params);
390 1 : if (res.containsKey(ethResultKey)) {
391 1 : if (res[ethResultKey] != null) {
392 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
393 : } else {
394 : return 0;
395 : }
396 : }
397 0 : _processError(method, res);
398 : return null;
399 1 : }
400 :
401 : /// Block Uncle Count By Hash
402 : /// The number of uncles in a block from a block matching the given block hash.
403 : /// If the method returns null a count of 0 is returned, this is to distinguish between
404 : /// this and an error.
405 : Future<int> getUncleCountByHash(int blockHash) async {
406 : if (blockHash == null) {
407 1 : throw new ArgumentError.notNull(
408 : "Ethereum::getUncleCountByHash - blockHash");
409 : }
410 : final String method = EthereumRpcMethods.blockUncleCountByBlockHash;
411 2 : final List params = [EthereumUtilities.intToHex(blockHash)];
412 3 : final res = await rpcClient.request(method, params);
413 1 : if (res.containsKey(ethResultKey)) {
414 1 : if (res[ethResultKey] != null) {
415 0 : return EthereumUtilities.hexToInt(res[ethResultKey]);
416 : } else {
417 : return 0;
418 : }
419 : }
420 0 : _processError(method, res);
421 : return null;
422 1 : }
423 :
424 : /// Block Uncle Count By Number
425 : /// The number of uncles in a block matching the given block number.
426 : /// If the method returns null a count of 0 is returned, this is to distinguish between
427 : /// this and an error.
428 : Future<int> getUncleCountByNumber(EthereumDefaultBlock blockNumber) async {
429 : if (blockNumber == null) {
430 1 : throw new ArgumentError.notNull(
431 : "Ethereum::getUncleCountByNumber - blockNumber");
432 : }
433 : final String method = EthereumRpcMethods.blockUncleCountByBlockNumber;
434 1 : final String blockString = blockNumber.getSelection();
435 1 : final List params = [blockString];
436 3 : final res = await rpcClient.request(method, params);
437 1 : if (res.containsKey(ethResultKey)) {
438 1 : if (res[ethResultKey] != null) {
439 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
440 : } else {
441 : return 0;
442 : }
443 : }
444 0 : _processError(method, res);
445 : return null;
446 1 : }
447 :
448 : /// Get code, the code at the given address.
449 : Future<int> getCode(int address, EthereumDefaultBlock block) async {
450 : if (address == null) {
451 1 : throw new ArgumentError.notNull("Ethereum::getCode - address");
452 : }
453 : if (block == null) {
454 1 : throw new ArgumentError.notNull("Ethereum::getCode - block");
455 : }
456 : final String method = EthereumRpcMethods.code;
457 1 : final String blockString = block.getSelection();
458 2 : final List params = [EthereumUtilities.intToHex(address), blockString];
459 3 : final res = await rpcClient.request(method, params);
460 1 : if (res.containsKey(ethResultKey)) {
461 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
462 : }
463 0 : _processError(method, res);
464 : return null;
465 1 : }
466 :
467 : /// Sign
468 : /// The sign method calculates an Ethereum specific signature with:
469 : /// sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).
470 : /// Note the address to sign with must be unlocked.
471 : Future<int> sign(int account, int message) async {
472 : if (account == null) {
473 1 : throw new ArgumentError.notNull("Ethereum::sign - account");
474 : }
475 : if (message == null) {
476 1 : throw new ArgumentError.notNull("Ethereum::sign - message");
477 : }
478 : final String method = EthereumRpcMethods.sign;
479 1 : final List params = [
480 1 : EthereumUtilities.intToHex(account),
481 1 : EthereumUtilities.intToHex(message)
482 : ];
483 3 : final res = await rpcClient.request(method, params);
484 1 : if (res.containsKey(ethResultKey)) {
485 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
486 : }
487 0 : _processError(method, res);
488 : return null;
489 1 : }
490 :
491 : /// Send transaction
492 : /// Creates new message call transaction or a contract creation, if the data field contains code.
493 : /// address: The address the transaction is sent from.
494 : /// to: (optional when creating new contract) The address the transaction is directed to.
495 : /// gas: (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas.
496 : /// gasPrice: (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas
497 : /// value: (optional) Integer of the value send with this transaction
498 : /// data: The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI
499 : /// nonce: optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
500 : /// Returns the transaction hash, or the zero hash if the transaction is not yet available.
501 : Future<int> sendTransaction(int address, int data,
502 : {int to, int gas: 9000, int gasPrice, int value, int nonce}) async {
503 : if (address == null) {
504 1 : throw new ArgumentError.notNull("Ethereum::sendTransaction - address");
505 : }
506 : if (data == null) {
507 1 : throw new ArgumentError.notNull("Ethereum::sendTransaction - data");
508 : }
509 : final String method = EthereumRpcMethods.sendTransaction;
510 1 : Map<String, String> paramBlock = {
511 1 : "from": EthereumUtilities.intToHex(address),
512 1 : "to": to == null ? null : EthereumUtilities.intToHex(to),
513 1 : "gas": EthereumUtilities.intToHex(gas),
514 : "gasPrice":
515 1 : gasPrice == null ? null : EthereumUtilities.intToHex(gasPrice),
516 1 : "value": value == null ? null : EthereumUtilities.intToHex(value),
517 1 : "data": EthereumUtilities.intToHex(data),
518 1 : "nonce": nonce == null ? null : EthereumUtilities.intToHex(nonce)
519 : };
520 1 : paramBlock = EthereumUtilities.removeNull(paramBlock);
521 1 : final dynamic params = [paramBlock];
522 3 : final res = await rpcClient.request(method, params);
523 1 : if (res.containsKey(ethResultKey)) {
524 0 : return EthereumUtilities.hexToInt(res[ethResultKey]);
525 : }
526 1 : _processError(method, res);
527 : return null;
528 1 : }
529 :
530 : /// Send raw transaction
531 : /// Creates new message call transaction or a contract creation for signed transactions.
532 : /// Takes the signed transaction data.
533 : /// Returns the transaction hash, or the zero hash if the transaction is not yet available.
534 : Future<int> sendRawTransaction(int signedTransaction) async {
535 : if (signedTransaction == null) {
536 1 : throw new ArgumentError.notNull(
537 : "Ethereum::sendRawTransaction - signedTransaction");
538 : }
539 : final String method = EthereumRpcMethods.sendRawTransaction;
540 2 : final dynamic params = [EthereumUtilities.intToHex(signedTransaction)];
541 3 : final res = await rpcClient.request(method, params);
542 1 : if (res.containsKey(ethResultKey)) {
543 0 : return EthereumUtilities.hexToInt(res[ethResultKey]);
544 : }
545 1 : _processError(method, res);
546 : return null;
547 1 : }
548 :
549 : /// Call
550 : /// Executes a new message call immediately without creating a transaction on the block chain.
551 : /// address: The address the transaction is sent to.
552 : /// from: (optional) The address the transaction is sent from.
553 : /// gas: (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas,
554 : /// but this parameter may be needed by some executions.
555 : /// gasPrice: (optional) Integer of the gasPrice used for each paid gas
556 : /// value: (optional) Integer of the value send with this transaction
557 : /// data: (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI
558 : /// block: default block parameter
559 : /// Returns the return value of executed contract.
560 : Future<int> call(int address, EthereumDefaultBlock block,
561 : {int from, int gas, int gasPrice, int value, int data}) async {
562 : if (address == null) {
563 1 : throw new ArgumentError.notNull("Ethereum::call - address");
564 : }
565 : if (block == null) {
566 1 : throw new ArgumentError.notNull("Ethereum::call - block");
567 : }
568 : final String method = EthereumRpcMethods.call;
569 1 : final String blockString = block.getSelection();
570 1 : Map<String, String> paramBlock = {
571 1 : "from": from == null ? null : EthereumUtilities.intToHex(from),
572 1 : "to": EthereumUtilities.intToHex(address),
573 1 : "gas": gas == null ? null : EthereumUtilities.intToHex(gas),
574 : "gasPrice":
575 1 : gasPrice == null ? null : EthereumUtilities.intToHex(gasPrice),
576 1 : "value": value == null ? null : EthereumUtilities.intToHex(value),
577 1 : "data": data == null ? null : EthereumUtilities.intToHex(data)
578 : };
579 1 : paramBlock = EthereumUtilities.removeNull(paramBlock);
580 1 : final dynamic params = [paramBlock, blockString];
581 3 : final res = await rpcClient.request(method, params);
582 1 : if (res.containsKey(ethResultKey)) {
583 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
584 : }
585 1 : _processError(method, res);
586 : return null;
587 1 : }
588 :
589 : /// Estimate gas
590 : /// Makes a call or transaction, which won't be added to the blockchain and returns the used gas,
591 : /// which can be used for estimating the used gas.
592 : /// See eth_call parameters, expect that all properties are optional. If no gas limit is specified geth
593 : /// uses the block gas limit from the pending block as an upper bound. As a result the returned estimate
594 : /// might not be enough to executed the call/transaction when the amount of gas is higher than the
595 : /// pending block gas limit.
596 : /// Returns the amount of gas used.
597 : Future<int> estimateGas({int address,
598 : int from,
599 : int gas,
600 : int gasPrice,
601 : int value,
602 : int data}) async {
603 1 : Map<String, String> paramBlock = {
604 1 : "from": from == null ? null : EthereumUtilities.intToHex(from),
605 1 : "to": address == null ? null : EthereumUtilities.intToHex(address),
606 1 : "gas": gas == null ? null : EthereumUtilities.intToHex(gas),
607 : "gasPrice":
608 1 : gasPrice == null ? null : EthereumUtilities.intToHex(gasPrice),
609 1 : "value": value == null ? null : EthereumUtilities.intToHex(value),
610 1 : "data": data == null ? null : EthereumUtilities.intToHex(data)
611 : };
612 1 : paramBlock = EthereumUtilities.removeNull(paramBlock);
613 1 : final dynamic params = [paramBlock];
614 : final String method = EthereumRpcMethods.estimateGas;
615 3 : final res = await rpcClient.request(method, params);
616 1 : if (res.containsKey(ethResultKey)) {
617 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
618 : }
619 0 : _processError(method, res);
620 : return null;
621 0 : }
622 :
623 : /// Get block by hash
624 : /// Returns information about a block by hash
625 : /// Hash of a block and a boolean, if true it returns the full transaction objects,
626 : /// if false only the hashes of the transactions, defaults to true.
627 : /// Returns A block object, or null when no block was found :
628 : Future<EthereumBlock> getBlockByHash(BigInteger blockHash,
629 : [bool full = true]) async {
630 : if (blockHash == null) {
631 1 : throw new ArgumentError.notNull("Ethereum::getBlockByHash - blockHash");
632 : }
633 2 : final dynamic params = [EthereumUtilities.bigIntegerToHex(blockHash), full];
634 : final String method = EthereumRpcMethods.getBlockByHash;
635 3 : final res = await rpcClient.request(method, params);
636 1 : if (res.containsKey(ethResultKey)) {
637 2 : return new EthereumBlock.fromMap(res[ethResultKey]);
638 : }
639 0 : _processError(method, res);
640 : return null;
641 1 : }
642 :
643 : /// Get block by number
644 : /// Returns information about a block by block number.
645 : /// blockNumber - defualt block parameter
646 : /// as in the default block parameter.
647 : /// A boolean, if true it returns the full transaction objects,
648 : /// if false only the hashes of the transactions, defaults to true.
649 : /// Returns See getBlockByHash
650 : Future<EthereumBlock> getBlockByNumber(EthereumDefaultBlock blockNumber,
651 : [bool full = true]) async {
652 : if (blockNumber == null) {
653 1 : throw new ArgumentError.notNull(
654 : "Ethereum::getBlockByNumber - blockNumber");
655 : }
656 1 : final String blockString = blockNumber.getSelection();
657 1 : final dynamic params = [blockString, full];
658 : final String method = EthereumRpcMethods.getBlockByNumber;
659 3 : final res = await rpcClient.request(method, params);
660 1 : if (res.containsKey(ethResultKey)) {
661 2 : return new EthereumBlock.fromMap(res[ethResultKey]);
662 : }
663 0 : _processError(method, res);
664 : return null;
665 1 : }
666 :
667 : /// Get transaction by hash
668 : /// Returns the information about a transaction requested by transaction hash.
669 : /// Hash of a transaction
670 : /// Returns a transaction object, or null when no transaction was found:
671 : Future<EthereumTransaction> getTransactionByHash(BigInteger hash) async {
672 : if (hash == null) {
673 1 : throw new ArgumentError.notNull("Ethereum::getTransactionByHash - hash");
674 : }
675 2 : final dynamic params = [EthereumUtilities.bigIntegerToHex(hash)];
676 : final String method = EthereumRpcMethods.getTransactionByHash;
677 3 : final res = await rpcClient.request(method, params);
678 1 : if (res.containsKey(ethResultKey)) {
679 2 : return new EthereumTransaction.fromMap(res[ethResultKey]);
680 : }
681 0 : _processError(method, res);
682 : return null;
683 1 : }
684 :
685 : /// Get transaction by block hash and index.
686 : /// Returns information about a transaction by block hash and transaction index position.
687 : /// Hash of a block and integer of the transaction index position.
688 : /// Returns see getTransactionByHash.
689 : Future<EthereumTransaction> getTransactionByBlockHashAndIndex(
690 : BigInteger blockHash, int index) async {
691 : if (blockHash == null) {
692 1 : throw new ArgumentError.notNull(
693 : "Ethereum::getTransactionByBlockHashAndIndex - blockHash");
694 : }
695 : if (index == null) {
696 1 : throw new ArgumentError.notNull(
697 : "Ethereum::getTransactionByBlockHashAndIndex - index");
698 : }
699 1 : final dynamic params = [
700 1 : EthereumUtilities.bigIntegerToHex(blockHash),
701 1 : EthereumUtilities.intToHex(index)
702 : ];
703 : final String method = EthereumRpcMethods.getTransactionByBlockHashAndIndex;
704 3 : final res = await rpcClient.request(method, params);
705 1 : if (res.containsKey(ethResultKey)) {
706 2 : return new EthereumTransaction.fromMap(res[ethResultKey]);
707 : }
708 0 : _processError(method, res);
709 : return null;
710 1 : }
711 :
712 : /// Get transaction by block number and index.
713 : /// Returns information about a transaction by block number and transaction index position.
714 : /// A block number as in the default block parameter.
715 : /// Returns see getTransactionByHash.
716 : Future<EthereumTransaction> getTransactionByBlockNumberAndIndex(
717 : EthereumDefaultBlock blockNumber, int index) async {
718 : if (blockNumber == null) {
719 1 : throw new ArgumentError.notNull(
720 : "Ethereum::getTransactionByBlockNumberAndIndex - blockNumber");
721 : }
722 : if (index == null) {
723 1 : throw new ArgumentError.notNull(
724 : "Ethereum::getTransactionByBlockNumberAndIndex - index");
725 : }
726 1 : final String blockNumberString = blockNumber.getSelection();
727 1 : final dynamic params = [
728 : blockNumberString,
729 1 : EthereumUtilities.intToHex(index)
730 : ];
731 : final String method =
732 : EthereumRpcMethods.getTransactionByBlockNumberAndIndex;
733 3 : final res = await rpcClient.request(method, params);
734 1 : if (res.containsKey(ethResultKey)) {
735 2 : return new EthereumTransaction.fromMap(res[ethResultKey]);
736 : }
737 0 : _processError(method, res);
738 : return null;
739 1 : }
740 :
741 : /// Get transaction receipt
742 : /// Returns the receipt of a transaction by transaction hash.
743 : /// Note That the receipt is not available for pending transactions.
744 : /// Hash of a transaction
745 : /// Returns a transaction receipt object, or null when no receipt was found:
746 : Future<EthereumTransactionReceipt> getTransactionReceipt(
747 : BigInteger transactionHash) async {
748 : if (transactionHash == null) {
749 1 : throw new ArgumentError.notNull(
750 : "Ethereum::getTransactionReceipt - transactionHash");
751 : }
752 2 : final dynamic params = [EthereumUtilities.bigIntegerToHex(transactionHash)];
753 : final String method = EthereumRpcMethods.getTransactionReceipt;
754 3 : final res = await rpcClient.request(method, params);
755 1 : if (res.containsKey(ethResultKey)) {
756 2 : return new EthereumTransactionReceipt.fromMap(res[ethResultKey]);
757 : }
758 0 : _processError(method, res);
759 : return null;
760 1 : }
761 :
762 : /// Get uncle by block hash and index.
763 : /// Returns information about an uncle by block hash and uncle index position.
764 : /// Note: An uncle doesn't contain individual transactions.
765 : /// Hash of a block and integer of the uncle index position.
766 : /// Returns see getBlockByHash.
767 : Future<EthereumBlock> getUncleByBlockHashAndIndex(BigInteger blockHash,
768 : int index) async {
769 : if (blockHash == null) {
770 1 : throw new ArgumentError.notNull(
771 : "Ethereum::getUncleByBlockHashAndIndex - blockHash");
772 : }
773 : if (index == null) {
774 1 : throw new ArgumentError.notNull(
775 : "Ethereum::getUncleByBlockHashAndIndex - index");
776 : }
777 1 : final dynamic params = [
778 1 : EthereumUtilities.bigIntegerToHex(blockHash),
779 1 : EthereumUtilities.intToHex(index)
780 : ];
781 : final String method = EthereumRpcMethods.getUncleByBlockHashAndIndex;
782 3 : final res = await rpcClient.request(method, params);
783 1 : if (res.containsKey(ethResultKey)) {
784 2 : return new EthereumBlock.fromMap(res[ethResultKey]);
785 : }
786 0 : _processError(method, res);
787 : return null;
788 1 : }
789 :
790 : /// Get uncle by block number and index.
791 : /// Returns information about an uncle by block number and uncle index position.
792 : /// Note: An uncle doesn't contain individual transactions.
793 : /// A block number as in the default block parameter.
794 : /// Returns see getBlockByHash.
795 : Future<EthereumBlock> getUncleByBlockNumberAndIndex(
796 : EthereumDefaultBlock blockNumber,
797 : int index) async {
798 : if (blockNumber == null) {
799 1 : throw new ArgumentError.notNull(
800 : "Ethereum::getUncleByBlockNumberAndIndex - blockNumber");
801 : }
802 : if (index == null) {
803 1 : throw new ArgumentError.notNull(
804 : "Ethereum::getUncleByBlockNumberAndIndex - index");
805 : }
806 1 : final String blockNumberString = blockNumber.getSelection();
807 1 : final dynamic params = [
808 : blockNumberString,
809 1 : EthereumUtilities.intToHex(index)
810 : ];
811 : final String method = EthereumRpcMethods.getUncleByBlockNumberAndIndex;
812 3 : final res = await rpcClient.request(method, params);
813 1 : if (res.containsKey(ethResultKey)) {
814 2 : return new EthereumBlock.fromMap(res[ethResultKey]);
815 : }
816 0 : _processError(method, res);
817 : return null;
818 1 : }
819 :
820 : /// New filter
821 : /// Creates a filter object, based on filter options, to notify when the state changes (logs).
822 : /// To check if the state has changed, call getFilterChanges.
823 : /// note on specifying topic filters:
824 : /// Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters:
825 : /// [] "anything"
826 : /// ['A'] "A in first position (and anything after)"
827 : /// [null, B] "anything in first position AND B in second position (and anything after)"
828 : /// [A, B] "A in first position AND B in second position (and anything after)"
829 : /// [[A, B], [A, B]] "(A OR B) in first position AND (A OR B) in second position (and anything after)"
830 : /// fromBlock: - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending",
831 : /// "earliest" for not yet mined transactions.
832 : /// toBlock: - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not
833 : /// yet mined transactions.
834 : /// address: - (optional) Contract address or a list of addresses from which logs should originate.
835 : /// topics: - (optional) topics. Topics are order-dependent.
836 : /// Note: the user must build this structure using the utilities in the EthereumUtilities class. See the Ethereum
837 : /// Wiki RPC page for examples.
838 : /// Returns a filter id.
839 : Future<int> newFilter({EthereumDefaultBlock fromBlock,
840 : EthereumDefaultBlock toBlock,
841 : dynamic address,
842 : List<BigInteger> topics}) async {
843 1 : final String fromBlockString = fromBlock.getSelection();
844 1 : final String toBlockString = toBlock.getSelection();
845 1 : final Map params = {"toBlock": toBlockString, "fromBlock": fromBlockString};
846 : if (address != null) {
847 1 : if (address is List) {
848 : final List<String> addresses =
849 1 : EthereumUtilities.bigIntegerToHexList(address);
850 1 : params["address"] = addresses;
851 : } else {
852 2 : params["address"] = (EthereumUtilities.bigIntegerToHex(address));
853 : }
854 : }
855 : if (topics != null) {
856 2 : params["topics"] = EthereumUtilities.bigIntegerToHexList(topics);
857 : }
858 1 : final List paramBlock = [params];
859 : final String method = EthereumRpcMethods.newFilter;
860 3 : final res = await rpcClient.request(method, paramBlock);
861 1 : if (res.containsKey(ethResultKey)) {
862 0 : return EthereumUtilities.hexToInt(res[ethResultKey]);
863 : }
864 1 : _processError(method, res);
865 : return null;
866 0 : }
867 :
868 : /// New block filter
869 : /// Creates a filter in the node, to notify when a new block arrives.
870 : /// To check if the state has changed, call getFilterChanges.
871 : /// Returns a filter id.
872 : Future<int> newBlockFilter() async {
873 1 : final List params = [];
874 : final String method = EthereumRpcMethods.newBlockFilter;
875 3 : final res = await rpcClient.request(method, params);
876 1 : if (res.containsKey(ethResultKey)) {
877 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
878 : }
879 0 : _processError(method, res);
880 : return null;
881 0 : }
882 :
883 : /// New pending transaction filter
884 : /// Creates a filter in the node, to notify when a new pending transaction arrives.
885 : /// To check if the state has changed, call getFilterChanges.
886 : /// Returns a filter id.
887 : Future<int> newPendingTransactionFilter() async {
888 1 : final List params = [];
889 : final String method = EthereumRpcMethods.newPendingTransactionFilter;
890 3 : final res = await rpcClient.request(method, params);
891 1 : if (res.containsKey(ethResultKey)) {
892 2 : return EthereumUtilities.hexToInt(res[ethResultKey]);
893 : }
894 0 : _processError(method, res);
895 : return null;
896 0 : }
897 :
898 : /// Uninstall filter
899 : /// Uninstalls a filter with given id. Should always be called when watch is no longer needed.
900 : /// Additionally Filters timeout when they aren't requested with getFilterChanges for a period of time.
901 : /// Filter id
902 : /// Returns true if the filter was successfully uninstalled, otherwise false.
903 : Future<bool> uninstallFilter(int filterId) async {
904 : if (filterId == null) {
905 1 : throw new ArgumentError.notNull("Ethereum::uninstallFilter - filterId");
906 : }
907 2 : final List params = [EthereumUtilities.intToHex(filterId)];
908 : final String method = EthereumRpcMethods.uninstallFilter;
909 3 : final res = await rpcClient.request(method, params);
910 1 : if (res.containsKey(ethResultKey)) {
911 1 : return res[ethResultKey];
912 : }
913 0 : _processError(method, res);
914 : return null;
915 1 : }
916 :
917 : /// Get filter changes
918 : /// Polling method for a filter, which returns an list of logs which occurred since last poll.
919 : /// Filter Id
920 : /// Returns an EthereumFilter object or null
921 : Future<EthereumFilter> getFilterChanges(int filterId) async {
922 : if (filterId == null) {
923 1 : throw new ArgumentError.notNull("Ethereum::getFilterChanges - filterId");
924 : }
925 2 : final List params = [EthereumUtilities.intToHex(filterId)];
926 : final String method = EthereumRpcMethods.getFilterChanges;
927 3 : final res = await rpcClient.request(method, params);
928 1 : if (res.containsKey(ethResultKey)) {
929 0 : return new EthereumFilter.fromMap(res[ethResultKey]);
930 : }
931 1 : _processError(method, res);
932 : return null;
933 1 : }
934 :
935 : /// Get filter logs
936 : /// Filter Id
937 : /// Returns see getFilterChanges
938 : Future<EthereumFilter> getFilterLogs(int filterId) async {
939 : if (filterId == null) {
940 1 : throw new ArgumentError.notNull("Ethereum::getFilterLogs - filterId");
941 : }
942 2 : final List params = [EthereumUtilities.intToHex(filterId)];
943 : final String method = EthereumRpcMethods.getFilterLogs;
944 3 : final res = await rpcClient.request(method, params);
945 1 : if (res.containsKey(ethResultKey)) {
946 0 : return new EthereumFilter.fromMap(res[ethResultKey]);
947 : }
948 1 : _processError(method, res);
949 : return null;
950 1 : }
951 :
952 : /// Get logs
953 : /// The filter definition, see newFilter parameters.
954 : /// Returns see getFilterChanges
955 : Future<EthereumFilter> getLogs({EthereumDefaultBlock fromBlock,
956 : EthereumDefaultBlock toBlock,
957 : dynamic address,
958 : List topics}) async {
959 1 : final String fromBlockString = fromBlock.getSelection();
960 1 : final String toBlockString = toBlock.getSelection();
961 1 : final Map params = {"toBlock": toBlockString, "fromBlock": fromBlockString};
962 : if (address != null) {
963 1 : if (address is List) {
964 : final List<String> addresses =
965 0 : EthereumUtilities.bigIntegerToHexList(address);
966 0 : params["address"] = addresses;
967 : } else {
968 2 : params["address"] = (EthereumUtilities.bigIntegerToHex(address));
969 : }
970 : }
971 : if (topics != null) {
972 2 : params["topics"] = EthereumUtilities.bigIntegerToHexList(topics);
973 : }
974 1 : final List paramBlock = [params];
975 : final String method = EthereumRpcMethods.getLogs;
976 3 : final res = await rpcClient.request(method, paramBlock);
977 1 : if (res.containsKey(ethResultKey)) {
978 0 : return new EthereumFilter.fromMap(res[ethResultKey]);
979 : }
980 1 : _processError(method, res);
981 : return null;
982 0 : }
983 :
984 : /// Get work
985 : /// Returns the hash of the current block, the seedHash, and the boundary condition to be met ("target").
986 : /// Returns an EthereumWork object or null
987 : Future<EthereumWork> getWork() async {
988 1 : final List paramBlock = [];
989 : final String method = EthereumRpcMethods.getWork;
990 3 : final res = await rpcClient.request(method, paramBlock);
991 1 : if (res.containsKey(ethResultKey)) {
992 2 : return new EthereumWork.fromList(res[ethResultKey]);
993 : }
994 0 : _processError(method, res);
995 : return null;
996 0 : }
997 :
998 : /// Submit work
999 : /// Used for submitting a proof-of-work solution.
1000 : /// The nonce found
1001 : /// The header's pow-hash
1002 : /// The mix digest
1003 : /// Returns true if the provided solution is valid, otherwise false.
1004 : Future<bool> submitWork(BigInteger nonce, BigInteger powHash,
1005 : BigInteger digest) async {
1006 : if (nonce == null) {
1007 1 : throw new ArgumentError.notNull("Ethereum::submitWork - nonce");
1008 : }
1009 : if (powHash == null) {
1010 1 : throw new ArgumentError.notNull("Ethereum::submitWork - powHash");
1011 : }
1012 : if (digest == null) {
1013 1 : throw new ArgumentError.notNull("Ethereum::submitWork - digest");
1014 : }
1015 1 : final List params = [
1016 1 : EthereumUtilities.bigIntegerToHex(nonce),
1017 1 : EthereumUtilities.bigIntegerToHex(powHash),
1018 1 : EthereumUtilities.bigIntegerToHex(digest)
1019 : ];
1020 : final String method = EthereumRpcMethods.submitWork;
1021 3 : final res = await rpcClient.request(method, params);
1022 1 : if (res.containsKey(ethResultKey)) {
1023 1 : return res[ethResultKey];
1024 : }
1025 0 : _processError(method, res);
1026 : return null;
1027 1 : }
1028 :
1029 : /// Submit hash rate
1030 : /// Used for submitting mining hashrate.
1031 : /// Hash rate
1032 : /// Id, a random hexadecimal(32 bytes) string identifying the client
1033 : /// Returns true if submitting went through successfully and false otherwise.
1034 : Future<bool> submitHashrate(BigInteger hashRate, String id) async {
1035 : if (hashRate == null) {
1036 1 : throw new ArgumentError.notNull("Ethereum::submitHashRate - hashRate");
1037 : }
1038 : if (id == null) {
1039 1 : throw new ArgumentError.notNull("Ethereum::submitHashRate - id");
1040 : }
1041 2 : final List params = [EthereumUtilities.bigIntegerToHex(hashRate), id];
1042 : final String method = EthereumRpcMethods.submitHashrate;
1043 3 : final res = await rpcClient.request(method, params);
1044 1 : if (res.containsKey(ethResultKey)) {
1045 1 : return res[ethResultKey];
1046 : }
1047 0 : _processError(method, res);
1048 : return null;
1049 1 : }
1050 :
1051 : /// SHH version
1052 : /// Returns the current whisper protocol version.
1053 : Future<String> shhVersion() async {
1054 1 : final List params = [];
1055 : final String method = EthereumRpcMethods.shhVersion;
1056 3 : final res = await rpcClient.request(method, params);
1057 1 : if (res.containsKey(ethResultKey)) {
1058 1 : return res[ethResultKey];
1059 : }
1060 0 : _processError(method, res);
1061 : return null;
1062 0 : }
1063 :
1064 : /// SHH post
1065 : /// Sends a whisper message
1066 : /// from: - (optional) The identity of the sender.
1067 : /// to: - (optional) The identity of the receiver. When present whisper will encrypt the message so that only
1068 : /// the receiver can decrypt it.
1069 : /// topics: - List of topics, for the receiver to identify messages.
1070 : /// payload: - The payload of the message.
1071 : /// priority: - The integer of the priority in a range from ... (?).
1072 : /// ttl: - integer of the time to live in seconds.
1073 : /// Returns true if the message was send, otherwise false.
1074 : Future<bool> shhPost(List<BigInteger> topics, BigInteger payload,
1075 : int priority, int ttl,
1076 : {BigInteger to, BigInteger from}) async {
1077 : if (topics == null) {
1078 1 : throw new ArgumentError.notNull("Ethereum::shhPost - topics");
1079 : }
1080 : if (payload == null) {
1081 1 : throw new ArgumentError.notNull("Ethereum::shhPost - payload");
1082 : }
1083 : if (priority == null) {
1084 1 : throw new ArgumentError.notNull("Ethereum::shhPost - priority");
1085 : }
1086 : if (ttl == null) {
1087 1 : throw new ArgumentError.notNull("Ethereum::shhPost - ttl");
1088 : }
1089 1 : Map<String, dynamic> params = {
1090 1 : "topics": EthereumUtilities.bigIntegerToHexList(topics),
1091 1 : "payload": EthereumUtilities.bigIntegerToHex(payload),
1092 1 : "priority": EthereumUtilities.intToHex(priority),
1093 : "ttl": ttl,
1094 1 : "to": EthereumUtilities.bigIntegerToHex(to),
1095 1 : "from": EthereumUtilities.bigIntegerToHex(from)
1096 : };
1097 1 : params = EthereumUtilities.removeNull(params);
1098 1 : final List paramBlock = [params];
1099 : final String method = EthereumRpcMethods.shhPost;
1100 3 : final res = await rpcClient.request(method, paramBlock);
1101 1 : if (res.containsKey(ethResultKey)) {
1102 0 : return res[ethResultKey];
1103 : }
1104 1 : _processError(method, res);
1105 : return null;
1106 1 : }
1107 : }
|