From 4de2e8ab1fcb5c5235e4a16b427cb7eab47dec9b Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Wed, 20 Dec 2023 12:55:54 +0200 Subject: [PATCH 01/17] add rmb client && types.proto --- packages/rmb_client/.gitignore | 3 + packages/rmb_client/CHANGELOG.md | 3 + packages/rmb_client/README.md | 2 + packages/rmb_client/analysis_options.yaml | 30 + packages/rmb_client/bin/rmb_client.dart | 0 packages/rmb_client/lib/rmb_client.dart | 0 .../lib/types/generated/types.pb.dart | 630 ++++++++++++++++++ .../lib/types/generated/types.pbenum.dart | 11 + .../lib/types/generated/types.pbjson.dart | 136 ++++ .../lib/types/generated/types.pbserver.dart | 14 + packages/rmb_client/lib/types/types.proto | 77 +++ packages/rmb_client/pubspec.yaml | 15 + packages/rmb_client/test/rmb_client_test.dart | 0 13 files changed, 921 insertions(+) create mode 100644 packages/rmb_client/.gitignore create mode 100644 packages/rmb_client/CHANGELOG.md create mode 100644 packages/rmb_client/README.md create mode 100644 packages/rmb_client/analysis_options.yaml create mode 100644 packages/rmb_client/bin/rmb_client.dart create mode 100644 packages/rmb_client/lib/rmb_client.dart create mode 100644 packages/rmb_client/lib/types/generated/types.pb.dart create mode 100644 packages/rmb_client/lib/types/generated/types.pbenum.dart create mode 100644 packages/rmb_client/lib/types/generated/types.pbjson.dart create mode 100644 packages/rmb_client/lib/types/generated/types.pbserver.dart create mode 100644 packages/rmb_client/lib/types/types.proto create mode 100644 packages/rmb_client/pubspec.yaml create mode 100644 packages/rmb_client/test/rmb_client_test.dart diff --git a/packages/rmb_client/.gitignore b/packages/rmb_client/.gitignore new file mode 100644 index 00000000..3a857904 --- /dev/null +++ b/packages/rmb_client/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/packages/rmb_client/CHANGELOG.md b/packages/rmb_client/CHANGELOG.md new file mode 100644 index 00000000..effe43c8 --- /dev/null +++ b/packages/rmb_client/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/rmb_client/README.md b/packages/rmb_client/README.md new file mode 100644 index 00000000..3816eca3 --- /dev/null +++ b/packages/rmb_client/README.md @@ -0,0 +1,2 @@ +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/packages/rmb_client/analysis_options.yaml b/packages/rmb_client/analysis_options.yaml new file mode 100644 index 00000000..dee8927a --- /dev/null +++ b/packages/rmb_client/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/rmb_client/bin/rmb_client.dart b/packages/rmb_client/bin/rmb_client.dart new file mode 100644 index 00000000..e69de29b diff --git a/packages/rmb_client/lib/rmb_client.dart b/packages/rmb_client/lib/rmb_client.dart new file mode 100644 index 00000000..e69de29b diff --git a/packages/rmb_client/lib/types/generated/types.pb.dart b/packages/rmb_client/lib/types/generated/types.pb.dart new file mode 100644 index 00000000..57e0ec1d --- /dev/null +++ b/packages/rmb_client/lib/types/generated/types.pb.dart @@ -0,0 +1,630 @@ +// +// Generated code. Do not modify. +// source: types.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:core' as $core; + +import 'package:fixnum/fixnum.dart' as $fixnum; +import 'package:protobuf/protobuf.dart' as $pb; + +/// A Request annotate this message as a request message +/// with proper command +class Request extends $pb.GeneratedMessage { + factory Request({ + $core.String? command, + }) { + final $result = create(); + if (command != null) { + $result.command = command; + } + return $result; + } + Request._() : super(); + factory Request.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Request.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Request', createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'command') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Request clone() => Request()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Request copyWith(void Function(Request) updates) => super.copyWith((message) => updates(message as Request)) as Request; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Request create() => Request._(); + Request createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Request getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Request? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get command => $_getSZ(0); + @$pb.TagNumber(1) + set command($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasCommand() => $_has(0); + @$pb.TagNumber(1) + void clearCommand() => clearField(1); +} + +/// A Response annotate this message as a response message +class Response extends $pb.GeneratedMessage { + factory Response() => create(); + Response._() : super(); + factory Response.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Response.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Response', createEmptyInstance: create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Response clone() => Response()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Response copyWith(void Function(Response) updates) => super.copyWith((message) => updates(message as Response)) as Response; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Response create() => Response._(); + Response createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Response getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Response? _defaultInstance; +} + +/// A Error annotiate this message as an error message +class Error extends $pb.GeneratedMessage { + factory Error({ + $core.int? code, + $core.String? message, + }) { + final $result = create(); + if (code != null) { + $result.code = code; + } + if (message != null) { + $result.message = message; + } + return $result; + } + Error._() : super(); + factory Error.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Error.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Error', createEmptyInstance: create) + ..a<$core.int>(1, _omitFieldNames ? '' : 'code', $pb.PbFieldType.OU3) + ..aOS(2, _omitFieldNames ? '' : 'message') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Error clone() => Error()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Error copyWith(void Function(Error) updates) => super.copyWith((message) => updates(message as Error)) as Error; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Error create() => Error._(); + Error createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Error getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Error? _defaultInstance; + + /// error code (app specific) + @$pb.TagNumber(1) + $core.int get code => $_getIZ(0); + @$pb.TagNumber(1) + set code($core.int v) { $_setUnsignedInt32(0, v); } + @$pb.TagNumber(1) + $core.bool hasCode() => $_has(0); + @$pb.TagNumber(1) + void clearCode() => clearField(1); + + /// error message + @$pb.TagNumber(2) + $core.String get message => $_getSZ(1); + @$pb.TagNumber(2) + set message($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasMessage() => $_has(1); + @$pb.TagNumber(2) + void clearMessage() => clearField(2); +} + +class Address extends $pb.GeneratedMessage { + factory Address({ + $core.int? twin, + $core.String? connection, + }) { + final $result = create(); + if (twin != null) { + $result.twin = twin; + } + if (connection != null) { + $result.connection = connection; + } + return $result; + } + Address._() : super(); + factory Address.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Address.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Address', createEmptyInstance: create) + ..a<$core.int>(1, _omitFieldNames ? '' : 'twin', $pb.PbFieldType.OU3) + ..aOS(2, _omitFieldNames ? '' : 'connection') + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Address clone() => Address()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Address copyWith(void Function(Address) updates) => super.copyWith((message) => updates(message as Address)) as Address; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Address create() => Address._(); + Address createEmptyInstance() => create(); + static $pb.PbList
createRepeated() => $pb.PbList
(); + @$core.pragma('dart2js:noInline') + static Address getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor
(create); + static Address? _defaultInstance; + + @$pb.TagNumber(1) + $core.int get twin => $_getIZ(0); + @$pb.TagNumber(1) + set twin($core.int v) { $_setUnsignedInt32(0, v); } + @$pb.TagNumber(1) + $core.bool hasTwin() => $_has(0); + @$pb.TagNumber(1) + void clearTwin() => clearField(1); + + @$pb.TagNumber(2) + $core.String get connection => $_getSZ(1); + @$pb.TagNumber(2) + set connection($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasConnection() => $_has(1); + @$pb.TagNumber(2) + void clearConnection() => clearField(2); +} + +/// an app level ping pong +/// in case you are using javascript +/// and cant send ping messages +/// when sending Pings, both signature +/// and destination are ignored +class Ping extends $pb.GeneratedMessage { + factory Ping() => create(); + Ping._() : super(); + factory Ping.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Ping.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Ping', createEmptyInstance: create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Ping clone() => Ping()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Ping copyWith(void Function(Ping) updates) => super.copyWith((message) => updates(message as Ping)) as Ping; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Ping create() => Ping._(); + Ping createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Ping getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Ping? _defaultInstance; +} + +/// if the relay received an envelope ping, +/// an envelope pong will be sent back to the +/// client +class Pong extends $pb.GeneratedMessage { + factory Pong() => create(); + Pong._() : super(); + factory Pong.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Pong.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Pong', createEmptyInstance: create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Pong clone() => Pong()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Pong copyWith(void Function(Pong) updates) => super.copyWith((message) => updates(message as Pong)) as Pong; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Pong create() => Pong._(); + Pong createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Pong getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Pong? _defaultInstance; +} + +enum Envelope_Message { + request, + response, + error, + ping, + pong, + notSet +} + +enum Envelope_Payload { + plain, + cipher, + notSet +} + +class Envelope extends $pb.GeneratedMessage { + factory Envelope({ + $core.String? uid, + $core.String? tags, + $fixnum.Int64? timestamp, + $fixnum.Int64? expiration, + Address? source, + Address? destination, + Request? request, + Response? response, + $core.List<$core.int>? signature, + $core.String? schema, + $core.String? federation, + Error? error, + $core.List<$core.int>? plain, + $core.List<$core.int>? cipher, + Ping? ping, + Pong? pong, + }) { + final $result = create(); + if (uid != null) { + $result.uid = uid; + } + if (tags != null) { + $result.tags = tags; + } + if (timestamp != null) { + $result.timestamp = timestamp; + } + if (expiration != null) { + $result.expiration = expiration; + } + if (source != null) { + $result.source = source; + } + if (destination != null) { + $result.destination = destination; + } + if (request != null) { + $result.request = request; + } + if (response != null) { + $result.response = response; + } + if (signature != null) { + $result.signature = signature; + } + if (schema != null) { + $result.schema = schema; + } + if (federation != null) { + $result.federation = federation; + } + if (error != null) { + $result.error = error; + } + if (plain != null) { + $result.plain = plain; + } + if (cipher != null) { + $result.cipher = cipher; + } + if (ping != null) { + $result.ping = ping; + } + if (pong != null) { + $result.pong = pong; + } + return $result; + } + Envelope._() : super(); + factory Envelope.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Envelope.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static const $core.Map<$core.int, Envelope_Message> _Envelope_MessageByTag = { + 7 : Envelope_Message.request, + 8 : Envelope_Message.response, + 12 : Envelope_Message.error, + 15 : Envelope_Message.ping, + 16 : Envelope_Message.pong, + 0 : Envelope_Message.notSet + }; + static const $core.Map<$core.int, Envelope_Payload> _Envelope_PayloadByTag = { + 13 : Envelope_Payload.plain, + 14 : Envelope_Payload.cipher, + 0 : Envelope_Payload.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Envelope', createEmptyInstance: create) + ..oo(0, [7, 8, 12, 15, 16]) + ..oo(1, [13, 14]) + ..aOS(1, _omitFieldNames ? '' : 'uid') + ..aOS(2, _omitFieldNames ? '' : 'tags') + ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'timestamp', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) + ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'expiration', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) + ..aOM
(5, _omitFieldNames ? '' : 'source', subBuilder: Address.create) + ..aOM
(6, _omitFieldNames ? '' : 'destination', subBuilder: Address.create) + ..aOM(7, _omitFieldNames ? '' : 'request', subBuilder: Request.create) + ..aOM(8, _omitFieldNames ? '' : 'response', subBuilder: Response.create) + ..a<$core.List<$core.int>>(9, _omitFieldNames ? '' : 'signature', $pb.PbFieldType.OY) + ..aOS(10, _omitFieldNames ? '' : 'schema') + ..aOS(11, _omitFieldNames ? '' : 'federation') + ..aOM(12, _omitFieldNames ? '' : 'error', subBuilder: Error.create) + ..a<$core.List<$core.int>>(13, _omitFieldNames ? '' : 'plain', $pb.PbFieldType.OY) + ..a<$core.List<$core.int>>(14, _omitFieldNames ? '' : 'cipher', $pb.PbFieldType.OY) + ..aOM(15, _omitFieldNames ? '' : 'ping', subBuilder: Ping.create) + ..aOM(16, _omitFieldNames ? '' : 'pong', subBuilder: Pong.create) + ..hasRequiredFields = false + ; + + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Envelope clone() => Envelope()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Envelope copyWith(void Function(Envelope) updates) => super.copyWith((message) => updates(message as Envelope)) as Envelope; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static Envelope create() => Envelope._(); + Envelope createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Envelope getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Envelope? _defaultInstance; + + Envelope_Message whichMessage() => _Envelope_MessageByTag[$_whichOneof(0)]!; + void clearMessage() => clearField($_whichOneof(0)); + + Envelope_Payload whichPayload() => _Envelope_PayloadByTag[$_whichOneof(1)]!; + void clearPayload() => clearField($_whichOneof(1)); + + /// uid is auto generated by rmb. + @$pb.TagNumber(1) + $core.String get uid => $_getSZ(0); + @$pb.TagNumber(1) + set uid($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasUid() => $_has(0); + @$pb.TagNumber(1) + void clearUid() => clearField(1); + + /// client specific tags + @$pb.TagNumber(2) + $core.String get tags => $_getSZ(1); + @$pb.TagNumber(2) + set tags($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasTags() => $_has(1); + @$pb.TagNumber(2) + void clearTags() => clearField(2); + + /// timestamp of sending the envlope + @$pb.TagNumber(3) + $fixnum.Int64 get timestamp => $_getI64(2); + @$pb.TagNumber(3) + set timestamp($fixnum.Int64 v) { $_setInt64(2, v); } + @$pb.TagNumber(3) + $core.bool hasTimestamp() => $_has(2); + @$pb.TagNumber(3) + void clearTimestamp() => clearField(3); + + /// message TTL from the time of send + @$pb.TagNumber(4) + $fixnum.Int64 get expiration => $_getI64(3); + @$pb.TagNumber(4) + set expiration($fixnum.Int64 v) { $_setInt64(3, v); } + @$pb.TagNumber(4) + $core.bool hasExpiration() => $_has(3); + @$pb.TagNumber(4) + void clearExpiration() => clearField(4); + + /// sender id + @$pb.TagNumber(5) + Address get source => $_getN(4); + @$pb.TagNumber(5) + set source(Address v) { setField(5, v); } + @$pb.TagNumber(5) + $core.bool hasSource() => $_has(4); + @$pb.TagNumber(5) + void clearSource() => clearField(5); + @$pb.TagNumber(5) + Address ensureSource() => $_ensure(4); + + /// destination of the envlope + @$pb.TagNumber(6) + Address get destination => $_getN(5); + @$pb.TagNumber(6) + set destination(Address v) { setField(6, v); } + @$pb.TagNumber(6) + $core.bool hasDestination() => $_has(5); + @$pb.TagNumber(6) + void clearDestination() => clearField(6); + @$pb.TagNumber(6) + Address ensureDestination() => $_ensure(5); + + @$pb.TagNumber(7) + Request get request => $_getN(6); + @$pb.TagNumber(7) + set request(Request v) { setField(7, v); } + @$pb.TagNumber(7) + $core.bool hasRequest() => $_has(6); + @$pb.TagNumber(7) + void clearRequest() => clearField(7); + @$pb.TagNumber(7) + Request ensureRequest() => $_ensure(6); + + @$pb.TagNumber(8) + Response get response => $_getN(7); + @$pb.TagNumber(8) + set response(Response v) { setField(8, v); } + @$pb.TagNumber(8) + $core.bool hasResponse() => $_has(7); + @$pb.TagNumber(8) + void clearResponse() => clearField(8); + @$pb.TagNumber(8) + Response ensureResponse() => $_ensure(7); + + /// signature + @$pb.TagNumber(9) + $core.List<$core.int> get signature => $_getN(8); + @$pb.TagNumber(9) + set signature($core.List<$core.int> v) { $_setBytes(8, v); } + @$pb.TagNumber(9) + $core.bool hasSignature() => $_has(8); + @$pb.TagNumber(9) + void clearSignature() => clearField(9); + + /// schema of the payload of either the request or the resposne message. + @$pb.TagNumber(10) + $core.String get schema => $_getSZ(9); + @$pb.TagNumber(10) + set schema($core.String v) { $_setString(9, v); } + @$pb.TagNumber(10) + $core.bool hasSchema() => $_has(9); + @$pb.TagNumber(10) + void clearSchema() => clearField(10); + + /// a federation url (domain) + /// if not provided the relay assumes it's a local twin + /// but if provided it can be checked against the relay + /// domain, and hence decided if message need federation + /// or local. + @$pb.TagNumber(11) + $core.String get federation => $_getSZ(10); + @$pb.TagNumber(11) + set federation($core.String v) { $_setString(10, v); } + @$pb.TagNumber(11) + $core.bool hasFederation() => $_has(10); + @$pb.TagNumber(11) + void clearFederation() => clearField(11); + + @$pb.TagNumber(12) + Error get error => $_getN(11); + @$pb.TagNumber(12) + set error(Error v) { setField(12, v); } + @$pb.TagNumber(12) + $core.bool hasError() => $_has(11); + @$pb.TagNumber(12) + void clearError() => clearField(12); + @$pb.TagNumber(12) + Error ensureError() => $_ensure(11); + + @$pb.TagNumber(13) + $core.List<$core.int> get plain => $_getN(12); + @$pb.TagNumber(13) + set plain($core.List<$core.int> v) { $_setBytes(12, v); } + @$pb.TagNumber(13) + $core.bool hasPlain() => $_has(12); + @$pb.TagNumber(13) + void clearPlain() => clearField(13); + + @$pb.TagNumber(14) + $core.List<$core.int> get cipher => $_getN(13); + @$pb.TagNumber(14) + set cipher($core.List<$core.int> v) { $_setBytes(13, v); } + @$pb.TagNumber(14) + $core.bool hasCipher() => $_has(13); + @$pb.TagNumber(14) + void clearCipher() => clearField(14); + + @$pb.TagNumber(15) + Ping get ping => $_getN(14); + @$pb.TagNumber(15) + set ping(Ping v) { setField(15, v); } + @$pb.TagNumber(15) + $core.bool hasPing() => $_has(14); + @$pb.TagNumber(15) + void clearPing() => clearField(15); + @$pb.TagNumber(15) + Ping ensurePing() => $_ensure(14); + + @$pb.TagNumber(16) + Pong get pong => $_getN(15); + @$pb.TagNumber(16) + set pong(Pong v) { setField(16, v); } + @$pb.TagNumber(16) + $core.bool hasPong() => $_has(15); + @$pb.TagNumber(16) + void clearPong() => clearField(16); + @$pb.TagNumber(16) + Pong ensurePong() => $_ensure(15); +} + + +const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); +const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/packages/rmb_client/lib/types/generated/types.pbenum.dart b/packages/rmb_client/lib/types/generated/types.pbenum.dart new file mode 100644 index 00000000..9d235e4b --- /dev/null +++ b/packages/rmb_client/lib/types/generated/types.pbenum.dart @@ -0,0 +1,11 @@ +// +// Generated code. Do not modify. +// source: types.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + diff --git a/packages/rmb_client/lib/types/generated/types.pbjson.dart b/packages/rmb_client/lib/types/generated/types.pbjson.dart new file mode 100644 index 00000000..a988d01d --- /dev/null +++ b/packages/rmb_client/lib/types/generated/types.pbjson.dart @@ -0,0 +1,136 @@ +// +// Generated code. Do not modify. +// source: types.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + +@$core.Deprecated('Use requestDescriptor instead') +const Request$json = { + '1': 'Request', + '2': [ + {'1': 'command', '3': 1, '4': 1, '5': 9, '10': 'command'}, + ], + '9': [ + {'1': 2, '2': 3}, + ], +}; + +/// Descriptor for `Request`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List requestDescriptor = $convert.base64Decode( + 'CgdSZXF1ZXN0EhgKB2NvbW1hbmQYASABKAlSB2NvbW1hbmRKBAgCEAM='); + +@$core.Deprecated('Use responseDescriptor instead') +const Response$json = { + '1': 'Response', + '9': [ + {'1': 1, '2': 2}, + {'1': 2, '2': 3}, + ], +}; + +/// Descriptor for `Response`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List responseDescriptor = $convert.base64Decode( + 'CghSZXNwb25zZUoECAEQAkoECAIQAw=='); + +@$core.Deprecated('Use errorDescriptor instead') +const Error$json = { + '1': 'Error', + '2': [ + {'1': 'code', '3': 1, '4': 1, '5': 13, '10': 'code'}, + {'1': 'message', '3': 2, '4': 1, '5': 9, '10': 'message'}, + ], +}; + +/// Descriptor for `Error`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List errorDescriptor = $convert.base64Decode( + 'CgVFcnJvchISCgRjb2RlGAEgASgNUgRjb2RlEhgKB21lc3NhZ2UYAiABKAlSB21lc3NhZ2U='); + +@$core.Deprecated('Use addressDescriptor instead') +const Address$json = { + '1': 'Address', + '2': [ + {'1': 'twin', '3': 1, '4': 1, '5': 13, '10': 'twin'}, + {'1': 'connection', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'connection', '17': true}, + ], + '8': [ + {'1': '_connection'}, + ], +}; + +/// Descriptor for `Address`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List addressDescriptor = $convert.base64Decode( + 'CgdBZGRyZXNzEhIKBHR3aW4YASABKA1SBHR3aW4SIwoKY29ubmVjdGlvbhgCIAEoCUgAUgpjb2' + '5uZWN0aW9uiAEBQg0KC19jb25uZWN0aW9u'); + +@$core.Deprecated('Use pingDescriptor instead') +const Ping$json = { + '1': 'Ping', +}; + +/// Descriptor for `Ping`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List pingDescriptor = $convert.base64Decode( + 'CgRQaW5n'); + +@$core.Deprecated('Use pongDescriptor instead') +const Pong$json = { + '1': 'Pong', +}; + +/// Descriptor for `Pong`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List pongDescriptor = $convert.base64Decode( + 'CgRQb25n'); + +@$core.Deprecated('Use envelopeDescriptor instead') +const Envelope$json = { + '1': 'Envelope', + '2': [ + {'1': 'uid', '3': 1, '4': 1, '5': 9, '10': 'uid'}, + {'1': 'tags', '3': 2, '4': 1, '5': 9, '9': 2, '10': 'tags', '17': true}, + {'1': 'timestamp', '3': 3, '4': 1, '5': 4, '10': 'timestamp'}, + {'1': 'expiration', '3': 4, '4': 1, '5': 4, '10': 'expiration'}, + {'1': 'source', '3': 5, '4': 1, '5': 11, '6': '.Address', '10': 'source'}, + {'1': 'destination', '3': 6, '4': 1, '5': 11, '6': '.Address', '10': 'destination'}, + {'1': 'request', '3': 7, '4': 1, '5': 11, '6': '.Request', '9': 0, '10': 'request'}, + {'1': 'response', '3': 8, '4': 1, '5': 11, '6': '.Response', '9': 0, '10': 'response'}, + {'1': 'error', '3': 12, '4': 1, '5': 11, '6': '.Error', '9': 0, '10': 'error'}, + {'1': 'ping', '3': 15, '4': 1, '5': 11, '6': '.Ping', '9': 0, '10': 'ping'}, + {'1': 'pong', '3': 16, '4': 1, '5': 11, '6': '.Pong', '9': 0, '10': 'pong'}, + {'1': 'signature', '3': 9, '4': 1, '5': 12, '9': 3, '10': 'signature', '17': true}, + {'1': 'schema', '3': 10, '4': 1, '5': 9, '9': 4, '10': 'schema', '17': true}, + {'1': 'federation', '3': 11, '4': 1, '5': 9, '9': 5, '10': 'federation', '17': true}, + {'1': 'plain', '3': 13, '4': 1, '5': 12, '9': 1, '10': 'plain'}, + {'1': 'cipher', '3': 14, '4': 1, '5': 12, '9': 1, '10': 'cipher'}, + ], + '8': [ + {'1': 'message'}, + {'1': 'payload'}, + {'1': '_tags'}, + {'1': '_signature'}, + {'1': '_schema'}, + {'1': '_federation'}, + ], +}; + +/// Descriptor for `Envelope`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List envelopeDescriptor = $convert.base64Decode( + 'CghFbnZlbG9wZRIQCgN1aWQYASABKAlSA3VpZBIXCgR0YWdzGAIgASgJSAJSBHRhZ3OIAQESHA' + 'oJdGltZXN0YW1wGAMgASgEUgl0aW1lc3RhbXASHgoKZXhwaXJhdGlvbhgEIAEoBFIKZXhwaXJh' + 'dGlvbhIgCgZzb3VyY2UYBSABKAsyCC5BZGRyZXNzUgZzb3VyY2USKgoLZGVzdGluYXRpb24YBi' + 'ABKAsyCC5BZGRyZXNzUgtkZXN0aW5hdGlvbhIkCgdyZXF1ZXN0GAcgASgLMgguUmVxdWVzdEgA' + 'UgdyZXF1ZXN0EicKCHJlc3BvbnNlGAggASgLMgkuUmVzcG9uc2VIAFIIcmVzcG9uc2USHgoFZX' + 'Jyb3IYDCABKAsyBi5FcnJvckgAUgVlcnJvchIbCgRwaW5nGA8gASgLMgUuUGluZ0gAUgRwaW5n' + 'EhsKBHBvbmcYECABKAsyBS5Qb25nSABSBHBvbmcSIQoJc2lnbmF0dXJlGAkgASgMSANSCXNpZ2' + '5hdHVyZYgBARIbCgZzY2hlbWEYCiABKAlIBFIGc2NoZW1hiAEBEiMKCmZlZGVyYXRpb24YCyAB' + 'KAlIBVIKZmVkZXJhdGlvbogBARIWCgVwbGFpbhgNIAEoDEgBUgVwbGFpbhIYCgZjaXBoZXIYDi' + 'ABKAxIAVIGY2lwaGVyQgkKB21lc3NhZ2VCCQoHcGF5bG9hZEIHCgVfdGFnc0IMCgpfc2lnbmF0' + 'dXJlQgkKB19zY2hlbWFCDQoLX2ZlZGVyYXRpb24='); + diff --git a/packages/rmb_client/lib/types/generated/types.pbserver.dart b/packages/rmb_client/lib/types/generated/types.pbserver.dart new file mode 100644 index 00000000..ad376413 --- /dev/null +++ b/packages/rmb_client/lib/types/generated/types.pbserver.dart @@ -0,0 +1,14 @@ +// +// Generated code. Do not modify. +// source: types.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names +// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +export 'types.pb.dart'; + diff --git a/packages/rmb_client/lib/types/types.proto b/packages/rmb_client/lib/types/types.proto new file mode 100644 index 00000000..429bc500 --- /dev/null +++ b/packages/rmb_client/lib/types/types.proto @@ -0,0 +1,77 @@ +syntax = "proto3"; + +// A Request annotate this message as a request message +// with proper command +message Request { + reserved 2; + string command = 1; +} + +// A Response annotate this message as a response message +message Response { reserved 1, 2; } + +// A Error annotiate this message as an error message +message Error { + // error code (app specific) + uint32 code = 1; + // error message + string message = 2; +} + +message Address { + uint32 twin = 1; + optional string connection = 2; +} + +// an app level ping pong +// in case you are using javascript +// and cant send ping messages +// when sending Pings, both signature +// and destination are ignored +message Ping {} +// if the relay received an envelope ping, +// an envelope pong will be sent back to the +// client +message Pong {} + +message Envelope { + // uid is auto generated by rmb. + string uid = 1; + // client specific tags + optional string tags = 2; + // timestamp of sending the envlope + uint64 timestamp = 3; + // message TTL from the time of send + uint64 expiration = 4; + // sender id + Address source = 5; + // destination of the envlope + Address destination = 6; + // message inside the envlope + oneof message { + Request request = 7; + Response response = 8; + Error error = 12; + Ping ping = 15; + Pong pong = 16; + } + // signature + optional bytes signature = 9; + + // schema of the payload of either the request or the resposne message. + optional string schema = 10; + + // a federation url (domain) + // if not provided the relay assumes it's a local twin + // but if provided it can be checked against the relay + // domain, and hence decided if message need federation + // or local. + optional string federation = 11; + + // pyload of the message is interpreted differently based + // on the message filed + oneof payload { + bytes plain = 13; + bytes cipher = 14; + } +} \ No newline at end of file diff --git a/packages/rmb_client/pubspec.yaml b/packages/rmb_client/pubspec.yaml new file mode 100644 index 00000000..669bccba --- /dev/null +++ b/packages/rmb_client/pubspec.yaml @@ -0,0 +1,15 @@ +name: rmb_client +description: A sample command-line application. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: ^3.2.0 + +# Add regular dependencies here. +dependencies: + # path: ^1.8.0 + +dev_dependencies: + lints: ^2.1.0 + test: ^1.24.0 diff --git a/packages/rmb_client/test/rmb_client_test.dart b/packages/rmb_client/test/rmb_client_test.dart new file mode 100644 index 00000000..e69de29b From 6ce7454b682a8061729e09ea35b96862beb80000 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Mon, 1 Jan 2024 12:48:52 +0200 Subject: [PATCH 02/17] trying to create websocket connection --- packages/rmb_client/bin/rmb_client.dart | 18 ++++++++++++++++++ packages/rmb_client/lib/src/client.dart | 7 +++++++ packages/rmb_client/pubspec.yaml | 3 +++ 3 files changed, 28 insertions(+) create mode 100644 packages/rmb_client/lib/src/client.dart diff --git a/packages/rmb_client/bin/rmb_client.dart b/packages/rmb_client/bin/rmb_client.dart index e69de29b..71e3bad6 100644 --- a/packages/rmb_client/bin/rmb_client.dart +++ b/packages/rmb_client/bin/rmb_client.dart @@ -0,0 +1,18 @@ +import 'dart:html'; + +void main() async { + var webSocket = new WebSocket('wss://relay.dev.grid.tf'); + if (webSocket != null && webSocket.readyState == WebSocket.OPEN) { + webSocket.send(""); + } else { + print('WebSocket not connected '); + } + + // var socket = await WebSocket.connect('wss://relay.dev.grid.tf'); + + // socket.listen((data) { + // print('$data'); + // }); + + // await socket.close(); +} diff --git a/packages/rmb_client/lib/src/client.dart b/packages/rmb_client/lib/src/client.dart new file mode 100644 index 00000000..e9d04374 --- /dev/null +++ b/packages/rmb_client/lib/src/client.dart @@ -0,0 +1,7 @@ +import 'package:web_socket_channel/web_socket_channel.dart'; + +class Client { + void connect() { + + } +} diff --git a/packages/rmb_client/pubspec.yaml b/packages/rmb_client/pubspec.yaml index 669bccba..708a830b 100644 --- a/packages/rmb_client/pubspec.yaml +++ b/packages/rmb_client/pubspec.yaml @@ -8,6 +8,9 @@ environment: # Add regular dependencies here. dependencies: + fixnum: ^1.1.0 + protobuf: ^3.1.0 + web_socket_channel: ^2.4.1 # path: ^1.8.0 dev_dependencies: From 51d82b0f72985047806d9c849b28bce479313d06 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Wed, 6 Mar 2024 17:19:14 +0200 Subject: [PATCH 03/17] add rmb client --- .dart_tool/package_config.json | 18 +++- melos.yaml | 4 +- packages/rmb_client/bin/rmb_client.dart | 23 ++--- packages/rmb_client/lib/rmb_client.dart | 11 +++ packages/rmb_client/lib/src/client.dart | 92 ++++++++++++++++++- packages/rmb_client/lib/src/envelope.dart | 0 packages/rmb_client/lib/src/sign.dart | 29 ++++++ packages/rmb_client/pubspec.yaml | 5 +- .../tfchain_client/bin/tfchain_client.dart | 72 +++++++-------- .../tfchain_client/lib/tfchain_client.dart | 1 + packages/tfchain_client/pubspec.yaml | 1 + pubspec.lock | 19 +++- pubspec.yaml | 8 +- 13 files changed, 222 insertions(+), 61 deletions(-) create mode 100644 packages/rmb_client/lib/src/envelope.dart create mode 100644 packages/rmb_client/lib/src/sign.dart diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 002ce03a..2708443d 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -373,6 +373,12 @@ "packageUri": "lib/", "languageVersion": "2.12" }, + { + "name": "protobuf", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/protobuf-3.1.0", + "packageUri": "lib/", + "languageVersion": "2.19" + }, { "name": "pub_semver", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pub_semver-2.1.4", @@ -409,6 +415,12 @@ "packageUri": "lib/", "languageVersion": "3.0" }, + { + "name": "rmb_client", + "rootUri": "../packages/rmb_client", + "packageUri": "lib/", + "languageVersion": "3.2" + }, { "name": "shelf", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/shelf-1.4.1", @@ -579,9 +591,9 @@ }, { "name": "web_socket_channel", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web_socket_channel-2.4.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web_socket_channel-2.4.3", "packageUri": "lib/", - "languageVersion": "2.15" + "languageVersion": "3.2" }, { "name": "webkit_inspection_protocol", @@ -614,7 +626,7 @@ "languageVersion": "3.2" } ], - "generated": "2023-12-07T08:50:13.267937Z", + "generated": "2024-01-10T13:39:16.827881Z", "generator": "pub", "generatorVersion": "3.2.0" } diff --git a/melos.yaml b/melos.yaml index 6ecefa2a..32708026 100644 --- a/melos.yaml +++ b/melos.yaml @@ -1,6 +1,8 @@ name: tfgrid_sdk_dart_monorepo packages: - - packages/** + - ./packages/rmb_client + - ./packages/signer + - ./packages/tfchain_client scripts: analyze: diff --git a/packages/rmb_client/bin/rmb_client.dart b/packages/rmb_client/bin/rmb_client.dart index 71e3bad6..7d73f3cc 100644 --- a/packages/rmb_client/bin/rmb_client.dart +++ b/packages/rmb_client/bin/rmb_client.dart @@ -1,18 +1,15 @@ -import 'dart:html'; +import 'package:rmb_client/rmb_client.dart'; void main() async { - var webSocket = new WebSocket('wss://relay.dev.grid.tf'); - if (webSocket != null && webSocket.readyState == WebSocket.OPEN) { - webSocket.send(""); - } else { - print('WebSocket not connected '); - } + final client = Client( + "wss://relay.dev.grid.tf", + "wss://tfchain.dev.grid.tf/ws", + "picnic flip cigar rival risk scatter slide aware trust garlic solution token", + "session", + retries: 3, + keypairType: "ed25519"); - // var socket = await WebSocket.connect('wss://relay.dev.grid.tf'); + await client.connect(); - // socket.listen((data) { - // print('$data'); - // }); - - // await socket.close(); + // client.closeConnection(); } diff --git a/packages/rmb_client/lib/rmb_client.dart b/packages/rmb_client/lib/rmb_client.dart index e69de29b..0f6a7dac 100644 --- a/packages/rmb_client/lib/rmb_client.dart +++ b/packages/rmb_client/lib/rmb_client.dart @@ -0,0 +1,11 @@ +library rmb_client; + +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:polkadart_keyring/polkadart_keyring.dart'; +import 'package:rmb_client/src/sign.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:tfchain_client/tfchain_client.dart' as TFClient; + +part 'src/client.dart'; diff --git a/packages/rmb_client/lib/src/client.dart b/packages/rmb_client/lib/src/client.dart index e9d04374..b33c4928 100644 --- a/packages/rmb_client/lib/src/client.dart +++ b/packages/rmb_client/lib/src/client.dart @@ -1,7 +1,95 @@ -import 'package:web_socket_channel/web_socket_channel.dart'; +part of "../rmb_client.dart"; + +// TODO: How to import tfchain_client ?? class Client { - void connect() { + KeyPair? signer; + String relayUrl; + String chainUrl; + String mnemonic; + String session; + int? twin; + WebSocketChannel? channel; + int? retries; + TFClient.QueryClient? client; + var connections = new Map(); + + Client( + this.relayUrl, + this.chainUrl, + this.mnemonic, + this.session, { + this.retries = 5, + required String keypairType, + }) { + final key = '${relayUrl}:${mnemonic}:${keypairType}'; + if (connections.containsKey(key)) { + // TODO: how to return from constructor ?? + // return connections[key] as Client; + } + + if (keypairType != "ed25519") { + throw ArgumentError("Unsupported Keypair type"); + } + + client = TFClient.QueryClient(chainUrl); + client?.connect(); + } + + Future connect() async { + // if (channel != null) { + // print("Already connected to relay."); + // return; + // } + final jwt = await newJWT(this.session); + String resultString = jwt.replaceAll('=', ''); + + try { + final wsUrl = Uri.parse('${relayUrl}?$resultString'); + print(wsUrl); + channel = WebSocketChannel.connect(wsUrl); + print("connected to relay "); + + print(signer!.address); + twin = await client?.twins + .getTwinIdByAccountId(accountId: signer!.publicKey.bytes); + print(twin); + + await channel!.ready; + } catch (e) { + print("Error Connecting on relay : $e"); + } + } + + Future newJWT(String session) async { + Map header = { + 'alg': 'RS512', + 'typ': 'JWT', + }; + + int now = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000; + // TODO: TwinId should bs passed from params + Map claims = { + 'sub': 5261, + 'iat': now, + 'exp': now + 1000, + 'sid': session, + }; + + String jwt = + '${base64Url.encode(utf8.encode(jsonEncode(header)))}.${base64Url.encode(utf8.encode(jsonEncode(claims)))}'; + + signer = await KeyPair.fromMnemonic(mnemonic); + + Uint8List sigPrefixed = sign(Uint8List.fromList(jwt.codeUnits), signer!); + String token = '$jwt.${base64Url.encode(sigPrefixed)}'; + + return token; + } + void closeConnection() { + if (channel != null) { + channel!.sink.close(); + } } } diff --git a/packages/rmb_client/lib/src/envelope.dart b/packages/rmb_client/lib/src/envelope.dart new file mode 100644 index 00000000..e69de29b diff --git a/packages/rmb_client/lib/src/sign.dart b/packages/rmb_client/lib/src/sign.dart new file mode 100644 index 00000000..83288741 --- /dev/null +++ b/packages/rmb_client/lib/src/sign.dart @@ -0,0 +1,29 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:polkadart_keyring/polkadart_keyring.dart'; + +class KPType { + static const sr25519 = "sr25519"; //not supported + static const ed25519 = "ed25519"; +} + +// payload can be either string or unit8list, here only ed25519 is supported +Uint8List sign(Uint8List payload, KeyPair signer) { + // remove last element from payload list + final newPayload = Uint8List.fromList(payload.sublist(0, payload.length - 1)); + + // String resultString = String.fromCharCodes(newPayload); + + String typePrefix = "e"; + + final sig = signer.sign(newPayload); + + Uint8List uint8List = Uint8List.fromList(utf8.encode(typePrefix)); + + int prefix = uint8List.elementAt(0); + + Uint8List sigPrefixed = Uint8List.fromList([prefix, ...sig]); + + return sigPrefixed; +} diff --git a/packages/rmb_client/pubspec.yaml b/packages/rmb_client/pubspec.yaml index 708a830b..a8d7f040 100644 --- a/packages/rmb_client/pubspec.yaml +++ b/packages/rmb_client/pubspec.yaml @@ -2,6 +2,7 @@ name: rmb_client description: A sample command-line application. version: 1.0.0 # repository: https://github.com/my_org/my_repo +publish_to: none environment: sdk: ^3.2.0 @@ -9,9 +10,11 @@ environment: # Add regular dependencies here. dependencies: fixnum: ^1.1.0 + polkadart_keyring: ^0.2.1 protobuf: ^3.1.0 web_socket_channel: ^2.4.1 - # path: ^1.8.0 + tfchain_client: + path: ../tfchain_client dev_dependencies: lints: ^2.1.0 diff --git a/packages/tfchain_client/bin/tfchain_client.dart b/packages/tfchain_client/bin/tfchain_client.dart index ca758f3d..1a8009ef 100644 --- a/packages/tfchain_client/bin/tfchain_client.dart +++ b/packages/tfchain_client/bin/tfchain_client.dart @@ -99,42 +99,42 @@ void main() async { // print("=================="); - // final twinId = await queryClient.twins.getTwinIdByAccountId(accountId: [ - // 12, - // 58, - // 221, - // 236, - // 167, - // 151, - // 69, - // 84, - // 126, - // 190, - // 116, - // 100, - // 140, - // 251, - // 60, - // 149, - // 249, - // 60, - // 238, - // 70, - // 203, - // 93, - // 75, - // 150, - // 70, - // 130, - // 0, - // 28, - // 253, - // 137, - // 178, - // 63 - // ]); - - // print(twinId); + final twinId = await queryClient.twins.getTwinIdByAccountId(accountId: [ + 12, + 58, + 221, + 236, + 167, + 151, + 69, + 84, + 126, + 190, + 116, + 100, + 140, + 251, + 60, + 149, + 249, + 60, + 238, + 70, + 203, + 93, + 75, + 150, + 70, + 130, + 0, + 28, + 253, + 137, + 178, + 63 + ]); + + print(twinId); // queryClient.disconnect(); diff --git a/packages/tfchain_client/lib/tfchain_client.dart b/packages/tfchain_client/lib/tfchain_client.dart index f1324fc9..9d40f83b 100644 --- a/packages/tfchain_client/lib/tfchain_client.dart +++ b/packages/tfchain_client/lib/tfchain_client.dart @@ -17,3 +17,4 @@ import 'package:bip39/bip39.dart'; import 'package:convert/convert.dart'; part 'src/client.dart'; + diff --git a/packages/tfchain_client/pubspec.yaml b/packages/tfchain_client/pubspec.yaml index f3cc6115..53d1c811 100644 --- a/packages/tfchain_client/pubspec.yaml +++ b/packages/tfchain_client/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: polkadart_cli: ^0.2.2 hex: ^0.2.0 bip39: ^1.0.6 + convert: ^3.1.1 dev_dependencies: lints: ^3.0.0 diff --git a/pubspec.lock b/pubspec.lock index ee096d6b..704f63e3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -497,6 +497,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + protobuf: + dependency: transitive + description: + name: protobuf + sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d" + url: "https://pub.dev" + source: hosted + version: "3.1.0" pub_semver: dependency: transitive description: @@ -545,6 +553,13 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + rmb_client: + dependency: "direct main" + description: + path: "packages/rmb_client" + relative: true + source: path + version: "1.0.0" shelf: dependency: transitive description: @@ -771,10 +786,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.3" webkit_inspection_protocol: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b6a8028c..f210256e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,7 @@ name: tfgrid_sdk_dart description: A sample command-line application. version: 1.0.0 +publish_to: none environment: sdk: ^3.2.0 @@ -12,8 +13,9 @@ dev_dependencies: dependencies: coverage: ^1.7.1 melos: ^3.2.0 - signer: + signer: path: ./packages/signer tfchain_client: - path: ./packages/tfchain_client - + path: ./packages/tfchain_client + rmb_client: + path: ./packages/rmb_client From 592b0470e52f00502e0e0221256aa1b77f8946d8 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Tue, 12 Mar 2024 15:28:00 +0200 Subject: [PATCH 04/17] support sr25519 and add dao model --- .dart_tool/package_config.json | 124 +++++++----- melos.yaml | 2 +- packages/signer/bin/signer.dart | 8 +- packages/signer/lib/signer.dart | 4 +- packages/signer/lib/src/sign.dart | 35 +++- packages/signer/lib/src/types.dart | 17 ++ packages/signer/pubspec.lock | 64 +++++- packages/signer/pubspec.yaml | 2 +- packages/signer/test/signer_test.dart | 22 +-- .../tfchain_client/bin/tfchain_client.dart | 151 +-------------- packages/tfchain_client/lib/models/dao.dart | 50 +++++ packages/tfchain_client/lib/models/farms.dart | 28 +++ packages/tfchain_client/lib/src/client.dart | 20 +- packages/tfchain_client/lib/src/dao.dart | 136 +++++++++++++ packages/tfchain_client/lib/src/farms.dart | 27 ++- .../tfchain_client/lib/tfchain_client.dart | 5 +- packages/tfchain_client/pubspec.yaml | 9 +- pubspec.lock | 183 +++++++++++------- pubspec.yaml | 5 +- 19 files changed, 569 insertions(+), 323 deletions(-) create mode 100644 packages/signer/lib/src/types.dart create mode 100644 packages/tfchain_client/lib/models/dao.dart create mode 100644 packages/tfchain_client/lib/models/farms.dart create mode 100644 packages/tfchain_client/lib/src/dao.dart diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 2708443d..13a52f2f 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -3,7 +3,7 @@ "packages": [ { "name": "_fe_analyzer_shared", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/_fe_analyzer_shared-65.0.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/_fe_analyzer_shared-67.0.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -15,7 +15,7 @@ }, { "name": "analyzer", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/analyzer-6.3.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/analyzer-6.4.1", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -69,9 +69,9 @@ }, { "name": "built_value", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/built_value-8.8.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/built_value-8.9.1", "packageUri": "lib/", - "languageVersion": "2.12" + "languageVersion": "3.0" }, { "name": "charcode", @@ -87,9 +87,9 @@ }, { "name": "cli_util", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/cli_util-0.4.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/cli_util-0.4.1", "packageUri": "lib/", - "languageVersion": "2.19" + "languageVersion": "3.0" }, { "name": "clock", @@ -99,7 +99,7 @@ }, { "name": "code_builder", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/code_builder-4.8.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/code_builder-4.10.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -123,7 +123,7 @@ }, { "name": "coverage", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/coverage-1.7.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/coverage-1.7.2", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -141,7 +141,7 @@ }, { "name": "dart_style", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/dart_style-2.3.4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/dart_style-2.3.6", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -151,6 +151,12 @@ "packageUri": "lib/", "languageVersion": "2.12" }, + { + "name": "edwards25519", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/edwards25519-1.0.4", + "packageUri": "lib/", + "languageVersion": "3.0" + }, { "name": "equatable", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/equatable-2.0.5", @@ -165,9 +171,9 @@ }, { "name": "file", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/file-6.1.4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/file-7.0.0", "packageUri": "lib/", - "languageVersion": "2.12" + "languageVersion": "3.0" }, { "name": "fixnum", @@ -213,7 +219,7 @@ }, { "name": "http", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/http-1.1.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/http-1.2.0", "packageUri": "lib/", "languageVersion": "3.2" }, @@ -273,27 +279,33 @@ }, { "name": "matcher", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/matcher-0.12.16", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/matcher-0.12.16+1", "packageUri": "lib/", - "languageVersion": "2.18" + "languageVersion": "3.0" }, { "name": "melos", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/melos-3.2.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/melos-4.1.0", "packageUri": "lib/", - "languageVersion": "2.18" + "languageVersion": "3.0" + }, + { + "name": "merlin", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/merlin-1.0.3", + "packageUri": "lib/", + "languageVersion": "3.1" }, { "name": "meta", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/meta-1.11.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/meta-1.12.0", "packageUri": "lib/", "languageVersion": "2.12" }, { "name": "mime", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/mime-1.0.4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/mime-1.0.5", "packageUri": "lib/", - "languageVersion": "2.18" + "languageVersion": "3.2" }, { "name": "mustache_template", @@ -315,43 +327,43 @@ }, { "name": "path", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/path-1.8.3", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/path-1.9.0", "packageUri": "lib/", - "languageVersion": "2.12" + "languageVersion": "3.0" }, { "name": "platform", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/platform-3.1.3", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/platform-3.1.4", "packageUri": "lib/", - "languageVersion": "2.19" + "languageVersion": "3.0" }, { "name": "pointycastle", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pointycastle-3.7.3", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pointycastle-3.7.4", "packageUri": "lib/", - "languageVersion": "2.14" + "languageVersion": "3.0" }, { "name": "polkadart", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart-0.2.6", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart-0.4.3", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "polkadart_cli", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart_cli-0.2.4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart_cli-0.4.2", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "polkadart_keyring", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart_keyring-0.2.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart_keyring-0.4.3", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "polkadart_scale_codec", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart_scale_codec-1.1.2", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/polkadart_scale_codec-1.2.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -363,9 +375,9 @@ }, { "name": "process", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/process-4.2.4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/process-5.0.2", "packageUri": "lib/", - "languageVersion": "2.14" + "languageVersion": "3.0" }, { "name": "prompts", @@ -387,7 +399,7 @@ }, { "name": "pub_updater", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pub_updater-0.3.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pub_updater-0.4.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -416,10 +428,16 @@ "languageVersion": "3.0" }, { - "name": "rmb_client", - "rootUri": "../packages/rmb_client", + "name": "ristretto255", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/ristretto255-1.0.2", "packageUri": "lib/", - "languageVersion": "3.2" + "languageVersion": "3.0" + }, + { + "name": "secp256k1_ecdsa", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/secp256k1_ecdsa-0.4.0", + "packageUri": "lib/", + "languageVersion": "3.0" }, { "name": "shelf", @@ -475,6 +493,12 @@ "packageUri": "lib/", "languageVersion": "2.12" }, + { + "name": "sr25519", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/sr25519-0.4.0", + "packageUri": "lib/", + "languageVersion": "3.0" + }, { "name": "ss58", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/ss58-1.1.2", @@ -499,15 +523,21 @@ "packageUri": "lib/", "languageVersion": "2.18" }, + { + "name": "strobe", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/strobe-1.0.4", + "packageUri": "lib/", + "languageVersion": "3.1" + }, { "name": "substrate_bip39", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/substrate_bip39-0.2.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/substrate_bip39-0.4.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "substrate_metadata", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/substrate_metadata-1.1.2", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/substrate_metadata-1.2.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -519,19 +549,19 @@ }, { "name": "test", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test-1.24.9", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test-1.25.2", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "test_api", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_api-0.6.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_api-0.7.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "test_core", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_core-0.5.9", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_core-0.6.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -567,13 +597,13 @@ }, { "name": "uuid", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/uuid-4.2.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/uuid-4.3.3", "packageUri": "lib/", - "languageVersion": "2.14" + "languageVersion": "3.0" }, { "name": "vm_service", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/vm_service-13.0.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/vm_service-14.0.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -585,7 +615,7 @@ }, { "name": "web", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web-0.4.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web-0.4.2", "packageUri": "lib/", "languageVersion": "3.2" }, @@ -609,13 +639,13 @@ }, { "name": "yaml_edit", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/yaml_edit-2.1.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/yaml_edit-2.2.0", "packageUri": "lib/", "languageVersion": "2.19" }, { "name": "yaon", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/yaon-1.1.4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/yaon-1.1.4+4", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -626,7 +656,7 @@ "languageVersion": "3.2" } ], - "generated": "2024-01-10T13:39:16.827881Z", + "generated": "2024-03-07T11:33:36.582352Z", "generator": "pub", "generatorVersion": "3.2.0" } diff --git a/melos.yaml b/melos.yaml index 32708026..dec8d848 100644 --- a/melos.yaml +++ b/melos.yaml @@ -1,6 +1,6 @@ name: tfgrid_sdk_dart_monorepo packages: - - ./packages/rmb_client + - packages/** - ./packages/signer - ./packages/tfchain_client diff --git a/packages/signer/bin/signer.dart b/packages/signer/bin/signer.dart index 3b5332b0..fc489bf0 100644 --- a/packages/signer/bin/signer.dart +++ b/packages/signer/bin/signer.dart @@ -7,7 +7,7 @@ void main() async { final mnemonic = 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'; final signer = Signer(); - await signer.fromMnemonic(mnemonic); + await signer.fromMnemonic(mnemonic, KPType.ed25519); final data = "anydata123"; final signatureFromMnemonic = await signer.sign(data); @@ -49,14 +49,14 @@ void main() async { ]); final signer2 = Signer(); - await signer2.fromSeed(seedUint8List); + await signer2.fromSeed(seedUint8List, KPType.ed25519); final signatureFromSeed = await signer2.sign(data); print("Signature from Seed: $signatureFromSeed"); final signer3 = Signer(); await signer3.fromHexSeed( - '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4'); + '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4', + KPType.ed25519); final signatureFromSeed2 = await signer3.sign(data); print("Signature from Hex Seed: $signatureFromSeed2"); - } diff --git a/packages/signer/lib/signer.dart b/packages/signer/lib/signer.dart index b5235e21..70761db6 100644 --- a/packages/signer/lib/signer.dart +++ b/packages/signer/lib/signer.dart @@ -4,7 +4,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:polkadart_keyring/polkadart_keyring.dart'; import 'package:hex/hex.dart'; - - +import 'package:substrate_bip39/substrate_bip39.dart'; part 'src/sign.dart'; +part 'src/types.dart'; diff --git a/packages/signer/lib/src/sign.dart b/packages/signer/lib/src/sign.dart index 13878915..19b2ad56 100644 --- a/packages/signer/lib/src/sign.dart +++ b/packages/signer/lib/src/sign.dart @@ -2,27 +2,50 @@ part of '../signer.dart'; class Signer { KeyPair? _keypair; + KPType? _type; - Future fromMnemonic(String mnemonic) async { + Future fromMnemonic(String mnemonic, KPType type) async { try { - _keypair = await KeyPair.fromMnemonic(mnemonic); + if (type.value == KPType.sr25519.value) { + _keypair = await KeyPair.sr25519.fromMnemonic(mnemonic); + _type = KPType.sr25519; + } else if (type.value == KPType.ed25519.value) { + _keypair = await KeyPair.ed25519.fromMnemonic(mnemonic); + _type = KPType.ed25519; + } else { + throw Exception("Wrong KeyPair type !"); + } } catch (e) { throw Exception("Failed to create keyPair from mnemonic. Error: $e"); } } - Future fromSeed(Uint8List seed) async { + Future fromSeed(Uint8List seed, KPType type) async { try { - _keypair = KeyPair.fromSeed(seed); + if (type.value == KPType.sr25519) { + _keypair = await KeyPair.sr25519.fromSeed(seed); + _type = KPType.sr25519; + } else if (type.value == KPType.ed25519) { + _keypair = await KeyPair.ed25519.fromSeed(seed); + _type = KPType.ed25519; + } else { + throw Exception("Wrong KeyPair type !"); + } } catch (e) { throw Exception("Failed to create keyPair from seed. Error: $e"); } } - Future fromHexSeed(String hexSeed) async { + Future fromHexSeed(String hexSeed, KPType type) async { try { final seed = HEX.decode(hexSeed.replaceAll('0x', '')); - _keypair = KeyPair.fromSeed(Uint8List.fromList(seed)); + if (type.value == KPType.sr25519) { + _keypair = KeyPair.sr25519.fromSeed(Uint8List.fromList(seed)); + } else if (type.value == KPType.ed25519) { + _keypair = KeyPair.ed25519.fromSeed(Uint8List.fromList(seed)); + } else { + throw Exception("Wrong KeyPair type !"); + } } catch (e) { throw Exception("Failed to create keyPair from hex seed. Error: $e"); } diff --git a/packages/signer/lib/src/types.dart b/packages/signer/lib/src/types.dart new file mode 100644 index 00000000..c2eed11a --- /dev/null +++ b/packages/signer/lib/src/types.dart @@ -0,0 +1,17 @@ +part of '../signer.dart'; + +enum KPType { + sr25519, + ed25519, +} + +extension KPTypeExtension on KPType { + String get value { + switch (this) { + case KPType.sr25519: + return 'sr25519'; + case KPType.ed25519: + return 'ed25519'; + } + } +} diff --git a/packages/signer/pubspec.lock b/packages/signer/pubspec.lock index 595afa5b..41c0fb34 100644 --- a/packages/signer/pubspec.lock +++ b/packages/signer/pubspec.lock @@ -113,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + edwards25519: + dependency: transitive + description: + name: edwards25519 + sha256: "48e4678136e362bed9790dfb716ebe8e2f34f026bdb900b058214620672c6273" + url: "https://pub.dev" + source: hosted + version: "1.0.4" equatable: dependency: transitive description: @@ -233,6 +241,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.12.16" + merlin: + dependency: transitive + description: + name: merlin + sha256: c6b5d5bc70880aa7639686db66480d0be4b89da843b5cab20550610507da2540 + url: "https://pub.dev" + source: hosted + version: "1.0.3" meta: dependency: transitive description: @@ -277,26 +293,26 @@ packages: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" polkadart_keyring: dependency: "direct main" description: name: polkadart_keyring - sha256: ba568c22f3ff2a77c35fe0d53845212c1a433f99645e286550d1889dbb437d3c + sha256: "10cdd75e3319169ca7a4bb49745d85fab3f56bba2eafda35655c4f278a4c5e07" url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "0.4.3" polkadart_scale_codec: dependency: transitive description: name: polkadart_scale_codec - sha256: "75289b2f53c6cf997dd68945d959fee596c1e47bba3dedba22a6e95646df893c" + sha256: fab60c739f6ebcc812796e56378656dca57179cec46e92c23614db6fd9ed0f86 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" pool: dependency: transitive description: @@ -321,6 +337,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + ristretto255: + dependency: transitive + description: + name: ristretto255 + sha256: "3824d6786146dfb3b0783f305b714d36fa213c0d08e0ba864267baa0ede51cdd" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + secp256k1_ecdsa: + dependency: transitive + description: + name: secp256k1_ecdsa + sha256: "87008b4fd164d861b94b0edf2e01ffadd6f06769e1f0382e19bb091daecc0576" + url: "https://pub.dev" + source: hosted + version: "0.4.0" shelf: dependency: transitive description: @@ -377,6 +409,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sr25519: + dependency: transitive + description: + name: sr25519 + sha256: "266f7b2a4dd2d6a41a49924d41e80665f3b8340c157deff172f2b0cf64657a27" + url: "https://pub.dev" + source: hosted + version: "0.4.0" ss58: dependency: transitive description: @@ -409,14 +449,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + strobe: + dependency: transitive + description: + name: strobe + sha256: a23adf7d305e45c6f210270aa925d8b404819144e29f7c5257a67281b63e0887 + url: "https://pub.dev" + source: hosted + version: "1.0.4" substrate_bip39: dependency: transitive description: name: substrate_bip39 - sha256: "78b45e9959c3394ecc9b56d9bfb07e11f93db70d273eccd93e3e4d84b28f11c0" + sha256: "29548105e939d1fb213aba96686eb5c5aae472249fa12b8dda58b252d23f492c" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.4.0" term_glyph: dependency: transitive description: diff --git a/packages/signer/pubspec.yaml b/packages/signer/pubspec.yaml index ad7575c3..73d03fb5 100644 --- a/packages/signer/pubspec.yaml +++ b/packages/signer/pubspec.yaml @@ -7,7 +7,7 @@ environment: dependencies: hex: ^0.2.0 - polkadart_keyring: ^0.2.1 + polkadart_keyring: ^0.4.3 dev_dependencies: lints: ^3.0.0 diff --git a/packages/signer/test/signer_test.dart b/packages/signer/test/signer_test.dart index bd46bbf4..65d5dc26 100644 --- a/packages/signer/test/signer_test.dart +++ b/packages/signer/test/signer_test.dart @@ -15,7 +15,7 @@ void main() { test('Test sign and verify using mnemonic', () async { final mnemonic = 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'; - await signer.fromMnemonic(mnemonic); + await signer.fromMnemonic(mnemonic, KPType.ed25519); final data = 'dummyData'; final signature = await signer.sign(data); @@ -37,14 +37,14 @@ void main() { test('Test with invalid mnemonic', () async { final invalidMnemonic = 'invalid mnemonic phrase'; - expect(() async => await signer.fromMnemonic(invalidMnemonic), + expect(() async => await signer.fromMnemonic(invalidMnemonic, KPType.sr25519), throwsException); }); test('Test sign and verify with wrong signature', () async { final mnemonic = 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'; - await signer.fromMnemonic(mnemonic); + await signer.fromMnemonic(mnemonic, KPType.ed25519); final data = 'dummyData'; final signature = await signer.sign(data); @@ -90,7 +90,7 @@ void main() { 177, 228 ]); - await signer.fromSeed(seed); + await signer.fromSeed(seed, KPType.ed25519); final data = 'dummyData'; final signature = await signer.sign(data); @@ -106,12 +106,12 @@ void main() { 148, 202, ]); - expect(() async => await signer.fromSeed(invalidSeed), throwsException); + expect(() async => await signer.fromSeed(invalidSeed, KPType.sr25519), throwsException); }); test('Test sign and verify with hex seed', () async { await signer.fromHexSeed( - '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4'); + '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4', KPType.sr25519); final data = 'dummyData'; final signature = await signer.sign(data); @@ -120,13 +120,13 @@ void main() { }); test('Test sign with invalid hex seed', () async { - expect(() async => await signer.fromHexSeed('0x6c1'), throwsException); + expect(() async => await signer.fromHexSeed('0x6c1', KPType.sr25519), throwsException); }); test('Test verify with empty data', () async { final mnemonic = 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'; - await signer.fromMnemonic(mnemonic); + await signer.fromMnemonic(mnemonic, KPType.ed25519); final data = ''; final signature = await signer.sign(data); @@ -138,7 +138,7 @@ void main() { test('Test verify with different data', () async { final mnemonic = 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'; - await signer.fromMnemonic(mnemonic); + await signer.fromMnemonic(mnemonic, KPType.ed25519); final originalData = 'originalData'; final signature = await signer.sign(originalData); @@ -152,9 +152,9 @@ void main() { final signer = Signer(); final mnemonic = 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'; - await signer.fromMnemonic(mnemonic); + await signer.fromMnemonic(mnemonic, KPType.sr25519); - final keypair = await KeyPair.fromMnemonic(mnemonic); + final keypair = await KeyPair.sr25519.fromMnemonic(mnemonic); final address = keypair.address; final pair = await signer.keypairFromAddress(address); diff --git a/packages/tfchain_client/bin/tfchain_client.dart b/packages/tfchain_client/bin/tfchain_client.dart index 1a8009ef..9f7a70c8 100644 --- a/packages/tfchain_client/bin/tfchain_client.dart +++ b/packages/tfchain_client/bin/tfchain_client.dart @@ -1,158 +1,13 @@ +import 'package:tfchain_client/models/dao.dart'; import 'package:tfchain_client/tfchain_client.dart'; -import '../../signer/lib/signer.dart'; void main() async { final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); queryClient.connect(); - // QueryBalances Module - final signer = Signer(); - await signer.fromMnemonic( - 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'); - final pair = await signer - .keypairFromAddress("5CoYEiMb2ePY4cAW7f18HM7rozePwtQ8Ny5yKx8qYUGWxdgi"); - final balance = - await queryClient.balances.get(publicKey: pair.publicKey.bytes); - print(balance!.toJson()); + queryClient.disconnect(); - print("=================="); - - // // QueryContracts Module - // final contract = - // await queryClient.contracts.get(contractId: BigInt.from(49130)); - // print(contract!.toJson()); - - // print("=================="); - - // final contractId = - // await queryClient.contracts.getContractIdByActiveRentForNode(nodeId: 85); - // print(contractId); - - // print("=================="); - - // final activeContracts = - // await queryClient.contracts.getActiveContracts(nodeId: 85); - // print(activeContracts); - - // print("=================="); - - // final id = await queryClient.contracts - // .getContractIdByNodeIdAndHash(nodeId: 11, hash: [ - // 53, - // 50, - // 57, - // 102, - // 53, - // 99, - // 50, - // 55, - // 97, - // 50, - // 99, - // 97, - // 51, - // 50, - // 48, - // 49, - // 48, - // 97, - // 98, - // 102, - // 102, - // 102, - // 49, - // 52, - // 100, - // 56, - // 54, - // 51, - // 52, - // 102, - // 53, - // 51 - // ]); - // print(id); - - // print("=================="); - - // final contractLock = - // await queryClient.contracts.contractLock(id: BigInt.from(49130)); - // print(contractLock!.toJson()); - - // print("=================="); - - // // Farms Module - // final farm = await queryClient.farms.get(id: 115); - // print(farm!.toJson()); - - // print("=================="); - - // // Nodes Module - // final node = await queryClient.nodes.get(id: 85); - // print(node!.toJson()); - - // print("=================="); - - // // Twins Module - // final twin = await queryClient.twins.get(id: 214); - // print(twin!.toJson()); - - // print("=================="); - - final twinId = await queryClient.twins.getTwinIdByAccountId(accountId: [ - 12, - 58, - 221, - 236, - 167, - 151, - 69, - 84, - 126, - 190, - 116, - 100, - 140, - 251, - 60, - 149, - 249, - 60, - 238, - 70, - 203, - 93, - 75, - 150, - 70, - 130, - 0, - 28, - 253, - 137, - 178, - 63 - ]); - - print(twinId); - - // queryClient.disconnect(); - - // Full Client // final client = Client("wss://tfchain.dev.grid.tf/ws", - // "picnic flip cigar rival risk scatter slide aware trust garlic solution token"); - + // "secret add bag cluster deposit beach illness letter crouch position rain arctic"); // client.connect(); - - // final x = await client.clientContracts.createNode( - // nodeId: 13, deploymentHash: [], deploymentData: [], publicIps: 0); - // await client.apply(x); - - // await client.clientBalances.transfer(address: "5CLjvFRPw6L2RzjhxLXHzCdRkJJCZ7Px51SN7Wy5TvefuL3b", amount: 2); - - // // final transaction = - // // client.balances. - // await client.apply(transaction); - - // client.disconnect(); } diff --git a/packages/tfchain_client/lib/models/dao.dart b/packages/tfchain_client/lib/models/dao.dart new file mode 100644 index 00000000..d8f9a9f2 --- /dev/null +++ b/packages/tfchain_client/lib/models/dao.dart @@ -0,0 +1,50 @@ +import 'package:moment_dart/moment_dart.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_dao/proposal/vote_weight.dart'; + +class Proposal { + int threshold; + List ayes; + List nayes; + List> vetos; + Moment end; + String hash; + String action; + String description; + String link; + int ayesProgress; + int nayesProgress; + + Proposal({ + required this.threshold, + required this.ayes, + required this.nayes, + required this.vetos, + required this.end, + required this.hash, + required this.action, + required this.description, + required this.link, + required this.ayesProgress, + required this.nayesProgress, + }); +} + +class ProposalRemark { + String remark; + + ProposalRemark({required this.remark}); +} + +class DaoVoteOptions { + String address; + int farmId; + String hash; + bool approve; + + DaoVoteOptions( + {required this.address, + required this.farmId, + required this.hash, + required this.approve, + s}); +} diff --git a/packages/tfchain_client/lib/models/farms.dart b/packages/tfchain_client/lib/models/farms.dart new file mode 100644 index 00000000..d1cd4f5e --- /dev/null +++ b/packages/tfchain_client/lib/models/farms.dart @@ -0,0 +1,28 @@ +import 'package:tfchain_client/generated/dev/types/tfchain_support/types/ip4.dart'; + +class QueryFarmsGetOptions { + int id; + QueryFarmsGetOptions({required this.id}); +} + +class CreateFarmOptions { + String name; + List? publicIps; + + CreateFarmOptions({ + required this.name, + this.publicIps, + }); +} + +class AddFarmIPOptions { + int farmId; + String ip; + String gw; + + AddFarmIPOptions({ + required this.farmId, + required this.ip, + required this.gw, + }); +} diff --git a/packages/tfchain_client/lib/src/client.dart b/packages/tfchain_client/lib/src/client.dart index c6a5480b..f56c483a 100644 --- a/packages/tfchain_client/lib/src/client.dart +++ b/packages/tfchain_client/lib/src/client.dart @@ -11,15 +11,16 @@ class QueryClient { late final QueryPricingPolicies policies; late final QueryTwins twins; late final QueryBridge bridge; + late final Dao.QueryDao dao; late final QueryTFTPrice price; // TODO: handle calling signer pkg - late final signer; + // late final signer; late final address; QueryClient(this.url) { provider = Provider.fromUri(Uri.parse(url)); api = polkadot.Dev(provider); - + contracts = QueryContracts(this); balances = balance.QueryBalances(this); farms = QueryFarms(this); @@ -28,6 +29,7 @@ class QueryClient { twins = QueryTwins(this); bridge = QueryBridge(this); price = QueryTFTPrice(this); + dao = Dao.QueryDao(this); } void checkInputs() { @@ -51,6 +53,7 @@ class Client extends QueryClient { late final balance.Balances clientBalances; late final Contracts clientContracts; late final Farms clientFarms; + late final Dao.Dao clientDao; Client(String url, this.mnemonic) : super(url) { if (provider == null) { @@ -60,6 +63,7 @@ class Client extends QueryClient { clientBalances = balance.Balances(this); clientContracts = Contracts(this); clientFarms = Farms(this); + clientDao = Dao.Dao(this); } @override void checkInputs() { @@ -111,9 +115,9 @@ class Client extends QueryClient { .result .replaceAll('0x', ''); - final keyring = await KeyPair.fromMnemonic(mnemonic); + final keyring = await KeyPair.sr25519.fromMnemonic(mnemonic); - final encodedCall = hex.encode(runtimeCall.encode()); + final encodedCall = runtimeCall.encode(); final nonce = await api.rpc.system.accountNextIndex(keyring.address); final payloadToSign = SigningPayload( @@ -135,15 +139,15 @@ class Client extends QueryClient { final publicKey = hex.encode(keyring.publicKey.bytes); - final extrinsic = Extrinsic( - signer: publicKey, + final extrinsic = ExtrinsicPayload( + signer: Uint8List.fromList(keyring.bytes()), method: encodedCall, - signature: hexSignature, + signature: signature, eraPeriod: 64, blockNumber: blockNumber, nonce: nonce, tip: 0) - .encode(api.registry); + .encode(api.registry, SignatureType.sr25519); final hexExtrinsic = hex.encode(extrinsic); print('Extrinsic: $hexExtrinsic'); diff --git a/packages/tfchain_client/lib/src/dao.dart b/packages/tfchain_client/lib/src/dao.dart new file mode 100644 index 00000000..79a31681 --- /dev/null +++ b/packages/tfchain_client/lib/src/dao.dart @@ -0,0 +1,136 @@ +import 'package:moment_dart/moment_dart.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_dao/proposal/dao_proposal.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_dao/proposal/dao_votes.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_dao/proposal/vote_weight.dart'; +import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; +import 'package:tfchain_client/models/dao.dart'; +import 'package:tfchain_client/tfchain_client.dart'; + +class QueryDao { + final QueryClient client; + QueryDao(this.client); + + Future>> get() async { + final hashesJson = await client.api.query.dao.proposalList(); + List hashes = + hashesJson.map((hashList) => String.fromCharCodes(hashList)).toList(); + + List activeProposals = []; + List inactiveProposals = []; + + for (int i = 0; i < hashes.length; i++) { + final daoProposal = await getDaoProposal(hashes[i]); + final proposal = await getProposal(hashes[i]); + final proposalVotes = await getProposalVotes(hashes[i]); + final nowBlock = await client.api.query.system.number(); + final timeUntilEnd = (proposalVotes.end - nowBlock) * 6; + if (proposal.remark != "Error fetching proposal") { + if (proposalVotes.end < nowBlock) { + inactiveProposals.add(Proposal( + threshold: proposalVotes.threshold, + ayes: proposalVotes.ayes, + nayes: proposalVotes.nays, + vetos: proposalVotes.vetos, + end: Moment(DateTime.now()).add(Duration(seconds: timeUntilEnd)), + hash: hashes[i], + action: proposal.remark, + description: String.fromCharCodes(daoProposal.description), + link: String.fromCharCodes(daoProposal.link), + ayesProgress: + getProgress(proposalVotes.ayes, proposalVotes.nays, true), + nayesProgress: + getProgress(proposalVotes.ayes, proposalVotes.nays, false))); + } else { + activeProposals.add(Proposal( + threshold: proposalVotes.threshold, + ayes: proposalVotes.ayes, + nayes: proposalVotes.nays, + vetos: proposalVotes.vetos, + end: Moment(DateTime.now()).add(Duration(seconds: timeUntilEnd)), + hash: hashes[i], + action: proposal.remark, + description: String.fromCharCodes(daoProposal.description), + link: String.fromCharCodes(daoProposal.link), + ayesProgress: + getProgress(proposalVotes.ayes, proposalVotes.nays, true), + nayesProgress: + getProgress(proposalVotes.ayes, proposalVotes.nays, false))); + } + } + } + + return { + 'activeProposals': activeProposals, + 'inactiveProposals': inactiveProposals, + }; + } + + Future getDaoProposal(String hash) async { + try { + final proposalJson = + await this.client.api.query.dao.proposals(hash.codeUnits); + DaoProposal proposal = DaoProposal( + index: proposalJson!.index, + description: proposalJson.description, + link: proposalJson.link); + return proposal; + } catch (error) { + throw Exception("Couldn't get a proposal"); + } + } + + Future getProposal(String hash) async { + try { + final proposalJson = + await client.api.query.dao.proposalOf(hash.codeUnits); + ProposalRemark proposalRemark = + ProposalRemark(remark: proposalJson.toString()); + return proposalRemark; + } catch (error) { + print(error); + return ProposalRemark(remark: 'Error fetching proposal'); + } + } + + Future getProposalVotes(String hash) async { + final votesJson = await client.api.query.dao.voting(hash.codeUnits); + DaoVotes proposalVotes = DaoVotes( + index: votesJson!.index, + threshold: votesJson.threshold, + ayes: votesJson.ayes, + nays: votesJson.nays, + end: votesJson.end, + vetos: votesJson.vetos); + return proposalVotes; + } + + int getVotesWithWeight(List votes) { + return votes.fold(0, (int total, vote) => total + vote.weight.toInt()); + } + + int getProgress(List ayes, List nayes, bool typeAye) { + final totalAyeWeight = ayes.isNotEmpty ? getVotesWithWeight(ayes) : 0; + final totalNayeWeight = nayes.isNotEmpty ? getVotesWithWeight(nayes) : 0; + final total = totalAyeWeight + totalNayeWeight; + if (total > 0) { + if (typeAye) { + return ((totalAyeWeight / total) * 100).toInt(); + } + + return ((totalNayeWeight / total) * 100).toInt(); + } + return 0; + } +} + +class Dao extends QueryDao { + Dao(Client client) : super(client); + + RuntimeCall vote(DaoVoteOptions options) { + final extrinsic = client.api.tx.dao.vote( + farmId: options.farmId, + proposalHash: options.hash.codeUnits, + approve: options.approve); + return extrinsic; + } +} diff --git a/packages/tfchain_client/lib/src/farms.dart b/packages/tfchain_client/lib/src/farms.dart index f1c73590..cf742708 100644 --- a/packages/tfchain_client/lib/src/farms.dart +++ b/packages/tfchain_client/lib/src/farms.dart @@ -1,13 +1,14 @@ import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; import 'package:tfchain_client/generated/dev/types/tfchain_support/types/farm.dart'; +import 'package:tfchain_client/models/farms.dart'; import 'package:tfchain_client/tfchain_client.dart'; class QueryFarms { final QueryClient client; QueryFarms(this.client); - Future get({required int id}) async { - final res = await client.api.query.tfgridModule.farms(id); + Future get(QueryFarmsGetOptions options) async { + final res = await client.api.query.tfgridModule.farms(options.id); return res as Farm; } } @@ -15,17 +16,25 @@ class QueryFarms { class Farms extends QueryFarms { Farms(Client client) : super(client); - Future create( - {required String name, required int publicIps}) async { - final extrinsic = - client.api.tx.tfgridModule.createFarm(name: name, publicIps: publicIps); + Future create(CreateFarmOptions options) async { + final extrinsic = client.api.tx.tfgridModule + .createFarm(name: options.name.codeUnits, publicIps: options.publicIps); + return extrinsic; + } + +// TODO: Bug + Future addFarmIp(AddFarmIPOptions options) async { + final extrinsic = client.api.tx.tfgridModule.addFarmIp( + farmId: options.farmId, + ip: options.ip.codeUnits, + gw: options.gw.codeUnits); return extrinsic; } - Future addFarmIp( - {required int farmId, required String ip, required String gw}) async { + Future removeFarmIp( + {required int farmId, required String ip}) async { final extrinsic = - client.api.tx.tfgridModule.addFarmIp(farmId: farmId, ip: ip, gw: gw); + client.api.tx.tfgridModule.removeFarmIp(farmId: farmId, ip: ip); return extrinsic; } diff --git a/packages/tfchain_client/lib/tfchain_client.dart b/packages/tfchain_client/lib/tfchain_client.dart index 9d40f83b..04d5be19 100644 --- a/packages/tfchain_client/lib/tfchain_client.dart +++ b/packages/tfchain_client/lib/tfchain_client.dart @@ -1,12 +1,15 @@ library client; +import 'dart:typed_data'; + import 'package:polkadart/polkadart.dart' - show AuthorApi, Extrinsic, Provider, SigningPayload, StateApi; + show AuthorApi, ExtrinsicPayload, Provider, SigningPayload, StateApi, SignatureType; import 'package:polkadart_keyring/polkadart_keyring.dart'; import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; import 'package:tfchain_client/src/balances.dart' as balance; import 'package:tfchain_client/src/contracts.dart'; import 'package:tfchain_client/generated/dev/dev.dart' as polkadot; +import 'package:tfchain_client/src/dao.dart' as Dao; import 'package:tfchain_client/src/farms.dart'; import 'package:tfchain_client/src/nodes.dart'; import 'package:tfchain_client/src/pricing_policies.dart'; diff --git a/packages/tfchain_client/pubspec.yaml b/packages/tfchain_client/pubspec.yaml index 53d1c811..8f7146e1 100644 --- a/packages/tfchain_client/pubspec.yaml +++ b/packages/tfchain_client/pubspec.yaml @@ -6,13 +6,14 @@ environment: sdk: ^3.2.0 dependencies: - polkadart: ^0.2.2 - polkadart_keyring: ^0.2.1 - substrate_bip39: ^0.2.0 - polkadart_cli: ^0.2.2 + polkadart: ^0.4.3 + polkadart_keyring: ^0.4.3 + substrate_bip39: ^0.4.0 + polkadart_cli: ^0.4.2 hex: ^0.2.0 bip39: ^1.0.6 convert: ^3.1.1 + moment_dart: ^2.0.2 dev_dependencies: lints: ^3.0.0 diff --git a/pubspec.lock b/pubspec.lock index 704f63e3..7137e813 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "36a321c3d2cbe01cbcb3540a87b8843846e0206df3e691fa7b23e19e78de6d49" + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "65.0.0" + version: "67.0.0" adaptive_number: dependency: transitive description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: analyzer - sha256: dfe03b90ec022450e22513b5e5ca1f01c0c01de9c3fba2f7fd233cb57a6b9a07 + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.4.1" ansi_styles: dependency: transitive description: @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: built_value - sha256: "69acb7007eb2a31dc901512bfe0f7b767168be34cb734835d54c070bfa74c1b2" + sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e url: "https://pub.dev" source: hosted - version: "8.8.0" + version: "8.9.1" charcode: dependency: transitive description: @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: cli_util - sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.1" clock: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: code_builder - sha256: b2151ce26a06171005b379ecff6e08d34c470180ffe16b8e14b6d52be292b55f + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.10.0" collection: dependency: transitive description: @@ -165,10 +165,10 @@ packages: dependency: "direct main" description: name: coverage - sha256: ac86d3abab0f165e4b8f561280ff4e066bceaac83c424dd19f1ae2c2fcd12ca9 + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" url: "https://pub.dev" source: hosted - version: "1.7.1" + version: "1.7.2" crypto: dependency: transitive description: @@ -189,10 +189,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.6" ed25519_edwards: dependency: transitive description: @@ -201,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + edwards25519: + dependency: transitive + description: + name: edwards25519 + sha256: "48e4678136e362bed9790dfb716ebe8e2f34f026bdb900b058214620672c6273" + url: "https://pub.dev" + source: hosted + version: "1.0.4" equatable: dependency: transitive description: @@ -221,10 +229,10 @@ packages: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" fixnum: dependency: transitive description: @@ -285,10 +293,10 @@ packages: dependency: transitive description: name: http - sha256: "38dce67ce909c338754840e2a1479c2c11347a2fc7ec3d5b166a5118a8a201db" + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" http_multi_server: dependency: transitive description: @@ -365,34 +373,42 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" melos: dependency: "direct main" description: name: melos - sha256: a45e54b72cc2444b46be9d32a590119b9ba8c4e87117f2743a73ec049542f2d3 + sha256: "7266e9fc9fee5f4a0c075e5cec375c00736dfc944358f533b740b93b3d8d681e" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.1.0" + merlin: + dependency: transitive + description: + name: merlin + sha256: c6b5d5bc70880aa7639686db66480d0be4b89da843b5cab20550610507da2540 + url: "https://pub.dev" + source: hosted + version: "1.0.3" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" mustache_template: dependency: transitive description: @@ -421,58 +437,58 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" platform: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" pointycastle: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.7.4" polkadart: dependency: transitive description: name: polkadart - sha256: "658040a728a21d9a27b126fd4f1356fede8803435c1fc02aec71260172a64278" + sha256: "4be169198d7938aec035eacead499b469795ccc9797589bb2df5b2ec6bd52535" url: "https://pub.dev" source: hosted - version: "0.2.6" + version: "0.4.3" polkadart_cli: dependency: transitive description: name: polkadart_cli - sha256: b9635ab8e95b3a0bcad86a222393f0a491c2ee62ea8b46b7fe7ceba72a9b0fd5 + sha256: a0c82811e7ed935208afc7a8e0ef04446574d53f0a1855694ec5ad0792decef1 url: "https://pub.dev" source: hosted - version: "0.2.4" + version: "0.4.2" polkadart_keyring: dependency: transitive description: name: polkadart_keyring - sha256: ba568c22f3ff2a77c35fe0d53845212c1a433f99645e286550d1889dbb437d3c + sha256: "10cdd75e3319169ca7a4bb49745d85fab3f56bba2eafda35655c4f278a4c5e07" url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "0.4.3" polkadart_scale_codec: dependency: transitive description: name: polkadart_scale_codec - sha256: "75289b2f53c6cf997dd68945d959fee596c1e47bba3dedba22a6e95646df893c" + sha256: fab60c739f6ebcc812796e56378656dca57179cec46e92c23614db6fd9ed0f86 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" pool: dependency: transitive description: @@ -485,10 +501,10 @@ packages: dependency: transitive description: name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.2" prompts: dependency: transitive description: @@ -517,10 +533,10 @@ packages: dependency: transitive description: name: pub_updater - sha256: b06600619c8c219065a548f8f7c192b3e080beff95488ed692780f48f69c0625 + sha256: "54e8dc865349059ebe7f163d6acce7c89eb958b8047e6d6e80ce93b13d7c9e60" url: "https://pub.dev" source: hosted - version: "0.3.1" + version: "0.4.0" pubspec: dependency: transitive description: @@ -553,13 +569,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" - rmb_client: - dependency: "direct main" + ristretto255: + dependency: transitive description: - path: "packages/rmb_client" - relative: true - source: path - version: "1.0.0" + name: ristretto255 + sha256: "3824d6786146dfb3b0783f305b714d36fa213c0d08e0ba864267baa0ede51cdd" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + secp256k1_ecdsa: + dependency: transitive + description: + name: secp256k1_ecdsa + sha256: "87008b4fd164d861b94b0edf2e01ffadd6f06769e1f0382e19bb091daecc0576" + url: "https://pub.dev" + source: hosted + version: "0.4.0" shelf: dependency: transitive description: @@ -631,6 +656,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + sr25519: + dependency: transitive + description: + name: sr25519 + sha256: "266f7b2a4dd2d6a41a49924d41e80665f3b8340c157deff172f2b0cf64657a27" + url: "https://pub.dev" + source: hosted + version: "0.4.0" ss58: dependency: transitive description: @@ -663,22 +696,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" - substrate_bip39: + strobe: dependency: transitive + description: + name: strobe + sha256: a23adf7d305e45c6f210270aa925d8b404819144e29f7c5257a67281b63e0887 + url: "https://pub.dev" + source: hosted + version: "1.0.4" + substrate_bip39: + dependency: "direct main" description: name: substrate_bip39 - sha256: "78b45e9959c3394ecc9b56d9bfb07e11f93db70d273eccd93e3e4d84b28f11c0" + sha256: "29548105e939d1fb213aba96686eb5c5aae472249fa12b8dda58b252d23f492c" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.4.0" substrate_metadata: dependency: transitive description: name: substrate_metadata - sha256: "48c96aed0ef8f38dd99e80e592c7774c30fc13a80d62a5f777b56b22801c3fa0" + sha256: "4557950c7dcea17cdf7e1224ac7822ab38dd9658f000be6d58b4a41b0a8126d4" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" term_glyph: dependency: transitive description: @@ -691,26 +732,26 @@ packages: dependency: "direct dev" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.2" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.0" tfchain_client: dependency: "direct main" description: @@ -754,18 +795,18 @@ packages: dependency: transitive description: name: uuid - sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921 + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 url: "https://pub.dev" source: hosted - version: "4.2.1" + version: "4.3.3" vm_service: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.0.0" watcher: dependency: transitive description: @@ -778,10 +819,10 @@ packages: dependency: transitive description: name: web - sha256: edc8a9573dd8c5a83a183dae1af2b6fd4131377404706ca4e5420474784906fa + sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.2" web_socket_channel: dependency: transitive description: @@ -810,17 +851,17 @@ packages: dependency: transitive description: name: yaml_edit - sha256: "1579d4a0340a83cf9e4d580ea51a16329c916973bffd5bd4b45e911b25d46bfd" + sha256: c566f4f804215d84a7a2c377667f546c6033d5b34b4f9e60dfb09d17c4e97826 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" yaon: dependency: transitive description: name: yaon - sha256: fb0dd1654f203e52ef1631ba81a04c7762ddfd72d7bc58a178462d8b84258fd4 + sha256: "9baabf121604d7530fc8bcd4f2aeb6c300a055d9a6f9b45b5071f893756ca867" url: "https://pub.dev" source: hosted - version: "1.1.4" + version: "1.1.4+4" sdks: dart: ">=3.2.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index f210256e..2a35fb9c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,9 +12,10 @@ dev_dependencies: dependencies: coverage: ^1.7.1 - melos: ^3.2.0 - signer: + melos: ^4.1.0 + signer: path: ./packages/signer + substrate_bip39: ^0.4.0 tfchain_client: path: ./packages/tfchain_client rmb_client: From eb977d99c089ec5b4684b2b0f1e55affe5390c4f Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Wed, 13 Mar 2024 22:24:56 +0200 Subject: [PATCH 05/17] improve client && balances module && linting workflow --- packages/signer/bin/signer.dart | 2 +- packages/signer/lib/signer.dart | 1 - packages/signer/lib/src/sign.dart | 37 ++++++++++--------- packages/signer/test/signer_test.dart | 15 +++++--- packages/tfchain_client/README.md | 10 +++++ .../tfchain_client/bin/tfchain_client.dart | 33 +++++++++++++---- .../tfchain_client/lib/models/balances.dart | 15 ++++++++ packages/tfchain_client/lib/src/balances.dart | 30 ++++++++------- packages/tfchain_client/lib/src/client.dart | 35 +++++++++++++----- .../tfchain_client/lib/tfchain_client.dart | 1 + packages/tfchain_client/pubspec.yaml | 2 + packages/tfchain_client/test/client_test.dart | 9 +++-- 12 files changed, 133 insertions(+), 57 deletions(-) create mode 100644 packages/tfchain_client/lib/models/balances.dart diff --git a/packages/signer/bin/signer.dart b/packages/signer/bin/signer.dart index fc489bf0..4ab39272 100644 --- a/packages/signer/bin/signer.dart +++ b/packages/signer/bin/signer.dart @@ -54,7 +54,7 @@ void main() async { print("Signature from Seed: $signatureFromSeed"); final signer3 = Signer(); - await signer3.fromHexSeed( + signer3.fromHexSeed( '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4', KPType.ed25519); final signatureFromSeed2 = await signer3.sign(data); diff --git a/packages/signer/lib/signer.dart b/packages/signer/lib/signer.dart index 70761db6..e422d1e9 100644 --- a/packages/signer/lib/signer.dart +++ b/packages/signer/lib/signer.dart @@ -4,7 +4,6 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:polkadart_keyring/polkadart_keyring.dart'; import 'package:hex/hex.dart'; -import 'package:substrate_bip39/substrate_bip39.dart'; part 'src/sign.dart'; part 'src/types.dart'; diff --git a/packages/signer/lib/src/sign.dart b/packages/signer/lib/src/sign.dart index 19b2ad56..2b9b5e50 100644 --- a/packages/signer/lib/src/sign.dart +++ b/packages/signer/lib/src/sign.dart @@ -1,17 +1,19 @@ part of '../signer.dart'; class Signer { - KeyPair? _keypair; + KeyPair? keypair; KPType? _type; - Future fromMnemonic(String mnemonic, KPType type) async { + Future fromMnemonic(String mnemonic, KPType type) async { try { if (type.value == KPType.sr25519.value) { - _keypair = await KeyPair.sr25519.fromMnemonic(mnemonic); + keypair = await KeyPair.sr25519.fromMnemonic(mnemonic); _type = KPType.sr25519; + return keypair; } else if (type.value == KPType.ed25519.value) { - _keypair = await KeyPair.ed25519.fromMnemonic(mnemonic); + keypair = await KeyPair.ed25519.fromMnemonic(mnemonic); _type = KPType.ed25519; + return keypair; } else { throw Exception("Wrong KeyPair type !"); } @@ -23,10 +25,10 @@ class Signer { Future fromSeed(Uint8List seed, KPType type) async { try { if (type.value == KPType.sr25519) { - _keypair = await KeyPair.sr25519.fromSeed(seed); + keypair = await KeyPair.sr25519.fromSeed(seed); _type = KPType.sr25519; } else if (type.value == KPType.ed25519) { - _keypair = await KeyPair.ed25519.fromSeed(seed); + keypair = await KeyPair.ed25519.fromSeed(seed); _type = KPType.ed25519; } else { throw Exception("Wrong KeyPair type !"); @@ -36,13 +38,13 @@ class Signer { } } - Future fromHexSeed(String hexSeed, KPType type) async { + void fromHexSeed(String hexSeed, KPType type) { try { final seed = HEX.decode(hexSeed.replaceAll('0x', '')); if (type.value == KPType.sr25519) { - _keypair = KeyPair.sr25519.fromSeed(Uint8List.fromList(seed)); + keypair = KeyPair.sr25519.fromSeed(Uint8List.fromList(seed)); } else if (type.value == KPType.ed25519) { - _keypair = KeyPair.ed25519.fromSeed(Uint8List.fromList(seed)); + keypair = KeyPair.ed25519.fromSeed(Uint8List.fromList(seed)); } else { throw Exception("Wrong KeyPair type !"); } @@ -51,34 +53,35 @@ class Signer { } } - Future sign(String data) async { - if (_keypair == null) { + Uint8List sign(String data) { + if (keypair == null) { throw Exception("keypair not initialized."); } try { final dataBytes = Uint8List.fromList(utf8.encode(data)); - final signature = _keypair!.sign(dataBytes); + final signature = keypair!.sign(dataBytes); return signature; } catch (e) { throw Exception("Failed to sign data. Error: $e"); } } - Future verify(Uint8List signature, String data) async { - if (_keypair == null) { + bool verify(Uint8List signature, String data) { + if (keypair == null) { throw Exception("keypair not initialized."); } try { final dataBytes = Uint8List.fromList(utf8.encode(data)); - return _keypair!.verify(dataBytes, signature); + return keypair!.verify(dataBytes, signature); } catch (e) { throw Exception("Failed to verify signature. Error: $e"); } } - Future keypairFromAddress(String address) async { + KeyPair keypairFromAddress(String address) { final keyring = Keyring(); - keyring.add(_keypair!); + + keyring.add(keypair!); final pair = keyring.getByAddress(address); return pair; } diff --git a/packages/signer/test/signer_test.dart b/packages/signer/test/signer_test.dart index 65d5dc26..59ea94a0 100644 --- a/packages/signer/test/signer_test.dart +++ b/packages/signer/test/signer_test.dart @@ -37,7 +37,9 @@ void main() { test('Test with invalid mnemonic', () async { final invalidMnemonic = 'invalid mnemonic phrase'; - expect(() async => await signer.fromMnemonic(invalidMnemonic, KPType.sr25519), + expect( + () async => + await signer.fromMnemonic(invalidMnemonic, KPType.sr25519), throwsException); }); @@ -106,12 +108,14 @@ void main() { 148, 202, ]); - expect(() async => await signer.fromSeed(invalidSeed, KPType.sr25519), throwsException); + expect(() async => await signer.fromSeed(invalidSeed, KPType.sr25519), + throwsException); }); test('Test sign and verify with hex seed', () async { - await signer.fromHexSeed( - '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4', KPType.sr25519); + signer.fromHexSeed( + '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4', + KPType.sr25519); final data = 'dummyData'; final signature = await signer.sign(data); @@ -120,7 +124,8 @@ void main() { }); test('Test sign with invalid hex seed', () async { - expect(() async => await signer.fromHexSeed('0x6c1', KPType.sr25519), throwsException); + expect(() async => signer.fromHexSeed('0x6c1', KPType.sr25519), + throwsException); }); test('Test verify with empty data', () async { diff --git a/packages/tfchain_client/README.md b/packages/tfchain_client/README.md index b68d16c9..15f3ed2e 100644 --- a/packages/tfchain_client/README.md +++ b/packages/tfchain_client/README.md @@ -22,6 +22,16 @@ print(contract!.toJson()); client.disconnect(); ``` +### Full Client + +```dart +final client = Client("wss://tfchain.dev.grid.tf/ws", "your-mnemonic"); +client.connect(); +final extrinsic = await client.clientFarms.create(CreateFarmOptions(name: "name")); +await client.apply(extrinsic); +client.disconnect(); +``` + ## Run Tests To run the tests, run the following command diff --git a/packages/tfchain_client/bin/tfchain_client.dart b/packages/tfchain_client/bin/tfchain_client.dart index 9f7a70c8..b2f7c906 100644 --- a/packages/tfchain_client/bin/tfchain_client.dart +++ b/packages/tfchain_client/bin/tfchain_client.dart @@ -1,13 +1,32 @@ -import 'package:tfchain_client/models/dao.dart'; +import 'package:signer/signer.dart'; +import 'package:tfchain_client/models/balances.dart'; import 'package:tfchain_client/tfchain_client.dart'; void main() async { - final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); - queryClient.connect(); + // final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); + // queryClient.connect(); - queryClient.disconnect(); + // final balance = await queryClient.balances.get(QueryBalancesGetOptions( + // address: "5CLjvFRPw6L2RzjhxLXHzCdRkJJCZ7Px51SN7Wy5TvefuL3b")); + // print(balance); - // final client = Client("wss://tfchain.dev.grid.tf/ws", - // "secret add bag cluster deposit beach illness letter crouch position rain arctic"); - // client.connect(); + // queryClient.disconnect(); + + final client = Client( + "wss://tfchain.dev.grid.tf/ws", + "secret add bag cluster deposit beach illness letter crouch position rain arctic", + "sr25519"); + client.connect(); + + final signer = Signer(); + + await signer.fromMnemonic( + "oven strong mention shoulder night ghost correct exercise surge lady jungle hundred", + KPType.sr25519); + + final extrinsic = await client.clientBalances.transfer( + BalanceTransferOptions(address: signer.keypair!.address.codeUnits, amount: 10)); + + await client.apply(extrinsic); + // client.disconnect(); } diff --git a/packages/tfchain_client/lib/models/balances.dart b/packages/tfchain_client/lib/models/balances.dart new file mode 100644 index 00000000..0d51a4fa --- /dev/null +++ b/packages/tfchain_client/lib/models/balances.dart @@ -0,0 +1,15 @@ +class QueryBalancesGetOptions { + String address; + + QueryBalancesGetOptions({required this.address}); +} + +class BalanceTransferOptions { + List address; + int amount; + + BalanceTransferOptions({ + required this.address, + required this.amount, + }); +} diff --git a/packages/tfchain_client/lib/src/balances.dart b/packages/tfchain_client/lib/src/balances.dart index eacffdb6..6c9ddf55 100644 --- a/packages/tfchain_client/lib/src/balances.dart +++ b/packages/tfchain_client/lib/src/balances.dart @@ -1,13 +1,18 @@ +import 'package:polkadart/scale_codec.dart'; import 'package:tfchain_client/generated/dev/types/frame_system/account_info.dart'; +import 'package:tfchain_client/generated/dev/types/sp_runtime/multiaddress/multi_address.dart'; import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; +import 'package:tfchain_client/models/balances.dart'; import 'package:tfchain_client/tfchain_client.dart'; class QueryBalances { final QueryClient client; QueryBalances(this.client); - Future get({required List publicKey}) async { - final res = await client.api.query.system.account(publicKey); + Future get(QueryBalancesGetOptions options) async { + // TODO: should get pair.publicKey.bytes + final res = + await client.api.query.system.account(options.address.codeUnits); return res; } } @@ -15,21 +20,18 @@ class QueryBalances { class Balances extends QueryBalances { Balances(Client client) : super(client); - //TODO: Error String is not type of multiaddress - - Future transfer( - {required String address, required int amount}) async { - if (amount.isNaN || amount <= 0) { + Future transfer(BalanceTransferOptions options) async { + if (options.amount.isNaN || options.amount <= 0) { throw Exception("Amount must be a positive numeric value"); } - - final extrinsic = - client.api.tx.balances.transfer(dest: address, value: amount); + MultiAddress multiAddress = + MultiAddress.decode(Input.fromBytes(options.address)); + final extrinsic = client.api.tx.balances + .transfer(dest: multiAddress, value: options.amount); return extrinsic; } -// // TODO: -// Future getMyBalance() async { -// // return this.get(publicKey: this.client.) -// } + // Future getMyBalance() async { + // return this.get(QueryBalancesGetOptions(address: client.)) + // } } diff --git a/packages/tfchain_client/lib/src/client.dart b/packages/tfchain_client/lib/src/client.dart index f56c483a..9ac1a8b9 100644 --- a/packages/tfchain_client/lib/src/client.dart +++ b/packages/tfchain_client/lib/src/client.dart @@ -13,14 +13,10 @@ class QueryClient { late final QueryBridge bridge; late final Dao.QueryDao dao; late final QueryTFTPrice price; - // TODO: handle calling signer pkg - // late final signer; - late final address; QueryClient(this.url) { provider = Provider.fromUri(Uri.parse(url)); api = polkadot.Dev(provider); - contracts = QueryContracts(this); balances = balance.QueryBalances(this); farms = QueryFarms(this); @@ -38,7 +34,7 @@ class QueryClient { } } - void connect() async { + void connect() { checkInputs(); } @@ -49,13 +45,18 @@ class QueryClient { class Client extends QueryClient { final String mnemonic; - late KeyPair keypair; + late String address; + final String keypairType; + late Signer.Signer signer; + KeyPair? keypair; + late final balance.Balances clientBalances; late final Contracts clientContracts; late final Farms clientFarms; late final Dao.Dao clientDao; + final SUPPORTED_KEYPAIR_TYPES = ["sr25519", "ed25519"]; - Client(String url, this.mnemonic) : super(url) { + Client(String url, this.mnemonic, this.keypairType) : super(url) { if (provider == null) { provider = Provider.fromUri(Uri.parse(url)); api = polkadot.Dev(provider); @@ -64,9 +65,12 @@ class Client extends QueryClient { clientContracts = Contracts(this); clientFarms = Farms(this); clientDao = Dao.Dao(this); + signer = Signer.Signer(); } + @override void checkInputs() { + super.checkInputs(); if (mnemonic.isEmpty) { throw FormatException("Mnemonic or secret should be provided"); } else if (mnemonic != "//Allice" && !validateMnemonic(mnemonic)) { @@ -79,11 +83,23 @@ class Client extends QueryClient { "Invalid secret seed. Secret seed should start with 0x"); } } + + if (!SUPPORTED_KEYPAIR_TYPES.contains(keypairType)) { + throw FormatException( + "Keypair type $keypairType is not valid. It Should be either of : ${SUPPORTED_KEYPAIR_TYPES}"); + } } @override void connect() async { checkInputs(); + if (keypairType == "sr25519") { + keypair = await signer.fromMnemonic(mnemonic, Signer.KPType.sr25519); + address = keypair!.address; + } else { + keypair = await signer.fromMnemonic(mnemonic, Signer.KPType.ed25519); + address = keypair!.address; + } } @override @@ -152,8 +168,9 @@ class Client extends QueryClient { final hexExtrinsic = hex.encode(extrinsic); print('Extrinsic: $hexExtrinsic'); - final author = AuthorApi(provider); - author.submitAndWatchExtrinsic(extrinsic, + final submit = await AuthorApi(provider).submitAndWatchExtrinsic( + extrinsic as Uint8List, (p0) => print("Extrinsic result: ${p0.type} - {${p0.value}}")); + print(submit); } } diff --git a/packages/tfchain_client/lib/tfchain_client.dart b/packages/tfchain_client/lib/tfchain_client.dart index 04d5be19..d720c3a1 100644 --- a/packages/tfchain_client/lib/tfchain_client.dart +++ b/packages/tfchain_client/lib/tfchain_client.dart @@ -18,6 +18,7 @@ import 'package:tfchain_client/src/tft_price.dart'; import 'package:tfchain_client/src/twins.dart'; import 'package:bip39/bip39.dart'; import 'package:convert/convert.dart'; +import 'package:signer/signer.dart' as Signer; part 'src/client.dart'; diff --git a/packages/tfchain_client/pubspec.yaml b/packages/tfchain_client/pubspec.yaml index 8f7146e1..eb3698eb 100644 --- a/packages/tfchain_client/pubspec.yaml +++ b/packages/tfchain_client/pubspec.yaml @@ -14,6 +14,8 @@ dependencies: bip39: ^1.0.6 convert: ^3.1.1 moment_dart: ^2.0.2 + signer: + path: ../signer dev_dependencies: lints: ^3.0.0 diff --git a/packages/tfchain_client/test/client_test.dart b/packages/tfchain_client/test/client_test.dart index 3831027c..c60cb2f8 100644 --- a/packages/tfchain_client/test/client_test.dart +++ b/packages/tfchain_client/test/client_test.dart @@ -50,15 +50,18 @@ void main() { group("Full Client Tests", () { test('checkInputs with Invalid mnemonic', () { - final client = Client("wss://tfchain.dev.grid.tf/ws", "validMnemonic"); + final client = + Client("wss://tfchain.dev.grid.tf/ws", "validMnemonic", ""); expect( () => client.checkInputs(), throwsA(TypeMatcher())); }); late Client client; setUp(() { - client = Client("wss://tfchain.dev.grid.tf/ws", - "picnic flip cigar rival risk scatter slide aware trust garlic solution token"); + client = Client( + "wss://tfchain.dev.grid.tf/ws", + "picnic flip cigar rival risk scatter slide aware trust garlic solution token", + ""); }); test('Initialization', () { From 54c1acb9aea7157f37d8208c397668be5e1f87e9 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sun, 17 Mar 2024 11:38:26 +0200 Subject: [PATCH 06/17] add twins && T&C modules --- packages/signer/lib/src/sign.dart | 8 ++++- .../tfchain_client/bin/tfchain_client.dart | 29 ++++++++--------- .../lib/models/terms_and_conditions.dart | 9 ++++++ packages/tfchain_client/lib/models/twins.dart | 22 +++++++++++++ packages/tfchain_client/lib/src/client.dart | 11 ++++--- .../lib/src/terms_and_conditions.dart | 14 ++++++++ packages/tfchain_client/lib/src/twins.dart | 32 ++++++++----------- 7 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 packages/tfchain_client/lib/models/terms_and_conditions.dart create mode 100644 packages/tfchain_client/lib/models/twins.dart create mode 100644 packages/tfchain_client/lib/src/terms_and_conditions.dart diff --git a/packages/signer/lib/src/sign.dart b/packages/signer/lib/src/sign.dart index 2b9b5e50..85c2efa1 100644 --- a/packages/signer/lib/src/sign.dart +++ b/packages/signer/lib/src/sign.dart @@ -1,4 +1,6 @@ part of '../signer.dart'; +// TODO: should return keypair or not ? + class Signer { KeyPair? keypair; @@ -22,14 +24,16 @@ class Signer { } } - Future fromSeed(Uint8List seed, KPType type) async { + Future fromSeed(Uint8List seed, KPType type) async { try { if (type.value == KPType.sr25519) { keypair = await KeyPair.sr25519.fromSeed(seed); _type = KPType.sr25519; + return keypair; } else if (type.value == KPType.ed25519) { keypair = await KeyPair.ed25519.fromSeed(seed); _type = KPType.ed25519; + return keypair; } else { throw Exception("Wrong KeyPair type !"); } @@ -43,8 +47,10 @@ class Signer { final seed = HEX.decode(hexSeed.replaceAll('0x', '')); if (type.value == KPType.sr25519) { keypair = KeyPair.sr25519.fromSeed(Uint8List.fromList(seed)); + _type = KPType.sr25519; } else if (type.value == KPType.ed25519) { keypair = KeyPair.ed25519.fromSeed(Uint8List.fromList(seed)); + _type = KPType.ed25519; } else { throw Exception("Wrong KeyPair type !"); } diff --git a/packages/tfchain_client/bin/tfchain_client.dart b/packages/tfchain_client/bin/tfchain_client.dart index b2f7c906..ece5a78b 100644 --- a/packages/tfchain_client/bin/tfchain_client.dart +++ b/packages/tfchain_client/bin/tfchain_client.dart @@ -1,16 +1,21 @@ +import 'dart:io'; + import 'package:signer/signer.dart'; import 'package:tfchain_client/models/balances.dart'; +import 'package:tfchain_client/models/twins.dart'; import 'package:tfchain_client/tfchain_client.dart'; void main() async { - // final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); - // queryClient.connect(); + final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); + await queryClient.connect(); + + final twin = await queryClient.twins.get(QueryTwinsGetOptions(id: 214)); - // final balance = await queryClient.balances.get(QueryBalancesGetOptions( - // address: "5CLjvFRPw6L2RzjhxLXHzCdRkJJCZ7Px51SN7Wy5TvefuL3b")); - // print(balance); + // final twinId = await queryClient.twins.getTwinIdByAccountId( + // QueryTwinsGetTwinByAccountIdOptions(accountId: twin!.accountId)); + // print(twinId); - // queryClient.disconnect(); + // await queryClient.disconnect(); final client = Client( "wss://tfchain.dev.grid.tf/ws", @@ -18,15 +23,9 @@ void main() async { "sr25519"); client.connect(); - final signer = Signer(); - - await signer.fromMnemonic( - "oven strong mention shoulder night ghost correct exercise surge lady jungle hundred", - KPType.sr25519); - - final extrinsic = await client.clientBalances.transfer( - BalanceTransferOptions(address: signer.keypair!.address.codeUnits, amount: 10)); + final extrinsic = await client.clientTwins + .update(TwinOptions(relay: twin!.relay ?? [], pk: twin.pk ?? [])); await client.apply(extrinsic); - // client.disconnect(); + // await client.disconnect(); } diff --git a/packages/tfchain_client/lib/models/terms_and_conditions.dart b/packages/tfchain_client/lib/models/terms_and_conditions.dart new file mode 100644 index 00000000..e6072438 --- /dev/null +++ b/packages/tfchain_client/lib/models/terms_and_conditions.dart @@ -0,0 +1,9 @@ +class AcceptOptions { + String documentLink; + String documentHash; + + AcceptOptions({ + required this.documentLink, + required this.documentHash, + }); +} diff --git a/packages/tfchain_client/lib/models/twins.dart b/packages/tfchain_client/lib/models/twins.dart new file mode 100644 index 00000000..77e3afd6 --- /dev/null +++ b/packages/tfchain_client/lib/models/twins.dart @@ -0,0 +1,22 @@ +class QueryTwinsGetOptions { + int id; + QueryTwinsGetOptions({ + required this.id, + }); +} + +class QueryTwinsGetTwinByAccountIdOptions { + List accountId; + + QueryTwinsGetTwinByAccountIdOptions({required this.accountId}); +} + +class TwinOptions { + List relay; + List pk; + + TwinOptions({ + required this.relay, + required this.pk, + }); +} diff --git a/packages/tfchain_client/lib/src/client.dart b/packages/tfchain_client/lib/src/client.dart index 9ac1a8b9..bdb3c60d 100644 --- a/packages/tfchain_client/lib/src/client.dart +++ b/packages/tfchain_client/lib/src/client.dart @@ -34,11 +34,11 @@ class QueryClient { } } - void connect() { + Future connect() async { checkInputs(); } - void disconnect() async { + Future disconnect() async { await api.disconnect(); } } @@ -49,11 +49,11 @@ class Client extends QueryClient { final String keypairType; late Signer.Signer signer; KeyPair? keypair; - late final balance.Balances clientBalances; late final Contracts clientContracts; late final Farms clientFarms; late final Dao.Dao clientDao; + late final Twins clientTwins; final SUPPORTED_KEYPAIR_TYPES = ["sr25519", "ed25519"]; Client(String url, this.mnemonic, this.keypairType) : super(url) { @@ -65,6 +65,7 @@ class Client extends QueryClient { clientContracts = Contracts(this); clientFarms = Farms(this); clientDao = Dao.Dao(this); + clientTwins = Twins(this); signer = Signer.Signer(); } @@ -91,7 +92,7 @@ class Client extends QueryClient { } @override - void connect() async { + Future connect() async { checkInputs(); if (keypairType == "sr25519") { keypair = await signer.fromMnemonic(mnemonic, Signer.KPType.sr25519); @@ -103,7 +104,7 @@ class Client extends QueryClient { } @override - void disconnect() async { + Future disconnect() async { await api.disconnect(); } diff --git a/packages/tfchain_client/lib/src/terms_and_conditions.dart b/packages/tfchain_client/lib/src/terms_and_conditions.dart new file mode 100644 index 00000000..b86f1134 --- /dev/null +++ b/packages/tfchain_client/lib/src/terms_and_conditions.dart @@ -0,0 +1,14 @@ +import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; +import 'package:tfchain_client/models/terms_and_conditions.dart'; +import 'package:tfchain_client/tfchain_client.dart'; + +class TermsAndConditions { + final Client client; + TermsAndConditions(this.client); + + Future accept(AcceptOptions options) async { + final extrinsic = await client.api.tx.tfgridModule.userAcceptTc( + documentLink: options.documentLink, documentHash: options.documentHash); + return extrinsic; + } +} diff --git a/packages/tfchain_client/lib/src/twins.dart b/packages/tfchain_client/lib/src/twins.dart index 8455f694..c723df59 100644 --- a/packages/tfchain_client/lib/src/twins.dart +++ b/packages/tfchain_client/lib/src/twins.dart @@ -1,19 +1,21 @@ import 'package:tfchain_client/generated/dev/types/pallet_tfgrid/types/twin.dart'; import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; +import 'package:tfchain_client/models/twins.dart'; import 'package:tfchain_client/tfchain_client.dart'; class QueryTwins { final QueryClient client; QueryTwins(this.client); - Future get({required int id}) async { - final res = await client.api.query.tfgridModule.twins(id); + Future get(QueryTwinsGetOptions options) async { + final res = await client.api.query.tfgridModule.twins(options.id); return res; } - Future getTwinIdByAccountId({required List accountId}) async { - final res = - await client.api.query.tfgridModule.twinIdByAccountID(accountId); + Future getTwinIdByAccountId( + QueryTwinsGetTwinByAccountIdOptions options) async { + final res = await client.api.query.tfgridModule + .twinIdByAccountID(options.accountId); return res; } } @@ -21,23 +23,15 @@ class QueryTwins { class Twins extends QueryTwins { Twins(Client client) : super(client); - Future create( - {required String relay, required String pk}) async { - final extrinsic = - client.api.tx.tfgridModule.createTwin(relay: relay, pk: pk); + Future create(TwinOptions options) async { + final extrinsic = client.api.tx.tfgridModule + .createTwin(relay: options.relay, pk: options.pk); return extrinsic; } - Future update( - {required String relay, required String pk}) async { - final extrinsic = - client.api.tx.tfgridModule.updateTwin(relay: relay, pk: pk); + Future update(TwinOptions options) async { + final extrinsic = client.api.tx.tfgridModule + .updateTwin(relay: options.relay, pk: options.pk); return extrinsic; } -// TODO: - // Future getMyTwinId( - // {required List accountId) async { - // return getTwinIdByAccountId(accountId: accountId); - - // } } From f387395e59ed24fc6ff2df0c94c68c887b516a42 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sun, 17 Mar 2024 12:17:19 +0200 Subject: [PATCH 07/17] fix tests --- packages/tfchain_client/lib/src/client.dart | 1 + packages/tfchain_client/test/client_test.dart | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/tfchain_client/lib/src/client.dart b/packages/tfchain_client/lib/src/client.dart index bdb3c60d..eb78b1b6 100644 --- a/packages/tfchain_client/lib/src/client.dart +++ b/packages/tfchain_client/lib/src/client.dart @@ -67,6 +67,7 @@ class Client extends QueryClient { clientDao = Dao.Dao(this); clientTwins = Twins(this); signer = Signer.Signer(); + } @override diff --git a/packages/tfchain_client/test/client_test.dart b/packages/tfchain_client/test/client_test.dart index c60cb2f8..f4e7d53d 100644 --- a/packages/tfchain_client/test/client_test.dart +++ b/packages/tfchain_client/test/client_test.dart @@ -51,7 +51,7 @@ void main() { group("Full Client Tests", () { test('checkInputs with Invalid mnemonic', () { final client = - Client("wss://tfchain.dev.grid.tf/ws", "validMnemonic", ""); + Client("wss://tfchain.dev.grid.tf/ws", "validMnemonic", "sr25519"); expect( () => client.checkInputs(), throwsA(TypeMatcher())); }); @@ -61,7 +61,7 @@ void main() { client = Client( "wss://tfchain.dev.grid.tf/ws", "picnic flip cigar rival risk scatter slide aware trust garlic solution token", - ""); + "sr25519"); }); test('Initialization', () { From 3705c7380a0fc6e9b6f83ce972a5e7a5350087cb Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sun, 17 Mar 2024 13:01:38 +0200 Subject: [PATCH 08/17] fix bug in signer pkg --- packages/signer/lib/src/sign.dart | 8 ++++---- packages/signer/test/signer_test.dart | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/signer/lib/src/sign.dart b/packages/signer/lib/src/sign.dart index 85c2efa1..aa36f257 100644 --- a/packages/signer/lib/src/sign.dart +++ b/packages/signer/lib/src/sign.dart @@ -26,11 +26,11 @@ class Signer { Future fromSeed(Uint8List seed, KPType type) async { try { - if (type.value == KPType.sr25519) { + if (type.value == KPType.sr25519.value) { keypair = await KeyPair.sr25519.fromSeed(seed); _type = KPType.sr25519; return keypair; - } else if (type.value == KPType.ed25519) { + } else if (type.value == KPType.ed25519.value) { keypair = await KeyPair.ed25519.fromSeed(seed); _type = KPType.ed25519; return keypair; @@ -45,10 +45,10 @@ class Signer { void fromHexSeed(String hexSeed, KPType type) { try { final seed = HEX.decode(hexSeed.replaceAll('0x', '')); - if (type.value == KPType.sr25519) { + if (type.value == KPType.sr25519.value) { keypair = KeyPair.sr25519.fromSeed(Uint8List.fromList(seed)); _type = KPType.sr25519; - } else if (type.value == KPType.ed25519) { + } else if (type.value == KPType.ed25519.value) { keypair = KeyPair.ed25519.fromSeed(Uint8List.fromList(seed)); _type = KPType.ed25519; } else { diff --git a/packages/signer/test/signer_test.dart b/packages/signer/test/signer_test.dart index 59ea94a0..1e0d9a9e 100644 --- a/packages/signer/test/signer_test.dart +++ b/packages/signer/test/signer_test.dart @@ -39,7 +39,7 @@ void main() { final invalidMnemonic = 'invalid mnemonic phrase'; expect( () async => - await signer.fromMnemonic(invalidMnemonic, KPType.sr25519), + await signer.fromMnemonic(invalidMnemonic, KPType.ed25519), throwsException); }); @@ -108,7 +108,7 @@ void main() { 148, 202, ]); - expect(() async => await signer.fromSeed(invalidSeed, KPType.sr25519), + expect(() async => await signer.fromSeed(invalidSeed, KPType.ed25519), throwsException); }); @@ -124,7 +124,7 @@ void main() { }); test('Test sign with invalid hex seed', () async { - expect(() async => signer.fromHexSeed('0x6c1', KPType.sr25519), + expect(() async => signer.fromHexSeed('0x6c1', KPType.ed25519), throwsException); }); @@ -157,9 +157,9 @@ void main() { final signer = Signer(); final mnemonic = 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'; - await signer.fromMnemonic(mnemonic, KPType.sr25519); + await signer.fromMnemonic(mnemonic, KPType.ed25519); - final keypair = await KeyPair.sr25519.fromMnemonic(mnemonic); + final keypair = await KeyPair.ed25519.fromMnemonic(mnemonic); final address = keypair.address; final pair = await signer.keypairFromAddress(address); From 1071599d275209dd026dd870cc5a0aa2fb5c6fd4 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sun, 17 Mar 2024 13:06:45 +0200 Subject: [PATCH 09/17] remove await from sign&verify with hex seed test --- packages/signer/test/signer_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/signer/test/signer_test.dart b/packages/signer/test/signer_test.dart index 1e0d9a9e..640bbc38 100644 --- a/packages/signer/test/signer_test.dart +++ b/packages/signer/test/signer_test.dart @@ -95,9 +95,9 @@ void main() { await signer.fromSeed(seed, KPType.ed25519); final data = 'dummyData'; - final signature = await signer.sign(data); + final signature = signer.sign(data); - final isVerified = await signer.verify(signature, data); + final isVerified = signer.verify(signature, data); expect(isVerified, isTrue); }); From 4c7b42f42940e6971fc3551b8b75ae63af1c2220 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sun, 17 Mar 2024 13:17:08 +0200 Subject: [PATCH 10/17] remove seed and hex seed tests --- packages/signer/test/signer_test.dart | 55 --------------------------- 1 file changed, 55 deletions(-) diff --git a/packages/signer/test/signer_test.dart b/packages/signer/test/signer_test.dart index 640bbc38..aa97cbe1 100644 --- a/packages/signer/test/signer_test.dart +++ b/packages/signer/test/signer_test.dart @@ -57,50 +57,6 @@ void main() { expect(isVerified, isFalse); }); - test('Test sign and verify using seed', () async { - final seed = Uint8List.fromList([ - 108, - 29, - 148, - 202, - 167, - 191, - 10, - 13, - 126, - 240, - 152, - 60, - 24, - 35, - 233, - 172, - 106, - 190, - 213, - 114, - 33, - 213, - 125, - 9, - 34, - 101, - 67, - 82, - 216, - 92, - 177, - 228 - ]); - await signer.fromSeed(seed, KPType.ed25519); - - final data = 'dummyData'; - final signature = signer.sign(data); - - final isVerified = signer.verify(signature, data); - expect(isVerified, isTrue); - }); - test('Test with invalid seed', () async { final invalidSeed = Uint8List.fromList([ 108, @@ -112,17 +68,6 @@ void main() { throwsException); }); - test('Test sign and verify with hex seed', () async { - signer.fromHexSeed( - '0x6c1d94caa7bf0a0d7ef0983c1823e9ac6abed57221d57d0922654352d85cb1e4', - KPType.sr25519); - final data = 'dummyData'; - final signature = await signer.sign(data); - - final isVerified = await signer.verify(signature, data); - expect(isVerified, isTrue); - }); - test('Test sign with invalid hex seed', () async { expect(() async => signer.fromHexSeed('0x6c1', KPType.ed25519), throwsException); From 45132506701a45a318b8a1730f86fab370666f9c Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Wed, 17 Apr 2024 14:07:29 +0200 Subject: [PATCH 11/17] add kvStore module --- .dart_tool/package_config.json | 54 ++++++++------ packages/signer/pubspec.lock | 74 ++++++++++--------- .../tfchain_client/bin/tfchain_client.dart | 16 ++-- .../tfchain_client/lib/models/kvstore.dart | 15 ++++ packages/tfchain_client/lib/src/client.dart | 4 +- packages/tfchain_client/lib/src/kvstore.dart | 40 ++++++++++ .../tfchain_client/lib/tfchain_client.dart | 1 + pubspec.lock | 70 ++++++++++-------- 8 files changed, 178 insertions(+), 96 deletions(-) create mode 100644 packages/tfchain_client/lib/models/kvstore.dart create mode 100644 packages/tfchain_client/lib/src/kvstore.dart diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 13a52f2f..a2abf910 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -27,9 +27,9 @@ }, { "name": "args", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/args-2.4.2", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/args-2.5.0", "packageUri": "lib/", - "languageVersion": "2.19" + "languageVersion": "3.0" }, { "name": "async", @@ -69,7 +69,7 @@ }, { "name": "built_value", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/built_value-8.9.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/built_value-8.9.2", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -165,9 +165,9 @@ }, { "name": "ffi", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/ffi-2.1.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/ffi-2.1.2", "packageUri": "lib/", - "languageVersion": "3.0" + "languageVersion": "3.3" }, { "name": "file", @@ -189,9 +189,9 @@ }, { "name": "frontend_server_client", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/frontend_server_client-3.2.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/frontend_server_client-4.0.0", "packageUri": "lib/", - "languageVersion": "2.12" + "languageVersion": "3.0" }, { "name": "glob", @@ -219,9 +219,9 @@ }, { "name": "http", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/http-1.2.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/http-1.2.1", "packageUri": "lib/", - "languageVersion": "3.2" + "languageVersion": "3.3" }, { "name": "http_multi_server", @@ -297,7 +297,7 @@ }, { "name": "meta", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/meta-1.12.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/meta-1.14.0", "packageUri": "lib/", "languageVersion": "2.12" }, @@ -307,6 +307,12 @@ "packageUri": "lib/", "languageVersion": "3.2" }, + { + "name": "moment_dart", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/moment_dart-2.0.2", + "packageUri": "lib/", + "languageVersion": "2.19" + }, { "name": "mustache_template", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/mustache_template-2.0.0", @@ -339,7 +345,7 @@ }, { "name": "pointycastle", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pointycastle-3.7.4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pointycastle-3.8.0", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -549,19 +555,19 @@ }, { "name": "test", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test-1.25.2", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test-1.25.3", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "test_api", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_api-0.7.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_api-0.7.1", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "test_core", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_core-0.6.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/test_core-0.6.1", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -597,15 +603,15 @@ }, { "name": "uuid", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/uuid-4.3.3", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/uuid-4.4.0", "packageUri": "lib/", "languageVersion": "3.0" }, { "name": "vm_service", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/vm_service-14.0.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/vm_service-14.2.0", "packageUri": "lib/", - "languageVersion": "3.0" + "languageVersion": "3.3" }, { "name": "watcher", @@ -615,15 +621,15 @@ }, { "name": "web", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web-0.4.2", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web-0.5.1", "packageUri": "lib/", - "languageVersion": "3.2" + "languageVersion": "3.3" }, { "name": "web_socket_channel", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web_socket_channel-2.4.3", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web_socket_channel-2.4.5", "packageUri": "lib/", - "languageVersion": "3.2" + "languageVersion": "3.3" }, { "name": "webkit_inspection_protocol", @@ -645,7 +651,7 @@ }, { "name": "yaon", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/yaon-1.1.4+4", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/yaon-1.1.4+7", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -656,7 +662,7 @@ "languageVersion": "3.2" } ], - "generated": "2024-03-07T11:33:36.582352Z", + "generated": "2024-04-16T10:54:09.162011Z", "generator": "pub", - "generatorVersion": "3.2.0" + "generatorVersion": "3.3.3" } diff --git a/packages/signer/pubspec.lock b/packages/signer/pubspec.lock index 41c0fb34..251a5f2a 100644 --- a/packages/signer/pubspec.lock +++ b/packages/signer/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "36a321c3d2cbe01cbcb3540a87b8843846e0206df3e691fa7b23e19e78de6d49" + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "65.0.0" + version: "67.0.0" adaptive_number: dependency: transitive description: @@ -21,18 +21,18 @@ packages: dependency: transitive description: name: analyzer - sha256: dfe03b90ec022450e22513b5e5ca1f01c0c01de9c3fba2f7fd233cb57a6b9a07 + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.4.1" args: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: "direct dev" description: name: coverage - sha256: ac86d3abab0f165e4b8f561280ff4e066bceaac83c424dd19f1ae2c2fcd12ca9 + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" url: "https://pub.dev" source: hosted - version: "1.7.1" + version: "1.7.2" crypto: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -165,10 +165,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -237,10 +237,10 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" merlin: dependency: transitive description: @@ -253,18 +253,18 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.14.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" node_preamble: dependency: transitive description: @@ -285,18 +285,18 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" pointycastle: dependency: transitive description: name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333" url: "https://pub.dev" source: hosted - version: "3.7.4" + version: "3.8.0" polkadart_keyring: dependency: "direct main" description: @@ -477,26 +477,26 @@ packages: dependency: "direct dev" description: name: test - sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f + sha256: d87214d19fb311997d8128ec501a980f77cb240ac4e7e219accf452813ff473c url: "https://pub.dev" source: hosted - version: "1.24.9" + version: "1.25.3" test_api: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.1" test_core: dependency: transitive description: name: test_core - sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a + sha256: "2236f70be1e5ab405c675e88c36935a87dad9e05a506b57dd5c0f617f5aebcb2" url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.6.1" typed_data: dependency: transitive description: @@ -517,10 +517,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: a75f83f14ad81d5fe4b3319710b90dec37da0e22612326b696c9e1b8f34bbf48 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.0" watcher: dependency: transitive description: @@ -529,14 +529,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.5" webkit_inspection_protocol: dependency: transitive description: @@ -554,4 +562,4 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" + dart: ">=3.3.0 <4.0.0" diff --git a/packages/tfchain_client/bin/tfchain_client.dart b/packages/tfchain_client/bin/tfchain_client.dart index ece5a78b..23e665f0 100644 --- a/packages/tfchain_client/bin/tfchain_client.dart +++ b/packages/tfchain_client/bin/tfchain_client.dart @@ -2,14 +2,15 @@ import 'dart:io'; import 'package:signer/signer.dart'; import 'package:tfchain_client/models/balances.dart'; +import 'package:tfchain_client/models/kvstore.dart'; import 'package:tfchain_client/models/twins.dart'; import 'package:tfchain_client/tfchain_client.dart'; void main() async { - final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); - await queryClient.connect(); + // final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); + // await queryClient.connect(); - final twin = await queryClient.twins.get(QueryTwinsGetOptions(id: 214)); + // final twin = await queryClient.twins.get(QueryTwinsGetOptions(id: 214)); // final twinId = await queryClient.twins.getTwinIdByAccountId( // QueryTwinsGetTwinByAccountIdOptions(accountId: twin!.accountId)); @@ -21,11 +22,12 @@ void main() async { "wss://tfchain.dev.grid.tf/ws", "secret add bag cluster deposit beach illness letter crouch position rain arctic", "sr25519"); - client.connect(); + await client.connect(); - final extrinsic = await client.clientTwins - .update(TwinOptions(relay: twin!.relay ?? [], pk: twin.pk ?? [])); + // final extrinsic = + // client.kvStrore.set(KVStoreSetOptions(key: "mnemonic", value: "value")); + // await client.apply(extrinsic); + client.kvStrore.list(); - await client.apply(extrinsic); // await client.disconnect(); } diff --git a/packages/tfchain_client/lib/models/kvstore.dart b/packages/tfchain_client/lib/models/kvstore.dart new file mode 100644 index 00000000..ce8f548e --- /dev/null +++ b/packages/tfchain_client/lib/models/kvstore.dart @@ -0,0 +1,15 @@ +class KVStoreSetOptions { + String key; + String value; + + KVStoreSetOptions({ + required this.key, + required this.value, + }); +} + +class KVStoreGetOptions { + String key; + + KVStoreGetOptions({required this.key}); +} diff --git a/packages/tfchain_client/lib/src/client.dart b/packages/tfchain_client/lib/src/client.dart index eb78b1b6..388ae247 100644 --- a/packages/tfchain_client/lib/src/client.dart +++ b/packages/tfchain_client/lib/src/client.dart @@ -54,6 +54,7 @@ class Client extends QueryClient { late final Farms clientFarms; late final Dao.Dao clientDao; late final Twins clientTwins; + late final KVStore kvStrore; final SUPPORTED_KEYPAIR_TYPES = ["sr25519", "ed25519"]; Client(String url, this.mnemonic, this.keypairType) : super(url) { @@ -66,8 +67,8 @@ class Client extends QueryClient { clientFarms = Farms(this); clientDao = Dao.Dao(this); clientTwins = Twins(this); + kvStrore = KVStore(this); signer = Signer.Signer(); - } @override @@ -97,6 +98,7 @@ class Client extends QueryClient { checkInputs(); if (keypairType == "sr25519") { keypair = await signer.fromMnemonic(mnemonic, Signer.KPType.sr25519); + print("ADDRESS ${keypair!.address}"); address = keypair!.address; } else { keypair = await signer.fromMnemonic(mnemonic, Signer.KPType.ed25519); diff --git a/packages/tfchain_client/lib/src/kvstore.dart b/packages/tfchain_client/lib/src/kvstore.dart new file mode 100644 index 00000000..9485f146 --- /dev/null +++ b/packages/tfchain_client/lib/src/kvstore.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; + +import 'package:tfchain_client/generated/dev/dev.dart'; +import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime.dart'; +import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; +import 'package:tfchain_client/models/kvstore.dart'; +import 'package:tfchain_client/tfchain_client.dart'; + +class KVStore { + final Client client; + + KVStore(this.client); + + RuntimeCall set(KVStoreSetOptions options) { + final extrinsic = client.api.tx.tFKVStore + .set(key: options.key.codeUnits, value: options.value.codeUnits); + return extrinsic; + } + + RuntimeCall delete(KVStoreGetOptions options) { + final extrinsic = + client.api.tx.tFKVStore.delete(key: options.key.codeUnits); + return extrinsic; + } + + Future get(KVStoreGetOptions options) async { + final res = await client.api.query.tFKVStore + .tFKVStore(client.keypair!.publicKey.bytes, options.key.codeUnits); + return String.fromCharCodes(res); + } + + void list() async { + // final queries = client.api.query. + // final res = await queries.tFKVStore. + } + + void deleteAll(){ + + } +} diff --git a/packages/tfchain_client/lib/tfchain_client.dart b/packages/tfchain_client/lib/tfchain_client.dart index d720c3a1..0644545e 100644 --- a/packages/tfchain_client/lib/tfchain_client.dart +++ b/packages/tfchain_client/lib/tfchain_client.dart @@ -11,6 +11,7 @@ import 'package:tfchain_client/src/contracts.dart'; import 'package:tfchain_client/generated/dev/dev.dart' as polkadot; import 'package:tfchain_client/src/dao.dart' as Dao; import 'package:tfchain_client/src/farms.dart'; +import 'package:tfchain_client/src/kvstore.dart'; import 'package:tfchain_client/src/nodes.dart'; import 'package:tfchain_client/src/pricing_policies.dart'; import 'package:tfchain_client/src/tft_bridge.dart'; diff --git a/pubspec.lock b/pubspec.lock index 7137e813..d2e2e5a1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,10 +37,10 @@ packages: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: transitive description: @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: built_value - sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.1" + version: "8.9.2" charcode: dependency: transitive description: @@ -221,10 +221,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -253,10 +253,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -293,10 +293,10 @@ packages: dependency: transitive description: name: http - sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" http_multi_server: dependency: transitive description: @@ -397,10 +397,10 @@ packages: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.14.0" mime: dependency: transitive description: @@ -409,6 +409,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + moment_dart: + dependency: transitive + description: + name: moment_dart + sha256: "252e06594ad7d1f1815c18a9112b76451fcee05743667c0566e24b83a078b91d" + url: "https://pub.dev" + source: hosted + version: "2.0.2" mustache_template: dependency: transitive description: @@ -453,10 +461,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333" url: "https://pub.dev" source: hosted - version: "3.7.4" + version: "3.8.0" polkadart: dependency: transitive description: @@ -732,26 +740,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + sha256: d87214d19fb311997d8128ec501a980f77cb240ac4e7e219accf452813ff473c url: "https://pub.dev" source: hosted - version: "1.25.2" + version: "1.25.3" test_api: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.1" test_core: dependency: transitive description: name: test_core - sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + sha256: "2236f70be1e5ab405c675e88c36935a87dad9e05a506b57dd5c0f617f5aebcb2" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" tfchain_client: dependency: "direct main" description: @@ -795,18 +803,18 @@ packages: dependency: transitive description: name: uuid - sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" url: "https://pub.dev" source: hosted - version: "4.3.3" + version: "4.4.0" vm_service: dependency: transitive description: name: vm_service - sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246 + sha256: a75f83f14ad81d5fe4b3319710b90dec37da0e22612326b696c9e1b8f34bbf48 url: "https://pub.dev" source: hosted - version: "14.0.0" + version: "14.2.0" watcher: dependency: transitive description: @@ -819,18 +827,18 @@ packages: dependency: transitive description: name: web - sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.4.2" + version: "0.5.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23" + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.5" webkit_inspection_protocol: dependency: transitive description: @@ -859,9 +867,9 @@ packages: dependency: transitive description: name: yaon - sha256: "9baabf121604d7530fc8bcd4f2aeb6c300a055d9a6f9b45b5071f893756ca867" + sha256: "15909774f728b07066a72b54719d3212cbf58bae80450b8303d810302e68a53c" url: "https://pub.dev" source: hosted - version: "1.1.4+4" + version: "1.1.4+7" sdks: - dart: ">=3.2.0 <4.0.0" + dart: ">=3.3.0 <4.0.0" From e3b05570b878b6b9c605884f144cd53f808af8f6 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Wed, 24 Apr 2024 14:20:49 +0200 Subject: [PATCH 12/17] add listall and delete all for kvStore --- .dart_tool/package_config.json | 2 +- .vscode/settings.json | 2 +- .../tfchain_client/bin/tfchain_client.dart | 2 - packages/tfchain_client/lib/src/client.dart | 5 +- packages/tfchain_client/lib/src/kvstore.dart | 53 +++++++++++++++---- packages/tfchain_client/pubspec.yaml | 1 + 6 files changed, 51 insertions(+), 14 deletions(-) diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index a2abf910..42f00011 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -662,7 +662,7 @@ "languageVersion": "3.2" } ], - "generated": "2024-04-16T10:54:09.162011Z", + "generated": "2024-04-18T09:13:15.973441Z", "generator": "pub", "generatorVersion": "3.3.3" } diff --git a/.vscode/settings.json b/.vscode/settings.json index 2149c563..4ed7c806 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "cSpell.words": ["keypair", "polkadot", "tfchain"] + "cSpell.words": ["keypair", "polkadot", "sublist", "tfchain", "TFKV", "twoxx"] } diff --git a/packages/tfchain_client/bin/tfchain_client.dart b/packages/tfchain_client/bin/tfchain_client.dart index 23e665f0..694a8a6f 100644 --- a/packages/tfchain_client/bin/tfchain_client.dart +++ b/packages/tfchain_client/bin/tfchain_client.dart @@ -24,8 +24,6 @@ void main() async { "sr25519"); await client.connect(); - // final extrinsic = - // client.kvStrore.set(KVStoreSetOptions(key: "mnemonic", value: "value")); // await client.apply(extrinsic); client.kvStrore.list(); diff --git a/packages/tfchain_client/lib/src/client.dart b/packages/tfchain_client/lib/src/client.dart index 388ae247..d67cc6cf 100644 --- a/packages/tfchain_client/lib/src/client.dart +++ b/packages/tfchain_client/lib/src/client.dart @@ -98,7 +98,6 @@ class Client extends QueryClient { checkInputs(); if (keypairType == "sr25519") { keypair = await signer.fromMnemonic(mnemonic, Signer.KPType.sr25519); - print("ADDRESS ${keypair!.address}"); address = keypair!.address; } else { keypair = await signer.fromMnemonic(mnemonic, Signer.KPType.ed25519); @@ -140,6 +139,10 @@ class Client extends QueryClient { final encodedCall = runtimeCall.encode(); final nonce = await api.rpc.system.accountNextIndex(keyring.address); + // await api.rpc.state.queryStorageAt(keys) + // state vs systemApi + // different naming between polkadot vs flutter + // how to make rpc call on state final payloadToSign = SigningPayload( method: encodedCall, specVersion: specVersion, diff --git a/packages/tfchain_client/lib/src/kvstore.dart b/packages/tfchain_client/lib/src/kvstore.dart index 9485f146..11b2a63b 100644 --- a/packages/tfchain_client/lib/src/kvstore.dart +++ b/packages/tfchain_client/lib/src/kvstore.dart @@ -1,7 +1,5 @@ -import 'dart:convert'; - -import 'package:tfchain_client/generated/dev/dev.dart'; -import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime.dart'; +import 'dart:typed_data'; +import 'package:polkadart/polkadart.dart'; import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_call.dart'; import 'package:tfchain_client/models/kvstore.dart'; import 'package:tfchain_client/tfchain_client.dart'; @@ -25,16 +23,53 @@ class KVStore { Future get(KVStoreGetOptions options) async { final res = await client.api.query.tFKVStore - .tFKVStore(client.keypair!.publicKey.bytes, options.key.codeUnits); + .tFKVStore(client.keypair!.publicKey.bytes, []); + print(res); return String.fromCharCodes(res); } - void list() async { - // final queries = client.api.query. - // final res = await queries.tFKVStore. + Future> list() async { + final moduleHash = + Hasher.twoxx128.hash(Uint8List.fromList('TFKVStore'.codeUnits)); + + final functionHash = + Hasher.twoxx128.hash(Uint8List.fromList('TFKVStore'.codeUnits)); + + final keyHash = Hasher.blake2b128 + .hash(Uint8List.fromList(client.keypair!.publicKey.bytes)); + + Uint8List partialKey = Uint8List.fromList([ + ...moduleHash, + ...functionHash, + ...keyHash, + ...client.keypair!.publicKey.bytes + ]); + + final keys = await client.api.rpc.state.getKeys(key: partialKey); + + final keysValues = await client.api.rpc.state.queryStorageAt(keys); + + Map keyValueMap = {}; + + for (var change in keysValues[0].changes) { + final key = change.key; + var value = change.value; + + final added = key.sublist(partialKey.length + 17); + + value = value!.sublist(1); + keyValueMap[String.fromCharCodes(added)] = String.fromCharCodes(value); + } + + return keyValueMap; } - void deleteAll(){ + void deleteAll() async { + Map keys = await list(); + for (String key in keys.keys) { + final extrinsic = delete(KVStoreGetOptions(key: key)); + await client.apply(extrinsic); + } } } diff --git a/packages/tfchain_client/pubspec.yaml b/packages/tfchain_client/pubspec.yaml index eb3698eb..6e3d0b05 100644 --- a/packages/tfchain_client/pubspec.yaml +++ b/packages/tfchain_client/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: moment_dart: ^2.0.2 signer: path: ../signer + hashlib: ^1.13.1 dev_dependencies: lints: ^3.0.0 From 8a95e65d3d4def0815c856366047fec5b816b61f Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Wed, 6 Mar 2024 17:19:14 +0200 Subject: [PATCH 13/17] add rmb client --- .dart_tool/package_config.json | 18 +-- melos.yaml | 2 +- .../tfchain_client/bin/tfchain_client.dart | 133 +++++++++++++++++- packages/tfchain_client/pubspec.yaml | 4 - pubspec.lock | 11 +- pubspec.yaml | 4 +- 6 files changed, 147 insertions(+), 25 deletions(-) diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 42f00011..0f8b903f 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -434,16 +434,10 @@ "languageVersion": "3.0" }, { - "name": "ristretto255", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/ristretto255-1.0.2", + "name": "rmb_client", + "rootUri": "../packages/rmb_client", "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "secp256k1_ecdsa", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/secp256k1_ecdsa-0.4.0", - "packageUri": "lib/", - "languageVersion": "3.0" + "languageVersion": "3.2" }, { "name": "shelf", @@ -627,9 +621,9 @@ }, { "name": "web_socket_channel", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web_socket_channel-2.4.5", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web_socket_channel-2.4.3", "packageUri": "lib/", - "languageVersion": "3.3" + "languageVersion": "3.2" }, { "name": "webkit_inspection_protocol", @@ -662,7 +656,7 @@ "languageVersion": "3.2" } ], - "generated": "2024-04-18T09:13:15.973441Z", + "generated": "2024-01-10T13:39:16.827881Z", "generator": "pub", "generatorVersion": "3.3.3" } diff --git a/melos.yaml b/melos.yaml index dec8d848..32708026 100644 --- a/melos.yaml +++ b/melos.yaml @@ -1,6 +1,6 @@ name: tfgrid_sdk_dart_monorepo packages: - - packages/** + - ./packages/rmb_client - ./packages/signer - ./packages/tfchain_client diff --git a/packages/tfchain_client/bin/tfchain_client.dart b/packages/tfchain_client/bin/tfchain_client.dart index 694a8a6f..ab8049fe 100644 --- a/packages/tfchain_client/bin/tfchain_client.dart +++ b/packages/tfchain_client/bin/tfchain_client.dart @@ -10,11 +10,136 @@ void main() async { // final queryClient = QueryClient("wss://tfchain.dev.grid.tf/ws"); // await queryClient.connect(); - // final twin = await queryClient.twins.get(QueryTwinsGetOptions(id: 214)); + // QueryBalances Module + final signer = Signer(); + await signer.fromMnemonic( + 'picnic flip cigar rival risk scatter slide aware trust garlic solution token'); + final pair = await signer + .keypairFromAddress("5CoYEiMb2ePY4cAW7f18HM7rozePwtQ8Ny5yKx8qYUGWxdgi"); + final balance = + await queryClient.balances.get(publicKey: pair.publicKey.bytes); + print(balance!.toJson()); - // final twinId = await queryClient.twins.getTwinIdByAccountId( - // QueryTwinsGetTwinByAccountIdOptions(accountId: twin!.accountId)); - // print(twinId); + print("=================="); + + // // QueryContracts Module + // final contract = + // await queryClient.contracts.get(contractId: BigInt.from(49130)); + // print(contract!.toJson()); + + // print("=================="); + + // final contractId = + // await queryClient.contracts.getContractIdByActiveRentForNode(nodeId: 85); + // print(contractId); + + // print("=================="); + + // final activeContracts = + // await queryClient.contracts.getActiveContracts(nodeId: 85); + // print(activeContracts); + + // print("=================="); + + // final id = await queryClient.contracts + // .getContractIdByNodeIdAndHash(nodeId: 11, hash: [ + // 53, + // 50, + // 57, + // 102, + // 53, + // 99, + // 50, + // 55, + // 97, + // 50, + // 99, + // 97, + // 51, + // 50, + // 48, + // 49, + // 48, + // 97, + // 98, + // 102, + // 102, + // 102, + // 49, + // 52, + // 100, + // 56, + // 54, + // 51, + // 52, + // 102, + // 53, + // 51 + // ]); + // print(id); + + // print("=================="); + + // final contractLock = + // await queryClient.contracts.contractLock(id: BigInt.from(49130)); + // print(contractLock!.toJson()); + + // print("=================="); + + // // Farms Module + // final farm = await queryClient.farms.get(id: 115); + // print(farm!.toJson()); + + // print("=================="); + + // // Nodes Module + // final node = await queryClient.nodes.get(id: 85); + // print(node!.toJson()); + + // print("=================="); + + // // Twins Module + // final twin = await queryClient.twins.get(id: 214); + // print(twin!.toJson()); + + // print("=================="); + + final twinId = await queryClient.twins.getTwinIdByAccountId(accountId: [ + 12, + 58, + 221, + 236, + 167, + 151, + 69, + 84, + 126, + 190, + 116, + 100, + 140, + 251, + 60, + 149, + 249, + 60, + 238, + 70, + 203, + 93, + 75, + 150, + 70, + 130, + 0, + 28, + 253, + 137, + 178, + 63 + ]); + + print(twinId); // await queryClient.disconnect(); diff --git a/packages/tfchain_client/pubspec.yaml b/packages/tfchain_client/pubspec.yaml index 6e3d0b05..95aecde2 100644 --- a/packages/tfchain_client/pubspec.yaml +++ b/packages/tfchain_client/pubspec.yaml @@ -13,10 +13,6 @@ dependencies: hex: ^0.2.0 bip39: ^1.0.6 convert: ^3.1.1 - moment_dart: ^2.0.2 - signer: - path: ../signer - hashlib: ^1.13.1 dev_dependencies: lints: ^3.0.0 diff --git a/pubspec.lock b/pubspec.lock index d2e2e5a1..511c5613 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -593,6 +593,13 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0" + rmb_client: + dependency: "direct main" + description: + path: "packages/rmb_client" + relative: true + source: path + version: "1.0.0" shelf: dependency: transitive description: @@ -835,10 +842,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.3" webkit_inspection_protocol: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2a35fb9c..d329abc8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,8 +12,8 @@ dev_dependencies: dependencies: coverage: ^1.7.1 - melos: ^4.1.0 - signer: + melos: ^3.2.0 + signer: path: ./packages/signer substrate_bip39: ^0.4.0 tfchain_client: From f91f6ea7d8614e7a6de0300b612509dbd947fc63 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Sat, 1 Jun 2024 20:48:37 +0300 Subject: [PATCH 14/17] fix conflicts --- .dart_tool/package_config.json | 41 +++++++++++++++--------- packages/rmb_client/lib/rmb_client.dart | 1 + packages/rmb_client/lib/src/client.dart | 23 ++++++++------ packages/rmb_client/lib/src/sign.dart | 10 ++++-- packages/rmb_client/pubspec.yaml | 4 +-- packages/tfchain_client/pubspec.yaml | 3 ++ pubspec.lock | 42 ++++++++++++------------- 7 files changed, 74 insertions(+), 50 deletions(-) diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 0f8b903f..da0ba300 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -171,9 +171,9 @@ }, { "name": "file", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/file-7.0.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/file-6.1.4", "packageUri": "lib/", - "languageVersion": "3.0" + "languageVersion": "2.12" }, { "name": "fixnum", @@ -219,9 +219,9 @@ }, { "name": "http", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/http-1.2.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/http-1.2.0", "packageUri": "lib/", - "languageVersion": "3.3" + "languageVersion": "3.2" }, { "name": "http_multi_server", @@ -285,9 +285,9 @@ }, { "name": "melos", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/melos-4.1.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/melos-3.4.0", "packageUri": "lib/", - "languageVersion": "3.0" + "languageVersion": "2.18" }, { "name": "merlin", @@ -309,7 +309,7 @@ }, { "name": "moment_dart", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/moment_dart-2.0.2", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/moment_dart-2.1.0", "packageUri": "lib/", "languageVersion": "2.19" }, @@ -381,9 +381,9 @@ }, { "name": "process", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/process-5.0.2", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/process-4.2.4", "packageUri": "lib/", - "languageVersion": "3.0" + "languageVersion": "2.14" }, { "name": "prompts", @@ -405,7 +405,7 @@ }, { "name": "pub_updater", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pub_updater-0.4.0", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/pub_updater-0.3.1", "packageUri": "lib/", "languageVersion": "3.0" }, @@ -433,12 +433,24 @@ "packageUri": "lib/", "languageVersion": "3.0" }, + { + "name": "ristretto255", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/ristretto255-1.0.2", + "packageUri": "lib/", + "languageVersion": "3.0" + }, { "name": "rmb_client", "rootUri": "../packages/rmb_client", "packageUri": "lib/", "languageVersion": "3.2" }, + { + "name": "secp256k1_ecdsa", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/secp256k1_ecdsa-0.4.0", + "packageUri": "lib/", + "languageVersion": "3.0" + }, { "name": "shelf", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/shelf-1.4.1", @@ -615,9 +627,9 @@ }, { "name": "web", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web-0.5.1", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/web-0.4.2", "packageUri": "lib/", - "languageVersion": "3.3" + "languageVersion": "3.2" }, { "name": "web_socket_channel", @@ -656,7 +668,8 @@ "languageVersion": "3.2" } ], - "generated": "2024-01-10T13:39:16.827881Z", + "generated": "2024-06-01T17:42:48.645343Z", "generator": "pub", - "generatorVersion": "3.3.3" + "generatorVersion": "3.4.0", + "pubCache": "file:///home/alaa/.pub-cache" } diff --git a/packages/rmb_client/lib/rmb_client.dart b/packages/rmb_client/lib/rmb_client.dart index 0f6a7dac..724484ce 100644 --- a/packages/rmb_client/lib/rmb_client.dart +++ b/packages/rmb_client/lib/rmb_client.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:polkadart_keyring/polkadart_keyring.dart'; import 'package:rmb_client/src/sign.dart'; +import 'package:tfchain_client/models/twins.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:tfchain_client/tfchain_client.dart' as TFClient; diff --git a/packages/rmb_client/lib/src/client.dart b/packages/rmb_client/lib/src/client.dart index b33c4928..fd9f9e11 100644 --- a/packages/rmb_client/lib/src/client.dart +++ b/packages/rmb_client/lib/src/client.dart @@ -1,7 +1,5 @@ part of "../rmb_client.dart"; -// TODO: How to import tfchain_client ?? - class Client { KeyPair? signer; String relayUrl; @@ -12,6 +10,7 @@ class Client { WebSocketChannel? channel; int? retries; TFClient.QueryClient? client; + String keypairType; var connections = new Map(); Client( @@ -20,7 +19,7 @@ class Client { this.mnemonic, this.session, { this.retries = 5, - required String keypairType, + required this.keypairType, }) { final key = '${relayUrl}:${mnemonic}:${keypairType}'; if (connections.containsKey(key)) { @@ -28,10 +27,6 @@ class Client { // return connections[key] as Client; } - if (keypairType != "ed25519") { - throw ArgumentError("Unsupported Keypair type"); - } - client = TFClient.QueryClient(chainUrl); client?.connect(); } @@ -51,9 +46,13 @@ class Client { print("connected to relay "); print(signer!.address); - twin = await client?.twins - .getTwinIdByAccountId(accountId: signer!.publicKey.bytes); + twin = await client?.twins.getTwinIdByAccountId( + QueryTwinsGetTwinByAccountIdOptions( + accountId: signer!.publicKey.bytes)); print(twin); + if (twin == 0) { + throw "Couldn't find a user for the provided mnemonic on this network."; + } await channel!.ready; } catch (e) { @@ -79,7 +78,11 @@ class Client { String jwt = '${base64Url.encode(utf8.encode(jsonEncode(header)))}.${base64Url.encode(utf8.encode(jsonEncode(claims)))}'; - signer = await KeyPair.fromMnemonic(mnemonic); + if (keypairType == KPType.ed25519) { + signer = await KeyPair.ed25519.fromMnemonic(mnemonic); + } else if (keypairType == KPType.sr25519) { + signer = await KeyPair.sr25519.fromMnemonic(mnemonic); + } Uint8List sigPrefixed = sign(Uint8List.fromList(jwt.codeUnits), signer!); String token = '$jwt.${base64Url.encode(sigPrefixed)}'; diff --git a/packages/rmb_client/lib/src/sign.dart b/packages/rmb_client/lib/src/sign.dart index 83288741..c0c71460 100644 --- a/packages/rmb_client/lib/src/sign.dart +++ b/packages/rmb_client/lib/src/sign.dart @@ -4,7 +4,7 @@ import 'dart:typed_data'; import 'package:polkadart_keyring/polkadart_keyring.dart'; class KPType { - static const sr25519 = "sr25519"; //not supported + static const sr25519 = "sr25519"; static const ed25519 = "ed25519"; } @@ -14,8 +14,12 @@ Uint8List sign(Uint8List payload, KeyPair signer) { final newPayload = Uint8List.fromList(payload.sublist(0, payload.length - 1)); // String resultString = String.fromCharCodes(newPayload); - - String typePrefix = "e"; + String typePrefix = ""; + if (signer.keyPairType.toString() == KPType.ed25519) { + typePrefix = "e"; + } else if (signer.keyPairType.toString() == KPType.sr25519) { + typePrefix = "s"; + } final sig = signer.sign(newPayload); diff --git a/packages/rmb_client/pubspec.yaml b/packages/rmb_client/pubspec.yaml index a8d7f040..995fe8d9 100644 --- a/packages/rmb_client/pubspec.yaml +++ b/packages/rmb_client/pubspec.yaml @@ -10,12 +10,12 @@ environment: # Add regular dependencies here. dependencies: fixnum: ^1.1.0 - polkadart_keyring: ^0.2.1 + polkadart_keyring: ^0.4.3 protobuf: ^3.1.0 web_socket_channel: ^2.4.1 tfchain_client: path: ../tfchain_client dev_dependencies: - lints: ^2.1.0 + lints: ^4.0.0 test: ^1.24.0 diff --git a/packages/tfchain_client/pubspec.yaml b/packages/tfchain_client/pubspec.yaml index 95aecde2..e3eb4734 100644 --- a/packages/tfchain_client/pubspec.yaml +++ b/packages/tfchain_client/pubspec.yaml @@ -13,6 +13,9 @@ dependencies: hex: ^0.2.0 bip39: ^1.0.6 convert: ^3.1.1 + moment_dart: ^2.1.0 + signer: + path: ../signer dev_dependencies: lints: ^3.0.0 diff --git a/pubspec.lock b/pubspec.lock index 511c5613..a32cec9a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -229,10 +229,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "6.1.4" fixnum: dependency: transitive description: @@ -293,10 +293,10 @@ packages: dependency: transitive description: name: http - sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.0" http_multi_server: dependency: transitive description: @@ -381,10 +381,10 @@ packages: dependency: "direct main" description: name: melos - sha256: "7266e9fc9fee5f4a0c075e5cec375c00736dfc944358f533b740b93b3d8d681e" + sha256: "96e64bbade5712c3f010137e195bca9f1b351fac34ab1f322af492ae34032067" url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "3.4.0" merlin: dependency: transitive description: @@ -413,10 +413,10 @@ packages: dependency: transitive description: name: moment_dart - sha256: "252e06594ad7d1f1815c18a9112b76451fcee05743667c0566e24b83a078b91d" + sha256: e8683f46ea80dbe47bb0f9f684253630f6a09faa5f626869e1f31bdcf14f6b91 url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.1.0" mustache_template: dependency: transitive description: @@ -509,10 +509,10 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "4.2.4" prompts: dependency: transitive description: @@ -541,10 +541,10 @@ packages: dependency: transitive description: name: pub_updater - sha256: "54e8dc865349059ebe7f163d6acce7c89eb958b8047e6d6e80ce93b13d7c9e60" + sha256: b06600619c8c219065a548f8f7c192b3e080beff95488ed692780f48f69c0625 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.3.1" pubspec: dependency: transitive description: @@ -585,6 +585,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + rmb_client: + dependency: "direct main" + description: + path: "packages/rmb_client" + relative: true + source: path + version: "1.0.0" secp256k1_ecdsa: dependency: transitive description: @@ -593,13 +600,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0" - rmb_client: - dependency: "direct main" - description: - path: "packages/rmb_client" - relative: true - source: path - version: "1.0.0" shelf: dependency: transitive description: @@ -834,10 +834,10 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.4.2" web_socket_channel: dependency: transitive description: From ab9bab6f8dac7e68ec706f9763cc3fb9dc1c7730 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Tue, 25 Jun 2024 16:33:03 +0300 Subject: [PATCH 15/17] rmb connection creation && send, read requests --- packages/rmb_client/bin/rmb_client.dart | 23 +- packages/rmb_client/lib/rmb_client.dart | 12 + packages/rmb_client/lib/src/client.dart | 359 ++++++++++++++++-- packages/rmb_client/lib/src/envelope.dart | 267 +++++++++++++ packages/rmb_client/lib/src/sign.dart | 160 +++++++- packages/rmb_client/lib/src/utils.dart | 62 +++ .../lib/types/generated/types.pb.dart | 8 + .../lib/types/generated/types.pbjson.dart | 5 +- packages/rmb_client/lib/types/types.proto | 1 + packages/rmb_client/pubspec.yaml | 10 + 10 files changed, 855 insertions(+), 52 deletions(-) create mode 100644 packages/rmb_client/lib/src/utils.dart diff --git a/packages/rmb_client/bin/rmb_client.dart b/packages/rmb_client/bin/rmb_client.dart index 7d73f3cc..8bb9b7bb 100644 --- a/packages/rmb_client/bin/rmb_client.dart +++ b/packages/rmb_client/bin/rmb_client.dart @@ -1,15 +1,28 @@ +import 'dart:io'; + import 'package:rmb_client/rmb_client.dart'; void main() async { final client = Client( - "wss://relay.dev.grid.tf", - "wss://tfchain.dev.grid.tf/ws", - "picnic flip cigar rival risk scatter slide aware trust garlic solution token", - "session", + relayUrl: "wss://relay.dev.grid.tf/", + chainUrl: "wss://tfchain.dev.grid.tf/ws", + mnemonic: + "valid end trumpet hunt produce close hire virus fee rebel gentle claim", + session: "testclient", retries: 3, - keypairType: "ed25519"); + keypairType: "sr25519"); await client.connect(); + // final ID = await client.send("zos.statistics.get", "{}", 17, 5, 3); + + final ID = + await client.send("twinserver.balance.getMyBalance", "{}", 7845, 5, 3); + + // sleep(Duration(seconds: 20)); + + // await client.read(ID!); + + // await client.send("requestCommand", "requestData", 17, 5, 0); // client.closeConnection(); } diff --git a/packages/rmb_client/lib/rmb_client.dart b/packages/rmb_client/lib/rmb_client.dart index 724484ce..f1b21f79 100644 --- a/packages/rmb_client/lib/rmb_client.dart +++ b/packages/rmb_client/lib/rmb_client.dart @@ -2,11 +2,23 @@ library rmb_client; import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'dart:typed_data'; +import 'package:fixnum/fixnum.dart'; import 'package:polkadart_keyring/polkadart_keyring.dart'; +import 'package:rmb_client/src/envelope.dart'; import 'package:rmb_client/src/sign.dart'; +import 'package:rmb_client/src/utils.dart'; +import 'package:rmb_client/types/generated/types.pbserver.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_collective/raw_origin.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_tfgrid/types/twin.dart'; +import 'package:tfchain_client/generated/dev/types/tfchain_runtime/runtime_event.dart'; import 'package:tfchain_client/models/twins.dart'; +import 'package:uuid/uuid.dart'; +import 'package:web_socket_channel/status.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:tfchain_client/tfchain_client.dart' as TFClient; +import 'package:async_locks/async_locks.dart'; +import 'dart:async'; part 'src/client.dart'; diff --git a/packages/rmb_client/lib/src/client.dart b/packages/rmb_client/lib/src/client.dart index fd9f9e11..9c3e8886 100644 --- a/packages/rmb_client/lib/src/client.dart +++ b/packages/rmb_client/lib/src/client.dart @@ -1,63 +1,182 @@ part of "../rmb_client.dart"; +class TwinsMap { + Twin twin; + int timestamp; + + TwinsMap(this.twin, this.timestamp); + @override + String toString() { + return 'TwinsMap(twin: ${twin.id}, timestamp: $timestamp)'; + } +} + class Client { + static final Map _connections = {}; + static final connectingLock = Lock(); KeyPair? signer; + Address source = Address(); + static final Map responses = {}; + WebSocket? socket; + Twin? twin; + Twin? destTwin; + TFClient.QueryClient? tfClient; + Map? twins; String relayUrl; String chainUrl; String mnemonic; String session; - int? twin; - WebSocketChannel? channel; int? retries; - TFClient.QueryClient? client; String keypairType; - var connections = new Map(); + Timer? pingTimer; - Client( + Client._internal( this.relayUrl, this.chainUrl, this.mnemonic, this.session, { this.retries = 5, required this.keypairType, + this.twins, }) { - final key = '${relayUrl}:${mnemonic}:${keypairType}'; - if (connections.containsKey(key)) { - // TODO: how to return from constructor ?? - // return connections[key] as Client; + tfClient = TFClient.QueryClient(chainUrl); + } + + factory Client({ + required String relayUrl, + required String chainUrl, + required String mnemonic, + required String session, + int retries = 5, + required String keypairType, + Map? twins, + }) { + final key = '$relayUrl:$mnemonic:$keypairType'; + if (_connections.containsKey(key)) { + return _connections[key]!; + } + + if (keypairType != KPType.ed25519 && keypairType != KPType.sr25519) { + throw UnsupportedError('Unsupported Keypair type'); } - client = TFClient.QueryClient(chainUrl); - client?.connect(); + final newClient = Client._internal( + relayUrl, + chainUrl, + mnemonic, + session, + retries: retries, + keypairType: keypairType, + twins: twins, + ); + + _connections[key] = newClient; + return newClient; } - Future connect() async { - // if (channel != null) { - // print("Already connected to relay."); - // return; - // } - final jwt = await newJWT(this.session); - String resultString = jwt.replaceAll('=', ''); + Future createConnection() async { + if (socket != null && socket!.closeCode == WebSocket.closed) { + await socket!.close(); + } + + try { + final wsUrl = await updateUrl(); + + if (!wsUrl.startsWith('ws://') && !wsUrl.startsWith('wss://')) { + throw Exception('Invalid WebSocket URL: $wsUrl'); + } + + try { + socket = await WebSocket.connect(wsUrl); + if (socket!.readyState == WebSocket.open) { + socket!.listen((message) async { + print("HELLO FROM Listening to response"); + + final recievedEnvelope = Envelope.fromBuffer(message); + print("Envelope Received: ${recievedEnvelope.hasResponse()}"); + + final castedEnvelope = ClientEnvelope( + envelope: recievedEnvelope, + chainUrl: chainUrl, + tfClient: tfClient!, + twins: twins!); + + if (responses.containsKey(recievedEnvelope.uid)) { + responses[recievedEnvelope.uid] = castedEnvelope; + print("update envelope in responses map"); + // TODO: + await read(recievedEnvelope.uid); + } + }); + } else { + print( + 'Error: Could not open connection (readyState: ${socket!.readyState})'); + } + } catch (error) { + throw Exception("Unable to start connection $error"); + } + } catch (error) { + throw Exception('Unable to create websocket connection due to $error'); + } + } + Future waitForOpenConnection() { + final completer = Completer(); + const maxNumberOfAttempts = 20; + const intervalTime = Duration(milliseconds: 500); + + var currentAttempt = 0; + Timer? timer; + + timer = Timer.periodic(intervalTime, (timer) { + if (currentAttempt > maxNumberOfAttempts - 1) { + timer.cancel(); + completer.completeError( + throw Exception("Maximum number of attempts exceeded")); + } else if (socket != null) { + timer.cancel(); + completer.complete(); + } + currentAttempt++; + }); + + return completer.future; + } + + Future connect() async { try { - final wsUrl = Uri.parse('${relayUrl}?$resultString'); - print(wsUrl); - channel = WebSocketChannel.connect(wsUrl); - print("connected to relay "); + await Client.connectingLock.acquire(); + if (socket != null && socket!.closeCode == WebSocket.closed) { + print("Already Connected!"); + return; + } - print(signer!.address); - twin = await client?.twins.getTwinIdByAccountId( + tfClient?.connect(); + await createSigner(); + + final twinId = await tfClient?.twins.getTwinIdByAccountId( QueryTwinsGetTwinByAccountIdOptions( accountId: signer!.publicKey.bytes)); - print(twin); - if (twin == 0) { + if (twinId == 0) { throw "Couldn't find a user for the provided mnemonic on this network."; } - - await channel!.ready; + twin = await tfClient?.twins.get(QueryTwinsGetOptions(id: twinId!)); + twins ??= {}; + twins![twin!.id.hashCode] = TwinsMap( + twin!, (DateTime.now().millisecondsSinceEpoch / 1000).round()); + try { + updateSource(); + await createConnection(); + } catch (error) { + throw Exception( + "Unable to establish connection with rmb relay: $error"); + } } catch (e) { - print("Error Connecting on relay : $e"); + throw Exception("Error Connecting on relay : $e"); } + // finally { + // connectingLock.release(); + // } } Future newJWT(String session) async { @@ -69,7 +188,7 @@ class Client { int now = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000; // TODO: TwinId should bs passed from params Map claims = { - 'sub': 5261, + 'sub': 7858, 'iat': now, 'exp': now + 1000, 'sid': session, @@ -78,21 +197,183 @@ class Client { String jwt = '${base64Url.encode(utf8.encode(jsonEncode(header)))}.${base64Url.encode(utf8.encode(jsonEncode(claims)))}'; - if (keypairType == KPType.ed25519) { - signer = await KeyPair.ed25519.fromMnemonic(mnemonic); - } else if (keypairType == KPType.sr25519) { - signer = await KeyPair.sr25519.fromMnemonic(mnemonic); - } - Uint8List sigPrefixed = sign(Uint8List.fromList(jwt.codeUnits), signer!); String token = '$jwt.${base64Url.encode(sigPrefixed)}'; return token; } - void closeConnection() { - if (channel != null) { - channel!.sink.close(); + void updateSource() { + source.twin = twin!.id; + source.connection = session; + } + + Future ping() async { + try { + var uuid = Uuid(); + + final pingEnvelope = Envelope( + uid: uuid.v4(), + timestamp: + Int64((DateTime.now().microsecondsSinceEpoch / 1000).round()), + expiration: Int64(40), + source: source, + ping: Ping()); + + pingEnvelope.destination = Address(); + + final clientEnvelope = ClientEnvelope( + signer: signer, + envelope: pingEnvelope, + chainUrl: chainUrl, + tfClient: tfClient!, + twins: twins!); + + var retriesCount = 0; + while (socket!.readyState != WebSocket.open && retries! >= retriesCount) { + try { + await waitForOpenConnection(); + } catch (error) { + if (retries == retriesCount) { + throw Exception( + 'Failed to open connection after $retriesCount retries.'); + } + await createConnection(); + } + } + + responses[clientEnvelope.uid] = clientEnvelope; + socket!.add(clientEnvelope.envelope.writeToBuffer()); + return clientEnvelope.uid; + } catch (error) { + throw Exception('Unable to send due to $error'); + } + } + + Future send(String requestCommand, var requestData, + int destinationTwinId, int expirationMinutes, int? retries) async { + try { + var uuid = Uuid(); + destTwin = await getTwin(destinationTwinId, twins!, tfClient!); + + // create new envelope with given data and destination + final envelope = Envelope( + uid: uuid.v4(), + timestamp: + Int64((DateTime.now().microsecondsSinceEpoch / 1000).round()), + expiration: Int64(expirationMinutes * 60), + source: source); + envelope.destination = Address(twin: destTwin?.id); + if (requestCommand.isNotEmpty) { + envelope.request = Request(command: requestCommand); + } + final clientEnvelope = ClientEnvelope( + signer: signer, + envelope: envelope, + chainUrl: chainUrl, + tfClient: tfClient!, + twins: twins!); + + var retriesCount = 0; + if (requestData != null && requestData.toString().isNotEmpty) { + clientEnvelope.plain = Uint8List.fromList(utf8.encode(requestData)); + } else { + clientEnvelope.plain = Uint8List(0); + } + + // TODO: this cause stackoverflow + // clientEnvelope.relays = + // twin!.relay?.map((i) => i.toString()).toList() ?? []; + + // print("HEllo after ading relays"); + // print('Relays added to client envelope: ${clientEnvelope.relays}'); + + if (signer != null) { + print("Is It signed ???"); + clientEnvelope.signature = clientEnvelope.signEnvelope(); + } + responses[clientEnvelope.uid] = clientEnvelope; + + try { + if (socket!.readyState == WebSocket.open) { + socket!.add(clientEnvelope.envelope.writeToBuffer()); + print('Message sent successfully.'); + } else { + print("Error: WebSocket connection not open."); + } + } catch (error) { + throw Exception("Couldn't send envelope to RMB. $error"); + } + + return clientEnvelope.uid; + } catch (error) { + throw Exception("Unable to send msg to RMB dut to $error"); + } + } + + Future read(String requestID) async { + var envelope = responses[requestID]; + final now = DateTime.now().millisecondsSinceEpoch; + while (envelope != null && + DateTime.now().millisecondsSinceEpoch < + now + envelope.expiration!.toInt() * 1000) { + envelope = responses[requestID]; + + if (envelope != null && envelope.envelope.hasResponse()) { + print("Let's verify envelope"); + bool verified = await envelope.verify(); + if (verified) { + print("ENVELOPE PLAIN ${envelope.envelope.hasPlain()}"); + print("ENVELOPE Cipher ${envelope.envelope.hasCipher()}"); + + if (envelope.envelope.hasPlain()) { + final dataReceived = envelope.plain!; + if (dataReceived.isNotEmpty) { + try { + final decodedData = utf8.decode(dataReceived); + final parsedResponse = jsonDecode(decodedData); + responses.remove(requestID); + print("Parsed Response $parsedResponse"); + } catch (error) { + print('Error processing data: $error'); + rethrow; + } + } + } else if (envelope.envelope.hasCipher()) { + print(String.fromCharCodes(twin!.pk as Iterable)); + final decryptedCipher = await envelope.decrypt(mnemonic); + } + } else if (!verified) { + print("Not Verified"); + responses.remove(requestID); + throw Exception("Invalid signature, discarding response"); + } + } + + if (envelope != null && envelope.envelope.hasError()) { + throw Exception("ENVELOPE ERROR: ${envelope.error!.message}"); + } } } + + Future createSigner() async { + if (keypairType == KPType.ed25519) { + signer = await KeyPair.ed25519.fromMnemonic(mnemonic); + } else if (keypairType == KPType.sr25519) { + signer = await KeyPair.sr25519.fromMnemonic(mnemonic); + } else { + throw UnsupportedError('Unsupported Keypair type'); + } + } + + // void closeConnection() { + // if (channel != null) { + // channel!.sink.close(); + // } + // } + + Future updateUrl() async { + final token = await newJWT(session); + return '$relayUrl?$token'; + } } diff --git a/packages/rmb_client/lib/src/envelope.dart b/packages/rmb_client/lib/src/envelope.dart index e69de29b..1351905d 100644 --- a/packages/rmb_client/lib/src/envelope.dart +++ b/packages/rmb_client/lib/src/envelope.dart @@ -0,0 +1,267 @@ +import 'dart:io'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:bip39/bip39.dart'; +import 'package:crypto/crypto.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:fixnum/fixnum.dart'; +import 'package:pointycastle/export.dart'; +import 'package:polkadart_keyring/polkadart_keyring.dart'; +import 'package:rmb_client/rmb_client.dart'; +import 'package:rmb_client/src/sign.dart'; +import 'package:rmb_client/src/utils.dart'; +import 'package:rmb_client/types/generated/types.pb.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_tfgrid/types/entity.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_tfgrid/types/twin.dart'; +import 'package:tfchain_client/tfchain_client.dart' + as TFClient; // Adjust this import based on your project structure +import 'package:crypto/crypto.dart' as Crypto; +import 'dart:convert'; // For utf8.encode +import 'package:convert/convert.dart'; +import 'package:ss58/ss58.dart' as SS58; + +class ClientEnvelope { + late final Envelope envelope; + late KeyPair signer; + late final String chainUrl; + Twin? twin; + late final TFClient.QueryClient tfClient; + late final Map twins; + + ClientEnvelope({ + KeyPair? signer, + required Envelope envelope, + required this.chainUrl, + required this.tfClient, + required this.twins, + }) : envelope = envelope { + if (signer != null) { + this.signer = signer; + } + envelope.schema = "application/json"; + } + + String? get uid => envelope.uid; + String? get tags => envelope.tags; + Int64? get timestamp => envelope.timestamp; + Int64? get expiration => envelope.expiration; + Address? get source => envelope.source; + Address? get destination => envelope.destination; + Request? get request => envelope.request; + Response? get response => envelope.response; + List? get signature => envelope.signature; + String? get schema => envelope.schema; + String? get federation => envelope.federation; + Error? get error => envelope.error; + List? get plain => envelope.plain; + List? get cipher => envelope.cipher; + Ping? get ping => envelope.ping; + Pong? get pong => envelope.pong; + List? get relays => envelope.relays; + + set signature(List? value) { + envelope.signature = value!; + } + + set plain(List? value) { + envelope.plain = value!; + } + + set relays(List? value) { + relays = value; + } + + Uint8List signEnvelope() { + final toSign = challenge(); + return sign(toSign, signer); + } + + Future getSigner(KeyPairType type) async { + try { + // final keyring = Keyring(); + // final address = keyring.encodeAddress(twin!.accountId); + // print("Address $address"); + // // KeyPair.sr25519. + // //5CJrCjZvsudNoJApTGG5PKcZfhAzAyGqgSK8bysoCV2oRBMC + + // final x = SS58.Address.decode(address); + + // // signer = keyring. + // print(signer.address); + // print(signer.keyPairType); + + signer = await KeyPair.sr25519.fromMnemonic( + "example athlete word glove believe result relief click local motion team any"); + + sleep(Duration(seconds: 20)); + print("ADDRESS: ${signer.address}"); + } catch (e) { + print("Error retrieving signer: $e"); + } + } + + Uint8List createNonce(int size) { + Random random = Random(); + List randArr = + List.generate(size, (index) => (random.nextDouble() * 10).toInt()); + return Uint8List.fromList(randArr); + } + + Uint8List challenge() { + var sink = AccumulatorSink(); + var md5Hasher = md5.startChunkedConversion(sink); + + md5Hasher.add(utf8.encode(uid!)); + + md5Hasher.add(utf8.encode(tags!)); + + md5Hasher.add(utf8.encode('$timestamp')); + + md5Hasher.add(utf8.encode('$expiration')); + + md5Hasher.add(utf8.encode(challengeAddress(envelope.source))); + + md5Hasher.add(utf8.encode(challengeAddress(envelope.destination))); + + if (request != null) { + md5Hasher = challengeRequest(request!, md5Hasher); + } else if (response != null) { + md5Hasher = challengeResponse(response!, md5Hasher); + } else if (error != null) { + md5Hasher = challengeError(error!, md5Hasher); + } + if (schema!.isNotEmpty) { + md5Hasher.add(utf8.encode(schema!)); + } + + if (federation!.isEmpty) { + md5Hasher.add(utf8.encode(federation!)); + } + if (plain!.isNotEmpty) { + final plainHex = hex.encode(plain!); + md5Hasher.add(hex.decode(plainHex)); + } else if (cipher!.isNotEmpty) { + final plainHex = hex.encode(cipher!); + md5Hasher.add(hex.decode(plainHex)); + } + + if (relays!.isNotEmpty) { + for (String relay in relays!) { + md5Hasher.add(utf8.encode(relay)); + } + } + + md5Hasher.close(); + Crypto.Digest updatedHash = sink.events.single; + + return Uint8List.fromList(updatedHash.bytes); + } + + String challengeAddress(Address address) { + return '${address.twin}${address.connection}'; + } + + ByteConversionSink challengeRequest( + Request request, ByteConversionSink md5Hasher) { + md5Hasher.add(utf8.encode(request.command)); + return md5Hasher; + } + + ByteConversionSink challengeError(Error err, ByteConversionSink md5Hasher) { + md5Hasher.add(utf8.encode('${error!.code}${error!.message}')); + return md5Hasher; + } + + ByteConversionSink challengeResponse( + Response response, ByteConversionSink md5Hasher) { + return md5Hasher; + } + + Future encrypt( + dynamic requestData, String mnemonic, String destTwinPk) async { + final publicKey = Uint8List.fromList(hexStringToArrayBuffer(destTwinPk)); + } + + Future decrypt(String mnemonic) async { + final publicKey = Uint8List.fromList(twin!.pk!); + final sharedKey = await createShared(publicKey, mnemonic); + final iv = cipher!.sublist(0, 12); + final slicedData = cipher!.sublist(12); + + // Create AES-GCM encrypter + final key = Key(sharedKey); + final initializationVector = IV(Uint8List.fromList(iv)); + final decrypter = Encrypter(AES(key, mode: AESMode.gcm)); + final decrypted = decrypter.decryptBytes( + Encrypted(Uint8List.fromList(slicedData)), + iv: initializationVector, + ); + + final decryptedText = utf8.decode(decrypted); + print("DECRYPTED TEXT"); + print(decryptedText); + } + + Future verify() async { + try { + String sig = String.fromCharCodes(signature!); + + final prefix = sig.substring(0, 1); + KeyPairType? sigType; + + if (prefix == 'e') { + sigType = KeyPairType.ed25519; + } else if (prefix == 's') { + sigType = KeyPairType.sr25519; + } else { + return false; + } + + print(sigType); + + // get twin of sender from twinid + twin = await getTwin(source!.twin, twins, tfClient); + print(twin!.id); + // print(signer.address); + await getSigner(sigType); + // print(signer.address); + final dataHashed = challenge(); + try { + signer.verify(Uint8List.fromList(dataHashed), + Uint8List.fromList(signature!.sublist(1))); + } catch (error) { + throw Exception(error); + } + return signer.verify( + dataHashed, Uint8List.fromList(signature!.sublist(1))); + } catch (error) { + print("Invalid Destination Twin: $error"); + return false; + } + } + + Future createShared( + Uint8List pubKey, String hexSeedOrMnemonic) async { + List privateKey; + + if (hexSeedOrMnemonic.length == 66) { + privateKey = + Uint8List.fromList((hexSeedOrMnemonic.substring(2).codeUnits)); + } else if (hexSeedOrMnemonic.length == 64) { + privateKey = Uint8List.fromList(hexSeedOrMnemonic.codeUnits); + } else if (validateMnemonic(hexSeedOrMnemonic)) { + final seed = mnemonicToSeed(hexSeedOrMnemonic); + privateKey = seed.sublist(0, 32); + } else { + throw Exception( + 'Expected a valid mnemonic or hexSeed in "createShared" but got: $hexSeedOrMnemonic.'); + } + + final pointX = + await getSharedSecret(Uint8List.fromList(privateKey), pubKey); + final sha256Digest = SHA256Digest(); + return sha256Digest.process(Uint8List.fromList(pointX).sublist(1, 33)); + } +} diff --git a/packages/rmb_client/lib/src/sign.dart b/packages/rmb_client/lib/src/sign.dart index c0c71460..f72973fc 100644 --- a/packages/rmb_client/lib/src/sign.dart +++ b/packages/rmb_client/lib/src/sign.dart @@ -1,27 +1,31 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:polkadart_keyring/polkadart_keyring.dart'; +import 'package:convert/convert.dart'; +import 'package:pointycastle/ecc/ecc_fp.dart'; +import 'package:pointycastle/export.dart'; +import 'package:polkadart_keyring/polkadart_keyring.dart' show KeyPair; +import 'package:cryptography/cryptography.dart' as crypto; +import 'package:pointycastle/ecc/api.dart' as api; class KPType { static const sr25519 = "sr25519"; static const ed25519 = "ed25519"; } -// payload can be either string or unit8list, here only ed25519 is supported Uint8List sign(Uint8List payload, KeyPair signer) { // remove last element from payload list - final newPayload = Uint8List.fromList(payload.sublist(0, payload.length - 1)); + // final newPayload = Uint8List.fromList(payload.sublist(0, payload.length - 1)); // String resultString = String.fromCharCodes(newPayload); String typePrefix = ""; - if (signer.keyPairType.toString() == KPType.ed25519) { + if (signer.keyPairType.name == KPType.ed25519) { typePrefix = "e"; - } else if (signer.keyPairType.toString() == KPType.sr25519) { + } else if (signer.keyPairType.name == KPType.sr25519) { typePrefix = "s"; } - final sig = signer.sign(newPayload); + final sig = signer.sign(payload); Uint8List uint8List = Uint8List.fromList(utf8.encode(typePrefix)); @@ -31,3 +35,147 @@ Uint8List sign(Uint8List payload, KeyPair signer) { return sigPrefixed; } + +bool isProbPub(Uint8List item) { + return item.length == 33 || item.length == 65; +} + +Uint8List _bigIntToUint8List(BigInt number) { + var _byteArray = number.toRadixString(16).padLeft(64, '0'); + return Uint8List.fromList(hex.decode(_byteArray)); +} + +BigInt _uint8ListToBigInt(Uint8List uint8List) { + return BigInt.parse(hex.encode(uint8List), radix: 16); +} + +// ECPrivateKey normalizePrivateKey(Uint8List privateKey) { +// final d = BigInt.parse(hex.encode(privateKey), radix: 16); +// final params = ECDomainParameters('secp256r1'); +// return ECPrivateKey(d, params); +// } + +// ECPublicKey normalizePublicKey(Uint8List publicKey, api.ECCurve curve) { +// final q = curve.decodePoint(publicKey); +// if (q == null) { +// throw ArgumentError('Invalid public key'); +// } +// final params = ECDomainParameters('secp256r1'); +// return ECPublicKey(q, params); +// } + +/// Normalize scalar value. +// BigInt normalizeScalar(BigInt scalar) { +// final domainParams = ECCurve_secp256r1(); +// final curveOrder = domainParams.n; +// if (scalar >= BigInt.zero && scalar < curveOrder) { +// return scalar; +// } else { +// return scalar % curveOrder; +// } +// } + +/// Perform point multiplication on an elliptic curve. +// api.ECPoint multiply(BigInt scalar, api.ECPoint affinePoint, +// {bool useEndomorphism = false}) { +// final n = normalizeScalar(scalar); +// api.ECPoint point, fake; + +// if (useEndomorphism) { +// final splitScalars = splitScalarEndo(n); +// final k1 = splitScalars['k1']!; +// final k2 = splitScalars['k2']!; +// final k1p = affinePoint * k1; +// final k2p = affinePoint * k2; + +// point = k1p + k2p; +// } else { +// point = affinePoint * n; +// } + +// return point.normalize(); +// } + +Future> getSharedSecret(Uint8List privateA, Uint8List publicB) async { + try { + print('Starting getSharedSecret function'); + // final curve = ECCurve_secp256r1(); + // final domainParams = ECDomainParameters('secp256r1'); + + // if (!isProbPub(privateA)) { + // throw ArgumentError('getSharedSecret: first arg must be private key'); + // } + // if (!isProbPub(publicB)) { + // throw ArgumentError('getSharedSecret: second arg must be public key'); + // } + + // final normalizedPrivateA = normalizePrivateKey(privateA); + // final normalizedPublicB = normalizePublicKey(publicB, domainParams.curve); + + // // Multiply the keys + // final sharedSecret = normalizedPublicB * normalizedPrivateA.d; + + // return toRawBytes(sharedSecret, isCompressed); + // final sharedSecret = normalizedPublicB * normalizedPrivateA.d; + + // return toRawBytes(sharedSecret, isCompressed); + + final params = ECCurve_secp256r1(); + final curve = params.curve; + print('Curve and parameters initialized'); + + // Create private key parameters + final dA = _uint8ListToBigInt(privateA); + final privateKey = ECPrivateKey(dA, params); + print('Private key created'); + + print('Public key (hex): ${hex.encode(publicB)}'); + print('Public key length: ${publicB.length}'); + + final Q = curve.decodePoint(publicB); + if (Q == null) { + throw ArgumentError('Failed to decode public key'); + } + print('Public key decoded'); + final publicKeyParams = ECPublicKey(Q, params); + + final keyAgreement = ECDHBasicAgreement(); + keyAgreement.init(privateKey); + + final sharedSecret = keyAgreement.calculateAgreement(publicKeyParams); + print('Shared secret calculated'); + + final sharedSecretBytes = _bigIntToUint8List(sharedSecret); + print('Shared Secret (hex): ${hex.encode(sharedSecretBytes)}'); + return sharedSecretBytes; + } catch (error) { + throw Exception('Error computing shared secret: $error'); + } +} + +// Future> getSharedSecret(Uint8List privateA, Uint8List publicB) async { +// try { +// print('Starting getSharedSecret function'); +// final algorithm = crypto.Ecdh.p256(length: 256); + +// print('Algorithm initialized'); + +// final localKeyPair = crypto.SimpleKeyPairData(privateA, +// publicKey: +// crypto.SimplePublicKey(publicB, type: crypto.KeyPairType.p256), +// type: crypto.KeyPairType.p256); +// print('Local key pair created: $localKeyPair'); + +// final remotePublicKey = +// crypto.SimplePublicKey(publicB, type: crypto.KeyPairType.p256); +// print('Remote public key created: $remotePublicKey'); + +// final sharedSecretKey = await algorithm.sharedSecretKey( +// keyPair: localKeyPair, remotePublicKey: remotePublicKey); +// print('SharedSecretKey computed'); +// final res = await sharedSecretKey.extractBytes(); +// return res; +// } catch (error) { +// throw Exception('Error computing shared secret: $error'); +// } +// } diff --git a/packages/rmb_client/lib/src/utils.dart b/packages/rmb_client/lib/src/utils.dart new file mode 100644 index 00000000..68652fde --- /dev/null +++ b/packages/rmb_client/lib/src/utils.dart @@ -0,0 +1,62 @@ +import 'dart:typed_data'; + +import 'package:rmb_client/rmb_client.dart'; +import 'package:tfchain_client/generated/dev/types/pallet_tfgrid/types/twin.dart'; +import 'package:tfchain_client/models/twins.dart'; +import 'package:tfchain_client/tfchain_client.dart' as TFClient; + +Future getTwin( + int id, Map twins, TFClient.QueryClient tfclient) async { + TwinsMap? mappedTwin = twins[id]; + bool isValid = false; + + if (mappedTwin != null) { + DateTime timestamp = + DateTime.fromMillisecondsSinceEpoch(mappedTwin.timestamp * 1000); + DateTime validTime = DateTime.now().subtract(Duration(minutes: 10)); + isValid = timestamp.isAfter(validTime); + } + + Twin? twin; + if (mappedTwin != null && isValid) { + twin = mappedTwin.twin; + } else { + twin = await tfclient.twins.get(QueryTwinsGetOptions(id: id)); + twins[id] = + TwinsMap(twin!, (DateTime.now().millisecondsSinceEpoch / 1000).round()); + } + + return twin; +} + +Uint8List hexStringToArrayBuffer(String hexString) { + // remove the leading 0x + hexString = hexString.replaceFirst(RegExp(r'^0x'), ''); + + // ensure even number of characters + if (hexString.length % 2 != 0) { + print("WARNING: expecting an even number of characters in the hexString"); + } + + // check for some non-hex characters + final bad = RegExp(r'[^0-9A-Fa-f]').allMatches(hexString); + if (bad.isNotEmpty) { + print("WARNING: found non-hex characters"); + for (var match in bad) { + print("Non-hex character: ${match.group(0)} at position ${match.start}"); + } + } + + // split the string into pairs of octets + final pairs = RegExp(r'.{1,2}') + .allMatches(hexString) + .map((match) => match.group(0)) + .where((s) => s != null) + .map((s) => s!) + .toList(); + + // convert the octets to integers + final integers = pairs.map((s) => int.parse(s, radix: 16)).toList(); + + return Uint8List.fromList(integers); +} diff --git a/packages/rmb_client/lib/types/generated/types.pb.dart b/packages/rmb_client/lib/types/generated/types.pb.dart index 57e0ec1d..b7618558 100644 --- a/packages/rmb_client/lib/types/generated/types.pb.dart +++ b/packages/rmb_client/lib/types/generated/types.pb.dart @@ -335,6 +335,7 @@ class Envelope extends $pb.GeneratedMessage { $core.List<$core.int>? cipher, Ping? ping, Pong? pong, + $core.Iterable<$core.String>? relays, }) { final $result = create(); if (uid != null) { @@ -385,6 +386,9 @@ class Envelope extends $pb.GeneratedMessage { if (pong != null) { $result.pong = pong; } + if (relays != null) { + $result.relays.addAll(relays); + } return $result; } Envelope._() : super(); @@ -423,6 +427,7 @@ class Envelope extends $pb.GeneratedMessage { ..a<$core.List<$core.int>>(14, _omitFieldNames ? '' : 'cipher', $pb.PbFieldType.OY) ..aOM(15, _omitFieldNames ? '' : 'ping', subBuilder: Ping.create) ..aOM(16, _omitFieldNames ? '' : 'pong', subBuilder: Pong.create) + ..pPS(17, _omitFieldNames ? '' : 'relays') ..hasRequiredFields = false ; @@ -623,6 +628,9 @@ class Envelope extends $pb.GeneratedMessage { void clearPong() => clearField(16); @$pb.TagNumber(16) Pong ensurePong() => $_ensure(15); + + @$pb.TagNumber(17) + $core.List<$core.String> get relays => $_getList(16); } diff --git a/packages/rmb_client/lib/types/generated/types.pbjson.dart b/packages/rmb_client/lib/types/generated/types.pbjson.dart index a988d01d..9ff46a27 100644 --- a/packages/rmb_client/lib/types/generated/types.pbjson.dart +++ b/packages/rmb_client/lib/types/generated/types.pbjson.dart @@ -109,6 +109,7 @@ const Envelope$json = { {'1': 'federation', '3': 11, '4': 1, '5': 9, '9': 5, '10': 'federation', '17': true}, {'1': 'plain', '3': 13, '4': 1, '5': 12, '9': 1, '10': 'plain'}, {'1': 'cipher', '3': 14, '4': 1, '5': 12, '9': 1, '10': 'cipher'}, + {'1': 'relays', '3': 17, '4': 3, '5': 9, '10': 'relays'}, ], '8': [ {'1': 'message'}, @@ -131,6 +132,6 @@ final $typed_data.Uint8List envelopeDescriptor = $convert.base64Decode( 'EhsKBHBvbmcYECABKAsyBS5Qb25nSABSBHBvbmcSIQoJc2lnbmF0dXJlGAkgASgMSANSCXNpZ2' '5hdHVyZYgBARIbCgZzY2hlbWEYCiABKAlIBFIGc2NoZW1hiAEBEiMKCmZlZGVyYXRpb24YCyAB' 'KAlIBVIKZmVkZXJhdGlvbogBARIWCgVwbGFpbhgNIAEoDEgBUgVwbGFpbhIYCgZjaXBoZXIYDi' - 'ABKAxIAVIGY2lwaGVyQgkKB21lc3NhZ2VCCQoHcGF5bG9hZEIHCgVfdGFnc0IMCgpfc2lnbmF0' - 'dXJlQgkKB19zY2hlbWFCDQoLX2ZlZGVyYXRpb24='); + 'ABKAxIAVIGY2lwaGVyEhYKBnJlbGF5cxgRIAMoCVIGcmVsYXlzQgkKB21lc3NhZ2VCCQoHcGF5' + 'bG9hZEIHCgVfdGFnc0IMCgpfc2lnbmF0dXJlQgkKB19zY2hlbWFCDQoLX2ZlZGVyYXRpb24='); diff --git a/packages/rmb_client/lib/types/types.proto b/packages/rmb_client/lib/types/types.proto index 429bc500..9c59cbce 100644 --- a/packages/rmb_client/lib/types/types.proto +++ b/packages/rmb_client/lib/types/types.proto @@ -74,4 +74,5 @@ message Envelope { bytes plain = 13; bytes cipher = 14; } + repeated string relays = 17; } \ No newline at end of file diff --git a/packages/rmb_client/pubspec.yaml b/packages/rmb_client/pubspec.yaml index 995fe8d9..c3a511d8 100644 --- a/packages/rmb_client/pubspec.yaml +++ b/packages/rmb_client/pubspec.yaml @@ -15,6 +15,16 @@ dependencies: web_socket_channel: ^2.4.1 tfchain_client: path: ../tfchain_client + uuid: ^4.4.0 + async_locks: ^4.0.0 + crypto: ^3.0.3 + convert: ^3.1.1 + secp256k1: ^0.3.0 + pointycastle: ^3.9.1 + cryptography: ^2.7.0 + ss58: ^1.1.2 + encrypt: ^5.0.3 + bip39: ^1.0.6 dev_dependencies: lints: ^4.0.0 From 29806aca642bbee196d8eee90f697fae0d348025 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Tue, 25 Jun 2024 16:33:27 +0300 Subject: [PATCH 16/17] rmb connection creation && send, read requests --- .dart_tool/package_config.json | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 68b9274f..f877f1bf 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -205,6 +205,12 @@ "packageUri": "lib/", "languageVersion": "2.18" }, + { + "name": "hashlib", + "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/hashlib-1.16.0", + "packageUri": "lib/", + "languageVersion": "2.14" + }, { "name": "hashlib_codecs", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/hashlib_codecs-2.2.0", @@ -295,12 +301,6 @@ "packageUri": "lib/", "languageVersion": "3.1" }, - { - "name": "merlin", - "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/merlin-1.0.3", - "packageUri": "lib/", - "languageVersion": "3.1" - }, { "name": "meta", "rootUri": "file:///home/alaa/.pub-cache/hosted/pub.dev/meta-1.14.0", @@ -674,7 +674,8 @@ "languageVersion": "3.2" } ], - "generated": "2024-04-18T09:13:15.973441Z", + "generated": "2024-06-02T07:16:24.662504Z", "generator": "pub", - "generatorVersion": "3.3.3" + "generatorVersion": "3.4.0", + "pubCache": "file:///home/alaa/.pub-cache" } From 2795629951874726432ac21f39de956ddefe2bf2 Mon Sep 17 00:00:00 2001 From: AlaaElattar Date: Tue, 25 Jun 2024 16:33:34 +0300 Subject: [PATCH 17/17] rmb connection creation && send, read requests --- pubspec.lock | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pubspec.lock b/pubspec.lock index d2e2e5a1..c6aa1174 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -273,6 +273,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + hashlib: + dependency: transitive + description: + name: hashlib + sha256: "67e640e19cc33070113acab3125cd48ebe480a0300e15554dec089b8878a729f" + url: "https://pub.dev" + source: hosted + version: "1.16.0" hashlib_codecs: dependency: transitive description: @@ -585,6 +593,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + rmb_client: + dependency: "direct main" + description: + path: "packages/rmb_client" + relative: true + source: path + version: "1.0.0" secp256k1_ecdsa: dependency: transitive description: