Skip to content
Snippets Groups Projects
Commit c4b3926c authored by vjrj's avatar vjrj
Browse files

More work with WOT

parent d564a938
No related branches found
No related tags found
No related merge requests found
import '../../ui/ui_helpers.dart';
import 'contact.dart'; import 'contact.dart';
import 'identity_status.dart';
class ContactWotInfo { class ContactWotInfo {
ContactWotInfo({ ContactWotInfo({
...@@ -11,16 +11,10 @@ class ContactWotInfo { ...@@ -11,16 +11,10 @@ class ContactWotInfo {
final Contact you; final Contact you;
bool? canCert; bool? canCert;
bool? canCreateIdty; bool? canCreateIdty;
bool? waitingForCerts;
bool get isMe { @override
return me.pubKey == you.pubKey; String toString() {
} return 'ContactWotInfo{me: ${humanizeContact('', me)}, you: ${humanizeContact('', you)}, canCert: $canCert, canCreateIdty: $canCreateIdty}, waitingForCert: $waitingForCerts}';
bool get isMember {
return you.status == IdentityStatus.MEMBER;
}
bool get iAmMember {
return me.status == IdentityStatus.MEMBER;
} }
} }
...@@ -514,3 +514,126 @@ Uri parseNodeUrl(String url) { ...@@ -514,3 +514,126 @@ Uri parseNodeUrl(String url) {
final Uri parsedUri = Uri.parse(url); final Uri parsedUri = Uri.parse(url);
return parsedUri; return parsedUri;
} }
Future<String> requestDistanceEvaluation(int idtyIndex,
{Duration timeout = defPolkadotTimeout}) async {
final CesiumWallet walletV1 = await SharedPreferencesHelper().getWallet();
final KeyPair wallet = KeyPair.ed25519.fromSeed(walletV1.seed);
final Completer<String> result = Completer<String>();
return executeOnNodes<String>(
(Node node, Provider provider, Gdev gdev) async {
// distance rule has been evaluated positively locally on web of trust at block storage.distance.evaluationBlock()
// TODO(vjrj): Implement this
// gdev.query.distance.evaluationBlock();
final RuntimeCall call =
gdev.tx.distance.requestDistanceEvaluationFor(target: idtyIndex);
return signAndSend(gdev, wallet, call, provider, result, timeout);
});
}
Future<String> signAndSend(Gdev polkadot, KeyPair wallet, RuntimeCall call,
Provider provider, Completer<String> result, Duration timeout) async {
final RuntimeVersion runtimeVersion =
await polkadot.rpc.state.getRuntimeVersion();
final int currentBlockNumber = (await polkadot.query.system.number()) - 1;
final H256 currentBlockHash =
await polkadot.query.system.blockHash(currentBlockNumber);
final int nonce = await polkadot.rpc.system.accountNextIndex(wallet.address);
final H256 genesisHash = await polkadot.query.system.blockHash(0);
final Uint8List encodedCall = call.encode();
final Uint8List payload = SigningPayload(
method: encodedCall,
specVersion: runtimeVersion.specVersion,
transactionVersion: runtimeVersion.transactionVersion,
genesisHash: encodeHex(genesisHash),
blockHash: encodeHex(currentBlockHash),
blockNumber: currentBlockNumber,
eraPeriod: 64,
nonce: nonce,
tip: 0)
.encode(polkadot.registry);
final Uint8List signature = wallet.sign(payload);
final Uint8List extrinsic = ExtrinsicPayload(
signer: wallet.bytes(),
method: encodedCall,
signature: signature,
eraPeriod: 64,
blockNumber: currentBlockNumber,
nonce: nonce,
tip: 0)
.encode(polkadot.registry, SignatureType.ed25519);
final AuthorApi<Provider> author = AuthorApi<Provider>(provider);
await author.submitAndWatchExtrinsic(extrinsic, (ExtrinsicStatus status) {
switch (status.type) {
case 'finalized':
result.complete('');
break;
case 'dropped':
result.complete(tr('op_dropped'));
break;
case 'invalid':
result.complete(tr('op_invalid'));
break;
case 'usurped':
result.complete(tr('op_usurped'));
break;
case 'future':
break;
case 'ready':
break;
case 'inBlock':
break;
case 'broadcast':
break;
default:
result.complete('Unexpected transaction status: ${status.type}.');
loggerDev('Unexpected transaction status: ${status.type}.');
break;
}
}).timeout(timeout);
return result.future;
}
Future<String> createIdentity(
{required Contact you, Duration timeout = defPolkadotTimeout}) async {
final List<Node> nodes = NodeManager().getBestNodes(NodeType.endpoint);
nodes.shuffle();
final CesiumWallet walletV1 = await SharedPreferencesHelper().getWallet();
final KeyPair wallet = KeyPair.ed25519.fromSeed(walletV1.seed);
final Completer<String> result = Completer<String>();
return executeOnNodes((Node node, Provider provider, Gdev polkadot) async {
final RuntimeCall call = polkadot.tx.identity.createIdentity(
ownerKey: Address.decode(you.address).pubkey,
);
return signAndSend(polkadot, wallet, call, provider, result, timeout);
});
}
Future<String> confirmIdentity(String identityName,
{Duration timeout = defPolkadotTimeout}) async {
final List<Node> nodes = NodeManager().getBestNodes(NodeType.endpoint);
nodes.shuffle();
final CesiumWallet walletV1 = await SharedPreferencesHelper().getWallet();
final KeyPair wallet = KeyPair.ed25519.fromSeed(walletV1.seed);
final Completer<String> result = Completer<String>();
return executeOnNodes((Node node, Provider provider, Gdev polkadot) async {
final RuntimeCall call =
polkadot.tx.identity.confirmIdentity(idtyName: identityName.codeUnits);
return signAndSend(polkadot, wallet, call, provider, result, timeout);
});
}
Constants gdevConstants() {
final Provider provider =
Provider.fromUri(parseNodeUrl(NodeManager().endpointNodes.first.url));
final Gdev gdev = Gdev(provider);
return gdev.constant;
}
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'package:durt/durt.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:polkadart/apis/apis.dart';
import 'package:polkadart/extrinsic/extrinsic_payload.dart';
import 'package:polkadart/extrinsic/signature_type.dart';
import 'package:polkadart/extrinsic/signing_payload.dart';
import 'package:polkadart/primitives/primitives.dart';
import 'package:polkadart/provider.dart';
import 'package:polkadart/scale_codec.dart';
import 'package:polkadart_keyring/polkadart_keyring.dart';
import 'package:ss58/ss58.dart';
import '../data/models/contact.dart';
import '../data/models/contact_wot_info.dart'; import '../data/models/contact_wot_info.dart';
import '../data/models/identity_status.dart'; import '../data/models/identity_status.dart';
import '../data/models/menu_action.dart'; import '../data/models/menu_action.dart';
import '../data/models/node.dart';
import '../data/models/node_manager.dart';
import '../data/models/node_type.dart';
import '../generated/gdev/gdev.dart';
import '../generated/gdev/types/gdev_runtime/runtime_call.dart';
import '../generated/gdev/types/primitive_types/h256.dart';
import '../shared_prefs_helper.dart';
import '../ui/logger.dart'; import '../ui/logger.dart';
import 'g1_helper.dart'; import '../ui/ui_helpers.dart';
import 'g1_v2_helper_others.dart'; import 'g1_v2_helper_others.dart';
Future<String> requestDistanceEvaluation(int idtyIndex,
{Duration timeout = defPolkadotTimeout}) async {
final CesiumWallet walletV1 = await SharedPreferencesHelper().getWallet();
final KeyPair wallet = KeyPair.ed25519.fromSeed(walletV1.seed);
final Completer<String> result = Completer<String>();
return executeOnNodes<String>(
(Node node, Provider provider, Gdev gdev) async {
// distance rule has been evaluated positively locally on web of trust at block storage.distance.evaluationBlock()
// TODO(vjrj): Implement this
// gdev.query.distance.evaluationBlock();
final RuntimeCall call =
gdev.tx.distance.requestDistanceEvaluationFor(target: idtyIndex);
return signAndSend(gdev, wallet, call, provider, result, timeout);
});
}
Future<String> signAndSend(Gdev polkadot, KeyPair wallet, RuntimeCall call,
Provider provider, Completer<String> result, Duration timeout) async {
final RuntimeVersion runtimeVersion =
await polkadot.rpc.state.getRuntimeVersion();
final int currentBlockNumber = (await polkadot.query.system.number()) - 1;
final H256 currentBlockHash =
await polkadot.query.system.blockHash(currentBlockNumber);
final int nonce = await polkadot.rpc.system.accountNextIndex(wallet.address);
final H256 genesisHash = await polkadot.query.system.blockHash(0);
final Uint8List encodedCall = call.encode();
final Uint8List payload = SigningPayload(
method: encodedCall,
specVersion: runtimeVersion.specVersion,
transactionVersion: runtimeVersion.transactionVersion,
genesisHash: encodeHex(genesisHash),
blockHash: encodeHex(currentBlockHash),
blockNumber: currentBlockNumber,
eraPeriod: 64,
nonce: nonce,
tip: 0)
.encode(polkadot.registry);
final Uint8List signature = wallet.sign(payload);
final Uint8List extrinsic = ExtrinsicPayload(
signer: wallet.bytes(),
method: encodedCall,
signature: signature,
eraPeriod: 64,
blockNumber: currentBlockNumber,
nonce: nonce,
tip: 0)
.encode(polkadot.registry, SignatureType.ed25519);
final AuthorApi<Provider> author = AuthorApi<Provider>(provider);
await author.submitAndWatchExtrinsic(extrinsic, (ExtrinsicStatus status) {
switch (status.type) {
case 'finalized':
result.complete('');
break;
case 'dropped':
result.complete(tr('op_dropped'));
break;
case 'invalid':
result.complete(tr('op_invalid'));
break;
case 'usurped':
result.complete(tr('op_usurped'));
break;
case 'future':
break;
case 'ready':
break;
case 'inBlock':
break;
case 'broadcast':
break;
default:
result.complete('Unexpected transaction status: ${status.type}.');
loggerDev('Unexpected transaction status: ${status.type}.');
break;
}
}).timeout(timeout);
return result.future;
}
Future<String> createIdentity(
{required Contact you, Duration timeout = defPolkadotTimeout}) async {
final List<Node> nodes = NodeManager().getBestNodes(NodeType.endpoint);
nodes.shuffle();
final CesiumWallet walletV1 = await SharedPreferencesHelper().getWallet();
final KeyPair wallet = KeyPair.ed25519.fromSeed(walletV1.seed);
final Completer<String> result = Completer<String>();
return executeOnNodes((Node node, Provider provider, Gdev polkadot) async {
final RuntimeCall call = polkadot.tx.identity.createIdentity(
ownerKey: Address.decode(you.address).pubkey,
);
return signAndSend(polkadot, wallet, call, provider, result, timeout);
});
}
Future<String> confirmIdentity(String identityName,
{Duration timeout = defPolkadotTimeout}) async {
final List<Node> nodes = NodeManager().getBestNodes(NodeType.endpoint);
nodes.shuffle();
final CesiumWallet walletV1 = await SharedPreferencesHelper().getWallet();
final KeyPair wallet = KeyPair.ed25519.fromSeed(walletV1.seed);
final Completer<String> result = Completer<String>();
return executeOnNodes((Node node, Provider provider, Gdev polkadot) async {
final RuntimeCall call =
polkadot.tx.identity.confirmIdentity(idtyName: identityName.codeUnits);
return signAndSend(polkadot, wallet, call, provider, result, timeout);
});
}
List<MenuAction> getWotMenuActions( List<MenuAction> getWotMenuActions(
BuildContext context, bool isMe, ContactWotInfo wotInfo) { BuildContext context, bool isMe, ContactWotInfo wotInfo) {
final List<MenuAction> actions = <MenuAction>[]; final List<MenuAction> actions = <MenuAction>[];
final IdentityStatus? status = wotInfo.you.status; final IdentityStatus? status = wotInfo.you.status;
if (inDevelopment) {
actions.add(
MenuAction(
name: 'isMe: $isMe $wotInfo',
icon: Icons.info,
action: () {
return Future<String>.value('');
},
),
);
}
switch (status) { switch (status) {
case IdentityStatus.MEMBER: case IdentityStatus.MEMBER:
if (isMe) { if (isMe) {
actions.addAll(<MenuAction>[ actions.addAll(<MenuAction>[
MenuAction( MenuAction(
name: 'Renew Membership', name: tr('renew_membership'),
icon: Icons.refresh, icon: Icons.refresh,
action: () { action: () {
loggerDev('Renewing Membership'); loggerDev('Renewing Membership');
...@@ -163,7 +38,7 @@ List<MenuAction> getWotMenuActions( ...@@ -163,7 +38,7 @@ List<MenuAction> getWotMenuActions(
}, },
), ),
MenuAction( MenuAction(
name: 'Revoke Membership', name: tr('revoke_membership'),
icon: Icons.cancel, icon: Icons.cancel,
action: () { action: () {
loggerDev('Revoking Membership'); loggerDev('Revoking Membership');
...@@ -195,20 +70,20 @@ List<MenuAction> getWotMenuActions( ...@@ -195,20 +70,20 @@ List<MenuAction> getWotMenuActions(
if (isMe) { if (isMe) {
actions.add( actions.add(
MenuAction( MenuAction(
name: 'Confirm Identity', name: tr('confirm_identity'),
icon: Icons.verified, icon: Icons.verified,
action: () { action: () {
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
final RegExp validateIdtyName = RegExp(r'^[a-zA-Z0-9_-]{1,42}$'); final RegExp validateIdtyName = RegExp(r'^[a-zA-Z0-9_-]{1,42}$');
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
title: Text('Confirm Identity'), title: Text(tr('confirm_identity')),
content: TextField( content: TextField(
controller: controller, controller: controller,
decoration: InputDecoration(hintText: 'Identity Name'), decoration:
InputDecoration(hintText: tr('identity_name_hint')),
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
...@@ -234,7 +109,7 @@ List<MenuAction> getWotMenuActions( ...@@ -234,7 +109,7 @@ List<MenuAction> getWotMenuActions(
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text(tr('Invalid identity name'))), content: Text(tr('invalid_identity_name'))),
); );
} }
}, },
...@@ -272,7 +147,7 @@ List<MenuAction> getWotMenuActions( ...@@ -272,7 +147,7 @@ List<MenuAction> getWotMenuActions(
void _requestDistanceAction(int? idtyIndex, List<MenuAction> actions) { void _requestDistanceAction(int? idtyIndex, List<MenuAction> actions) {
if (idtyIndex != null) { if (idtyIndex != null) {
actions.add(MenuAction( actions.add(MenuAction(
name: 'Request Distance Evaluation', name: tr('request_distance_evaluation'),
icon: Icons.social_distance, icon: Icons.social_distance,
action: () { action: () {
return requestDistanceEvaluation(idtyIndex); return requestDistanceEvaluation(idtyIndex);
...@@ -284,7 +159,7 @@ void _certAction(ContactWotInfo wotInfo, List<MenuAction> actions) { ...@@ -284,7 +159,7 @@ void _certAction(ContactWotInfo wotInfo, List<MenuAction> actions) {
if (wotInfo.canCert ?? false) { if (wotInfo.canCert ?? false) {
actions.add( actions.add(
MenuAction( MenuAction(
name: 'Certify Member', name: tr('certify'),
icon: Icons.verified, icon: Icons.verified,
action: () { action: () {
loggerDev('Certifying Member'); loggerDev('Certifying Member');
......
...@@ -446,6 +446,14 @@ class _ContactPageState extends State<ContactPage> { ...@@ -446,6 +446,14 @@ class _ContactPageState extends State<ContactPage> {
idtyCertMeta.issuedCount < Constants().maxByIssuer; idtyCertMeta.issuedCount < Constants().maxByIssuer;
wotInfo.canCert = canCert; wotInfo.canCert = canCert;
} }
// Waiting for Certifications
if (you.certsReceived != null &&
you.certsReceived!.isNotEmpty &&
you.certsReceived!.length <
gdevConstants().wot.minCertForMembership) {
wotInfo.waitingForCerts = true;
}
} }
return wotInfo; return wotInfo;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment