From 824489bfeee313fbc91f1028e1dce8b775658bf7 Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 13 Jan 2021 15:08:10 +0530 Subject: [PATCH 1/6] basic function are done for depoy a contract --- example/lib/main.dart | 130 +++++++++++++++-------- example/pubspec.lock | 28 +++++ lib/chain/tezos/tezos_language_util.dart | 30 ++++++ lib/chain/tezos/tezos_message_codec.dart | 32 ++++++ lib/chain/tezos/tezos_node_writer.dart | 71 +++++++++++++ lib/models/operation_model.dart | 36 +++++-- lib/src/tezster_dart.dart | 46 ++++++++ lib/tezster_dart.dart | 3 + lib/types/tezos/tezos_chain_types.dart | 5 + pubspec.lock | 28 +++++ pubspec.yaml | 1 + 11 files changed, 354 insertions(+), 56 deletions(-) create mode 100644 lib/chain/tezos/tezos_language_util.dart create mode 100644 lib/types/tezos/tezos_chain_types.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index e5cb99d..12427b9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -18,53 +18,93 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { tezosWalletUtil() async { - //Generate mnemonic - String mnemonic = TezsterDart - .generateMnemonic(); // strength is optional, by default it's 256 ==> Generates 24 words. - print("mnemonic ===> $mnemonic"); - //mnemonic ===> 24 random words, [If strength parameter is changed the words length differs.] - - //Generate keys from mnemonic - List keys = await TezsterDart.getKeysFromMnemonic( - mnemonic: - "luxury bulb roast timber sense stove sugar sketch goddess host meadow decorate gather salmon funny person canoe daring machine network camp moment wrong dice", - ); - print("keys ===> $keys"); - //keys ===> [privateKey, publicKey, publicKeyHash] - //Accessing: private key ===> keys[0] | public key ===> keys[1] | public Key Hash ===> identity[2] all of type string - - //Create / Unlock identity from mnemonic and passphrase. - List identity = await TezsterDart.getKeysFromMnemonicAndPassphrase( - mnemonic: - "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", - passphrase: "5tjpU0cimq", - ); - print("identity ===> $identity"); - // identityWithMnemonic ===> [privateKey, publicKey, publicKeyHash] - // Accessing: private key ===> identity[0] | public key ===> identity[1] | public Key Hash ===> identity[2] all of type string. - - //Sign operation with public-Key and forged operation - List signOpGrp = await TezsterDart.signOperationGroup( - privateKey: - "edskRdVS5H9YCRAG8yqZkX2nUTbGcaDqjYgopkJwRuPUnYzCn3t9ZGksncTLYe33bFjq29pRhpvjQizCCzmugMGhJiXezixvdC", - forgedOperation: - "713cb068fe3ac078351727eb5c34279e22b75b0cf4dc0a8d3d599e27031db136040cb9f9da085607c05cac1ca4c62a3f3cfb8146aa9b7f631e52f877a1d363474404da8130b0b940ee", + // //Generate mnemonic + // String mnemonic = TezsterDart + // .generateMnemonic(); // strength is optional, by default it's 256 ==> Generates 24 words. + // print("mnemonic ===> $mnemonic"); + // //mnemonic ===> 24 random words, [If strength parameter is changed the words length differs.] + + // //Generate keys from mnemonic + // List keys = await TezsterDart.getKeysFromMnemonic( + // mnemonic: + // "luxury bulb roast timber sense stove sugar sketch goddess host meadow decorate gather salmon funny person canoe daring machine network camp moment wrong dice", + // ); + // print("keys ===> $keys"); + // //keys ===> [privateKey, publicKey, publicKeyHash] + // //Accessing: private key ===> keys[0] | public key ===> keys[1] | public Key Hash ===> identity[2] all of type string + + // //Create / Unlock identity from mnemonic and passphrase. + // List identity = await TezsterDart.getKeysFromMnemonicAndPassphrase( + // mnemonic: + // "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", + // passphrase: "5tjpU0cimq", + // ); + // print("identity ===> $identity"); + // // identityWithMnemonic ===> [privateKey, publicKey, publicKeyHash] + // // Accessing: private key ===> identity[0] | public key ===> identity[1] | public Key Hash ===> identity[2] all of type string. + + // //Sign operation with public-Key and forged operation + // List signOpGrp = await TezsterDart.signOperationGroup( + // privateKey: + // "edskRdVS5H9YCRAG8yqZkX2nUTbGcaDqjYgopkJwRuPUnYzCn3t9ZGksncTLYe33bFjq29pRhpvjQizCCzmugMGhJiXezixvdC", + // forgedOperation: + // "713cb068fe3ac078351727eb5c34279e22b75b0cf4dc0a8d3d599e27031db136040cb9f9da085607c05cac1ca4c62a3f3cfb8146aa9b7f631e52f877a1d363474404da8130b0b940ee", + // ); + // print("signOperationGroup ===> $signOpGrp"); + // //signOperationGroup ===> [hexSignature, signedOpBytes] + // //Accessing: hex signature ===> signOpGrp[0] | signed Operation bytes ===> signOpGrp[1] all of type string + + // //Unlock fundraiser identity. + // List identityFundraiser = + // await TezsterDart.unlockFundraiserIdentity( + // mnemonic: + // "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", + // email: "lkbpoife.tobqgidu@tezos.example.org", + // passphrase: "5tjpU0cimq", + // ); + // print("identityFundraiser ===> $identityFundraiser"); + // //identityFundraiser ===> [privateKey, publicKey, publicKeyHash] + // //Accessing: private key ===> identityFundraiser[0] | public key ===> identityFundraiser[1] | public Key Hash ===> identityFundraiser[2] all of type string. + + var keyStore = KeyStoreModel( + publicKey: 'edpkuh9tUmMMVKJVqG4bJxNLsCob6y8wXycshi6Pn11SQ5hx7SAVjf', + secretKey: + 'edskRs9KBdoU675PBVyHdM3fqixemkykm7hgHeXAYKUjdoVn3Aev8dP11p47zc4iuWJsefSP4t2vdHPoQisQC3DjZY3ZbbSP9Y', + publicKeyHash: 'tz1LRibbLEEWpaXb4aKrXXgWPvx9ue9haAAV', ); - print("signOperationGroup ===> $signOpGrp"); - //signOperationGroup ===> [hexSignature, signedOpBytes] - //Accessing: hex signature ===> signOpGrp[0] | signed Operation bytes ===> signOpGrp[1] all of type string - - //Unlock fundraiser identity. - List identityFundraiser = - await TezsterDart.unlockFundraiserIdentity( - mnemonic: - "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", - email: "lkbpoife.tobqgidu@tezos.example.org", - passphrase: "5tjpU0cimq", + + const contract = """parameter string; + storage string; + code { DUP; + DIP { CDR ; NIL string ; SWAP ; CONS } ; + CAR ; CONS ; + CONCAT; + NIL operation; PAIR}"""; + + var storage = '"Sample"'; + + var signer = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + + print(signer); + + const server = 'https://testnet.tezster.tech'; + + var result = await TezsterDart.sendContractOriginationOperation( + server, + signer, + keyStore, + 0, + null, + 100000, + 1000, + 100000, + contract, + storage, + codeFormat: TezosParameterFormat.Michelson, ); - print("identityFundraiser ===> $identityFundraiser"); - //identityFundraiser ===> [privateKey, publicKey, publicKeyHash] - //Accessing: private key ===> identityFundraiser[0] | public key ===> identityFundraiser[1] | public Key Hash ===> identityFundraiser[2] all of type string. + + print("Injected operation group id ${result['operationGroupID']}"); } @override diff --git a/example/pubspec.lock b/example/pubspec.lock index 26dec30..5fe68ad 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -123,6 +123,20 @@ packages: description: flutter source: sdk version: "0.0.0" + fs_extensions: + dependency: transitive + description: + name: fs_extensions + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.10" + guard: + dependency: transitive + description: + name: guard + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" hex: dependency: transitive description: @@ -130,6 +144,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + l_cli: + dependency: transitive + description: + name: l_cli + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" matcher: dependency: transitive description: @@ -219,6 +240,13 @@ packages: relative: true source: path version: "1.0.1" + tokenizer: + dependency: transitive + description: + name: tokenizer + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1" typed_data: dependency: transitive description: diff --git a/lib/chain/tezos/tezos_language_util.dart b/lib/chain/tezos/tezos_language_util.dart new file mode 100644 index 0000000..6870149 --- /dev/null +++ b/lib/chain/tezos/tezos_language_util.dart @@ -0,0 +1,30 @@ +import 'package:tokenizer/tokenizer.dart'; + +class TezosLanguageUtil { + static String normalizeMichelineWhiteSpace(String fragment) { + return fragment + .replaceAll(new RegExp(r'/\n/g'), ' ') + .replaceAll(new RegExp(r'/ +/g'), ' ') + .replaceAll(new RegExp(r'/\[{/g'), '[ {') + .replaceAll(new RegExp(r'/}\]/g'), '} ]') + .replaceAll(new RegExp(r'/},{/g'), '}, {') + .replaceAll(new RegExp(r'/\]}/g'), '] }') + .replaceAll(new RegExp(r'/":"/g'), '": "') + .replaceAll(new RegExp(r'/":\[/g'), '": [') + .replaceAll(new RegExp(r'/{"/g'), '{ "') + .replaceAll(new RegExp(r'/"}/g'), '" }') + .replaceAll(new RegExp(r'/,"/g'), ', "') + .replaceAll(new RegExp(r'/","/g'), '", "') + .replaceAll(new RegExp(r'/\[\[/g'), '[ [') + .replaceAll(new RegExp(r'/\]\]/g'), '] ]') + .replaceAll(new RegExp(r'/\["/g'), '\[ "') + .replaceAll(new RegExp(r'/"\]/g'), '" \]') + .replaceAll(new RegExp(r'/\[ +\]/g'), '\[\]') + .trim(); + } + + static String translateMichelsonToMicheline(String code) { + final tokenizer = Tokenizer({'{'}); + + } +} diff --git a/lib/chain/tezos/tezos_message_codec.dart b/lib/chain/tezos/tezos_message_codec.dart index 58464cb..f6ad404 100644 --- a/lib/chain/tezos/tezos_message_codec.dart +++ b/lib/chain/tezos/tezos_message_codec.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; + +import 'package:tezster_dart/chain/tezos/tezos_language_util.dart'; import 'package:tezster_dart/chain/tezos/tezos_message_utils.dart'; import 'package:tezster_dart/models/operation_model.dart'; @@ -6,6 +9,7 @@ class TezosMessageCodec { if (message.kind == 'transaction') return encodeTransaction(message); if (message.kind == 'reveal') return encodeReveal(message); if (message.kind == 'delegation') return encodeDelegation(message); + if (message.kind == 'origination') return encodeOrigination(message); } static String encodeTransaction(OperationModel message) { @@ -47,4 +51,32 @@ class TezosMessageCodec { } return hex; } + + static String encodeOrigination(OperationModel origination) { + var hex = TezosMessageUtils.writeInt(109); + hex += TezosMessageUtils.writeAddress(origination.source).substring(2); + hex += TezosMessageUtils.writeInt(int.parse(origination.fee)); + hex += TezosMessageUtils.writeInt(origination.counter); + hex += TezosMessageUtils.writeInt(origination.gasLimit); + hex += TezosMessageUtils.writeInt(origination.storageLimit); + hex += TezosMessageUtils.writeInt(int.parse(origination.amount)); + + if (origination.delegate != null) { + hex += TezosMessageUtils.writeBoolean(true); + hex += TezosMessageUtils.writeAddress(origination.delegate).substring(2); + } else { + hex += TezosMessageUtils.writeBoolean(false); + } + if (origination.script != null) { + // var parts = []; + // parts.add(origination.script['code']); + // parts.add(origination.script['storage']); + // hex += parts + // .map((e) => + // TezosLanguageUtil.normalizeMichelineWhiteSpace(jsonEncode(e))) + // .map((e) => TezosLanguageUtil.translateMichelineToHex(e)); + } + + return hex; + } } diff --git a/lib/chain/tezos/tezos_node_writer.dart b/lib/chain/tezos/tezos_node_writer.dart index ae4aa18..168aa63 100644 --- a/lib/chain/tezos/tezos_node_writer.dart +++ b/lib/chain/tezos/tezos_node_writer.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:convert/convert.dart'; +import 'package:tezster_dart/chain/tezos/tezos_language_util.dart'; import 'package:tezster_dart/chain/tezos/tezos_message_codec.dart'; import 'package:tezster_dart/chain/tezos/tezos_message_utils.dart'; import 'package:tezster_dart/chain/tezos/tezos_node_reader.dart'; @@ -10,6 +11,7 @@ import 'package:tezster_dart/helper/http_helper.dart'; import 'package:tezster_dart/models/key_store_model.dart'; import 'package:tezster_dart/models/operation_model.dart'; import 'package:tezster_dart/src/soft-signer/soft_signer.dart'; +import 'package:tezster_dart/types/tezos/tezos_chain_types.dart'; class TezosNodeWriter { static Future> sendTransactionOperation(String server, @@ -50,6 +52,38 @@ class TezosNodeWriter { return sendOperation(server, operations, signer, offset); } + static sendContractOriginationOperation( + String server, + SoftSigner signer, + KeyStoreModel keyStore, + int amount, + String delegate, + int fee, + int storageLimit, + int gasLimit, + String code, + String storage, + TezosParameterFormat codeFormat, + int offset) async { + var counter = await TezosNodeReader.getCounterForAccount( + server, keyStore.publicKeyHash) + + 1; + var operation = constructContractOriginationOperation( + keyStore, + amount, + delegate, + fee, + storageLimit, + gasLimit, + code, + storage, + codeFormat, + counter); + var operations = await appendRevealOperation(server, keyStore.publicKey, + keyStore.publicKeyHash, counter - 1, [operation]); + return sendOperation(server, operations, signer, offset); + } + static Future> appendRevealOperation( String server, String publicKey, @@ -203,4 +237,41 @@ class TezosNodeWriter { // parseRPCError(response); return response; } + + static OperationModel constructContractOriginationOperation( + KeyStoreModel keyStore, + int amount, + String delegate, + int fee, + int storageLimit, + int gasLimit, + String code, + String storage, + TezosParameterFormat codeFormat, + int counter) { + var parsedCode; + var parsedStorage; + print("using code Format ==> ${codeFormat.toString()}"); + if (codeFormat == TezosParameterFormat.Michelson) { + parsedCode = + jsonDecode(TezosLanguageUtil.translateMichelsonToMicheline(code)); + } else if (codeFormat == TezosParameterFormat.Micheline) { + parsedCode = jsonDecode(code); + parsedStorage = jsonDecode(storage); + } + return OperationModel( + kind: 'origination', + source: keyStore.publicKeyHash, + fee: fee.toString(), + counter: counter, + gasLimit: gasLimit, + storageLimit: storageLimit, + amount: amount.toString(), + delegate: delegate, + script: { + 'code': parsedCode, + 'storage': parsedStorage, + }, + ); + } } diff --git a/lib/models/operation_model.dart b/lib/models/operation_model.dart index 516f157..d7b0bcc 100644 --- a/lib/models/operation_model.dart +++ b/lib/models/operation_model.dart @@ -11,6 +11,7 @@ class OperationModel { String kind; String publicKey; String delegate; + Map script; OperationModel({ this.destination, @@ -23,6 +24,7 @@ class OperationModel { this.storageLimit = TezosConstants.DefaultTransactionStorageLimit, this.publicKey, this.delegate, + this.script, }) { if (kind == 'delegation') { gasLimit = TezosConstants.DefaultDelegationGasLimit; @@ -30,7 +32,7 @@ class OperationModel { } } - Map toJson() => kind == 'delegation' + Map toJson() => kind == 'delegation' ? { 'counter': counter.toString(), 'delegate': delegate, @@ -41,14 +43,26 @@ class OperationModel { 'storage_limit': TezosConstants.DefaultDelegationStorageLimit.toString(), } - : { - 'destination': destination, - 'amount': amount, - 'storage_limit': storageLimit.toString(), - 'gas_limit': gasLimit.toString(), - 'counter': counter.toString(), - 'fee': fee, - 'source': source, - 'kind': kind, - }; + : kind == 'origination' + ? { + 'kind': kind, + 'source': source, + 'fee': fee, + 'counter': counter.toString(), + 'gas_limit': gasLimit.toString(), + 'storage_limit': storageLimit.toString(), + 'balance': amount, + 'delegate': delegate, + 'script': script, + } + : { + 'destination': destination, + 'amount': amount, + 'storage_limit': storageLimit.toString(), + 'gas_limit': gasLimit.toString(), + 'counter': counter.toString(), + 'fee': fee, + 'source': source, + 'kind': kind, + }; } diff --git a/lib/src/tezster_dart.dart b/lib/src/tezster_dart.dart index 82c5ba3..7eba4d0 100644 --- a/lib/src/tezster_dart.dart +++ b/lib/src/tezster_dart.dart @@ -15,6 +15,7 @@ import 'package:tezster_dart/helper/constants.dart'; import 'package:tezster_dart/helper/http_helper.dart'; import 'package:tezster_dart/src/soft-signer/soft_signer.dart'; import 'package:tezster_dart/tezster_dart.dart'; +import 'package:tezster_dart/types/tezos/tezos_chain_types.dart'; import "package:unorm_dart/unorm_dart.dart" as unorm; import 'package:flutter_sodium/flutter_sodium.dart'; @@ -169,4 +170,49 @@ class TezsterDart { return await TezosNodeWriter.sendDelegationOperation( server, signer, keyStore, delegate, fee, offset); } + + static sendContractOriginationOperation( + String server, + SoftSigner signer, + KeyStoreModel keyStore, + int amount, + String delegate, + int fee, + int storageLimit, + int gasLimit, + String code, + String storage, { + TezosParameterFormat codeFormat = TezosParameterFormat.Micheline, + int offset = 54, + }) async { + assert(server != null); + assert(signer != null); + assert(keyStore != null); + assert(keyStore.publicKeyHash != null); + assert(keyStore.publicKey != null); + assert(keyStore.secretKey != null); + assert(amount != null); + // assert(delegate != null); + assert(fee != null); + assert(storageLimit != null); + assert(gasLimit != null); + assert(code != null); + assert(storage != null); + assert(codeFormat != null); + assert(offset != null); + return await TezosNodeWriter.sendContractOriginationOperation( + server, + signer, + keyStore, + amount, + delegate, + fee, + storageLimit, + gasLimit, + code, + storage, + codeFormat, + offset, + ); + } } diff --git a/lib/tezster_dart.dart b/lib/tezster_dart.dart index a80299f..54f017d 100644 --- a/lib/tezster_dart.dart +++ b/lib/tezster_dart.dart @@ -4,3 +4,6 @@ export 'src/tezster_dart.dart'; // KeyStore Model export 'models/key_store_model.dart'; + +// tezos types +export 'types/tezos/tezos_chain_types.dart'; \ No newline at end of file diff --git a/lib/types/tezos/tezos_chain_types.dart b/lib/types/tezos/tezos_chain_types.dart new file mode 100644 index 0000000..bbf6184 --- /dev/null +++ b/lib/types/tezos/tezos_chain_types.dart @@ -0,0 +1,5 @@ +enum TezosParameterFormat { + Michelson, + Micheline, + MichelsonLambda, +} diff --git a/pubspec.lock b/pubspec.lock index 369c852..165c16c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -116,6 +116,20 @@ packages: description: flutter source: sdk version: "0.0.0" + fs_extensions: + dependency: transitive + description: + name: fs_extensions + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.10" + guard: + dependency: transitive + description: + name: guard + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" hex: dependency: transitive description: @@ -123,6 +137,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + l_cli: + dependency: transitive + description: + name: l_cli + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" matcher: dependency: transitive description: @@ -205,6 +226,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.19-nullsafety.2" + tokenizer: + dependency: "direct main" + description: + name: tokenizer + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 423891d..61f6972 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: flutter_sodium: ^0.1.9 password_hash: ^2.0.0 unorm_dart: ^0.1.2 + tokenizer: ^0.0.1 dev_dependencies: flutter_test: From 994d8b0c5b1afc5b61341591b539d120fd70ad17 Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 17 Feb 2021 11:20:25 +0530 Subject: [PATCH 2/6] invoke contract function added --- example/lib/main.dart | 36 ++++++- example/pubspec.lock | 45 +++------ lib/chain/tezos/tezos_language_util.dart | 31 ++---- lib/chain/tezos/tezos_message_codec.dart | 56 +++++++++-- lib/chain/tezos/tezos_node_writer.dart | 98 +++++++++++++++---- lib/helper/http_helper.dart | 17 +++- lib/models/operation_model.dart | 69 ++++++++++--- lib/reporting/conseil_data_client.dart | 32 ++++++ lib/reporting/conseil_query_builder.dart | 56 +++++++++++ lib/reporting/tezos/tezos_conseil_client.dart | 69 +++++++++++++ lib/src/tezster_dart.dart | 63 +++++++++++- lib/types/tezos/query_types.dart | 16 +++ lib/utils/sodium_utils.dart | 7 +- pubspec.lock | 45 +++------ pubspec.yaml | 4 +- test/tezos_test.dart | 4 +- 16 files changed, 502 insertions(+), 146 deletions(-) create mode 100644 lib/reporting/conseil_data_client.dart create mode 100644 lib/reporting/conseil_query_builder.dart create mode 100644 lib/reporting/tezos/tezos_conseil_client.dart create mode 100644 lib/types/tezos/query_types.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 12427b9..87cb847 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -73,7 +73,7 @@ class _MyAppState extends State { publicKeyHash: 'tz1LRibbLEEWpaXb4aKrXXgWPvx9ue9haAAV', ); - const contract = """parameter string; + var contract = """parameter string; storage string; code { DUP; DIP { CDR ; NIL string ; SWAP ; CONS } ; @@ -82,13 +82,12 @@ class _MyAppState extends State { NIL operation; PAIR}"""; var storage = '"Sample"'; - var signer = await TezsterDart.createSigner( TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); print(signer); - const server = 'https://testnet.tezster.tech'; + var server = 'https://testnet.tezster.tech'; var result = await TezsterDart.sendContractOriginationOperation( server, @@ -103,14 +102,43 @@ class _MyAppState extends State { storage, codeFormat: TezosParameterFormat.Michelson, ); - + var groupId = result['operationGroupID']; print("Injected operation group id ${result['operationGroupID']}"); + + var network = 'delphinet'; + var serverInfo = { + 'url': 'https://conseil-dev.cryptonomic-infra.tech:443', + 'apiKey': 'f420a571-d526-4252-89e4-d7a2eb7f26b4', + 'network': network + }; + + var conseilResult = await TezsterDart.awaitOperationConfirmation( + serverInfo, network, groupId, 5); + print('Originated contract at ${conseilResult['originated_contracts']}'); + + var contractAddress = conseilResult['originated_contracts']; + + var resultInvoke = await TezsterDart.sendContractInvocationOperation( + server, + signer, + keyStore, + contractAddress, + 10000, + 100000, + 1000, + 100000, + '', + '"Cryptonomicon"', + codeFormat: TezosParameterFormat.Michelson); + + print('Injected operation group id ${resultInvoke['operationGroupID']}'); } @override void initState() { super.initState(); tezosWalletUtil(); + // runNewTestingDemo(); } @override diff --git a/example/pubspec.lock b/example/pubspec.lock index 5fe68ad..5ac259d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: name: bip39 url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" blake2b: dependency: transitive description: @@ -117,26 +117,12 @@ packages: name: flutter_sodium url: "https://pub.dartlang.org" source: hosted - version: "0.1.9" + version: "0.1.11" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" - fs_extensions: - dependency: transitive - description: - name: fs_extensions - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.10" - guard: - dependency: transitive - description: - name: guard - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" hex: dependency: transitive description: @@ -144,13 +130,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" - l_cli: - dependency: transitive - description: - name: l_cli - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" matcher: dependency: transitive description: @@ -165,6 +144,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.3" + michelson_parser: + dependency: transitive + description: + path: "." + ref: HEAD + resolved-ref: cbda67adc5f8a3287c4b98e822f9d2766e55f51b + url: "https://github.com/Jay-Tezsure/michelson_parser.git" + source: git + version: "0.0.1" password_hash: dependency: transitive description: @@ -185,7 +173,7 @@ packages: name: pointycastle url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "2.0.1" sky_engine: dependency: transitive description: flutter @@ -240,13 +228,6 @@ packages: relative: true source: path version: "1.0.1" - tokenizer: - dependency: transitive - description: - name: tokenizer - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1" typed_data: dependency: transitive description: @@ -270,4 +251,4 @@ packages: version: "2.1.0-nullsafety.3" sdks: dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.10.0" + flutter: ">=1.20.0" diff --git a/lib/chain/tezos/tezos_language_util.dart b/lib/chain/tezos/tezos_language_util.dart index 6870149..3bcd701 100644 --- a/lib/chain/tezos/tezos_language_util.dart +++ b/lib/chain/tezos/tezos_language_util.dart @@ -1,30 +1,13 @@ -import 'package:tokenizer/tokenizer.dart'; +import 'package:michelson_parser/michelson_parser.dart'; class TezosLanguageUtil { - static String normalizeMichelineWhiteSpace(String fragment) { - return fragment - .replaceAll(new RegExp(r'/\n/g'), ' ') - .replaceAll(new RegExp(r'/ +/g'), ' ') - .replaceAll(new RegExp(r'/\[{/g'), '[ {') - .replaceAll(new RegExp(r'/}\]/g'), '} ]') - .replaceAll(new RegExp(r'/},{/g'), '}, {') - .replaceAll(new RegExp(r'/\]}/g'), '] }') - .replaceAll(new RegExp(r'/":"/g'), '": "') - .replaceAll(new RegExp(r'/":\[/g'), '": [') - .replaceAll(new RegExp(r'/{"/g'), '{ "') - .replaceAll(new RegExp(r'/"}/g'), '" }') - .replaceAll(new RegExp(r'/,"/g'), ', "') - .replaceAll(new RegExp(r'/","/g'), '", "') - .replaceAll(new RegExp(r'/\[\[/g'), '[ [') - .replaceAll(new RegExp(r'/\]\]/g'), '] ]') - .replaceAll(new RegExp(r'/\["/g'), '\[ "') - .replaceAll(new RegExp(r'/"\]/g'), '" \]') - .replaceAll(new RegExp(r'/\[ +\]/g'), '\[\]') - .trim(); - } - static String translateMichelsonToMicheline(String code) { - final tokenizer = Tokenizer({'{'}); + // jsonDecode() + var result = MichelsonParser.parseMichelson(code); + return result; + } + static String translateMichelineToHex(p) { + return MichelsonParser.translateMichelineToHex(p); } } diff --git a/lib/chain/tezos/tezos_message_codec.dart b/lib/chain/tezos/tezos_message_codec.dart index f6ad404..87f9783 100644 --- a/lib/chain/tezos/tezos_message_codec.dart +++ b/lib/chain/tezos/tezos_message_codec.dart @@ -10,6 +10,7 @@ class TezosMessageCodec { if (message.kind == 'reveal') return encodeReveal(message); if (message.kind == 'delegation') return encodeDelegation(message); if (message.kind == 'origination') return encodeOrigination(message); + return ''; } static String encodeTransaction(OperationModel message) { @@ -21,7 +22,42 @@ class TezosMessageCodec { hex += TezosMessageUtils.writeInt(message.storageLimit); hex += TezosMessageUtils.writeInt(int.parse(message.amount)); hex += TezosMessageUtils.writeAddress(message.destination); - hex += '00'; + if (message.parameters != null) { + var composite = message.parameters; + var result = TezosLanguageUtil.translateMichelineToHex( + jsonEncode(composite['value'])); + if ((composite['entrypoint'] == 'default' || + composite['entrypoint'] == '') && + result == '030b') { + hex += '00'; + } else { + hex += 'ff'; + if (composite['entrypoint'] == 'default' || + composite['entrypoint'] == '') { + hex += '00'; + } else if (composite['entrypoint'] == 'root') { + hex += '01'; + } else if (composite['entrypoint'] == 'do') { + hex += '02'; + } else if (composite['entrypoint'] == 'set_delegate') { + hex += '03'; + } else if (composite['entrypoint'] == 'remove_delegate') { + hex += '04'; + } else { + var entryStr = '0' + composite['entrypoint'].length.toRadixString(16); + hex += 'ff' + + (entryStr.substring(entryStr.length - 2)) + + composite['entrypoint'] + .split('') + .map((String c) => c.codeUnitAt(0).toRadixString(16)) + .join(''); + } + var resRad = '0000000' + (result.length ~/ 2).toRadixString(16); + hex += resRad.substring(resRad.length - 8) + result; + } + } else { + hex += '00'; + } return hex; } @@ -68,13 +104,17 @@ class TezosMessageCodec { hex += TezosMessageUtils.writeBoolean(false); } if (origination.script != null) { - // var parts = []; - // parts.add(origination.script['code']); - // parts.add(origination.script['storage']); - // hex += parts - // .map((e) => - // TezosLanguageUtil.normalizeMichelineWhiteSpace(jsonEncode(e))) - // .map((e) => TezosLanguageUtil.translateMichelineToHex(e)); + var parts = []; + parts.add(origination.script['code']); + parts.add(origination.script['storage']); + hex += parts + .map((p) => jsonEncode(p)) + .map((p) => TezosLanguageUtil.translateMichelineToHex(p)) + .fold('', (m, p) { + var result = ('0000000' + (p.length ~/ 2).toRadixString(16)); + result = result.substring(result.length - 8) + p; + return m + result; + }); } return hex; diff --git a/lib/chain/tezos/tezos_node_writer.dart b/lib/chain/tezos/tezos_node_writer.dart index 168aa63..b7fe8e7 100644 --- a/lib/chain/tezos/tezos_node_writer.dart +++ b/lib/chain/tezos/tezos_node_writer.dart @@ -84,6 +84,83 @@ class TezosNodeWriter { return sendOperation(server, operations, signer, offset); } + static sendContractInvocationOperation( + String server, + SoftSigner signer, + KeyStoreModel keyStore, + String contract, + int amount, + int fee, + int storageLimit, + int gasLimit, + entrypoint, + String parameters, + {TezosParameterFormat parameterFormat = TezosParameterFormat.Micheline, + offset = 54}) async { + var counter = await TezosNodeReader.getCounterForAccount( + server, keyStore.publicKeyHash) + + 1; + var transaction = constructContractInvocationOperation( + keyStore.publicKeyHash, + counter, + contract, + amount, + fee, + storageLimit, + gasLimit, + entrypoint, + parameters, + parameterFormat); + var operations = await appendRevealOperation(server, keyStore.publicKey, + keyStore.publicKeyHash, counter - 1, [transaction]); + return sendOperation(server, operations, signer, offset); + } + + static constructContractInvocationOperation( + String publicKeyHash, + int counter, + String contract, + int amount, + int fee, + int storageLimit, + int gasLimit, + entrypoint, + String parameters, + TezosParameterFormat parameterFormat) { + OperationModel transaction = new OperationModel( + destination: contract, + amount: amount.toString(), + counter: counter, + fee: fee.toString(), + source: publicKeyHash, + ); + if (parameters != null) { + if (parameterFormat == TezosParameterFormat.Michelson) { + var michelineParams = + TezosLanguageUtil.translateMichelsonToMicheline(parameters); + transaction.parameters = { + 'entrypoint': entrypoint.isEmpty ? 'default' : entrypoint, + 'value': jsonDecode(michelineParams) + }; + } else if (parameterFormat == TezosParameterFormat.Micheline) { + transaction.parameters = { + 'entrypoint': entrypoint.isEmpty ? 'default' : entrypoint, + 'value': jsonDecode(parameters) + }; + } else if (parameterFormat == TezosParameterFormat.MichelsonLambda) { + var michelineLambda = + TezosLanguageUtil.translateMichelsonToMicheline('code $parameters'); + transaction.parameters = { + 'entrypoint': entrypoint.isEmpty ? 'default' : entrypoint, + 'value': jsonDecode(michelineLambda) + }; + } + } else if (entrypoint != null) { + transaction.parameters = {'entrypoint': entrypoint, 'value': []}; + } + return transaction; + } + static Future> appendRevealOperation( String server, String publicKey, @@ -178,24 +255,7 @@ class TezosNodeWriter { } else if (arr.length == 1 && arr[0]['contents'].length == 1 && arr[0]['contents'][0]['kind'].toString() == "activate_account") { - } else { - // errors = arr.map((r) => r['contents']).map((o) { - // o - // .map((c) => c['metadata']['operation_result']) - // .addAll(o.expand((c) => - // c['metadata']['internal_operation_results'] != null - // ? c['metadata']['internal_operation_results'] - // : null) - // ..toList() - // // ..filter((c) => !!c) - // // ..map((c) => c['result']).toList(), - // ) - // .map((r) => parseRPCOperationResult(r)) - // .toList() - // // .where((i) => i.length > 0) - // .join(', '); - // }).join(', '); - } + } else {} } catch (err) { if (json.toString().startsWith('Failed to parse the request body: ')) { errors = json.toString().toString().substring(34); @@ -255,6 +315,8 @@ class TezosNodeWriter { if (codeFormat == TezosParameterFormat.Michelson) { parsedCode = jsonDecode(TezosLanguageUtil.translateMichelsonToMicheline(code)); + parsedStorage = + jsonDecode(TezosLanguageUtil.translateMichelsonToMicheline(storage)); } else if (codeFormat == TezosParameterFormat.Micheline) { parsedCode = jsonDecode(code); parsedStorage = jsonDecode(storage); diff --git a/lib/helper/http_helper.dart b/lib/helper/http_helper.dart index 0ac5e9f..81779c0 100644 --- a/lib/helper/http_helper.dart +++ b/lib/helper/http_helper.dart @@ -2,12 +2,21 @@ import 'dart:convert'; import 'dart:io'; class HttpHelper { - static Future performPostRequest(server, command, payload) async { + static Future performPostRequest(server, command, payload, + {Map headers}) async { HttpClient httpClient = new HttpClient(); - HttpClientRequest request = - await httpClient.postUrl(Uri.parse('$server/$command')); + HttpClientRequest request = await httpClient.postUrl( + command.isEmpty ? Uri.parse(server) : Uri.parse('$server/$command')); request.headers.set('content-type', 'application/json'); - request.add(utf8.encode(json.encode(payload))); + if (headers == null) { + request.add(utf8.encode(json.encode(payload))); + } else { + headers.entries.forEach( + (header) => request.headers.add(header.key, header.value), + ); + request.headers.add('body', json.encode(payload)); + request.add(utf8.encode(json.encode(payload))); + } HttpClientResponse response = await request.close(); String reply = await response.transform(utf8.decoder).join(); httpClient.close(); diff --git a/lib/models/operation_model.dart b/lib/models/operation_model.dart index d7b0bcc..c94e111 100644 --- a/lib/models/operation_model.dart +++ b/lib/models/operation_model.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:tezster_dart/helper/constants.dart'; class OperationModel { @@ -13,6 +15,8 @@ class OperationModel { String delegate; Map script; + Map parameters; + OperationModel({ this.destination, this.amount, @@ -32,7 +36,7 @@ class OperationModel { } } - Map toJson() => kind == 'delegation' + Map toJson() => kind == 'delegation' ? { 'counter': counter.toString(), 'delegate': delegate, @@ -43,26 +47,59 @@ class OperationModel { 'storage_limit': TezosConstants.DefaultDelegationStorageLimit.toString(), } - : kind == 'origination' + : kind == 'reveal' ? { 'kind': kind, 'source': source, - 'fee': fee, + 'fee': '0', 'counter': counter.toString(), 'gas_limit': gasLimit.toString(), 'storage_limit': storageLimit.toString(), - 'balance': amount, - 'delegate': delegate, - 'script': script, + 'public_key': publicKey } - : { - 'destination': destination, - 'amount': amount, - 'storage_limit': storageLimit.toString(), - 'gas_limit': gasLimit.toString(), - 'counter': counter.toString(), - 'fee': fee, - 'source': source, - 'kind': kind, - }; + : kind == "origination" + ? delegate == null + ? { + 'kind': 'origination', + 'source': source, + 'fee': fee.toString(), + 'counter': counter.toString(), + 'gas_limit': gasLimit.toString(), + 'storage_limit': storageLimit.toString(), + 'balance': amount.toString(), + 'script': script + } + : { + 'kind': 'origination', + 'source': source, + 'fee': fee.toString(), + 'counter': counter.toString(), + 'gas_limit': gasLimit.toString(), + 'storage_limit': storageLimit.toString(), + 'balance': amount.toString(), + 'delegate': delegate, + 'script': script + } + : parameters == null + ? { + 'destination': destination, + 'amount': amount, + 'storage_limit': storageLimit.toString(), + 'gas_limit': gasLimit.toString(), + 'counter': counter.toString(), + 'fee': fee, + 'source': source, + 'kind': kind, + } + : { + 'destination': destination, + 'amount': amount, + 'storage_limit': storageLimit.toString(), + 'gas_limit': gasLimit.toString(), + 'counter': counter.toString(), + 'fee': fee, + 'source': source, + 'kind': kind, + 'parameters': parameters, + }; } diff --git a/lib/reporting/conseil_data_client.dart b/lib/reporting/conseil_data_client.dart new file mode 100644 index 0000000..3db1744 --- /dev/null +++ b/lib/reporting/conseil_data_client.dart @@ -0,0 +1,32 @@ +import 'package:tezster_dart/helper/http_helper.dart'; + +class ConseilDataClient { + static executeEntityQuery( + serverInfo, platform, network, entity, query) async { + var url = '${serverInfo['url']}/v2/data/$platform/$network/$entity'; + // log.debug(`ConseilDataClient.executeEntityQuery request: ${url}, ${JSON.stringify(query)}`); + var res = await HttpHelper.performPostRequest(url, '', query, headers: { + 'apiKey': serverInfo['apiKey'], + // 'Content-Type': 'application/json', + 'cache': 'no-store', + }); + return res; + // .then((r) { + // if (!r.ok) { + // // log.error(`ConseilDataClient.executeEntityQuery request: ${url}, ${JSON.stringify(query)}, failed with ${r.statusText}(${r.status})`); + // throw new ConseilErrorTypes_1.ConseilRequestError( + // r.status, r.statusText, url, query); + // } + // return r; + // }) + // .then((r) { + // var isJSONResponse = r.headers + // .get('content-type') + // .toLowerCase() + // .includes('application/json'); + // var response = isJSONResponse != null ? r.json() : r.text(); + // // log.debug(`ConseilDataClient.executeEntityQuery response: ${isJSONResponse ? JSON.stringify(response) : response}`); + // return response; + // }); + } +} diff --git a/lib/reporting/conseil_query_builder.dart b/lib/reporting/conseil_query_builder.dart new file mode 100644 index 0000000..f33b0ef --- /dev/null +++ b/lib/reporting/conseil_query_builder.dart @@ -0,0 +1,56 @@ +import 'package:tezster_dart/types/tezos/query_types.dart'; + +class ConseilQueryBuilder { + static blankQuery() { + return { + 'fields': new List(), + 'predicates': new List(), + 'orderBy': new List(), + 'aggregation': new List(), + 'limit': 100 + }; + } + + static setLimit(query, limit) { + if (limit < 1) { + throw new Exception('Limit cannot be less than one.'); + } + var q = query; + q['limit'] = limit; + return q; + } + + static addOrdering(query, field, {direction}) { + if (direction == null) direction = QueryTypes.conseilSortDirection['ASC']; + var q = query; + q['orderBy'].add({'field': field, 'direction': direction}); + return q; + } + + static addPredicate(query, field, operation, values, + {invert = false, group = ''}) { + if (group == null) group = ''; + if (operation == QueryTypes.conseilOperator['BETWEEN'] && + values.length != 2) { + throw new Exception('BETWEEN operation requires a list of two values.'); + } else if (operation == QueryTypes.conseilOperator['IN'] && + values.length < 2) { + throw new Exception( + 'IN operation requires a list of two or more values.'); + } else if (values.length != 1 && + operation != QueryTypes.conseilOperator['IN'] && + operation != QueryTypes.conseilOperator['BETWEEN'] && + operation != QueryTypes.conseilOperator['ISNULL']) { + throw new Exception('invalid values list for $operation.'); + } + var q = query; + q['predicates'].add({ + 'field': field, + 'operation': operation ?? '', + 'set': values , + 'inverse': invert, + 'group': group ?? '', + }); + return q; + } +} diff --git a/lib/reporting/tezos/tezos_conseil_client.dart b/lib/reporting/tezos/tezos_conseil_client.dart new file mode 100644 index 0000000..372d0ae --- /dev/null +++ b/lib/reporting/tezos/tezos_conseil_client.dart @@ -0,0 +1,69 @@ +import 'dart:convert'; + +import 'package:tezster_dart/reporting/conseil_data_client.dart'; +import 'package:tezster_dart/reporting/conseil_query_builder.dart'; +import 'package:tezster_dart/types/tezos/query_types.dart'; + +var bLOCKS = 'blocks'; +var oPERATIONS = 'operations'; + +class TezosConseilClient { + static awaitOperationConfirmation(serverInfo, network, hash, duration, + {blocktime = 60}) async { + if (blocktime == null) blocktime = 60; + if (duration <= 0) { + throw new Exception('Invalid duration'); + } + var initialLevel = await getBlockHead(serverInfo, network); + initialLevel = initialLevel['level']; + var timeOffset = 180000; + var startTime = new DateTime.now().millisecondsSinceEpoch - timeOffset; + var estimatedEndTime = startTime + timeOffset + duration * blocktime * 1000; + var currentLevel = initialLevel; + var operationQuery = ConseilQueryBuilder.blankQuery(); + operationQuery = ConseilQueryBuilder.addPredicate(operationQuery, + 'operation_group_hash', QueryTypes.conseilOperator['EQ'], [hash], + invert: false); + operationQuery = ConseilQueryBuilder.addPredicate(operationQuery, + 'timestamp', QueryTypes.conseilOperator['AFTER'], [startTime], + invert: false); + operationQuery = ConseilQueryBuilder.setLimit(operationQuery, 1); + while (initialLevel + duration > currentLevel) { + var group = + jsonDecode(await getOperations(serverInfo, network, operationQuery)); + if (group.length > 0) { + return group[0]; + } + currentLevel = (await getBlockHead(serverInfo, network))['level']; + if (initialLevel + duration < currentLevel) { + break; + } + if (new DateTime.now().millisecondsSinceEpoch > estimatedEndTime) { + break; + } + await Future.delayed(Duration(milliseconds: blocktime * 1000)); + } + throw new Exception( + 'Did not observe $hash on $network in $duration block${duration > 1 ? 's' : ''} since $initialLevel'); + } + + static getBlockHead(serverInfo, network) async { + var query = ConseilQueryBuilder.setLimit( + ConseilQueryBuilder.addOrdering( + ConseilQueryBuilder.blankQuery(), 'level', + direction: QueryTypes.conseilSortDirection['DESC']), + 1); + var r = jsonDecode( + await getTezosEntityData(serverInfo, network, bLOCKS, query)); + return r[0]; + } + + static getTezosEntityData(serverInfo, network, entity, query) async { + return await ConseilDataClient.executeEntityQuery( + serverInfo, 'tezos', network, entity, query); + } + + static getOperations(serverInfo, network, query) { + return getTezosEntityData(serverInfo, network, oPERATIONS, query); + } +} diff --git a/lib/src/tezster_dart.dart b/lib/src/tezster_dart.dart index 7eba4d0..1cbd537 100644 --- a/lib/src/tezster_dart.dart +++ b/lib/src/tezster_dart.dart @@ -13,6 +13,7 @@ import 'package:bs58check/bs58check.dart' as bs58check; import 'package:tezster_dart/chain/tezos/tezos_node_writer.dart'; import 'package:tezster_dart/helper/constants.dart'; import 'package:tezster_dart/helper/http_helper.dart'; +import 'package:tezster_dart/reporting/tezos/tezos_conseil_client.dart'; import 'package:tezster_dart/src/soft-signer/soft_signer.dart'; import 'package:tezster_dart/tezster_dart.dart'; import 'package:tezster_dart/types/tezos/tezos_chain_types.dart'; @@ -22,10 +23,12 @@ import 'package:flutter_sodium/flutter_sodium.dart'; import 'package:tezster_dart/helper/generateKeys.dart'; class TezsterDart { + /// Generate mnemonic static String generateMnemonic({int strength = 256}) { return bip39.generateMnemonic(strength: strength); } + /// Generate keys from mnemonic static Future> getKeysFromMnemonic({ String mnemonic, }) async { @@ -39,6 +42,7 @@ class TezsterDart { return [skKey, pkKey, pkKeyHash]; } + /// Create / Unlock identity from mnemonic and passphrase. static Future> getKeysFromMnemonicAndPassphrase({ String mnemonic, String passphrase, @@ -51,6 +55,7 @@ class TezsterDart { ); } + /// Unlock fundraiser identity. static Future> unlockFundraiserIdentity({ String mnemonic, String email, @@ -65,6 +70,7 @@ class TezsterDart { ); } + /// Sign operation with private key and forged operation static Future> signOperationGroup({ String privateKey, String forgedOperation, @@ -119,6 +125,7 @@ class TezsterDart { return [skKey, pkKey, pkKeyHash]; } + // Get balance from given publicKeyHash and rpc static Future getBalance(String publicKeyHash, String rpc) async { assert(publicKeyHash != null); assert(rpc != null); @@ -133,11 +140,13 @@ class TezsterDart { return GenerateKeys.writeKeyWithHint(key, hint); } + // Create Signer from given secretKey static createSigner(Uint8List secretKey, {int validity = 60}) { assert(secretKey != null); return SoftSigner.createSigner(secretKey, validity); } + /// Transfer Balance static sendTransactionOperation(String server, SoftSigner signer, KeyStoreModel keyStore, String to, int amount, int fee, {int offset = 54}) async { @@ -156,6 +165,7 @@ class TezsterDart { server, signer, keyStore, to, amount, fee); } + /// Delegate an Account static sendDelegationOperation(String server, SoftSigner signer, KeyStoreModel keyStore, String delegate, int fee, {offset = 54}) async { @@ -192,7 +202,6 @@ class TezsterDart { assert(keyStore.publicKey != null); assert(keyStore.secretKey != null); assert(amount != null); - // assert(delegate != null); assert(fee != null); assert(storageLimit != null); assert(gasLimit != null); @@ -215,4 +224,56 @@ class TezsterDart { offset, ); } + + static awaitOperationConfirmation(serverInfo, network, hash, duration, + {blocktime}) async { + assert(serverInfo != null); + assert(network != null); + assert(hash != null); + assert(duration != null); + return await TezosConseilClient.awaitOperationConfirmation( + serverInfo, network, hash, duration, + blocktime: blocktime); + } + + static sendContractInvocationOperation( + String server, + SoftSigner signer, + KeyStoreModel keyStore, + String contract, + int amount, + int fee, + int storageLimit, + int gasLimit, + entrypoint, + String parameters, + {TezosParameterFormat codeFormat = TezosParameterFormat.Micheline, + offset = 54}) async { + assert(server != null); + assert(signer != null); + assert(keyStore != null); + assert(contract != null); + assert(keyStore.publicKeyHash != null); + assert(keyStore.publicKey != null); + assert(keyStore.secretKey != null); + assert(amount != null); + assert(entrypoint != null); + assert(parameters != null); + assert(fee != null); + assert(storageLimit != null); + assert(gasLimit != null); + return await TezosNodeWriter.sendContractInvocationOperation( + server, + signer, + keyStore, + contract, + amount, + fee, + storageLimit, + gasLimit, + entrypoint, + parameters, + parameterFormat: codeFormat ?? TezosParameterFormat.Micheline, + offset: offset ?? 54); + } } diff --git a/lib/types/tezos/query_types.dart b/lib/types/tezos/query_types.dart new file mode 100644 index 0000000..157d40d --- /dev/null +++ b/lib/types/tezos/query_types.dart @@ -0,0 +1,16 @@ +class QueryTypes { + static Map conseilSortDirection = {'ASC': "asc", 'DESC': "desc"}; + static Map conseilOperator = { + 'BETWEEN': "between", + 'EQ': "eq", + 'IN': "in", + 'LIKE': "like", + 'LT': "lt", + 'BEFORE': "before", + 'GT': "gt", + 'AFTER': "after", + 'STARTSWITH': "startsWith", + 'ENDSWITH': "endsWith", + 'ISNULL': "isnull" + }; +} diff --git a/lib/utils/sodium_utils.dart b/lib/utils/sodium_utils.dart index 64b65fb..2855783 100644 --- a/lib/utils/sodium_utils.dart +++ b/lib/utils/sodium_utils.dart @@ -1,4 +1,3 @@ -import 'dart:ffi'; import 'dart:typed_data'; import 'package:flutter_sodium/flutter_sodium.dart'; @@ -31,11 +30,11 @@ class SodiumUtils { return Sodium.cryptoSecretboxEasy(message, nonce, keyBytes); } - static Uint8List open(Uint8List nonce_and_ciphertext, Uint8List key) { + static Uint8List open(Uint8List nonceAndCiphertext, Uint8List key) { var nonce = - nonce_and_ciphertext.sublist(0, Sodium.cryptoSecretboxNoncebytes); + nonceAndCiphertext.sublist(0, Sodium.cryptoSecretboxNoncebytes); var ciphertext = - nonce_and_ciphertext.sublist(Sodium.cryptoSecretboxNoncebytes); + nonceAndCiphertext.sublist(Sodium.cryptoSecretboxNoncebytes); return Sodium.cryptoSecretboxOpenEasy(ciphertext, nonce, key); } diff --git a/pubspec.lock b/pubspec.lock index 165c16c..1118fbe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -14,7 +14,7 @@ packages: name: bip39 url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" blake2b: dependency: "direct main" description: @@ -110,26 +110,12 @@ packages: name: flutter_sodium url: "https://pub.dartlang.org" source: hosted - version: "0.1.9" + version: "0.1.11" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" - fs_extensions: - dependency: transitive - description: - name: fs_extensions - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.10" - guard: - dependency: transitive - description: - name: guard - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" hex: dependency: transitive description: @@ -137,13 +123,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" - l_cli: - dependency: transitive - description: - name: l_cli - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" matcher: dependency: transitive description: @@ -158,6 +137,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.3" + michelson_parser: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: cbda67adc5f8a3287c4b98e822f9d2766e55f51b + url: "https://github.com/Jay-Tezsure/michelson_parser.git" + source: git + version: "0.0.1" password_hash: dependency: "direct main" description: @@ -178,7 +166,7 @@ packages: name: pointycastle url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "2.0.1" sky_engine: dependency: transitive description: flutter @@ -226,13 +214,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.19-nullsafety.2" - tokenizer: - dependency: "direct main" - description: - name: tokenizer - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1" typed_data: dependency: transitive description: @@ -256,4 +237,4 @@ packages: version: "2.1.0-nullsafety.3" sdks: dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.10.0" + flutter: ">=1.20.0" diff --git a/pubspec.yaml b/pubspec.yaml index 61f6972..1aeaf16 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,9 @@ dependencies: flutter_sodium: ^0.1.9 password_hash: ^2.0.0 unorm_dart: ^0.1.2 - tokenizer: ^0.0.1 + michelson_parser: + git: + url: https://github.com/Jay-Tezsure/michelson_parser.git dev_dependencies: flutter_test: diff --git a/test/tezos_test.dart b/test/tezos_test.dart index 9e15c90..69a377c 100644 --- a/test/tezos_test.dart +++ b/test/tezos_test.dart @@ -51,9 +51,9 @@ void main() { publicKeyHash: 'tz1LRibbLEEWpaXb4aKrXXgWPvx9ue9haAAV', ); - var signer = await TezsterDart.createSigner( + await TezsterDart.createSigner( TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); - print(signer); + // print(signer); }); test('send-Transaction-Operation', () async { From 7be6fe6b0b1fc7c7e1c30b26897f2b105b19710d Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 17 Feb 2021 13:50:03 +0530 Subject: [PATCH 3/6] bugs fixed & example updated --- README.md | 217 +- example/lib/main.dart | 202 +- example/pubspec.lock | 11 +- lib/chain/tezos/tezos_language_util.dart | 3 +- .../grammar/michelin_grammar_tokenizer.dart | 198 ++ .../grammar/michelson_grammar_tokenizer.dart | 200 ++ lib/michelson_parser/michelson_parser.dart | 76 + .../parser/micheline_grammar.dart | 1154 ++++++++ .../parser/michelson_grammar.dart | 2365 +++++++++++++++++ lib/michelson_parser/parser/nearley.dart | 550 ++++ lib/models/operation_model.dart | 2 - pubspec.lock | 11 +- pubspec.yaml | 3 - 13 files changed, 4893 insertions(+), 99 deletions(-) create mode 100644 lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart create mode 100644 lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart create mode 100644 lib/michelson_parser/michelson_parser.dart create mode 100644 lib/michelson_parser/parser/micheline_grammar.dart create mode 100644 lib/michelson_parser/parser/michelson_grammar.dart create mode 100644 lib/michelson_parser/parser/nearley.dart diff --git a/README.md b/README.md index 120952a..08682ed 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,17 @@ Tezos is a decentralized blockchain that governs itself by establishing a true d ### Features * Tezos wallet utilities. + * Get Balance. * Generate mnemonics. * Generate keys from mnemonic. * Generate keys from mnemonics and passphrase. * Sign Operation Group. * Unlock fundraiser identity. + * Transfer Balance. + * Delegate an Account. + * Deploy a contract. + * Call a contract. + * Await operation Confirmation. ### Getting started @@ -32,6 +38,12 @@ import 'package:tezster_dart/tezster_dart.dart'; ### Usage +* Get Balance + +``` dart +String balance = await TezsterDart.getBalance('tz1c....ozGGs', 'your rpc server'); +``` + * Generate mnemonic ``` dart @@ -86,6 +98,209 @@ List identityFundraiser = await TezsterDart.unlockFundraiserIdentity( tz1hhkSbaocSWm3wawZUuUdX57L3maSH16Pv] */ ``` +* Transfer Balance. + * The most basic operation on the chain is the transfer of value between two accounts. In this example we have the account we activated above: tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy and some random testnet address to test with: tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc. Note all amounts are in µtz, as in micro-tez, hence 0.5tz is represented as 500000. The fee of 1500 was chosen arbitrarily, but some operations have minimum fee requirements. + +``` dart +var server = ''; + +var keyStore = KeyStoreModel( + publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj', + secretKey: + 'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH', + publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy', + ); + +var signer = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + +var result = await TezsterDart.sendTransactionOperation( + server, + signer, + keyStore, + 'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc', + 500000, + 1500, + ); + +print("Applied operation ===> $result['appliedOp']"); +print("Operation groupID ===> $result['operationGroupID']"); + +``` + +* Delegate an Account. + * One of the most exciting features of Tezos is delegation. This is a means for non-"baker" (non-validator) accounts to participate in the on-chain governance process and receive staking rewards. It is possible to delegate both implicit and originated accounts. For implicit addresses, those starting with tz1, tz2 and tz3, simply call sendDelegationOperation. Originated accounts, that is smart contracts, must explicitly support delegate assignment, but can also be deployed with a delegate already set. + +``` dart +var server = ''; + +var keyStore = KeyStoreModel( + publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj', + secretKey: + 'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH', + publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy', + ); + +var signer = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + +var result = await TezsterDart.sendDelegationOperation( + server, + signer, + keyStore, + 'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc', + 10000, + ); + +print("Applied operation ===> $result['appliedOp']"); +print("Operation groupID ===> $result['operationGroupID']"); + +``` + +* Deploy a contract. + * With this release we are excited to include the feature of trestles chain interactions, including contract deployment a user can directly write smart contracts in Michelson language and deploy it on Tezos chain using the `sendContractOriginationOperation()` method in return you'll get an origination id of the deployed contract that can be use to track the contract on chain. We have set an example for you below. + +``` dart +var server = ''; + +var contract = """parameter string; + storage string; + code { DUP; + DIP { CDR ; NIL string ; SWAP ; CONS } ; + CAR ; CONS ; + CONCAT; + NIL operation; PAIR}"""; + +var storage = '"Sample"'; + +var keyStore = KeyStoreModel( + publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj', + secretKey: + 'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH', + publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy', + ); + +var signer = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + +var result = await TezsterDart.sendContractOriginationOperation( + server, + signer, + keyStore, + 0, + null, + 100000, + 1000, + 100000, + contract, + storage, + codeFormat: TezosParameterFormat.Michelson, + ); + +print("Operation groupID ===> $result['operationGroupID']"); + +``` +reference link: `https://github.com/Tezsure/Tezster_dart/blob/master/example/lib/main.dart#L110` +
+ +* Call a contract. + * We have also included the feature to call or invoke a deployed contract just use the inbuilt `sendContractInvocationOperation()` method in return you'll get an origination id of the invoked contract that can be used to track the contracts on chain. We have set an example for you below. + +``` dart +var server = ''; + +var keyStore = KeyStoreModel( + publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj', + secretKey: + 'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH', + publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy', + ); + +var signer = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + +var contractAddress = 'KT1KA7DqFjShLC4CPtChPX8QtRYECUb99xMY'; + +var resultInvoke = await TezsterDart.sendContractInvocationOperation( + server, + signer, + keyStore, + contractAddress, + 10000, + 100000, + 1000, + 100000, + '', + '"Cryptonomicon"', + codeFormat: TezosParameterFormat.Michelson); + +print("Operation groupID ===> $result['operationGroupID']"); + +``` +reference link: `https://github.com/Tezsure/Tezster_dart/blob/master/example/lib/main.dart#L141` +
+ +* Await operation Confirmation. + * No wonder it's really important to await for confirmation for any on chain interactions. Hence, we have provided `awaitOperationConfirmation()` method with this release that developers can leverage for their advantage to confirm the originated contract's operations id. We have set an example for you how to use it. + +``` dart +var server = ''; + +var network = 'carthagenet'; + +var serverInfo = { + 'url': '', + 'apiKey': '', + 'network': network + }; + +var contract = """parameter string; + storage string; + code { DUP; + DIP { CDR ; NIL string ; SWAP ; CONS } ; + CAR ; CONS ; + CONCAT; + NIL operation; PAIR}"""; + +var storage = '"Sample"'; + +var keyStore = KeyStoreModel( + publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj', + secretKey: + 'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH', + publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy', + ); + +var signer = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + +var result = await TezsterDart.sendContractOriginationOperation( + server, + signer, + keyStore, + 0, + null, + 100000, + 1000, + 100000, + contract, + storage, + codeFormat: TezosParameterFormat.Michelson, + ); + +print("Operation groupID ===> $result['operationGroupID']"); + +var groupId = result['operationGroupID']; + +var conseilResult = await TezsterDart.awaitOperationConfirmation( + serverInfo, network, groupId, 5); + +print('Originated contract at ${conseilResult['originated_contracts']}'); + +``` +reference link: `https://github.com/Tezsure/Tezster_dart/blob/master/example/lib/main.dart#L162` +
+ --- **NOTE:** Use stable version of flutter to avoid package conflicts. @@ -94,4 +309,4 @@ Use stable version of flutter to avoid package conflicts. ### Feature requests and bugs -Please file feature requests and bugs at the [issue tracker](https://github.com/Tezsure/tezster_dart/issues/new). If you want to contribute to this libary, please submit a Pull Request. +Please file feature requests and bugs at the [issue tracker](https://github.com/Tezsure/tezster_dart/issues/new). If you want to contribute to this libary, please submit a Pull Request. \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 87cb847..fe6262c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -18,61 +18,96 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { tezosWalletUtil() async { - // //Generate mnemonic - // String mnemonic = TezsterDart - // .generateMnemonic(); // strength is optional, by default it's 256 ==> Generates 24 words. - // print("mnemonic ===> $mnemonic"); - // //mnemonic ===> 24 random words, [If strength parameter is changed the words length differs.] - - // //Generate keys from mnemonic - // List keys = await TezsterDart.getKeysFromMnemonic( - // mnemonic: - // "luxury bulb roast timber sense stove sugar sketch goddess host meadow decorate gather salmon funny person canoe daring machine network camp moment wrong dice", - // ); - // print("keys ===> $keys"); - // //keys ===> [privateKey, publicKey, publicKeyHash] - // //Accessing: private key ===> keys[0] | public key ===> keys[1] | public Key Hash ===> identity[2] all of type string - - // //Create / Unlock identity from mnemonic and passphrase. - // List identity = await TezsterDart.getKeysFromMnemonicAndPassphrase( - // mnemonic: - // "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", - // passphrase: "5tjpU0cimq", - // ); - // print("identity ===> $identity"); - // // identityWithMnemonic ===> [privateKey, publicKey, publicKeyHash] - // // Accessing: private key ===> identity[0] | public key ===> identity[1] | public Key Hash ===> identity[2] all of type string. - - // //Sign operation with public-Key and forged operation - // List signOpGrp = await TezsterDart.signOperationGroup( - // privateKey: - // "edskRdVS5H9YCRAG8yqZkX2nUTbGcaDqjYgopkJwRuPUnYzCn3t9ZGksncTLYe33bFjq29pRhpvjQizCCzmugMGhJiXezixvdC", - // forgedOperation: - // "713cb068fe3ac078351727eb5c34279e22b75b0cf4dc0a8d3d599e27031db136040cb9f9da085607c05cac1ca4c62a3f3cfb8146aa9b7f631e52f877a1d363474404da8130b0b940ee", - // ); - // print("signOperationGroup ===> $signOpGrp"); - // //signOperationGroup ===> [hexSignature, signedOpBytes] - // //Accessing: hex signature ===> signOpGrp[0] | signed Operation bytes ===> signOpGrp[1] all of type string - - // //Unlock fundraiser identity. - // List identityFundraiser = - // await TezsterDart.unlockFundraiserIdentity( - // mnemonic: - // "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", - // email: "lkbpoife.tobqgidu@tezos.example.org", - // passphrase: "5tjpU0cimq", - // ); - // print("identityFundraiser ===> $identityFundraiser"); - // //identityFundraiser ===> [privateKey, publicKey, publicKeyHash] - // //Accessing: private key ===> identityFundraiser[0] | public key ===> identityFundraiser[1] | public Key Hash ===> identityFundraiser[2] all of type string. + //Generate mnemonic + String mnemonic = TezsterDart + .generateMnemonic(); // strength is optional, by default it's 256 ==> Generates 24 words. + print("mnemonic ===> $mnemonic"); + //mnemonic ===> 24 random words, [If strength parameter is changed the words length differs.] + + //Generate keys from mnemonic + List keys = await TezsterDart.getKeysFromMnemonic( + mnemonic: + "luxury bulb roast timber sense stove sugar sketch goddess host meadow decorate gather salmon funny person canoe daring machine network camp moment wrong dice", + ); + print("keys ===> $keys"); + //keys ===> [privateKey, publicKey, publicKeyHash] + //Accessing: private key ===> keys[0] | public key ===> keys[1] | public Key Hash ===> identity[2] all of type string + + //Create / Unlock identity from mnemonic and passphrase. + List identity = await TezsterDart.getKeysFromMnemonicAndPassphrase( + mnemonic: + "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", + passphrase: "5tjpU0cimq", + ); + print("identity ===> $identity"); + // identityWithMnemonic ===> [privateKey, publicKey, publicKeyHash] + // Accessing: private key ===> identity[0] | public key ===> identity[1] | public Key Hash ===> identity[2] all of type string. + + //Sign operation with public-Key and forged operation + List signOpGrp = await TezsterDart.signOperationGroup( + privateKey: + "edskRdVS5H9YCRAG8yqZkX2nUTbGcaDqjYgopkJwRuPUnYzCn3t9ZGksncTLYe33bFjq29pRhpvjQizCCzmugMGhJiXezixvdC", + forgedOperation: + "713cb068fe3ac078351727eb5c34279e22b75b0cf4dc0a8d3d599e27031db136040cb9f9da085607c05cac1ca4c62a3f3cfb8146aa9b7f631e52f877a1d363474404da8130b0b940ee", + ); + print("signOperationGroup ===> $signOpGrp"); + //signOperationGroup ===> [hexSignature, signedOpBytes] + //Accessing: hex signature ===> signOpGrp[0] | signed Operation bytes ===> signOpGrp[1] all of type string + + //Unlock fundraiser identity. + List identityFundraiser = + await TezsterDart.unlockFundraiserIdentity( + mnemonic: + "cannon rabbit obvious drama slogan net acoustic donor core acoustic clinic poem travel plunge winter", + email: "lkbpoife.tobqgidu@tezos.example.org", + passphrase: "5tjpU0cimq", + ); + print("identityFundraiser ===> $identityFundraiser"); + //identityFundraiser ===> [privateKey, publicKey, publicKeyHash] + //Accessing: private key ===> identityFundraiser[0] | public key ===> identityFundraiser[1] | public Key Hash ===> identityFundraiser[2] all of type string. + + // Get Balance + String balance = + await TezsterDart.getBalance('tz1c....ozGGs', 'your rpc server'); + print("Accoutn Balance ===> $balance"); + + var server = ''; var keyStore = KeyStoreModel( - publicKey: 'edpkuh9tUmMMVKJVqG4bJxNLsCob6y8wXycshi6Pn11SQ5hx7SAVjf', + publicKey: 'edpkvQtuhdZQmjdjVfaY9Kf4hHfrRJYugaJErkCGvV3ER1S7XWsrrj', secretKey: - 'edskRs9KBdoU675PBVyHdM3fqixemkykm7hgHeXAYKUjdoVn3Aev8dP11p47zc4iuWJsefSP4t2vdHPoQisQC3DjZY3ZbbSP9Y', - publicKeyHash: 'tz1LRibbLEEWpaXb4aKrXXgWPvx9ue9haAAV', + 'edskRgu8wHxjwayvnmpLDDijzD3VZDoAH7ZLqJWuG4zg7LbxmSWZWhtkSyM5Uby41rGfsBGk4iPKWHSDniFyCRv3j7YFCknyHH', + publicKeyHash: 'tz1QSHaKpTFhgHLbqinyYRjxD5sLcbfbzhxy', ); + //Send transaction + var transactionSigner = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + var transactionResult = await TezsterDart.sendTransactionOperation( + server, + transactionSigner, + keyStore, + 'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc', + 500000, + 1500, + ); + print("Applied operation ===> $transactionResult['appliedOp']"); + print("Operation groupID ===> $transactionResult['operationGroupID']"); + + //Send delegation + var delegationSigner = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + var delegationResult = await TezsterDart.sendDelegationOperation( + server, + delegationSigner, + keyStore, + 'tz1RVcUP9nUurgEJMDou8eW3bVDs6qmP5Lnc', + 10000, + ); + print("Applied operation ===> $delegationResult['appliedOp']"); + print("Operation groupID ===> $delegationResult['operationGroupID']"); + + //Deploy a contract var contract = """parameter string; storage string; code { DUP; @@ -82,16 +117,13 @@ class _MyAppState extends State { NIL operation; PAIR}"""; var storage = '"Sample"'; - var signer = await TezsterDart.createSigner( + var contractOriginationSigner = await TezsterDart.createSigner( TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); - print(signer); - - var server = 'https://testnet.tezster.tech'; - - var result = await TezsterDart.sendContractOriginationOperation( + var resultContractOrigination = + await TezsterDart.sendContractOriginationOperation( server, - signer, + contractOriginationSigner, keyStore, 0, null, @@ -102,25 +134,19 @@ class _MyAppState extends State { storage, codeFormat: TezosParameterFormat.Michelson, ); - var groupId = result['operationGroupID']; - print("Injected operation group id ${result['operationGroupID']}"); - var network = 'delphinet'; - var serverInfo = { - 'url': 'https://conseil-dev.cryptonomic-infra.tech:443', - 'apiKey': 'f420a571-d526-4252-89e4-d7a2eb7f26b4', - 'network': network - }; + print( + "Operation groupID ===> $resultContractOrigination['operationGroupID']"); - var conseilResult = await TezsterDart.awaitOperationConfirmation( - serverInfo, network, groupId, 5); - print('Originated contract at ${conseilResult['originated_contracts']}'); + //Call a contract + var contractInvocationSigner = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); - var contractAddress = conseilResult['originated_contracts']; + var contractAddress = 'KT1KA7DqFjShLC4CPtChPX8QtRYECUb99xMY'; var resultInvoke = await TezsterDart.sendContractInvocationOperation( server, - signer, + contractInvocationSigner, keyStore, contractAddress, 10000, @@ -131,14 +157,46 @@ class _MyAppState extends State { '"Cryptonomicon"', codeFormat: TezosParameterFormat.Michelson); - print('Injected operation group id ${resultInvoke['operationGroupID']}'); + print("Operation groupID ===> $resultInvoke['operationGroupID']"); + + //Await opration Confirmation + var network = 'carthagenet'; + + var serverInfo = {'url': '', 'apiKey': '', 'network': network}; + + var operationConfirmationSigner = await TezsterDart.createSigner( + TezsterDart.writeKeyWithHint(keyStore.secretKey, 'edsk')); + + var resultoperationConfirmation = + await TezsterDart.sendContractOriginationOperation( + server, + operationConfirmationSigner, + keyStore, + 0, + null, + 100000, + 1000, + 100000, + contract, + storage, + codeFormat: TezosParameterFormat.Michelson, + ); + + print( + "Operation groupID ===> $resultoperationConfirmation['operationGroupID']"); + + var groupId = resultoperationConfirmation['operationGroupID']; + + var conseilResult = await TezsterDart.awaitOperationConfirmation( + serverInfo, network, groupId, 5); + + print('Originated contract at ${conseilResult['originated_contracts']}'); } @override void initState() { super.initState(); tezosWalletUtil(); - // runNewTestingDemo(); } @override diff --git a/example/pubspec.lock b/example/pubspec.lock index 5ac259d..0878060 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -144,15 +144,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.3" - michelson_parser: - dependency: transitive - description: - path: "." - ref: HEAD - resolved-ref: cbda67adc5f8a3287c4b98e822f9d2766e55f51b - url: "https://github.com/Jay-Tezsure/michelson_parser.git" - source: git - version: "0.0.1" password_hash: dependency: transitive description: @@ -251,4 +242,4 @@ packages: version: "2.1.0-nullsafety.3" sdks: dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.20.0" + flutter: ">=1.10.0" diff --git a/lib/chain/tezos/tezos_language_util.dart b/lib/chain/tezos/tezos_language_util.dart index 3bcd701..041ee8a 100644 --- a/lib/chain/tezos/tezos_language_util.dart +++ b/lib/chain/tezos/tezos_language_util.dart @@ -1,4 +1,5 @@ -import 'package:michelson_parser/michelson_parser.dart'; + +import 'package:tezster_dart/michelson_parser/michelson_parser.dart'; class TezosLanguageUtil { static String translateMichelsonToMicheline(String code) { diff --git a/lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart b/lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart new file mode 100644 index 0000000..502d155 --- /dev/null +++ b/lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart @@ -0,0 +1,198 @@ +import 'dart:math'; +import 'michelson_grammar_tokenizer.dart'; + +class MichelinGrammarTokenizer { + Map delimiters; + List tokens = []; + var buffer; + int index; + var line; + var lastLineBreak; + + MichelinGrammarTokenizer(this.delimiters) : super(); + + feed(String text) { + tokenize(text); + return tokens; + } + + var numindex = 0; + + next() { + if (tokens.isEmpty) feed(this.buffer.toString()); + var result = tokens.length > numindex + ? { + "type": tokens[numindex].type, + "value": tokens[numindex].value, + "text": tokens[numindex].value, + "col": tokens[numindex].columnNumber, + "line": '1', + // 'toString': () => tokens[numindex].value, + } + : null; + numindex++; + return result; + } + + has(tokenType) { + return true; + } + + reset(data, {state}) { + this.buffer = data; + this.index = 0; + this.line = state != null ? state.line : 1; + this.lastLineBreak = state != null ? -state.col : 0; + } + + save() { + return { + 'line': this.line, + 'col': this.index - this.lastLineBreak, + }; + } + + formatError(token, message) { + var value = token['text']; + int index = token['col']; + var start = max(0, index - token['col']); + var firstLine = this.buffer.substring(start, index + value.length); + message += " at line " + + token['line'] + + " col " + + token['col'].toString() + + ":\n\n"; + message += " " + firstLine + "\n"; + message += + " " + List.generate(token['col'] + 1, (e) => '').join(" ") + "^"; + return message; + } + + tokenize(String chunk) { + for (int i = 0; i < chunk.length; i++) { + final char = chunk[i]; + if (char == ' ') { + var argSeq = getKeyFromValue(char); + tokens.add(GrammarResultModel(argSeq.key, char)..columnNumber = i); + continue; + } + if (isArrayOrStringContaines(char, isRegexCheck: false)) { + var argSeq = getKeyFromValue(char); + tokens.add(GrammarResultModel(argSeq.key, char)..columnNumber = i); + continue; + } + if (isArrayOrStringContaines(char, isRegexCheck: true)) { + var seq = char; + for (int j = i + 1; j < i + 50; j++) { + if (j >= chunk.length - 1) break; + if (isArrayOrStringContaines(seq) && chunk[j] != '_') { + var __seq = chunk[j]; + for (var i = 1; i < 10; i++) { + try { + var ele = chunk[j + i]; + if (isArrayOrStringContaines(seq + __seq)) { + seq += __seq; + break; + } + __seq += ele; + } catch (e) {} + } + var argSeq = getKeyFromValue(seq); + tokens.add(GrammarResultModel(argSeq.key, seq)..columnNumber = i); + i += (seq.length - 1); + seq = ''; + break; + } + seq += chunk[j]; + } + // if (seq.isNotEmpty) { + // if (tokens.last.type == 'word' && + // getKeyFromValue(char, isRegex: false) == null) { + // tokens.last = tokens.last..value += char; + // } else if (tokens.last.type == 'number' && + // getKeyFromValue(char, isRegex: true).key == "number") { + // tokens.last = tokens.last..value += char; + // } else if (isArrayOrStringContaines(seq)) { + // var argSeq = getKeyFromValue(seq); + // tokens.add(GrammarResultModel(argSeq.key, seq)..columnNumber = i); + // i += (seq.length - 1); + // } else { + // if (char != '%') { + // var argSeq = getKeyFromValue(char); + // tokens + // .add(GrammarResultModel(argSeq.key, char)..columnNumber = i); + // } + // } + // } + } + // else if (char == '%' || char == ':') { + // var nextIndex = i + 30; + // if (nextIndex >= chunk.length - 1) nextIndex = chunk.length - 1; + // var data = chunk.substring( + // i, + // nextIndex, + // ); + // var endIndex = getEndIndexOfVar(data); + // tokens.add(GrammarResultModel('annot', data.substring(0, endIndex)) + // ..columnNumber = i); + // i += endIndex - 1; + // } + else if (char == '"') { + var nextIndex = i + 200; + if (nextIndex >= chunk.length - 1) nextIndex = chunk.length; + var data = chunk.substring( + i + 1, + nextIndex, + ); + var rs = chunk.substring(i, i + data.indexOf('"') + 2); + tokens.add(GrammarResultModel('quotedValue', rs)..columnNumber = i); + i += rs.length - 1; + } else { + print("No match found ==> $char"); + } + } + } + + int getEndIndexOfVar(String text) { + for (var i = 0; i < text.length; i++) { + if (isArrayOrStringContaines(text[i]) || text[i] == ' ') { + return i; + } + } + return text.length; + } + + bool isArrayOrStringContaines(char, {isRegexCheck = false}) { + if (delimiters.values.contains(char)) return true; + var result = false; + var _keys = delimiters.keys.toList(); + for (var i = 0; i < _keys.length; i++) { + // var key = _keys[i]; + var value = delimiters[_keys[i]]; + if (value is List) { + result = value.contains(char); + if (result) break; + } + if (value is RegExp && isRegexCheck) { + result = value.hasMatch(char); + if (result) break; + } + } + + return result; + } + + getKeyFromValue(String char, {isRegex = true}) { + var result; + for (var data in delimiters.entries) { + var isContain = data.value is List + ? data.value.contains(char) + : data.value is RegExp && isRegex + ? (data.value as RegExp).hasMatch(char) + : data.value == char; + if (isContain) result = data; + if (result != null) break; + } + return result; + } +} diff --git a/lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart b/lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart new file mode 100644 index 0000000..6e8d683 --- /dev/null +++ b/lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart @@ -0,0 +1,200 @@ +import 'dart:math'; + +class MichelsonGrammarTokenizer { + Map delimiters; + List tokens = []; + var buffer; + int index; + var line; + var lastLineBreak; + + MichelsonGrammarTokenizer(this.delimiters) : super(); + + feed(String text) { + tokenize(text); + return tokens; + } + + var numindex = 0; + + next() { + if (tokens.isEmpty) feed(this.buffer.toString()); + var result = tokens.length > numindex + ? { + "type": tokens[numindex].type, + "value": tokens[numindex].value, + "text": tokens[numindex].value, + "col": tokens[numindex].columnNumber, + "line": '1', + // 'toString': () => tokens[numindex].value, + } + : null; + numindex++; + return result; + } + + has(tokenType) { + return true; + } + + reset(data, {state}) { + this.buffer = data; + this.index = 0; + this.line = state != null ? state.line : 1; + this.lastLineBreak = state != null ? -state.col : 0; + } + + save() { + return { + 'line': this.line, + 'col': this.index - this.lastLineBreak, + }; + } + + formatError(token, message) { + var value = token['text']; + int index = token['col']; + var start = max(0, index - token['col']); + var firstLine = this.buffer.substring(start, index + value.length); + message += " at line " + + token['line'] + + " col " + + token['col'].toString() + + ":\n\n"; + message += " " + firstLine + "\n"; + message += + " " + List.generate(token['col'] + 1, (e) => '').join(" ") + "^"; + return message; + } + + tokenize(String chunk) { + for (int i = 0; i < chunk.length; i++) { + final char = chunk[i]; + if (char == ' ') { + var argSeq = getKeyFromValue(char); + tokens.add(GrammarResultModel(argSeq.key, char)..columnNumber = i); + continue; + } + if (isArrayOrStringContaines(char, isRegexCheck: true)) { + var seq = char; + for (int j = i + 1; j < i + 50; j++) { + if (j >= chunk.length - 1) break; + if (isArrayOrStringContaines(seq) && chunk[j] != '_') { + var __seq = chunk[j]; + for (var i = 1; i < 10; i++) { + try { + var ele = chunk[j + i]; + if (isArrayOrStringContaines(seq + __seq)) { + seq += __seq; + break; + } + __seq += ele; + } catch (e) {} + } + var argSeq = getKeyFromValue(seq); + tokens.add(GrammarResultModel(argSeq.key, seq)..columnNumber = i); + i += (seq.length - 1); + seq = ''; + break; + } + seq += chunk[j]; + } + if (seq.isNotEmpty) { + if (tokens.last.type == 'word' && + getKeyFromValue(char, isRegex: false) == null) { + tokens.last = tokens.last..value += char; + } else if (tokens.last.type == 'number' && + getKeyFromValue(char, isRegex: true).key == "number") { + tokens.last = tokens.last..value += char; + } else if (isArrayOrStringContaines(seq)) { + var argSeq = getKeyFromValue(seq); + tokens.add(GrammarResultModel(argSeq.key, seq)..columnNumber = i); + i += (seq.length - 1); + } else { + if (char != '%') { + var argSeq = getKeyFromValue(char); + tokens + .add(GrammarResultModel(argSeq.key, char)..columnNumber = i); + } + } + } + } else if (char == '%' || char == ':') { + var nextIndex = i + 30; + if (nextIndex >= chunk.length - 1) nextIndex = chunk.length - 1; + var data = chunk.substring( + i, + nextIndex, + ); + var endIndex = getEndIndexOfVar(data); + tokens.add(GrammarResultModel('annot', data.substring(0, endIndex)) + ..columnNumber = i); + i += endIndex - 1; + } else if (char == '"') { + var nextIndex = i + 200; + if (nextIndex >= chunk.length - 1) nextIndex = chunk.length; + var data = chunk.substring( + i + 1, + nextIndex, + ); + var rs = chunk.substring(i, i + data.indexOf('"') + 2); + tokens.add(GrammarResultModel('string', rs)..columnNumber = i); + i += rs.length - 1; + } else { + print("No match found ==> $char"); + } + } + } + + int getEndIndexOfVar(String text) { + for (var i = 0; i < text.length; i++) { + if (isArrayOrStringContaines(text[i]) || text[i] == ' ') { + return i; + } + } + return text.length; + } + + bool isArrayOrStringContaines(char, {isRegexCheck = false}) { + if (delimiters.values.contains(char)) return true; + var result = false; + var _keys = delimiters.keys.toList(); + for (var i = 0; i < _keys.length; i++) { + // var key = _keys[i]; + var value = delimiters[_keys[i]]; + if (value is List) { + result = value.contains(char); + if (result) break; + } + if (value is RegExp && isRegexCheck) { + result = value.hasMatch(char); + if (result) break; + } + } + + return result; + } + + getKeyFromValue(String char, {isRegex = true}) { + var result; + for (var data in delimiters.entries) { + var isContain = data.value is List + ? data.value.contains(char) + : data.value is RegExp && isRegex + ? (data.value as RegExp).hasMatch(char) + : data.value == char; + if (isContain) result = data; + if (result != null) break; + } + return result; + } +} + +class GrammarResultModel { + String type; + String value; + int columnNumber; + + GrammarResultModel(this.type, this.value); + + toJson() => {'type': type, 'value': value}; +} diff --git a/lib/michelson_parser/michelson_parser.dart b/lib/michelson_parser/michelson_parser.dart new file mode 100644 index 0000000..f4eab09 --- /dev/null +++ b/lib/michelson_parser/michelson_parser.dart @@ -0,0 +1,76 @@ +import 'package:tezster_dart/michelson_parser/parser/micheline_grammar.dart'; +import 'package:tezster_dart/michelson_parser/parser/michelson_grammar.dart'; +import 'package:tezster_dart/michelson_parser/parser/nearley.dart'; + +class MichelsonParser { + /// code = michelson code + static String parseMichelson(String code) { + var parser = Nearley(); + parser.parser(Nearley.fromCompiled(MichelsonGrammar().grammar)); + var cleanCode = preProcessMichelsonScript(code); + cleanCode.map((_code) => parser.feed(_code)).toList(); + return parser.results[0]; + } + + static translateMichelineToHex(code) { + var parser = Nearley(); + parser.parser(Nearley.fromCompiled(MichelineGrammar().grammar)); + parser.feed(normalizeMichelineWhiteSpace(code)); + return parser.results.join(''); + } + + static String normalizeMichelineWhiteSpace(String fragment) { + return fragment + .replaceAll(new RegExp(r'\n/g'), ' ') + .replaceAll(new RegExp(r' +'), ' ') + .replaceAll(new RegExp(r'\[{'), '[ {') + .replaceAll(new RegExp(r'}\]'), '} ]') + .replaceAll(new RegExp(r'},{'), '}, {') + .replaceAll(new RegExp(r'\]}'), '] }') + .replaceAll(new RegExp(r'":"'), '": "') + .replaceAll(new RegExp(r'":\['), '": [') + .replaceAll(new RegExp(r'{"'), '{ "') + .replaceAll(new RegExp(r'"}'), '" }') + .replaceAll(new RegExp(r',"'), ', "') + .replaceAll(new RegExp(r'","'), '", "') + .replaceAll(new RegExp(r'\[\['), '[ [') + .replaceAll(new RegExp(r'\]\]'), '] ]') + .replaceAll(new RegExp(r'\["'), '[ "') + .replaceAll(new RegExp(r'"\]'), '" ]') + .replaceAll(new RegExp(r'\[ +\]'), '\[\]') + .trim(); + } + + static List preProcessMichelsonScript(String code) { + var sections = Map(); + sections['parameter'] = code.indexOf(RegExp(r'(^|\s+)parameter')); + sections['storage'] = code.indexOf(RegExp(r'(^|\s+)storage')); + sections['code'] = code.indexOf(RegExp(r'(^|\s+)code')); + var boundaries = sections.values.toList(); + boundaries.sort((a, b) => a - b); + sections[ + sections.keys.firstWhere((key) => sections[key] == boundaries[0])] = + code.substring(boundaries[0] < 0 ? 0 : boundaries[0], + boundaries[1] < 0 ? 0 : boundaries[1]); + sections[ + sections.keys.firstWhere((key) => sections[key] == boundaries[1])] = + code.substring(boundaries[1] < 0 ? 0 : boundaries[1], + boundaries[2] < 0 ? 0 : boundaries[2]); + sections[ + sections.keys.firstWhere((key) => sections[key] == boundaries[2])] = + code.substring(boundaries[2] < 0 ? 0 : boundaries[2]); + var parts = [sections['parameter'], sections['storage'], sections['code']]; + return parts + .map((p) => p + .trim() + .split('\n') + .map( + (l) => l.replaceAll(RegExp(r'\#[\s\S]+$'), '').trim(), + ) + .toList() + .where((e) => e.toString().isNotEmpty) + .toList() + .join(' ')) + .toList(); + } +} diff --git a/lib/michelson_parser/parser/micheline_grammar.dart b/lib/michelson_parser/parser/micheline_grammar.dart new file mode 100644 index 0000000..15ad69d --- /dev/null +++ b/lib/michelson_parser/parser/micheline_grammar.dart @@ -0,0 +1,1154 @@ + +import 'package:tezster_dart/michelson_parser/grammar/michelin_grammar_tokenizer.dart'; + +class MichelineGrammar { + MichelinGrammarTokenizer lexer; + var lbrace, _, colon, quotedValue, rbrace, comma, lbracket, rbracket; + final List defaultMichelsonKeywords = [ + '"parameter"', + '"storage"', + '"code"', + '"False"', + '"Elt"', + '"Left"', + '"None"', + '"Pair"', + '"Right"', + '"Some"', + '"True"', + '"Unit"', + '"PACK"', + '"UNPACK"', + '"BLAKE2B"', + '"SHA256"', + '"SHA512"', + '"ABS"', + '"ADD"', + '"AMOUNT"', + '"AND"', + '"BALANCE"', + '"CAR"', + '"CDR"', + '"CHECK_SIGNATURE"', + '"COMPARE"', + '"CONCAT"', + '"CONS"', + '"CREATE_ACCOUNT"', + '"CREATE_CONTRACT"', + '"IMPLICIT_ACCOUNT"', + '"DIP"', + '"DROP"', + '"DUP"', + '"EDIV"', + '"EMPTY_MAP"', + '"EMPTY_SET"', + '"EQ"', + '"EXEC"', + '"FAILWITH"', + '"GE"', + '"GET"', + '"GT"', + '"HASH_KEY"', + '"IF"', + '"IF_CONS"', + '"IF_LEFT"', + '"IF_NONE"', + '"INT"', + '"LAMBDA"', + '"LE"', + '"LEFT"', + '"LOOP"', + '"LSL"', + '"LSR"', + '"LT"', + '"MAP"', + '"MEM"', + '"MUL"', + '"NEG"', + '"NEQ"', + '"NIL"', + '"NONE"', + '"NOT"', + '"NOW"', + '"OR"', + '"PAIR"', + '"PUSH"', + '"RIGHT"', + '"SIZE"', + '"SOME"', + '"SOURCE"', + '"SENDER"', + '"SELF"', + '"STEPS_TO_QUOTA"', + '"SUB"', + '"SWAP"', + '"TRANSFER_TOKENS"', + '"SET_DELEGATE"', + '"UNIT"', + '"UPDATE"', + '"XOR"', + '"ITER"', + '"LOOP_LEFT"', + '"ADDRESS"', + '"CONTRACT"', + '"ISNAT"', + '"CAST"', + '"RENAME"', + '"bool"', + '"contract"', + '"int"', + '"key"', + '"key_hash"', + '"lambda"', + '"list"', + '"map"', + '"big_map"', + '"nat"', + '"option"', + '"or"', + '"pair"', + '"set"', + '"signature"', + '"string"', + '"bytes"', + '"mutez"', + '"timestamp"', + '"unit"', + '"operation"', + '"address"', + '"SLICE"', + '"DIG"', + '"DUG"', + '"EMPTY_BIG_MAP"', + '"APPLY"', + '"chain_id"', + '"CHAIN_ID"' + ]; + List languageKeywords; + + MichelineGrammar() { + languageKeywords = defaultMichelsonKeywords; + lexer = MichelinGrammarTokenizer({ + 'lbrace': '{', + 'rbrace': '}', + 'lbracket': '[', + 'rbracket': ']', + 'colon': ":", + 'comma': ",", + '_': RegExp(r'[ \t]+'), + 'quotedValue': RegExp(r'"(?:\\["\\]|[^\n"\\])*"') + }); + } + + id(d) { + return d[0]; + } + + void setKeywordList(List list) { + languageKeywords = list; + } + + int getCodeForKeyword(String word) { + return languageKeywords.indexOf(word); + } + + String getKeywordForWord(int index) { + return languageKeywords[index]; + } + + String staticIntToHex(d) { + final prefix = '00'; + final String text = getMapValue(d[6]); + final value = writeSignedInt(int.parse(text.substring(1, text.length - 1))); + return prefix + value; + } + + String staticStringToHex(d) { + final String prefix = '01'; + var text = getMapValue(d[6]); + text = text.substring(1, text.length - 1); + text = text.replaceAll(RegExp(r'\\"'), '"'); + final len = encodeLength(text.length); + text = text + .split('') + .map((c) => c.codeUnitAt(0).toRadixString(16).toString()) + .join(''); + return prefix + len + text; + } + + String staticBytesToHex(d) { + final prefix = '0a'; + var bytes = getMapValue(d[6]); + bytes = bytes.substring(1, bytes.length - 1); + final len = encodeLength(int.parse((bytes.length ~/ 2).toString())); + return prefix + len + bytes; + } + + removeSameMatched(list) { + var newArr = [ + [-1] + ]; + for (var i = 0; i < list.length; i++) { + if (list[i][0] != newArr[newArr.length - 1][0]) { + newArr.add(list[i]); + } + } + return newArr..removeAt(0); + } + + removeIfNextIsSame(list) { + for (var i = 0; i < list.length; i++) { + if (i != 0 && list[i - 1][0] == list[i][0]) { + list.removeAt(i); + } + } + return list; + } + + String staticArrayToHex(List d) { + List matchedArray = d[2]; + matchedArray = removeIfNextIsSame(removeIfNextIsSame(matchedArray)); + final String prefix = '02'; + String content = matchedArray.map((e) => e[0]).join(''); + final len = encodeLength(int.parse((content.length ~/ 2).toString())); + return prefix + len + content; + } + + String primBareToHex(d) { + final String prefix = '03'; + final String prim = encodePrimitive(getMapValue(d[6])); + return prefix + prim; + } + + String primAnnToHex(List d) { + final String prefix = '04'; + final String prim = encodePrimitive(getMapValue(d[6])); + String ann = d[15].map((e) { + String t = getMapValue(e[0]); + t = t.substring(1, t.length - 1); + return t; + }).join(''); + ann = ann + .split('') + .map((e) => e.codeUnitAt(0).toRadixString(16).toString()) + .join(''); + ann = encodeLength(int.parse((ann.length ~/ 2).toString())) + ann; + return prefix + prim + ann; + } + + String primArgToHex(List d) { + String prefix = '05'; + if (d[15].length > 2) { + for (var i = 0; i < d[15].length; i++) { + if (i != 0 && d[15][i - 1][0] == d[15][i][0]) { + d[15].removeAt(i); + } + } + } + if (d[15].length == 2) { + prefix = '07'; + } else { + if (d[15].length > 2) { + prefix = '09'; + } + } + final String prim = encodePrimitive(getMapValue(d[6])); + String args = d[15].map((e) => e[0]).join(''); + String newArgs = ''; + if (prefix == '09') { + newArgs = '0000000' + + int.parse((args.length ~/ 2).toString()).toRadixString(16).toString(); + newArgs = newArgs.substring(newArgs.length - 8); + newArgs = newArgs + args + '00000000'; + } + newArgs = newArgs == '' ? args : newArgs; + return prefix + prim + newArgs; + } + + String primArgAnnToHex(List d) { + String prefix = '06'; + if (d[15].length > 2) { + for (var i = 0; i < d[15].length; i++) { + if (i != 0 && d[15][i - 1][0] == d[15][i][0]) { + d[15].removeAt(i); + } + } + } + if (d[15].length == 2) { + prefix = '08'; + } else if (d[15].length > 2) { + prefix = '09'; + } + String prim = encodePrimitive(getMapValue(d[6])); + String args = d[15].map((v) => v[0]).join(''); + String ann = d[26].map((v) { + String t = getMapValue(v[0]); + t = t.substring(1, t.length - 1); + return t; + }).join(' '); + ann = ann.split('').map((e) { + String d = e.codeUnitAt(0).toRadixString(16).toString(); + return d; + }).join(''); + ann = encodeLength(int.parse((ann.length ~/ 2).toString())) + ann; + String newArgs = ''; + if (prefix == '09') { + newArgs = '0000000' + + int.parse((args.length ~/ 2).toString()).toRadixString(16).toString(); + newArgs = newArgs.substring(newArgs.length - 8); + newArgs = newArgs + args; + } + newArgs = newArgs == '' ? args : newArgs; + return prefix + prim + newArgs + ann; + } + + String encodePrimitive(String p) { + String result = '00' + getCodeForKeyword(p).toRadixString(16).toString(); + result = result.substring(result.length - 2); + return result; + } + + String encodeLength(int l) { + String output = '0000000' + l.toRadixString(16).toString(); + return output.substring(output.length - 8); + } + + String writeSignedInt(int value) { + if (value == 0) { + return '00'; + } + final BigInt n = BigInt.from(value).abs(); + final l = n.bitLength.toInt(); + List arr = []; + BigInt v = n; + for (var i = 0; i < l; i += 7) { + BigInt byte = BigInt.zero; + if (i == 0) { + byte = v & BigInt.from(0x3f); + v = v >> 6; + } else { + byte = v & BigInt.from(0x7f); + v = v >> 7; + } + + if (value < 0 && i == 0) { + byte = byte | BigInt.from(0x40); + } + + if (i + 7 < l) { + byte = byte | BigInt.from(0x80); + } + arr.add(byte.toInt()); + } + + if (l % 7 == 0) { + arr[arr.length - 1] = + arr[arr.length - 1] == null ? 0x80 : arr[arr.length - 1]; + arr.add(1); + } + + var output = arr.map((v) { + int newNum = int.parse(v.toString()); + var str = '0' + newNum.toRadixString(16).toString(); + str = str.substring(str.length - 2); + return str; + }).join(''); + return output.substring(output.length - 2); + } + + getMapValue(d) => d is List ? d[0]['value'].toString() : d['value']; + +// interface NearleyToken { value: any; +// [key: string]: any; +// }; + +// interface NearleyLexer { +// reset: (chunk: string, info: any) => void; +// next: () => NearleyToken | undefined; +// save: () => any; +// formatError: (token: NearleyToken) => string; +// has: (tokenType: string) => boolean; +// }; + +// interface NearleyRule { +// name: string; +// symbols: NearleySymbol[]; +// postprocess?: (d: any[], loc?: number, reject?: {}) => any; +// }; + +// type NearleySymbol = string | { literal: any } | { test: (token: any) => boolean }; + +// interface Grammar { +// Lexer: NearleyLexer | undefined; +// ParserRules: NearleyRule[]; +// ParserStart: string; +// }; + + Map get grammar => { + 'Lexer': lexer, + 'ParserRules': [ + { + "name": "main", + "symbols": ["staticObject"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["primBare"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["primArg"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["primAnn"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["primArgAnn"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["anyArray"], + "postprocess": id + }, + {"name": r"staticInt$ebnf$1", "symbols": []}, + { + "name": r"staticInt$ebnf$1", + "symbols": [ + r"staticInt$ebnf$1", + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "staticInt", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"int\""}, + r"staticInt$ebnf$1", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": staticIntToHex + }, + {"name": r"staticString$ebnf$1", "symbols": []}, + { + "name": r"staticString$ebnf$1", + "symbols": [ + r"staticString$ebnf$1", + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "staticString", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"string\""}, + r"staticString$ebnf$1", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": staticStringToHex + }, + {"name": r"staticBytes$ebnf$1", "symbols": []}, + { + "name": r"staticBytes$ebnf$1", + "symbols": [ + r"staticBytes$ebnf$1", + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "staticBytes", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"bytes\""}, + r"staticBytes$ebnf$1", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": staticBytesToHex + }, + { + "name": "staticObject", + "symbols": ["staticInt"], + "postprocess": id + }, + { + "name": "staticObject", + "symbols": ["staticString"], + "postprocess": id + }, + { + "name": "staticObject", + "symbols": ["staticBytes"], + "postprocess": id + }, + {"name": r"primBare$ebnf$1", "symbols": []}, + { + "name": r"primBare$ebnf$1", + "symbols": [ + r"primBare$ebnf$1", + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "primBare", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"prim\""}, + r"primBare$ebnf$1", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": primBareToHex + }, + { + "name": r"primArg$ebnf$1", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArg$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArg$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArg$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArg$ebnf$3$subexpression$1$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primArg$ebnf$3$subexpression$1$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArg$ebnf$3$subexpression$1$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArg$ebnf$3$subexpression$1$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArg$ebnf$3$subexpression$1", + "symbols": [ + "any", + r"primArg$ebnf$3$subexpression$1$ebnf$1", + r"primArg$ebnf$3$subexpression$1$ebnf$2" + ] + }, + { + "name": r"primArg$ebnf$3", + "symbols": [r"primArg$ebnf$3$subexpression$1"] + }, + { + "name": r"primArg$ebnf$3$subexpression$2$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primArg$ebnf$3$subexpression$2$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArg$ebnf$3$subexpression$2$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArg$ebnf$3$subexpression$2$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArg$ebnf$3$subexpression$2", + "symbols": [ + "any", + r"primArg$ebnf$3$subexpression$2$ebnf$1", + r"primArg$ebnf$3$subexpression$2$ebnf$2" + ] + }, + { + "name": r"primArg$ebnf$3", + "symbols": [r"primArg$ebnf$3", r"primArg$ebnf$3$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "primArg", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"prim\""}, + r"primArg$ebnf$1", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + (lexer.has("comma") ? {'type': "comma"} : comma), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"args\""}, + r"primArg$ebnf$2", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("lbracket") ? {'type': "lbracket"} : lbracket), + (lexer.has("_") ? {'type': "_"} : _), + r"primArg$ebnf$3", + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbracket") ? {'type': "rbracket"} : rbracket), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": primArgToHex + }, + { + "name": r"primAnn$ebnf$1", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primAnn$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primAnn$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primAnn$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primAnn$ebnf$3$subexpression$1$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primAnn$ebnf$3$subexpression$1$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primAnn$ebnf$3$subexpression$1$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primAnn$ebnf$3$subexpression$1$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primAnn$ebnf$3$subexpression$1", + "symbols": [ + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + r"primAnn$ebnf$3$subexpression$1$ebnf$1", + r"primAnn$ebnf$3$subexpression$1$ebnf$2" + ] + }, + { + "name": r"primAnn$ebnf$3", + "symbols": [r"primAnn$ebnf$3$subexpression$1"] + }, + { + "name": r"primAnn$ebnf$3$subexpression$2$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primAnn$ebnf$3$subexpression$2$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primAnn$ebnf$3$subexpression$2$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primAnn$ebnf$3$subexpression$2$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primAnn$ebnf$3$subexpression$2", + "symbols": [ + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + r"primAnn$ebnf$3$subexpression$2$ebnf$1", + r"primAnn$ebnf$3$subexpression$2$ebnf$2" + ] + }, + { + "name": r"primAnn$ebnf$3", + "symbols": [r"primAnn$ebnf$3", r"primAnn$ebnf$3$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "primAnn", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"prim\""}, + r"primAnn$ebnf$1", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + (lexer.has("comma") ? {'type': "comma"} : comma), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"annots\""}, + r"primAnn$ebnf$2", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("lbracket") ? {'type': "lbracket"} : lbracket), + (lexer.has("_") ? {'type': "_"} : _), + r"primAnn$ebnf$3", + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbracket") ? {'type': "rbracket"} : rbracket), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": primAnnToHex + }, + { + "name": r"primArgAnn$ebnf$1", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$1$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$1$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$1$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$1$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$1", + "symbols": [ + "any", + r"primArgAnn$ebnf$3$subexpression$1$ebnf$1", + r"primArgAnn$ebnf$3$subexpression$1$ebnf$2" + ] + }, + { + "name": r"primArgAnn$ebnf$3", + "symbols": [r"primArgAnn$ebnf$3$subexpression$1"] + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$2$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$2$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$2$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$2$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$3$subexpression$2", + "symbols": [ + "any", + r"primArgAnn$ebnf$3$subexpression$2$ebnf$1", + r"primArgAnn$ebnf$3$subexpression$2$ebnf$2" + ] + }, + { + "name": r"primArgAnn$ebnf$3", + "symbols": [ + r"primArgAnn$ebnf$3", + r"primArgAnn$ebnf$3$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": r"primArgAnn$ebnf$4", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$4", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$1$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$1$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$1$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$1$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$1", + "symbols": [ + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + r"primArgAnn$ebnf$5$subexpression$1$ebnf$1", + r"primArgAnn$ebnf$5$subexpression$1$ebnf$2" + ] + }, + { + "name": r"primArgAnn$ebnf$5", + "symbols": [r"primArgAnn$ebnf$5$subexpression$1"] + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$2$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$2$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$2$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$2$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"primArgAnn$ebnf$5$subexpression$2", + "symbols": [ + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + r"primArgAnn$ebnf$5$subexpression$2$ebnf$1", + r"primArgAnn$ebnf$5$subexpression$2$ebnf$2" + ] + }, + { + "name": r"primArgAnn$ebnf$5", + "symbols": [ + r"primArgAnn$ebnf$5", + r"primArgAnn$ebnf$5$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "primArgAnn", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"prim\""}, + r"primArgAnn$ebnf$1", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("quotedValue") + ? {'type': "quotedValue"} + : quotedValue), + (lexer.has("comma") ? {'type': "comma"} : comma), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"args\""}, + r"primArgAnn$ebnf$2", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("lbracket") ? {'type': "lbracket"} : lbracket), + (lexer.has("_") ? {'type': "_"} : _), + r"primArgAnn$ebnf$3", + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbracket") ? {'type': "rbracket"} : rbracket), + (lexer.has("comma") ? {'type': "comma"} : comma), + (lexer.has("_") ? {'type': "_"} : _), + {"literal": "\"annots\""}, + r"primArgAnn$ebnf$4", + (lexer.has("colon") ? {'type': "colon"} : colon), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("lbracket") ? {'type': "lbracket"} : lbracket), + (lexer.has("_") ? {'type': "_"} : _), + r"primArgAnn$ebnf$5", + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbracket") ? {'type': "rbracket"} : rbracket), + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": primArgAnnToHex + }, + { + "name": "primAny", + "symbols": ["primBare"], + "postprocess": id + }, + { + "name": "primAny", + "symbols": ["primArg"], + "postprocess": id + }, + { + "name": "primAny", + "symbols": ["primAnn"], + "postprocess": id + }, + { + "name": "primAny", + "symbols": ["primArgAnn"], + "postprocess": id + }, + { + "name": "any", + "symbols": ["primAny"], + "postprocess": id + }, + { + "name": "any", + "symbols": ["staticObject"], + "postprocess": id + }, + { + "name": "any", + "symbols": ["anyArray"], + "postprocess": id + }, + { + "name": "anyArray", + "symbols": [ + (lexer.has("lbracket") ? {'type': "lbracket"} : lbracket), + (lexer.has("rbracket") ? {'type': "rbracket"} : rbracket) + ], + "postprocess": (d) => '0200000000' + }, + { + "name": r"anyArray$ebnf$1$subexpression$1$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"anyArray$ebnf$1$subexpression$1$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"anyArray$ebnf$1$subexpression$1$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"anyArray$ebnf$1$subexpression$1$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"anyArray$ebnf$1$subexpression$1", + "symbols": [ + "any", + r"anyArray$ebnf$1$subexpression$1$ebnf$1", + r"anyArray$ebnf$1$subexpression$1$ebnf$2" + ] + }, + { + "name": r"anyArray$ebnf$1", + "symbols": [r"anyArray$ebnf$1$subexpression$1"] + }, + { + "name": r"anyArray$ebnf$1$subexpression$2$ebnf$1", + "symbols": [ + (lexer.has("comma") ? {'type': "comma"} : comma) + ], + "postprocess": id + }, + { + "name": r"anyArray$ebnf$1$subexpression$2$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"anyArray$ebnf$1$subexpression$2$ebnf$2", + "symbols": [ + (lexer.has("_") ? {'type': "_"} : _) + ], + "postprocess": id + }, + { + "name": r"anyArray$ebnf$1$subexpression$2$ebnf$2", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": r"anyArray$ebnf$1$subexpression$2", + "symbols": [ + "any", + r"anyArray$ebnf$1$subexpression$2$ebnf$1", + r"anyArray$ebnf$1$subexpression$2$ebnf$2" + ] + }, + { + "name": r"anyArray$ebnf$1", + "symbols": [r"anyArray$ebnf$1", r"anyArray$ebnf$1$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "anyArray", + "symbols": [ + (lexer.has("lbracket") ? {'type': "lbracket"} : lbracket), + (lexer.has("_") ? {'type': "_"} : _), + r"anyArray$ebnf$1", + (lexer.has("_") ? {'type': "_"} : _), + (lexer.has("rbracket") ? {'type': "rbracket"} : rbracket) + ], + "postprocess": staticArrayToHex + } + ], + 'ParserStart': "main", + }; +} diff --git a/lib/michelson_parser/parser/michelson_grammar.dart b/lib/michelson_parser/parser/michelson_grammar.dart new file mode 100644 index 0000000..5255047 --- /dev/null +++ b/lib/michelson_parser/parser/michelson_grammar.dart @@ -0,0 +1,2365 @@ + +import 'package:tezster_dart/michelson_parser/grammar/michelson_grammar_tokenizer.dart'; + +class MichelsonGrammar { + MichelsonGrammarTokenizer lexer; + + var macroCADRconst = 'C[AD]+R'; + var macroSETCADRconst = 'SET_C[AD]+R'; + var dIPmatcher = new RegExp('DII+P'); + var dUPmatcher = new RegExp('DUU+P'); + var macroASSERTlistConst = [ + 'ASSERT', + 'ASSERT_EQ', + 'ASSERT_NEQ', + 'ASSERT_GT', + 'ASSERT_LT', + 'ASSERT_GE', + 'ASSERT_LE', + 'ASSERT_NONE', + 'ASSERT_SOME', + 'ASSERT_LEFT', + 'ASSERT_RIGHT', + 'ASSERT_CMPEQ', + 'ASSERT_CMPNEQ', + 'ASSERT_CMPGT', + 'ASSERT_CMPLT', + 'ASSERT_CMPGE', + 'ASSERT_CMPLE' + ]; + var macroIFCMPlist = [ + 'IFCMPEQ', + 'IFCMPNEQ', + 'IFCMPLT', + 'IFCMPGT', + 'IFCMPLE', + 'IFCMPGE' + ]; + var macroCMPlist = ['CMPEQ', 'CMPNEQ', 'CMPLT', 'CMPGT', 'CMPLE', 'CMPGE']; + var macroIFlist = ['IFEQ', 'IFNEQ', 'IFLT', 'IFGT', 'IFLE', 'IFGE']; + + var parameter; + var storage; + var code; + var comparableType; + var constantType; + var singleArgType; + var lparen; + var rparen; + var doubleArgType; + var annot; + var number; + var string; + var lbrace; + var rbrace; + var constantData; + var singleArgData; + var doubleArgData; + var bytes; + var elt; + var semicolon; + var baseInstruction; + var macroCADR; + var macroDIP; + var macroDUP; + var macroSETCADR; + var macroASSERTlist; + + MichelsonGrammar() { + lexer = new MichelsonGrammarTokenizer({ + 'annot': RegExp(r'[\@\%\:][a-z_A-Z0-9]+'), + 'lparen': '(', + 'rparen': ')', + 'lbrace': '{', + 'rbrace': '}', + 'ws': RegExp(r'[ \t]+'), + 'semicolon': ";", + 'bytes': RegExp(r'0x[0-9a-fA-F]+'), + 'number': RegExp('-?[0-9]+(?!x)'), + 'parameter': ['parameter', 'Parameter'], + 'storage': ['Storage', 'storage'], + 'code': ['Code', 'code'], + 'comparableType': [ + 'int', + 'nat', + 'string', + 'bytes', + 'mutez', + 'bool', + 'key_hash', + 'timestamp', + 'chain_id' + ], + 'constantType': ['key', 'unit', 'signature', 'operation', 'address'], + 'singleArgType': ['option', 'list', 'set', 'contract'], + 'doubleArgType': ['pair', 'or', 'lambda', 'map', 'big_map'], + 'baseInstruction': [ + 'ABS', 'ADD', 'ADDRESS', 'AMOUNT', 'AND', 'BALANCE', 'BLAKE2B', 'CAR', + 'CAST', 'CDR', 'CHECK_SIGNATURE', + 'COMPARE', 'CONCAT', 'CONS', 'CONTRACT', 'CREATE_CONTRACT', 'DIP', + /*'DROP',*/ /*'DUP',*/ 'EDIV', + /*'EMPTY_MAP',*/ + 'EMPTY_SET', 'EQ', 'EXEC', 'FAIL', 'FAILWITH', 'GE', 'GET', 'GT', + 'HASH_KEY', 'IF', 'IF_CONS', 'IF_LEFT', 'IF_NONE', + 'IF_RIGHT', 'IMPLICIT_ACCOUNT', 'INT', 'ISNAT', 'ITER', 'LAMBDA', 'LE', + 'LEFT', 'LOOP', 'LOOP_LEFT', 'LSL', 'LSR', 'LT', + 'MAP', 'MEM', 'MUL', 'NEG', 'NEQ', 'NIL', 'NONE', 'NOT', 'NOW', 'OR', + 'PACK', 'PAIR', /*'PUSH',*/ 'REDUCE', 'RENAME', 'RIGHT', 'SELF', + 'SENDER', 'SET_DELEGATE', 'SHA256', 'SHA512', 'SIZE', 'SLICE', 'SOME', + 'SOURCE', 'STEPS_TO_QUOTA', 'SUB', 'SWAP', + 'TRANSFER_TOKENS', 'UNIT', 'UNPACK', 'UPDATE', 'XOR', + 'UNPAIR', 'UNPAPAIR', // TODO: macro + 'IF_SOME', // TODO: macro + 'IFCMPEQ', 'IFCMPNEQ', 'IFCMPLT', 'IFCMPGT', 'IFCMPLE', 'IFCMPGE', + 'CMPEQ', 'CMPNEQ', 'CMPLT', 'CMPGT', 'CMPLE', + 'CMPGE', 'IFEQ', 'NEQ', 'IFLT', 'IFGT', 'IFLE', + 'IFGE', // TODO: should be separate + /*'DIG',*/ /*'DUG',*/ 'EMPTY_BIG_MAP', 'APPLY', 'CHAIN_ID' + ], + 'macroCADR': macroCADRconst, + 'macroDIP': dIPmatcher, + 'macroDUP': dUPmatcher, + // 'macroDIP': macroDIPconst, + // 'macroDUP': macroDUPconst, + 'macroSETCADR': macroSETCADRconst, + 'macroASSERTlist': macroASSERTlistConst, + 'constantData': ['Unit', 'True', 'False', 'None', 'instruction'], + 'singleArgData': ['Left', 'Right', 'Some'], + 'doubleArgData': ['Pair'], + 'elt': "Elt", + 'word': RegExp(r'[a-zA-Z_0-9]+'), + 'string': RegExp(r'\"(?:\\\\[\"\\\\]|[^\\n\"\\\\])*\"'), + }); + } + + scriptToJson(d) => + '[ ${d[0] is List ? d[0][0]['value'].toString() : d[0] is String ? d[0] : d[0]['value']}, ${d[2]}, { "prim": "code", "args": [ [ ${d[4].reduce((a, e) => a + ',' + e)} ] ] } ]'; + + singleArgKeywordToJson(d) => + '{ "prim": "${d[0] is List ? d[0][0]['value'].toString() : d[0]['value']}", "args": [ ${d[2]} ] }'; + + keywordToJson(d) { + var word = d[0] is List ? d[0][0]['value'].toString() : d[0]['value']; + + if (d.length == 1) { + if (checkKeyword(word)) { + return expandKeyword(word, null); + } else { + return '{ "prim": "$word" }'; + } + } else { + var annot = d[1].map((x) => '"${getMapValue(x[1])}"'); + if (checkKeyword(word)) { + return [expandKeyword(word, annot)]; + } else { + return '{ "prim": "$word", "annots": [${listToString(annot)}] }'; + } + } + } + + checkKeyword(word) { + if (checkAssert(word)) { + return true; + } + if (checkCompare(word)) { + return true; + } + if (checkDip(word)) { + return true; + } + if (checkDup(word)) { + return true; + } + if (checkFail(word)) { + return true; + } + if (checkIf(word)) { + return true; + } + if (checkCR(word)) { + return true; + } + if (checkOther(word)) { + return true; + } + if (checkSetCadr(word)) { + return true; + } + return false; + } + + expandKeyword(word, annot) { + if (checkCR(word)) { + return expandCR(word, annot); + } + if (checkAssert(word)) { + return expandAssert(word, annot); + } + if (checkCompare(word)) { + return expandCmp(word, annot); + } + if (checkDip(word)) { + return expandDIP(word, annot); + } + if (checkDup(word)) { + return expandDup(word, annot); + } + if (checkFail(word)) { + return expandFail(word, annot); + } + if (checkIf(word)) { + return expandIF(word, annot); + } + if (checkOther(word)) { + return expandOther(word, annot); + } + if (checkSetCadr(word)) { + return expandSetCadr(word, annot); + } + return false; + } + + checkAssert(asser) => macroASSERTlistConst.contains(asser); + expandAssert(asset, annot) { + var annotation = annot == null ? ', "annots": [$annot]' : ''; + switch (asset) { + case 'ASSERT': + return '[{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_CMPEQ': + return '[[{"prim":"COMPARE"},{"prim":"EQ"}],{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_CMPGE': + return '[[{"prim":"COMPARE"},{"prim":"GE"}],{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_CMPGT': + return '[[{"prim":"COMPARE"},{"prim":"GT"}],{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_CMPLE': + return '[[{"prim":"COMPARE"},{"prim":"LE"}],{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_CMPLT': + return '[[{"prim":"COMPARE"},{"prim":"LT"}],{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_CMPNEQ': + return '[[{"prim":"COMPARE"},{"prim":"NEQ"}],{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_EQ': + return '[{"prim":"EQ"},{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]]'; + case 'ASSERT_GE': + return '[{"prim":"GE"},{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_GT': + return '[{"prim":"GT"},{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_LE': + return '[{"prim":"LE"},{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_LT': + return '[{"prim":"LT"},{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_NEQ': + return '[{"prim":"NEQ"},{"prim":"IF","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"$annotation}]]]}]'; + case 'ASSERT_NONE': // IF_NONE {} {FAIL} + return '[{"prim":"IF_NONE","args":[[],[[{"prim":"UNIT"},{"prim":"FAILWITH"}]]]}]'; + case 'ASSERT_SOME': // IF_NONE {FAIL} {RENAME @x} + return '[{"prim":"IF_NONE","args":[[[{"prim":"UNIT"},{"prim":"FAILWITH"}]],[]]}]'; + case 'ASSERT_LEFT': // IF_LEFT {RENAME @x} {FAIL} + return ''; + case 'ASSERT_RIGHT': // IF_LEFT {FAIL} {RENAME @x} + return ''; + default: + throw new Exception('Could not process $asset'); + } + } + + checkCompare(cmp) => macroCMPlist.contains(cmp); + expandCmp(cmp, annot) { + var op = cmp.substring(3); + var binaryOp = keywordToJson(['$op']); + var compare = keywordToJson(['COMPARE']); + if (annot != null) { + binaryOp = '{ "prim": "$op", "annots": [$annot] }'; + } + + return '[$compare, $binaryOp]'; + } + + checkDip(dip) => dIPmatcher.hasMatch(dip); + expandDIP(dip, instruction, {annot}) { + var t = ''; + if (dIPmatcher.hasMatch(dip)) { + var c = dip.length - 2; + for (var i = 0; i < c; i++) { + t += '[{ "prim": "DIP", "args": [ '; + } + t = '$t [ $instruction ] ]'; + if (annot == null) { + t = '$t, "annots": [$annot]'; + } + t += ' }]'; + for (var i = 0; i < c - 1; i++) { + t += ' ] }]'; + } + return t; + } + + throw new Exception('Unexpected parameter for DIP processing: $dip'); + } + + checkDup(dup) => dUPmatcher.hasMatch(dup); + expandDup(dup, annot) { + var t = ''; + if (dUPmatcher.hasMatch(dup)) { + var c = dup.length - 3; + for (var i = 0; i < c; i++) { + t += '[{ "prim": "DIP", "args": [ '; + } + + if (annot == null) { + t += '[{ "prim": "DUP" }]'; + } else { + t += '[{ "prim": "DUP", "annots": [$annot] }]'; + } + + for (var i = 0; i < c; i++) { + t += ' ] },{"prim":"SWAP"}]'; + } + return t; + } + + throw new Exception(''); + } + + checkFail(fail) => fail == "FAIL"; + expandFail(fail, annot) { + if (annot == null) { + return '[ { "prim": "UNIT" }, { "prim": "FAILWITH" } ]'; + } else { + return '[ { "prim": "UNIT" }, { "prim": "FAILWITH", "annots": [$annot] } ]'; + } + } + + checkIf(ifStatement) => (macroIFCMPlist.contains(ifStatement) || + macroIFlist.contains(ifStatement) || + ifStatement == 'IF_SOME'); // TODO: IF_SOME + expandIF(ifInstr, ifTrue, {ifFalse, annot}) { + var annotation = annot != null ? ', "annots": [$annot]' : ''; + + switch (ifInstr) { + case 'IFCMPEQ': + return '[{"prim":"COMPARE"},{"prim":"EQ"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFCMPGE': + return '[{"prim":"COMPARE"},{"prim":"GE"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFCMPGT': + return '[{"prim":"COMPARE"},{"prim":"GT"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFCMPLE': + return '[{"prim":"COMPARE"},{"prim":"LE"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFCMPLT': + return '[{"prim":"COMPARE"},{"prim":"LT"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFCMPNEQ': + return '[{"prim":"COMPARE"},{"prim":"NEQ"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFEQ': + return '[{"prim":"EQ"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFGE': + return '[{"prim":"GE"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFGT': + return '[{"prim":"GT"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFLE': + return '[{"prim":"LE"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFLT': + return '[{"prim":"LT"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IFNEQ': + return '[{"prim":"NEQ"},{"prim":"IF","args":[ [$ifTrue] , [$ifFalse]]$annotation}]'; + case 'IF_SOME': + return '[{"prim":"IF_NONE","args":[ [$ifFalse], [$ifTrue]]$annotation}]'; + default: + throw new Exception('Could not process $ifInstr'); + } + } + + checkCR(cr) => RegExp(r'^C(A|D)(A|D)+R$').hasMatch(cr); + expandCR(word, annot) { + var expandedCR = word + .substring(1, word.length - 1) + .split('') + .map((c) => (c == 'A' ? '{ "prim": "CAR" }' : '{ "prim": "CDR" }')); + if (annot != null) { + var lastChar = word.substring(word.length - 2, word.length - 1); + if (lastChar == 'A') { + expandedCR[expandedCR.length - 1] = + '{ "prim": "CAR", "annots": [$annot] }'; + } else if (lastChar == 'D') { + expandedCR[expandedCR.length - 1] = + '{ "prim": "CDR", "annots": [$annot] }'; + } + } + + return '[${expandedCR.join(', ')}]'; + } + + checkOther(word) => + (word == "UNPAIR" || word == "UNPAPAIR"); // TODO: dynamic matching + expandOther(word, annot) { + if (word == 'UNPAIR') { + if (annot == null) { + return '[ [ { "prim": "DUP" }, { "prim": "CAR" }, { "prim": "DIP", "args": [ [ { "prim": "CDR" } ] ] } ] ]'; + } else if (annot.length == 1) { + return '[ [ { "prim": "DUP" }, { "prim": "CAR", "annots": [$annot] }, { "prim": "DIP", "args": [ [ { "prim": "CDR" } ] ] } ] ]'; + } else if (annot.length == 2) { + return r'[ [ { "prim": "DUP" }, { "prim": "CAR", "annots": [${annot[0]}] }, { "prim": "DIP", "args": [ [ { "prim": "CDR", "annots": [${annot[1]}] } ] ] } ] ]'; + } else { + return ''; + } + } + + if (word == 'UNPAPAIR') { + if (annot == null) { + return """[ [ { "prim": "DUP" }, + { "prim": "CAR" }, + { "prim": "DIP", "args": [ [ { "prim": "CDR" } ] ] } ], + {"prim":"DIP","args":[[[{"prim":"DUP"},{"prim":"CAR"},{"prim":"DIP","args":[[{"prim":"CDR"}]]}]]]}]"""; + } else { + return """[ [ { "prim": "DUP" }, + { "prim": "CAR" }, + { "prim": "DIP", "args": [ [ { "prim": "CDR" } ] ] } ], + {"prim":"DIP","args":[[[{"prim":"DUP"},{"prim":"CAR"},{"prim":"DIP","args":[[{"prim":"CDR"}]],"annots": [$annot]}]]]}]"""; + } + } + } + + checkSetCadr(s) => new RegExp(macroSETCADRconst).hasMatch(s); + expandSetCadr(word, annot) => nestSetCadr(word.substring(5, word.length - 1)); + nestSetCadr(r) { + if (r.length == 0) { + return ''; + } + + var c = r[0]; + if (r.length == 1) { + if (c == 'A') { + return '[{"prim": "CDR","annots":["@%%"]}, {"prim": "SWAP"}, {"prim": "PAIR","annots":["%","%@"]}]'; + } else if (c == 'D') { + return '[{"prim": "CAR","annots":["@%%"]}, {"prim": "PAIR","annots":["%@","%"]}]'; + } + } + + if (c == 'A') { + return '[{"prim": "DUP"}, {"prim": "DIP", "args": [[{"prim": "CAR","annots":["@%%"]}, ${nestSetCadr(r.substring(1))}]]}, {"prim": "CDR","annots":["@%%"]}, {"prim": "SWAP"}, {"prim": "PAIR","annots":["%@","%@"]}]'; + } else if (c == 'D') { + return '[{"prim": "DUP"}, {"prim": "DIP", "args": [[{"prim": "CDR","annots":["@%%"]}, ${nestSetCadr(r.substring(1))}]]}, {"prim": "CAR","annots":["@%%"]}, {"prim": "PAIR","annots":["%@","%@"]}]'; + } + } + + singleArgKeywordWithParenToJson(d) => + '{ "prim": "${d[2]}", "args": [ ${d[(4 + ((d.length == 7) ? 0 : 2))]} ] }'; + + doubleArgKeywordToJson(d) => + '{ "prim": "${d[0]['value']}", "args": [ ${d[2]}, ${d[4]} ] }'; + + doubleArgKeywordWithParenToJson(d) => + '{ "prim": "${d[2]['value']}", "args": [ ${d[4]}, ${d[6]} ] }'; + + comparableTypeToJson(d) { + var annot = + d[3].map((x) => '"${x[1]['value'].toString()}"').toList()[0].toString(); + return '{ "prim": "${d[2]['value']}", "annots": [$annot] }'; + } + + singleArgTypeKeywordWithParenToJson(d) { + var annot = d[3].map((x) => '"${getMapValue(x[1])}"'); + return '{ "prim": "${getMapValue(d[2])}", "args": [ ${d[5]} ], "annots": [${listToString(annot)}] }'; + } + + doubleArgTypeKeywordWithParenToJson(d) { + var annot = + d[3].map((x) => '"${x[1]['value'].toString()}"').toList()[0].toString(); + // d[3].map((x) => '"${x[1]}"'); + return '{ "prim": "${d[2]['value']}", "args": [ ${d[5]}, ${d[7]} ], "annots": [$annot] }'; + } + + intToJson(d) => '{ "int": "${int.parse(getMapValue(d[0]))}" }'; + + bytesToJson(d) => '{ "bytes": "${d[0].toString().substring(2)}" }'; + + stringToJson(d) => '{ "string": ${getMapValue(d[0])} }'; + + // ignore: slash_for_doc_comments + /** + * Given a list of michelson instructions, convert it into JSON. + * Example: "{CAR; NIL operation; PAIR;}" -> + * [ '{ prim: CAR }', + * '{ prim: NIL, args: [{ prim: operation }] }', + * '{ prim: PAIR }' ] + */ + instructionSetToJsonNoSemi(d) { + var _d = d[2].map((x) => x[0]).toList(); + if (d[3] is String) { + _d.add(d[3]); + } else { + _d.addAll(d[3]); + } + return removeIfNextIsSame(_d.map((x) => nestedArrayChecker(x)).toList()) + .toList(); + } + + instructionSetToJsonSemi(d) { + return '${listToString(d[2].map((x) => x[0]).map((x) => nestedArrayChecker(x)))}'; + } + + dataListToJsonSemi(d) { + return '[ ${listToString(d[2].map((x) => x[0]).map((x) => nestedArrayChecker(x)))} ]'; + } + + nestedArrayChecker(x) { + if (x is List && x[0] is List) { + // handles double array nesting + return x[0]; + } else { + return x; + } + } + + singleArgInstrKeywordToJson(d) { + var word = '${d[0] is List ? d[0][0]['value'].toString() : d[0]['value']}'; + if (checkDip(word)) { + return expandDIP(word, d[2]); + } else { + return '{ "prim": "$word", "args": [ [ ${listToString(d[2])} ] ] }'; + } + } + + singleArgTypeKeywordToJson(d) { + var word = '${d[0].toString()}'; + var annot = d[1].map((x) => '"${x[1]}"'); + if (checkDip(word)) { + return expandDIP(word, d[2], annot: annot); + } else { + return '{ "prim": "${d[0]}", "args": [ ${d[3]} ], "annots": [$annot] }'; + } + } + + tripleArgKeyWordToJson(d) => + '{ "prim": "${d[0]}", "args": [ ${d[2]}, ${d[4]}, [${d[6]}] ] }'; + + tripleArgTypeKeyWordToJson(d) { + var annot = d[1].map((x) => '"${x[1]}"'); + return '{ "prim": "${d[0]}", "args": [ ${d[3]}, ${d[5]}, ${d[7]} ], "annots": [$annot] }'; + } + + doubleArgInstrKeywordToJson(d) { + var word = '${d[0] is List ? d[0][0]['value'].toString() : d[0]['value']}'; + if (checkIf(word)) { + return expandIF(word, d[2], ifFalse: d[4] != null); + } else { + return '{ "prim": "$word", "args": [ [${d[2]}], [${d[4]}] ] }'; + } + } + + doubleArgTypeKeywordToJson(d) { + var annot = d[1].map((x) => '"${x[1]}"'); + return '{ "prim": "${d[0]}", "args": [ ${d[4]}, ${d[6]} ], "annots": [$annot] }'; + } + + pushToJson(d) => '{ "prim": "${d[0]}", "args": [${d[2]}, []] }'; + + pushWithAnnotsToJson(d) { + var annot = d[1].map((x) => '"${x[1]}"'); + return '{ "prim": "PUSH", "args": [ ${d[3]}, ${d[5]} ], "annots": [$annot] }'; + } + + dipnToJson(d) => (d.length > 4) + ? '{ "prim": "${d[0]}", "args": [ { "int": "${d[2]}" }, [ ${d[4]} ] ] }' + : '{ "prim": "${d[0]}", "args": [ ${d[2]} ] }'; + + dupnToJson(d) { + var n = int.parse(d[2].toString()); + + if (n == 1) { + return '{ "prim": "DUP" }'; + } else if (n == 2) { + return '[{ "prim": "DIP", "args": [[ {"prim": "DUP"} ]] }, { "prim": "SWAP" }]'; + } else { + return '[{ "prim": "DIP", "args": [ {"int": "${n - 1}"}, [{ "prim": "DUP" }] ] }, { "prim": "DIG", "args": [ {"int": "$n"} ] }]'; + } + } + + dignToJson(d) => + '{ "prim": "${getMapValue(d[0])}", "args": [ { "int": "${getMapValue(d[2])}" } ] }'; + + dropnToJson(d) => + '{ "prim": "${getMapValue(d[0])}", "args": [ { "int": "${getMapValue(d[2])}" } ] }'; + + subContractToJson(d) => + '{ "prim":"CREATE_CONTRACT", "args": [ [ ${d[4]}, ${d[6]}, {"prim": "code" , "args":[ [ ${d[8]} ] ] } ] ] }'; + + instructionListToJson(d) { + var instructionOne = [d[2]]; + var instructionList = d[3].map((x) => x[3]).toList(); + return instructionOne + ..addAll(instructionList) + ..map((x) => nestedArrayChecker(x)); + } + + doubleArgParenKeywordToJson(d) => + '{ "prim": "${d[0]}", "args": [ ${d[4]}, ${d[8]} ] }'; + + listToString(list) => + removeIfNextIsSame(list.toList()).reduce((a, e) => a + ',' + e); + + removeIfNextIsSame(list) { + for (var i = 0; i < list.length; i++) { + if (i != 0 && list[i - 1] == list[i]) { + list.removeAt(i); + } + } + return list; + } + + getMapValue(d) => d is List ? d[0]['value'].toString() : d['value']; + + id(x) => x[0]; + + Map get grammar => { + 'Lexer': lexer, + 'ParserRules': [ + { + "name": "main", + "symbols": ["instruction"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["data"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["type"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["parameter"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["storage"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["code"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["script"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["parameterValue"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["storageValue"], + "postprocess": id + }, + { + "name": "main", + "symbols": ["typeData"], + "postprocess": id + }, + { + "name": "script", + "symbols": ["parameter", "_", "storage", "_", "code"], + "postprocess": scriptToJson + }, + { + "name": "parameterValue", + "symbols": [ + (lexer.has("parameter") ? {'type': "parameter"} : parameter), + "_", + "typeData", + "_", + "semicolons" + ], + "postprocess": singleArgKeywordToJson + }, + { + "name": "storageValue", + "symbols": [ + (lexer.has("storage") ? {'type': "storage"} : storage), + "_", + "typeData", + "_", + "semicolons" + ], + "postprocess": singleArgKeywordToJson + }, + { + "name": "parameter", + "symbols": [ + (lexer.has("parameter") ? {'type': "parameter"} : parameter), + "_", + "type", + "_", + "semicolons" + ], + "postprocess": singleArgKeywordToJson + }, + { + "name": "storage", + "symbols": [ + (lexer.has("storage") ? {'type': "storage"} : storage), + "_", + "type", + "_", + "semicolons" + ], + "postprocess": singleArgKeywordToJson + }, + { + "name": "code", + "symbols": [ + (lexer.has("code") ? {'type': "code"} : code), + "_", + "subInstruction", + "_", + "semicolons", + "_" + ], + "postprocess": (d) => d[2] + }, + { + "name": "code", + "symbols": [ + (lexer.has("code") ? {'type': "code"} : code), + "_", + {"literal": "{};"} + ], + "postprocess": (d) => "code {}" + }, + { + "name": "type", + "symbols": [ + (lexer.has("comparableType") + ? {'type': "comparableType"} + : comparableType) + ], + "postprocess": keywordToJson + }, + { + "name": "type", + "symbols": [ + (lexer.has("constantType") + ? {'type': "constantType"} + : constantType) + ], + "postprocess": keywordToJson + }, + { + "name": "type", + "symbols": [ + (lexer.has("singleArgType") + ? {'type': "singleArgType"} + : singleArgType), + "_", + "type" + ], + "postprocess": singleArgKeywordToJson + }, + { + "name": "type", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("singleArgType") + ? {'type': "singleArgType"} + : singleArgType), + "_", + "type", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": singleArgKeywordWithParenToJson + }, + { + "name": "type", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("singleArgType") + ? {'type': "singleArgType"} + : singleArgType), + "_", + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + "type", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen), + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": singleArgKeywordWithParenToJson + }, + { + "name": "type", + "symbols": [ + (lexer.has("doubleArgType") + ? {'type': "doubleArgType"} + : doubleArgType), + "_", + "type", + "_", + "type" + ], + "postprocess": doubleArgKeywordToJson + }, + { + "name": "type", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("doubleArgType") + ? {'type': "doubleArgType"} + : doubleArgType), + "_", + "type", + "_", + "type", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": doubleArgKeywordWithParenToJson + }, + { + "name": r"type$ebnf$1$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$1", + "symbols": [r"type$ebnf$1$subexpression$1"] + }, + { + "name": r"type$ebnf$1$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$1", + "symbols": [r"type$ebnf$1", r"type$ebnf$1$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "type", + "symbols": [ + (lexer.has("comparableType") + ? {'type': "comparableType"} + : comparableType), + r"type$ebnf$1" + ], + "postprocess": keywordToJson + }, + { + "name": r"type$ebnf$2$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$2", + "symbols": [r"type$ebnf$2$subexpression$1"] + }, + { + "name": r"type$ebnf$2$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$2", + "symbols": [r"type$ebnf$2", r"type$ebnf$2$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "type", + "symbols": [ + (lexer.has("constantType") + ? {'type': "constantType"} + : constantType), + r"type$ebnf$2" + ], + "postprocess": keywordToJson + }, + { + "name": r"type$ebnf$3$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$3", + "symbols": [r"type$ebnf$3$subexpression$1"] + }, + { + "name": r"type$ebnf$3$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$3", + "symbols": [r"type$ebnf$3", r"type$ebnf$3$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "type", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("comparableType") + ? {'type': "comparableType"} + : comparableType), + r"type$ebnf$3", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": comparableTypeToJson + }, + { + "name": r"type$ebnf$4$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$4", + "symbols": [r"type$ebnf$4$subexpression$1"] + }, + { + "name": r"type$ebnf$4$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$4", + "symbols": [r"type$ebnf$4", r"type$ebnf$4$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "type", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("constantType") + ? {'type': "constantType"} + : constantType), + r"type$ebnf$4", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": comparableTypeToJson + }, + { + "name": r"type$ebnf$5$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$5", + "symbols": [r"type$ebnf$5$subexpression$1"] + }, + { + "name": r"type$ebnf$5$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$5", + "symbols": [r"type$ebnf$5", r"type$ebnf$5$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "type", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("singleArgType") + ? {'type': "singleArgType"} + : singleArgType), + r"type$ebnf$5", + "_", + "type", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": singleArgTypeKeywordWithParenToJson + }, + { + "name": r"type$ebnf$6$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$6", + "symbols": [r"type$ebnf$6$subexpression$1"] + }, + { + "name": r"type$ebnf$6$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"type$ebnf$6", + "symbols": [r"type$ebnf$6", r"type$ebnf$6$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "type", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("doubleArgType") + ? {'type': "doubleArgType"} + : doubleArgType), + r"type$ebnf$6", + "_", + "type", + "_", + "type", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": doubleArgTypeKeywordWithParenToJson + }, + { + "name": "typeData", + "symbols": [ + (lexer.has("singleArgType") + ? {'type': "singleArgType"} + : singleArgType), + "_", + "typeData" + ], + "postprocess": singleArgKeywordToJson + }, + { + "name": "typeData", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("singleArgType") + ? {'type': "singleArgType"} + : singleArgType), + "_", + "typeData", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": singleArgKeywordWithParenToJson + }, + { + "name": "typeData", + "symbols": [ + (lexer.has("doubleArgType") + ? {'type': "doubleArgType"} + : doubleArgType), + "_", + "typeData", + "_", + "typeData" + ], + "postprocess": doubleArgKeywordToJson + }, + { + "name": "typeData", + "symbols": [ + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + (lexer.has("doubleArgType") + ? {'type': "doubleArgType"} + : doubleArgType), + "_", + "typeData", + "_", + "typeData", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen) + ], + "postprocess": doubleArgKeywordWithParenToJson + }, + { + "name": "typeData", + "symbols": ["subTypeData"], + "postprocess": id + }, + { + "name": "typeData", + "symbols": ["subTypeElt"], + "postprocess": id + }, + { + "name": "typeData", + "symbols": [ + (lexer.has("number") ? {'type': "number"} : number) + ], + "postprocess": intToJson + }, + { + "name": "typeData", + "symbols": [ + (lexer.has("string") ? {'type': "string"} : string) + ], + "postprocess": stringToJson + }, + { + "name": "typeData", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": (d) => [] + }, + { + "name": "data", + "symbols": [ + (lexer.has("constantData") + ? {'type': "constantData"} + : constantData) + ], + "postprocess": keywordToJson + }, + { + "name": "data", + "symbols": [ + (lexer.has("singleArgData") + ? {'type': "singleArgData"} + : singleArgData), + "_", + "data" + ], + "postprocess": singleArgKeywordToJson + }, + { + "name": "data", + "symbols": [ + (lexer.has("doubleArgData") + ? {'type': "doubleArgData"} + : doubleArgData), + "_", + "data", + "_", + "data" + ], + "postprocess": doubleArgKeywordToJson + }, + { + "name": "data", + "symbols": ["subData"], + "postprocess": id + }, + { + "name": "data", + "symbols": ["subElt"], + "postprocess": id + }, + { + "name": "data", + "symbols": [ + (lexer.has("string") ? {'type': "string"} : string) + ], + "postprocess": stringToJson + }, + { + "name": "data", + "symbols": [ + (lexer.has("bytes") ? {'type': "bytes"} : bytes) + ], + "postprocess": bytesToJson + }, + { + "name": "data", + "symbols": [ + (lexer.has("number") ? {'type': "number"} : number) + ], + "postprocess": intToJson + }, + { + "name": "subData", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": (d) => "[]" + }, + { + "name": r"subData$ebnf$1$subexpression$1", + "symbols": ["data", "_"] + }, + { + "name": r"subData$ebnf$1", + "symbols": [r"subData$ebnf$1$subexpression$1"] + }, + { + "name": r"subData$ebnf$1$subexpression$2", + "symbols": ["data", "_"] + }, + { + "name": r"subData$ebnf$1", + "symbols": [r"subData$ebnf$1", r"subData$ebnf$1$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subData", + "symbols": [ + {"literal": "("}, + "_", + r"subData$ebnf$1", + {"literal": ")"} + ], + "postprocess": instructionSetToJsonSemi + }, + { + "name": r"subData$ebnf$2$subexpression$1$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subData$ebnf$2$subexpression$1$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subData$ebnf$2$subexpression$1", + "symbols": [ + "data", + "_", + r"subData$ebnf$2$subexpression$1$ebnf$1", + "_" + ] + }, + { + "name": r"subData$ebnf$2", + "symbols": [r"subData$ebnf$2$subexpression$1"] + }, + { + "name": r"subData$ebnf$2$subexpression$2$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subData$ebnf$2$subexpression$2$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subData$ebnf$2$subexpression$2", + "symbols": [ + "data", + "_", + r"subData$ebnf$2$subexpression$2$ebnf$1", + "_" + ] + }, + { + "name": r"subData$ebnf$2", + "symbols": [r"subData$ebnf$2", r"subData$ebnf$2$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subData", + "symbols": [ + {"literal": "{"}, + "_", + r"subData$ebnf$2", + {"literal": "}"} + ], + "postprocess": dataListToJsonSemi + }, + { + "name": "subElt", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": (d) => "[]" + }, + { + "name": r"subElt$ebnf$1$subexpression$1$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subElt$ebnf$1$subexpression$1$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subElt$ebnf$1$subexpression$1", + "symbols": ["elt", r"subElt$ebnf$1$subexpression$1$ebnf$1", "_"] + }, + { + "name": r"subElt$ebnf$1", + "symbols": [r"subElt$ebnf$1$subexpression$1"] + }, + { + "name": r"subElt$ebnf$1$subexpression$2$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subElt$ebnf$1$subexpression$2$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subElt$ebnf$1$subexpression$2", + "symbols": ["elt", r"subElt$ebnf$1$subexpression$2$ebnf$1", "_"] + }, + { + "name": r"subElt$ebnf$1", + "symbols": [r"subElt$ebnf$1", r"subElt$ebnf$1$subexpression$2"], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subElt", + "symbols": [ + {"literal": "{"}, + "_", + r"subElt$ebnf$1", + {"literal": "}"} + ], + "postprocess": dataListToJsonSemi + }, + { + "name": "elt", + "symbols": [ + (lexer.has("elt") ? {'type': "elt"} : elt), + "_", + "data", + "_", + "data" + ], + "postprocess": doubleArgKeywordToJson + }, + { + "name": "subTypeData", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": (d) => "[]" + }, + { + "name": r"subTypeData$ebnf$1$subexpression$1$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeData$ebnf$1$subexpression$1$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeData$ebnf$1$subexpression$1", + "symbols": [ + "data", + r"subTypeData$ebnf$1$subexpression$1$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeData$ebnf$1", + "symbols": [r"subTypeData$ebnf$1$subexpression$1"] + }, + { + "name": r"subTypeData$ebnf$1$subexpression$2$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeData$ebnf$1$subexpression$2$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeData$ebnf$1$subexpression$2", + "symbols": [ + "data", + r"subTypeData$ebnf$1$subexpression$2$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeData$ebnf$1", + "symbols": [ + r"subTypeData$ebnf$1", + r"subTypeData$ebnf$1$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subTypeData", + "symbols": [ + {"literal": "{"}, + "_", + r"subTypeData$ebnf$1", + {"literal": "}"} + ], + "postprocess": instructionSetToJsonSemi + }, + { + "name": r"subTypeData$ebnf$2$subexpression$1$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeData$ebnf$2$subexpression$1$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeData$ebnf$2$subexpression$1", + "symbols": [ + "data", + r"subTypeData$ebnf$2$subexpression$1$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeData$ebnf$2", + "symbols": [r"subTypeData$ebnf$2$subexpression$1"] + }, + { + "name": r"subTypeData$ebnf$2$subexpression$2$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeData$ebnf$2$subexpression$2$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeData$ebnf$2$subexpression$2", + "symbols": [ + "data", + r"subTypeData$ebnf$2$subexpression$2$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeData$ebnf$2", + "symbols": [ + r"subTypeData$ebnf$2", + r"subTypeData$ebnf$2$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subTypeData", + "symbols": [ + {"literal": "("}, + "_", + r"subTypeData$ebnf$2", + {"literal": ")"} + ], + "postprocess": instructionSetToJsonSemi + }, + { + "name": "subTypeElt", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": (d) => "[]" + }, + { + "name": r"subTypeElt$ebnf$1$subexpression$1$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeElt$ebnf$1$subexpression$1$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeElt$ebnf$1$subexpression$1", + "symbols": [ + "typeElt", + r"subTypeElt$ebnf$1$subexpression$1$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeElt$ebnf$1", + "symbols": [r"subTypeElt$ebnf$1$subexpression$1"] + }, + { + "name": r"subTypeElt$ebnf$1$subexpression$2$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeElt$ebnf$1$subexpression$2$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeElt$ebnf$1$subexpression$2", + "symbols": [ + "typeElt", + r"subTypeElt$ebnf$1$subexpression$2$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeElt$ebnf$1", + "symbols": [ + r"subTypeElt$ebnf$1", + r"subTypeElt$ebnf$1$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subTypeElt", + "symbols": [ + {"literal": "[{"}, + "_", + r"subTypeElt$ebnf$1", + {"literal": "}]"} + ], + "postprocess": instructionSetToJsonSemi + }, + { + "name": r"subTypeElt$ebnf$2$subexpression$1$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeElt$ebnf$2$subexpression$1$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeElt$ebnf$2$subexpression$1", + "symbols": [ + "typeElt", + "_", + r"subTypeElt$ebnf$2$subexpression$1$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeElt$ebnf$2", + "symbols": [r"subTypeElt$ebnf$2$subexpression$1"] + }, + { + "name": r"subTypeElt$ebnf$2$subexpression$2$ebnf$1", + "symbols": [ + {"literal": ";"} + ], + "postprocess": id + }, + { + "name": r"subTypeElt$ebnf$2$subexpression$2$ebnf$1", + "symbols": [], + // "postprocess": () => null + }, + { + "name": r"subTypeElt$ebnf$2$subexpression$2", + "symbols": [ + "typeElt", + "_", + r"subTypeElt$ebnf$2$subexpression$2$ebnf$1", + "_" + ] + }, + { + "name": r"subTypeElt$ebnf$2", + "symbols": [ + r"subTypeElt$ebnf$2", + r"subTypeElt$ebnf$2$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subTypeElt", + "symbols": [ + {"literal": "[{"}, + "_", + r"subTypeElt$ebnf$2", + {"literal": "}]"} + ], + "postprocess": instructionSetToJsonSemi + }, + { + "name": "typeElt", + "symbols": [ + (lexer.has("elt") ? {'type': "elt"} : elt), + "_", + "typeData", + "_", + "typeData" + ], + "postprocess": doubleArgKeywordToJson + }, + { + "name": "subInstruction", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": (d) => "" + }, + { + "name": "subInstruction", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + "instruction", + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": (d) => d[2] + }, + { + "name": r"subInstruction$ebnf$1$subexpression$1", + "symbols": [ + "instruction", + "_", + (lexer.has("semicolon") ? {'type': "semicolon"} : semicolon), + "_" + ] + }, + { + "name": r"subInstruction$ebnf$1", + "symbols": [r"subInstruction$ebnf$1$subexpression$1"] + }, + { + "name": r"subInstruction$ebnf$1$subexpression$2", + "symbols": [ + "instruction", + "_", + (lexer.has("semicolon") ? {'type': "semicolon"} : semicolon), + "_" + ] + }, + { + "name": r"subInstruction$ebnf$1", + "symbols": [ + r"subInstruction$ebnf$1", + r"subInstruction$ebnf$1$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subInstruction", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + r"subInstruction$ebnf$1", + "instruction", + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": instructionSetToJsonNoSemi + }, + { + "name": r"subInstruction$ebnf$2$subexpression$1", + "symbols": [ + "instruction", + "_", + (lexer.has("semicolon") ? {'type': "semicolon"} : semicolon), + "_" + ] + }, + { + "name": r"subInstruction$ebnf$2", + "symbols": [r"subInstruction$ebnf$2$subexpression$1"] + }, + { + "name": r"subInstruction$ebnf$2$subexpression$2", + "symbols": [ + "instruction", + "_", + (lexer.has("semicolon") ? {'type': "semicolon"} : semicolon), + "_" + ] + }, + { + "name": r"subInstruction$ebnf$2", + "symbols": [ + r"subInstruction$ebnf$2", + r"subInstruction$ebnf$2$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "subInstruction", + "symbols": [ + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + r"subInstruction$ebnf$2", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": instructionSetToJsonSemi + }, + { + "name": "instructions", + "symbols": [ + (lexer.has("baseInstruction") + ? {'type': "baseInstruction"} + : baseInstruction) + ] + }, + { + "name": "instructions", + "symbols": [ + (lexer.has("macroCADR") ? {'type': "macroCADR"} : macroCADR) + ] + }, + { + "name": "instructions", + "symbols": [ + (lexer.has("macroDIP") ? {'type': "macroDIP"} : macroDIP) + ] + }, + { + "name": "instructions", + "symbols": [ + (lexer.has("macroDUP") ? {'type': "macroDUP"} : macroDUP) + ] + }, + { + "name": "instructions", + "symbols": [ + (lexer.has("macroSETCADR") + ? {'type': "macroSETCADR"} + : macroSETCADR) + ] + }, + { + "name": "instructions", + "symbols": [ + (lexer.has("macroASSERTlist") + ? {'type': "macroASSERTlist"} + : macroASSERTlist) + ] + }, + { + "name": "instruction", + "symbols": ["instructions"], + "postprocess": keywordToJson + }, + { + "name": "instruction", + "symbols": ["subInstruction"], + "postprocess": id + }, + { + "name": r"instruction$ebnf$1$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$1", + "symbols": [r"instruction$ebnf$1$subexpression$1"] + }, + { + "name": r"instruction$ebnf$1$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$1", + "symbols": [ + r"instruction$ebnf$1", + r"instruction$ebnf$1$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": ["instructions", r"instruction$ebnf$1", "_"], + "postprocess": keywordToJson + }, + { + "name": "instruction", + "symbols": ["instructions", "_", "subInstruction"], + "postprocess": singleArgInstrKeywordToJson + }, + { + "name": r"instruction$ebnf$2$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$2", + "symbols": [r"instruction$ebnf$2$subexpression$1"] + }, + { + "name": r"instruction$ebnf$2$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$2", + "symbols": [ + r"instruction$ebnf$2", + r"instruction$ebnf$2$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + "instructions", + r"instruction$ebnf$2", + "_", + "subInstruction" + ], + "postprocess": singleArgTypeKeywordToJson + }, + { + "name": "instruction", + "symbols": ["instructions", "_", "type"], + "postprocess": singleArgKeywordToJson + }, + { + "name": r"instruction$ebnf$3$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$3", + "symbols": [r"instruction$ebnf$3$subexpression$1"] + }, + { + "name": r"instruction$ebnf$3$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$3", + "symbols": [ + r"instruction$ebnf$3", + r"instruction$ebnf$3$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": ["instructions", r"instruction$ebnf$3", "_", "type"], + "postprocess": singleArgTypeKeywordToJson + }, + { + "name": "instruction", + "symbols": ["instructions", "_", "data"], + "postprocess": singleArgKeywordToJson + }, + { + "name": r"instruction$ebnf$4$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$4", + "symbols": [r"instruction$ebnf$4$subexpression$1"] + }, + { + "name": r"instruction$ebnf$4$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$4", + "symbols": [ + r"instruction$ebnf$4", + r"instruction$ebnf$4$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": ["instructions", r"instruction$ebnf$4", "_", "data"], + "postprocess": singleArgTypeKeywordToJson + }, + { + "name": "instruction", + "symbols": [ + "instructions", + "_", + "type", + "_", + "type", + "_", + "subInstruction" + ], + "postprocess": tripleArgKeyWordToJson + }, + { + "name": r"instruction$ebnf$5$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$5", + "symbols": [r"instruction$ebnf$5$subexpression$1"] + }, + { + "name": r"instruction$ebnf$5$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$5", + "symbols": [ + r"instruction$ebnf$5", + r"instruction$ebnf$5$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + "instructions", + r"instruction$ebnf$5", + "_", + "type", + "_", + "type", + "_", + "subInstruction" + ], + "postprocess": tripleArgTypeKeyWordToJson + }, + { + "name": "instruction", + "symbols": [ + "instructions", + "_", + "subInstruction", + "_", + "subInstruction" + ], + "postprocess": doubleArgInstrKeywordToJson + }, + { + "name": r"instruction$ebnf$6$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$6", + "symbols": [r"instruction$ebnf$6$subexpression$1"] + }, + { + "name": r"instruction$ebnf$6$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$6", + "symbols": [ + r"instruction$ebnf$6", + r"instruction$ebnf$6$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + "instructions", + r"instruction$ebnf$6", + "_", + "subInstruction", + "_", + "subInstruction" + ], + "postprocess": doubleArgTypeKeywordToJson + }, + { + "name": "instruction", + "symbols": ["instructions", "_", "type", "_", "type"], + "postprocess": doubleArgKeywordToJson + }, + { + "name": r"instruction$ebnf$7$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$7", + "symbols": [r"instruction$ebnf$7$subexpression$1"] + }, + { + "name": r"instruction$ebnf$7$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$7", + "symbols": [ + r"instruction$ebnf$7", + r"instruction$ebnf$7$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + "instructions", + r"instruction$ebnf$7", + "_", + "type", + "_", + "type" + ], + "postprocess": doubleArgTypeKeywordToJson + }, + { + "name": "instruction", + "symbols": [ + {"literal": "PUSH"}, + "_", + "type", + "_", + "data" + ], + "postprocess": doubleArgKeywordToJson + }, + { + "name": "instruction", + "symbols": [ + {"literal": "PUSH"}, + "_", + "type", + "_", + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": pushToJson + }, + { + "name": r"instruction$ebnf$8$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$8", + "symbols": [r"instruction$ebnf$8$subexpression$1"] + }, + { + "name": r"instruction$ebnf$8$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$8", + "symbols": [ + r"instruction$ebnf$8", + r"instruction$ebnf$8$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + {"literal": "PUSH"}, + r"instruction$ebnf$8", + "_", + "type", + "_", + "data" + ], + "postprocess": pushWithAnnotsToJson + }, + { + "name": r"instruction$ebnf$9", + "symbols": [RegExp(r'[0-9]')] + }, + { + "name": r"instruction$ebnf$9", + "symbols": [r"instruction$ebnf$9", RegExp(r'[0-9]')], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DIP"}, + "_", + r"instruction$ebnf$9", + "_", + "subInstruction" + ], + "postprocess": dipnToJson + }, + { + "name": r"instruction$ebnf$10", + "symbols": [RegExp(r'[0-9]')] + }, + { + "name": r"instruction$ebnf$10", + "symbols": [r"instruction$ebnf$10", RegExp(r'[0-9]')], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DUP"}, + "_", + r"instruction$ebnf$10" + ], + "postprocess": dupnToJson + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DUP"} + ], + "postprocess": keywordToJson + }, + { + "name": r"instruction$ebnf$11$subexpression$1", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$11", + "symbols": [r"instruction$ebnf$11$subexpression$1"] + }, + { + "name": r"instruction$ebnf$11$subexpression$2", + "symbols": [ + "_", + (lexer.has("annot") ? {'type': "annot"} : annot) + ] + }, + { + "name": r"instruction$ebnf$11", + "symbols": [ + r"instruction$ebnf$11", + r"instruction$ebnf$11$subexpression$2" + ], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DUP"}, + r"instruction$ebnf$11", + "_" + ], + "postprocess": keywordToJson + }, + { + "name": r"instruction$ebnf$12", + "symbols": [RegExp(r'[0-9]')] + }, + { + "name": r"instruction$ebnf$12", + "symbols": [r"instruction$ebnf$12", RegExp(r'[0-9]')], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DIG"}, + "_", + r"instruction$ebnf$12" + ], + "postprocess": dignToJson + }, + { + "name": r"instruction$ebnf$13", + "symbols": [RegExp(r'[0-9]')] + }, + { + "name": r"instruction$ebnf$13", + "symbols": [r"instruction$ebnf$13", RegExp(r'[0-9]')], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DUG"}, + "_", + r"instruction$ebnf$13" + ], + "postprocess": dignToJson + }, + { + "name": r"instruction$ebnf$14", + "symbols": [RegExp(r'[0-9]')] + }, + { + "name": r"instruction$ebnf$14", + "symbols": [r"instruction$ebnf$14", RegExp(r'[0-9]')], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DROP"}, + "_", + r"instruction$ebnf$14" + ], + "postprocess": dropnToJson + }, + { + "name": "instruction", + "symbols": [ + {"literal": "DROP"} + ], + "postprocess": keywordToJson + }, + { + "name": "instruction", + "symbols": [ + {"literal": "CREATE_CONTRACT"}, + "_", + (lexer.has("lbrace") ? {'type': "lbrace"} : lbrace), + "_", + "parameter", + "_", + "storage", + "_", + "code", + "_", + (lexer.has("rbrace") ? {'type': "rbrace"} : rbrace) + ], + "postprocess": subContractToJson + }, + { + "name": "instruction", + "symbols": [ + {"literal": "EMPTY_MAP"}, + "_", + "type", + "_", + "type" + ], + "postprocess": doubleArgKeywordToJson + }, + { + "name": "instruction", + "symbols": [ + {"literal": "EMPTY_MAP"}, + "_", + (lexer.has("lparen") ? {'type': "lparen"} : lparen), + "_", + "type", + "_", + (lexer.has("rparen") ? {'type': "rparen"} : rparen), + "_", + "type" + ], + "postprocess": doubleArgParenKeywordToJson + }, + {"name": r"_$ebnf$1", "symbols": []}, + { + "name": r"_$ebnf$1", + "symbols": [r"_$ebnf$1", RegExp(r'[\s]')], + "postprocess": (d) => d[0]..addAll([d[1]]) + }, + { + "name": "_", + "symbols": [r"_$ebnf$1"] + }, + { + "name": r"semicolons$ebnf$1", + "symbols": [new RegExp('[;]')], + "postprocess": id + }, + { + "name": r"semicolons$ebnf$1", + "symbols": [], + "postprocess": (d) => null + }, + { + "name": "semicolons", + "symbols": [r"semicolons$ebnf$1"] + } + ], + 'ParserStart': "main" + }; + + arrpush(d) => d[0].addAll([d[1]]).toList(); + + joiner(d) => d.join(''); +} diff --git a/lib/michelson_parser/parser/nearley.dart b/lib/michelson_parser/parser/nearley.dart new file mode 100644 index 0000000..c3e36de --- /dev/null +++ b/lib/michelson_parser/parser/nearley.dart @@ -0,0 +1,550 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:tezster_dart/michelson_parser/grammar/michelson_grammar_tokenizer.dart'; + +var fail = {}; + +class Nearley { + NearleyGrammar grammar; + var options; + + var lexer; + var lexerState; + var table; + + int current; + var results; + + static NearleyGrammar fromCompiled(Map rules, {start}) { + var lexer = rules['Lexer']; + start = rules['ParserStart']; + var redefinedRules = rules['ParserRules'].toList(); + var _rules = redefinedRules.map((r) { + return (new Rule(r['name'], r['symbols'], r['postprocess'])); + }).toList(); + var g = NearleyGrammar(_rules, start); + g.lexer = lexer; + return g; + } + + void parser(NearleyGrammar rules, {start, options}) { + grammar = rules; + + options = { + 'keepHistory': false, + 'lexer': grammar.lexer ?? new StreamLexer(), + }; + + lexer = options['lexer']; + lexerState = null; + + var column = new Column(grammar, 0); + column.wants[grammar.start] = []; + column.predict(grammar.start); + column.process(); + table = [column]; + current = 0; + } + + feed(chunk) { + var lexer = this.lexer; + lexer.tokens = []; + lexer.numindex = 0; + lexer.reset(chunk); + var token = lexer.next(); + var column; + while (token != null) { + column = table[current]; + + if (current != 0) table[current - 1] = null; + + var n = current + 1; + var nextColumn = new Column(grammar, n); + + var literal = token['text'] != null ? token['text'] : token['value']; + var value = lexer is StreamLexer ? token['value'] : token; + var scannable = column.scannable; + for (var w = scannable.length - 1; 0 <= w; w--) { + var state = scannable[w]; + var expect = state.rule.symbols[state.dot]; + // Try to consume the token + // either regex or literal + if (expect is RegExp + ? expect.hasMatch(value['value']) + : expect['type'] != null + ? expect['type'] == token['type'] + : expect['literal'] == literal) { + // Add it + var next = state.nextState({ + 'data': value, + 'token': token, + 'isToken': true, + 'reference': n - 1 + }); + nextColumn.states.add(next); + } + } + + // Next, for each of the rules, we either + // (a) complete it, and try to see if the reference row expected that + // rule + // (b) predict the next nonterminal it expects by adding that + // nonterminal's start state + // To prevent duplication, we also keep track of rules we have already + // added + + nextColumn.process(); + table.add(nextColumn); + + // If needed, throw an error: + if (nextColumn.states.length == 0) { + var err = new NearleyError(reportError(token)); + err.offset = this.current; + err.token = token; + throw Exception(err.error); + } + + token = lexer.next(); + current++; + } + + if (column != null) { + this.lexerState = lexer.save(); + } + + // Incrementally keep track of results + results = this.finish(); + + return this; + } + + finish() { + // Return the possible parsings + var considerations = []; + var start = this.grammar.start; + var column = this.table[this.table.length - 1]; + column.states.forEach((t) { + if (t.rule.name == start && + t.dot == t.rule.symbols.length && + t.reference == 0 && + t.data != fail) { + considerations.add(t); + } + }); + return considerations.map((c) { + return c.data; + }).toList(); + } + + reportError(token) { + // var lexerMessage = this.lexer.formatError(token, "Syntax error"); + var lines = []; + var tokenDisplay = + (token['type'] != null ? token['type'] + " token: " : "") + + jsonEncode(token['value'] != null ? token['value'] : token); + lines.add(this.lexer.formatError(token, "Syntax error")); + lines.add('Unexpected ' + + tokenDisplay + + '. Instead, I was expecting to see one of the following:\n'); + var lastColumnIndex = this.table.length - 2; + var lastColumn = this.table[lastColumnIndex]; + var expectantStates = lastColumn.states.where((state) { + if (state.rule.symbols.isNotEmpty) { + var nextSymbol = + state.rule.symbols[state.dot - 1 < 0 ? 0 : state.dot - 1]; + return nextSymbol != null && !(nextSymbol is String); + } else { + return false; + } + }).toList(); + + // Display a "state stack" for each expectant state + // - which shows you how this state came to be, step by step. + // If there is more than one derivation, we only display the first one. + var stateStacks = expectantStates.map((state) { + return this.buildFirstStateStack(state, []); + }).toList(); + // Display each state that is expecting a terminal symbol next. + stateStacks.forEach((stateStack) { + var state = stateStack[0]; + var nextSymbol = + state.rule.symbols[state.dot - 1 < 0 ? 0 : state.dot - 1]; + var symbolDisplay = this.getSymbolDisplay(nextSymbol); + lines.add('A ' + symbolDisplay + ' based on:'); + this.displayStateStack(stateStack, lines); + }); + + lines.add(""); + return lines.join("\n"); + } + + String reportLexerError(lexerError) { + var tokenDisplay, lexerMessage; + // Planning to add a token property to moo's thrown error + // even on erroring tokens to be used in error display below + var token = lexerError.token; + if (token) { + tokenDisplay = "input " + jsonEncode(token.text[0]) + " (lexer error)"; + lexerMessage = this.lexer.formatError(token, "Syntax error"); + } else { + tokenDisplay = "input (lexer error)"; + lexerMessage = lexerError.message; + } + return this.reportErrorCommon(lexerMessage, tokenDisplay); + } + + reportErrorCommon(lexerMessage, tokenDisplay) { + var lines = []; + lines.add(lexerMessage); + var lastColumnIndex = this.table.length - 1; + var lastColumn = this.table[lastColumnIndex]; + var expectantStates = lastColumn.states.where((state) { + var nextSymbol = state.rule.symbols[state.dot] ?? null; + return nextSymbol != null && !(nextSymbol is String); + }).toList(); + + if (expectantStates.length == 0) { + lines.add('Unexpected ' + + tokenDisplay + + '. I did not expect any more input. Here is the state of my parse table:\n'); + this.displayStateStack(lastColumn.states, lines); + } else { + lines.add('Unexpected ' + + tokenDisplay + + '. Instead, I was expecting to see one of the following:\n'); + // Display a "state stack" for each expectant state + // - which shows you how this state came to be, step by step. + // If there is more than one derivation, we only display the first one. + var stateStacks = expectantStates.map((state) { + return this.buildFirstStateStack(state, []) ?? [state]; + }); + // Display each state that is expecting a terminal symbol next. + stateStacks.forEach((stateStack) { + var state = stateStack[0]; + var nextSymbol = state.rule.symbols[state.dot]; + var symbolDisplay = this.getSymbolDisplay(nextSymbol); + lines.add('A ' + symbolDisplay + ' based on:'); + this.displayStateStack(stateStack, lines); + }); + } + lines.add(""); + return lines.join("\n"); + } + + buildFirstStateStack(state, visited) { + if (visited.indexOf(state) != -1) { + // Found cycle, return null + // to eliminate this path from the results, because + // we don't know how to display it meaningfully + return null; + } + if (state.wantedBy.length == 0) { + return [state]; + } + var prevState = state.wantedBy[0]; + var childVisited = [state]..addAll(visited); + var childResult = this.buildFirstStateStack(prevState, childVisited); + if (childResult == null) { + return null; + } + return [state]..addAll(childResult); + } + + displayStateStack(stateStack, lines) { + var lastDisplay; + var sameDisplayCount = 0; + for (var j = 0; j < stateStack.length; j++) { + var state = stateStack[j]; + var display = state.rule.toStringWithData(state.dot); + if (display == lastDisplay) { + sameDisplayCount++; + } else { + if (sameDisplayCount > 0) { + lines.add(' ^ ' + + sameDisplayCount.toString() + + ' more lines identical to this'); + } + sameDisplayCount = 0; + lines.add(' ' + display); + } + lastDisplay = display; + } + } + + getSymbolDisplay(symbol) { + return getSymbolLongDisplay(symbol); + } + + getSymbolLongDisplay(symbol) { + // var type = typeof symbol; + if (symbol is String) { + return symbol; + } else if (symbol is Map) { + return jsonEncode(symbol['literal'] ?? ''); + } else if (symbol is RegExp) { + return 'character matching ' + symbol.toString(); + } else if (symbol['type'] != null) { + return symbol['type'] + ' token'; + } else if (symbol['test'] ?? null != null) { + return 'token matching ' + symbol['test'].toString(); + } else { + throw new Exception('Unknown symbol type: ' + symbol.toString()); + } + } +} + +class Column { + NearleyGrammar grammar; + int index; + + List states; + Map wants; + List scannable; + Map completed; + + Column(this.grammar, this.index) { + states = []; + wants = {}; + scannable = []; + completed = {}; + } + + void predict(exp) { + var rules = grammar.byName[exp] ?? []; + for (var i = 0; i < rules.length; i++) { + var r = rules[i]; + var wantBy = wants[exp]; + var s = new ColumnState(r, 0, index, wantBy); + states.add(s); + } + } + + void process() { + var _states = this.states; + var _wants = this.wants; + var _completed = this.completed; + + for (var w = 0; w < _states.length; w++) { + var state = _states[w]; + if (state.isComplete) { + state.finish(); + if (state.data != fail) { + var wantBy = state.wantedBy; + + // complete + for (var i = wantBy.length - 1; 0 <= i; i--) { + var left = wantBy[i]; + this.complete(left, state); + } + + // special-case nullables + if (state.reference == index) { + // make sure future predictors of this rule get completed. + var exp = state.rule.name; + this.completed[exp] = this.completed[exp] ?? []; + this.completed[exp].add(state); + } + } + } else { + // queue scannable states + var exp = state.rule.symbols[state.dot]; + if (!(exp is String)) { + this.scannable.add(state); + } + + // predict + if (_wants[exp] != null) { + _wants[exp].add(state); + if (_completed.containsKey(exp)) { + var nulls = _completed[exp]; + for (var i = 0; i < nulls.length; i++) { + var right = nulls[i]; + complete(state, right); + } + } + } else { + _wants[exp] = _wants[exp] is List ? _wants[exp].add(state) : [state]; + this.predict(exp); + } + } + } + } + + void complete(left, right) { + var copy = left.nextState(right); + states.add(copy); + } +} + +class ColumnState { + Rule rule; + var dot; + var reference; + var data; + var wantedBy; + var isComplete; + + ColumnState left; + var right; + + ColumnState(this.rule, this.dot, this.reference, this.wantedBy) { + data = []; + isComplete = dot == rule.symbols.length; + } + + void finish() { + if (rule.postprocess != null) { + try { + data = rule.postprocess(data); + } catch (e) { + print("Error In ===> " + rule.name); + } + } + } + + ColumnState nextState(child) { + var state = new ColumnState(rule, dot + 1, reference, wantedBy); + state.left = this; + state.right = child; + if (state.isComplete) { + state.data = state.build(); + } + return state; + } + + List build() { + var children = []; + var node = this; + do { + children.add( + node.right is ColumnState ? node.right.data : node.right['data']); + node = node.left; + } while (node.left != null); + children = children.reversed.toList(); + return children; + } +} + +class NearleyError { + var error; + int offset; + var token; + NearleyError(this.error); +} + +class NearleyGrammar { + List rules; + var start; + + var lexer; + var byName; + + NearleyGrammar(this.rules, this.start) { + this.rules = rules; + this.start = start ?? this.rules[0].name; + var byName = this.byName = {}; + this.rules.forEach((rule) { + if (!byName.containsKey(rule.name)) { + byName[rule.name] = []; + } + byName[rule.name].add(rule); + }); + } +} + +class Rule { + var name; + var symbols; + var postprocess; + Rule(this.name, this.symbols, this.postprocess); + + toStringWithData(withCursorAt) { + stringifySymbolSequence(e) { + return e is Map && e.containsKey('literal') + ? jsonEncode(e['literal']) + : e is Map && e.containsKey('type') + ? '%' + e['type'] + : e.toString(); + } + + var symbolSequence = (withCursorAt == null) + ? this.symbols.map(stringifySymbolSequence).join(' ') + : (this + .symbols + .take(withCursorAt - 1 < 0 ? 0 : withCursorAt - 1) + .map(stringifySymbolSequence) + .join(' ') + + " ● " + + this + .symbols + .take(withCursorAt) + .map(stringifySymbolSequence) + .join(' ')); + return this.name + " → " + symbolSequence; + } +} + +class StreamLexer { + var buffer; + int index; + var line; + var lastLineBreak; + + StreamLexer() { + this.reset(""); + } + + has(tokenType) { + return true; + } + + reset(data, {state}) { + this.buffer = data; + this.index = 0; + this.line = state != null ? state.line : 1; + this.lastLineBreak = state != null ? -state.col : 0; + } + + save() { + return { + 'line': this.line, + 'col': this.index - this.lastLineBreak, + }; + } + + formatError(token, message) { + pad(n, length) { + var s = (n).toString(); + return List.generate(length - s.length + 1, (index) => '').join(" ") + s; + } + + // nb. this gets called after consuming the offending token, + // so the culprit is index-1 + var buffer = this.buffer; + if (buffer is String) { + var lines = buffer.split("\n").sublist(max(0, this.line - 5), this.line); + + var nextLineBreak = buffer.indexOf('\n', this.index); + if (nextLineBreak == -1) nextLineBreak = buffer.length; + var col = this.index - this.lastLineBreak; + var lastLineDigits = (this.line).toString().length; + message += " at line " + + this.line.toString() + + " col " + + col.toString() + + ":\n\n"; + var msg = List(); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + msg.add( + pad(this.line - lines.length + i + 1, lastLineDigits) + " " + line); + } + message += msg.join("\n"); + message += "\n" + pad("", lastLineDigits + col) + "^\n"; + return message; + } else { + return message + " at index " + (this.index - 1); + } + } +} diff --git a/lib/models/operation_model.dart b/lib/models/operation_model.dart index c94e111..5d5aa07 100644 --- a/lib/models/operation_model.dart +++ b/lib/models/operation_model.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:tezster_dart/helper/constants.dart'; class OperationModel { diff --git a/pubspec.lock b/pubspec.lock index 1118fbe..e834510 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -137,15 +137,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.3" - michelson_parser: - dependency: "direct main" - description: - path: "." - ref: HEAD - resolved-ref: cbda67adc5f8a3287c4b98e822f9d2766e55f51b - url: "https://github.com/Jay-Tezsure/michelson_parser.git" - source: git - version: "0.0.1" password_hash: dependency: "direct main" description: @@ -237,4 +228,4 @@ packages: version: "2.1.0-nullsafety.3" sdks: dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.20.0" + flutter: ">=1.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 1aeaf16..423891d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,9 +20,6 @@ dependencies: flutter_sodium: ^0.1.9 password_hash: ^2.0.0 unorm_dart: ^0.1.2 - michelson_parser: - git: - url: https://github.com/Jay-Tezsure/michelson_parser.git dev_dependencies: flutter_test: From 0b0c18e09a5dd1096c1850f3491abb954e38bfed Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 17 Feb 2021 14:17:11 +0530 Subject: [PATCH 4/6] readme.md updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 08682ed..93b3c6f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Tezos is a decentralized blockchain that governs itself by establishing a true d * Delegate an Account. * Deploy a contract. * Call a contract. - * Await operation Confirmation. + * Operation confirmation. ### Getting started @@ -240,7 +240,7 @@ print("Operation groupID ===> $result['operationGroupID']"); reference link: `https://github.com/Tezsure/Tezster_dart/blob/master/example/lib/main.dart#L141`
-* Await operation Confirmation. +* Operation confirmation. * No wonder it's really important to await for confirmation for any on chain interactions. Hence, we have provided `awaitOperationConfirmation()` method with this release that developers can leverage for their advantage to confirm the originated contract's operations id. We have set an example for you how to use it. ``` dart From 61f28a082bc6e4a00c3db49ab3a2617897d4f085 Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 17 Feb 2021 17:56:50 +0530 Subject: [PATCH 5/6] changelog updated --- CHANGELOG.md | 16 +++++++++++++++- example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be97b35..9d1e480 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# [2.1.0+1] + +* Deploy contract +* Call contract +* Operation confirmation +* Fix for revelation of an account Ref #12 + +# [2.0.0] + +* Dependencies update. +* Added Get Balance. +* Added Transfer Balance. +* Added Delegate an Account. + # [1.0.1] * Dependencies update. @@ -11,4 +25,4 @@ Initial version of library. * Generate keys from mnemonic. * Generate keys from mnemonics and passphrase. * Sign Operation Group. - * Unlock fundraiser identity. + * Unlock fundraiser identity. \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 0878060..a28fc4d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -218,7 +218,7 @@ packages: path: ".." relative: true source: path - version: "1.0.1" + version: "2.1.0+1" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 423891d..515981b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: tezster_dart description: A flutter package which provides the functionalities to play around with tezos dApps -version: 1.0.1 +version: 2.1.0+1 homepage: https://github.com/Tezsure/tezster_dart repository: https://github.com/Tezsure/tezster_dart issue_tracker: https://github.com/Tezsure/tezster_dart/issues From e23a82479c593d805e654243da32bd9a74866031 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 18 Feb 2021 10:03:19 +0530 Subject: [PATCH 6/6] code refactored --- lib/chain/tezos/tezos_language_util.dart | 1 - lib/chain/tezos/tezos_message_codec.dart | 2 +- lib/chain/tezos/tezos_message_utils.dart | 1 - lib/chain/tezos/tezos_node_writer.dart | 1 - lib/helper/password_generater.dart | 14 +------ .../grammar/michelin_grammar_tokenizer.dart | 35 +--------------- .../grammar/michelson_grammar_tokenizer.dart | 2 - lib/michelson_parser/michelson_parser.dart | 1 - .../parser/micheline_grammar.dart | 26 ------------ .../parser/michelson_grammar.dart | 2 - lib/michelson_parser/parser/nearley.dart | 41 +++---------------- lib/reporting/conseil_data_client.dart | 20 +-------- lib/src/tezster_dart.dart | 9 ---- lib/tezster_dart.dart | 4 +- lib/utils/crypto_utils.dart | 6 +-- 15 files changed, 12 insertions(+), 153 deletions(-) diff --git a/lib/chain/tezos/tezos_language_util.dart b/lib/chain/tezos/tezos_language_util.dart index 041ee8a..ccda09f 100644 --- a/lib/chain/tezos/tezos_language_util.dart +++ b/lib/chain/tezos/tezos_language_util.dart @@ -3,7 +3,6 @@ import 'package:tezster_dart/michelson_parser/michelson_parser.dart'; class TezosLanguageUtil { static String translateMichelsonToMicheline(String code) { - // jsonDecode() var result = MichelsonParser.parseMichelson(code); return result; } diff --git a/lib/chain/tezos/tezos_message_codec.dart b/lib/chain/tezos/tezos_message_codec.dart index 87f9783..7341f33 100644 --- a/lib/chain/tezos/tezos_message_codec.dart +++ b/lib/chain/tezos/tezos_message_codec.dart @@ -62,7 +62,7 @@ class TezosMessageCodec { } static String encodeReveal(OperationModel message) { - var hex = TezosMessageUtils.writeInt(107); //sepyTnoitarepo['reveal']); + var hex = TezosMessageUtils.writeInt(107); hex += TezosMessageUtils.writeAddress(message.source).substring(2); hex += TezosMessageUtils.writeInt(int.parse(message.fee)); hex += TezosMessageUtils.writeInt(message.counter); diff --git a/lib/chain/tezos/tezos_message_utils.dart b/lib/chain/tezos/tezos_message_utils.dart index c6d13c4..de87cf8 100644 --- a/lib/chain/tezos/tezos_message_utils.dart +++ b/lib/chain/tezos/tezos_message_utils.dart @@ -12,7 +12,6 @@ class TezosMessageUtils { .decode(branch) .sublist(2, base58.decode(branch).length - 4) .toList()); - // return hex.encode(base58.decode(branch).sublist(2).toList()); } static String writeInt(int value) { diff --git a/lib/chain/tezos/tezos_node_writer.dart b/lib/chain/tezos/tezos_node_writer.dart index b7fe8e7..8679355 100644 --- a/lib/chain/tezos/tezos_node_writer.dart +++ b/lib/chain/tezos/tezos_node_writer.dart @@ -294,7 +294,6 @@ class TezosNodeWriter { var response = await HttpHelper.performPostRequest(server, 'injection/operation?chain=$chainid', hex.encode(opPair['bytes'])); response = response.toString().replaceAll('"', ''); - // parseRPCError(response); return response; } diff --git a/lib/helper/password_generater.dart b/lib/helper/password_generater.dart index 4421459..d18db72 100644 --- a/lib/helper/password_generater.dart +++ b/lib/helper/password_generater.dart @@ -3,29 +3,20 @@ import 'dart:math'; import 'package:flutter/cupertino.dart'; class PasswordGenerator { - /// @desc Function to generate password based on some criteria - /// @param bool isWithLetters: password must contain letters - /// @param bool isWithUppercase: password must contain uppercase letters - /// @param bool isWithNumbers: password must contain numbers - /// @param bool isWithSpecial: password must contain special chars - /// @param int length: password length - /// @return string: new password + static String generatePassword( {@required double length, bool isWithLetters, bool isWithUppercase, bool isWithNumbers, bool isWithSpecial}) { - //Define the allowed chars to use in the password String _lowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"; String _upperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; String _numbers = "0123456789"; String _special = r'!@#$%^&*()+_-=}{[]|:;"/?.><,`~'; - //Create the empty string that will contain the allowed chars String _allowedChars = ""; - //Put chars on the allowed ones based on the input values _allowedChars += (isWithLetters ? _lowerCaseLetters : ''); _allowedChars += (isWithUppercase ? _upperCaseLetters : ''); _allowedChars += (isWithNumbers ? _numbers : ''); @@ -34,11 +25,8 @@ class PasswordGenerator { int i = 0; String _result = ""; - //Create password while (i < length.round()) { - //Get random int int randomInt = Random.secure().nextInt(_allowedChars.length); - //Get random char and append it to the password _result += _allowedChars[randomInt]; i++; } diff --git a/lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart b/lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart index 502d155..97c2b1a 100644 --- a/lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart +++ b/lib/michelson_parser/grammar/michelin_grammar_tokenizer.dart @@ -27,7 +27,6 @@ class MichelinGrammarTokenizer { "text": tokens[numindex].value, "col": tokens[numindex].columnNumber, "line": '1', - // 'toString': () => tokens[numindex].value, } : null; numindex++; @@ -105,38 +104,9 @@ class MichelinGrammarTokenizer { } seq += chunk[j]; } - // if (seq.isNotEmpty) { - // if (tokens.last.type == 'word' && - // getKeyFromValue(char, isRegex: false) == null) { - // tokens.last = tokens.last..value += char; - // } else if (tokens.last.type == 'number' && - // getKeyFromValue(char, isRegex: true).key == "number") { - // tokens.last = tokens.last..value += char; - // } else if (isArrayOrStringContaines(seq)) { - // var argSeq = getKeyFromValue(seq); - // tokens.add(GrammarResultModel(argSeq.key, seq)..columnNumber = i); - // i += (seq.length - 1); - // } else { - // if (char != '%') { - // var argSeq = getKeyFromValue(char); - // tokens - // .add(GrammarResultModel(argSeq.key, char)..columnNumber = i); - // } - // } - // } + } - // else if (char == '%' || char == ':') { - // var nextIndex = i + 30; - // if (nextIndex >= chunk.length - 1) nextIndex = chunk.length - 1; - // var data = chunk.substring( - // i, - // nextIndex, - // ); - // var endIndex = getEndIndexOfVar(data); - // tokens.add(GrammarResultModel('annot', data.substring(0, endIndex)) - // ..columnNumber = i); - // i += endIndex - 1; - // } + else if (char == '"') { var nextIndex = i + 200; if (nextIndex >= chunk.length - 1) nextIndex = chunk.length; @@ -167,7 +137,6 @@ class MichelinGrammarTokenizer { var result = false; var _keys = delimiters.keys.toList(); for (var i = 0; i < _keys.length; i++) { - // var key = _keys[i]; var value = delimiters[_keys[i]]; if (value is List) { result = value.contains(char); diff --git a/lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart b/lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart index 6e8d683..7233f1b 100644 --- a/lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart +++ b/lib/michelson_parser/grammar/michelson_grammar_tokenizer.dart @@ -26,7 +26,6 @@ class MichelsonGrammarTokenizer { "text": tokens[numindex].value, "col": tokens[numindex].columnNumber, "line": '1', - // 'toString': () => tokens[numindex].value, } : null; numindex++; @@ -159,7 +158,6 @@ class MichelsonGrammarTokenizer { var result = false; var _keys = delimiters.keys.toList(); for (var i = 0; i < _keys.length; i++) { - // var key = _keys[i]; var value = delimiters[_keys[i]]; if (value is List) { result = value.contains(char); diff --git a/lib/michelson_parser/michelson_parser.dart b/lib/michelson_parser/michelson_parser.dart index f4eab09..a519b2a 100644 --- a/lib/michelson_parser/michelson_parser.dart +++ b/lib/michelson_parser/michelson_parser.dart @@ -3,7 +3,6 @@ import 'package:tezster_dart/michelson_parser/parser/michelson_grammar.dart'; import 'package:tezster_dart/michelson_parser/parser/nearley.dart'; class MichelsonParser { - /// code = michelson code static String parseMichelson(String code) { var parser = Nearley(); parser.parser(Nearley.fromCompiled(MichelsonGrammar().grammar)); diff --git a/lib/michelson_parser/parser/micheline_grammar.dart b/lib/michelson_parser/parser/micheline_grammar.dart index 15ad69d..bfdaf7b 100644 --- a/lib/michelson_parser/parser/micheline_grammar.dart +++ b/lib/michelson_parser/parser/micheline_grammar.dart @@ -358,32 +358,6 @@ class MichelineGrammar { getMapValue(d) => d is List ? d[0]['value'].toString() : d['value']; -// interface NearleyToken { value: any; -// [key: string]: any; -// }; - -// interface NearleyLexer { -// reset: (chunk: string, info: any) => void; -// next: () => NearleyToken | undefined; -// save: () => any; -// formatError: (token: NearleyToken) => string; -// has: (tokenType: string) => boolean; -// }; - -// interface NearleyRule { -// name: string; -// symbols: NearleySymbol[]; -// postprocess?: (d: any[], loc?: number, reject?: {}) => any; -// }; - -// type NearleySymbol = string | { literal: any } | { test: (token: any) => boolean }; - -// interface Grammar { -// Lexer: NearleyLexer | undefined; -// ParserRules: NearleyRule[]; -// ParserStart: string; -// }; - Map get grammar => { 'Lexer': lexer, 'ParserRules': [ diff --git a/lib/michelson_parser/parser/michelson_grammar.dart b/lib/michelson_parser/parser/michelson_grammar.dart index 5255047..2831757 100644 --- a/lib/michelson_parser/parser/michelson_grammar.dart +++ b/lib/michelson_parser/parser/michelson_grammar.dart @@ -119,8 +119,6 @@ class MichelsonGrammar { 'macroCADR': macroCADRconst, 'macroDIP': dIPmatcher, 'macroDUP': dUPmatcher, - // 'macroDIP': macroDIPconst, - // 'macroDUP': macroDUPconst, 'macroSETCADR': macroSETCADRconst, 'macroASSERTlist': macroASSERTlistConst, 'constantData': ['Unit', 'True', 'False', 'None', 'instruction'], diff --git a/lib/michelson_parser/parser/nearley.dart b/lib/michelson_parser/parser/nearley.dart index c3e36de..edd0c0c 100644 --- a/lib/michelson_parser/parser/nearley.dart +++ b/lib/michelson_parser/parser/nearley.dart @@ -68,14 +68,12 @@ class Nearley { for (var w = scannable.length - 1; 0 <= w; w--) { var state = scannable[w]; var expect = state.rule.symbols[state.dot]; - // Try to consume the token - // either regex or literal + if (expect is RegExp ? expect.hasMatch(value['value']) : expect['type'] != null ? expect['type'] == token['type'] : expect['literal'] == literal) { - // Add it var next = state.nextState({ 'data': value, 'token': token, @@ -86,18 +84,9 @@ class Nearley { } } - // Next, for each of the rules, we either - // (a) complete it, and try to see if the reference row expected that - // rule - // (b) predict the next nonterminal it expects by adding that - // nonterminal's start state - // To prevent duplication, we also keep track of rules we have already - // added - nextColumn.process(); table.add(nextColumn); - // If needed, throw an error: if (nextColumn.states.length == 0) { var err = new NearleyError(reportError(token)); err.offset = this.current; @@ -113,14 +102,12 @@ class Nearley { this.lexerState = lexer.save(); } - // Incrementally keep track of results results = this.finish(); return this; } finish() { - // Return the possible parsings var considerations = []; var start = this.grammar.start; var column = this.table[this.table.length - 1]; @@ -138,7 +125,6 @@ class Nearley { } reportError(token) { - // var lexerMessage = this.lexer.formatError(token, "Syntax error"); var lines = []; var tokenDisplay = (token['type'] != null ? token['type'] + " token: " : "") + @@ -159,13 +145,10 @@ class Nearley { } }).toList(); - // Display a "state stack" for each expectant state - // - which shows you how this state came to be, step by step. - // If there is more than one derivation, we only display the first one. var stateStacks = expectantStates.map((state) { return this.buildFirstStateStack(state, []); }).toList(); - // Display each state that is expecting a terminal symbol next. + stateStacks.forEach((stateStack) { var state = stateStack[0]; var nextSymbol = @@ -181,8 +164,7 @@ class Nearley { String reportLexerError(lexerError) { var tokenDisplay, lexerMessage; - // Planning to add a token property to moo's thrown error - // even on erroring tokens to be used in error display below + var token = lexerError.token; if (token) { tokenDisplay = "input " + jsonEncode(token.text[0]) + " (lexer error)"; @@ -213,13 +195,11 @@ class Nearley { lines.add('Unexpected ' + tokenDisplay + '. Instead, I was expecting to see one of the following:\n'); - // Display a "state stack" for each expectant state - // - which shows you how this state came to be, step by step. - // If there is more than one derivation, we only display the first one. + var stateStacks = expectantStates.map((state) { return this.buildFirstStateStack(state, []) ?? [state]; }); - // Display each state that is expecting a terminal symbol next. + stateStacks.forEach((stateStack) { var state = stateStack[0]; var nextSymbol = state.rule.symbols[state.dot]; @@ -234,9 +214,6 @@ class Nearley { buildFirstStateStack(state, visited) { if (visited.indexOf(state) != -1) { - // Found cycle, return null - // to eliminate this path from the results, because - // we don't know how to display it meaningfully return null; } if (state.wantedBy.length == 0) { @@ -277,7 +254,6 @@ class Nearley { } getSymbolLongDisplay(symbol) { - // var type = typeof symbol; if (symbol is String) { return symbol; } else if (symbol is Map) { @@ -332,28 +308,23 @@ class Column { if (state.data != fail) { var wantBy = state.wantedBy; - // complete for (var i = wantBy.length - 1; 0 <= i; i--) { var left = wantBy[i]; this.complete(left, state); } - // special-case nullables if (state.reference == index) { - // make sure future predictors of this rule get completed. var exp = state.rule.name; this.completed[exp] = this.completed[exp] ?? []; this.completed[exp].add(state); } } } else { - // queue scannable states var exp = state.rule.symbols[state.dot]; if (!(exp is String)) { this.scannable.add(state); } - // predict if (_wants[exp] != null) { _wants[exp].add(state); if (_completed.containsKey(exp)) { @@ -519,8 +490,6 @@ class StreamLexer { return List.generate(length - s.length + 1, (index) => '').join(" ") + s; } - // nb. this gets called after consuming the offending token, - // so the culprit is index-1 var buffer = this.buffer; if (buffer is String) { var lines = buffer.split("\n").sublist(max(0, this.line - 5), this.line); diff --git a/lib/reporting/conseil_data_client.dart b/lib/reporting/conseil_data_client.dart index 3db1744..8802e33 100644 --- a/lib/reporting/conseil_data_client.dart +++ b/lib/reporting/conseil_data_client.dart @@ -4,29 +4,11 @@ class ConseilDataClient { static executeEntityQuery( serverInfo, platform, network, entity, query) async { var url = '${serverInfo['url']}/v2/data/$platform/$network/$entity'; - // log.debug(`ConseilDataClient.executeEntityQuery request: ${url}, ${JSON.stringify(query)}`); + var res = await HttpHelper.performPostRequest(url, '', query, headers: { 'apiKey': serverInfo['apiKey'], - // 'Content-Type': 'application/json', 'cache': 'no-store', }); return res; - // .then((r) { - // if (!r.ok) { - // // log.error(`ConseilDataClient.executeEntityQuery request: ${url}, ${JSON.stringify(query)}, failed with ${r.statusText}(${r.status})`); - // throw new ConseilErrorTypes_1.ConseilRequestError( - // r.status, r.statusText, url, query); - // } - // return r; - // }) - // .then((r) { - // var isJSONResponse = r.headers - // .get('content-type') - // .toLowerCase() - // .includes('application/json'); - // var response = isJSONResponse != null ? r.json() : r.text(); - // // log.debug(`ConseilDataClient.executeEntityQuery response: ${isJSONResponse ? JSON.stringify(response) : response}`); - // return response; - // }); } } diff --git a/lib/src/tezster_dart.dart b/lib/src/tezster_dart.dart index 1cbd537..4abab96 100644 --- a/lib/src/tezster_dart.dart +++ b/lib/src/tezster_dart.dart @@ -23,12 +23,10 @@ import 'package:flutter_sodium/flutter_sodium.dart'; import 'package:tezster_dart/helper/generateKeys.dart'; class TezsterDart { - /// Generate mnemonic static String generateMnemonic({int strength = 256}) { return bip39.generateMnemonic(strength: strength); } - /// Generate keys from mnemonic static Future> getKeysFromMnemonic({ String mnemonic, }) async { @@ -42,7 +40,6 @@ class TezsterDart { return [skKey, pkKey, pkKeyHash]; } - /// Create / Unlock identity from mnemonic and passphrase. static Future> getKeysFromMnemonicAndPassphrase({ String mnemonic, String passphrase, @@ -55,7 +52,6 @@ class TezsterDart { ); } - /// Unlock fundraiser identity. static Future> unlockFundraiserIdentity({ String mnemonic, String email, @@ -70,7 +66,6 @@ class TezsterDart { ); } - /// Sign operation with private key and forged operation static Future> signOperationGroup({ String privateKey, String forgedOperation, @@ -125,7 +120,6 @@ class TezsterDart { return [skKey, pkKey, pkKeyHash]; } - // Get balance from given publicKeyHash and rpc static Future getBalance(String publicKeyHash, String rpc) async { assert(publicKeyHash != null); assert(rpc != null); @@ -140,13 +134,11 @@ class TezsterDart { return GenerateKeys.writeKeyWithHint(key, hint); } - // Create Signer from given secretKey static createSigner(Uint8List secretKey, {int validity = 60}) { assert(secretKey != null); return SoftSigner.createSigner(secretKey, validity); } - /// Transfer Balance static sendTransactionOperation(String server, SoftSigner signer, KeyStoreModel keyStore, String to, int amount, int fee, {int offset = 54}) async { @@ -165,7 +157,6 @@ class TezsterDart { server, signer, keyStore, to, amount, fee); } - /// Delegate an Account static sendDelegationOperation(String server, SoftSigner signer, KeyStoreModel keyStore, String delegate, int fee, {offset = 54}) async { diff --git a/lib/tezster_dart.dart b/lib/tezster_dart.dart index 54f017d..9804781 100644 --- a/lib/tezster_dart.dart +++ b/lib/tezster_dart.dart @@ -2,8 +2,6 @@ library tezster_dart; export 'src/tezster_dart.dart'; -// KeyStore Model export 'models/key_store_model.dart'; -// tezos types -export 'types/tezos/tezos_chain_types.dart'; \ No newline at end of file +export 'types/tezos/tezos_chain_types.dart'; diff --git a/lib/utils/crypto_utils.dart b/lib/utils/crypto_utils.dart index 12787c3..a1885f4 100644 --- a/lib/utils/crypto_utils.dart +++ b/lib/utils/crypto_utils.dart @@ -11,14 +11,10 @@ class CryptoUtils { var keyBytes = SodiumUtils.pwhash(passphrase, salt); var nonce = SodiumUtils.nonce(); var s = SodiumUtils.close(message, nonce, keyBytes); - // nonce.addAll(s); + return new Uint8List.fromList(nonce.toList() + s.toList()); } - // static signDetached(Uint8List simpleHash) { - // return - // } - static Uint8List decryptMessage(message, passphrase, salt) { var keyBytes = SodiumUtils.pwhash(passphrase, salt); return SodiumUtils.open(message, keyBytes);