Skip to content

Commit

Permalink
Merge pull request #14 from IdentityBlock/implementation/approve-reje…
Browse files Browse the repository at this point in the history
…ct-information-sharing

Closes #13
  • Loading branch information
Ishad-M-I-M authored Nov 12, 2022
2 parents fc0cd1c + b4ca7b5 commit 90b81a5
Show file tree
Hide file tree
Showing 9 changed files with 244 additions and 58 deletions.
Binary file added assets/images/contract-agreement.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions lib/bloc/verify/verify_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';

part 'verify_event.dart';
part 'verify_state.dart';

class VerifyBloc extends Bloc<VerifyEvent, VerifyState> {
VerifyBloc() : super(VerifyInitial()) {
on<VerifyEvent>((event, emit) {
// TODO: implement event handler
});
}
}
4 changes: 4 additions & 0 deletions lib/bloc/verify/verify_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
part of 'verify_bloc.dart';

@immutable
abstract class VerifyEvent {}
6 changes: 6 additions & 0 deletions lib/bloc/verify/verify_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
part of 'verify_bloc.dart';

@immutable
abstract class VerifyState {}

class VerifyInitial extends VerifyState {}
135 changes: 80 additions & 55 deletions lib/pages/qr_result_page.dart
Original file line number Diff line number Diff line change
@@ -1,81 +1,106 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:iblock/services/secure_storage_service.dart';
import 'package:iblock/services/user_contract_service.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';

import './error_page.dart';
import '../widgets/forms/button.dart';

class QRResultPage extends StatelessWidget {
class QRResultPage extends StatefulWidget {
final Barcode result;
const QRResultPage(this.result, {Key? key}) : super(key: key);

@override
State<QRResultPage> createState() => _QRResultPageState();
}

class _QRResultPageState extends State<QRResultPage> {
Map<String, dynamic> processQR(Barcode qr) {
Map<String, dynamic> data = jsonDecode(qr.code!);
return data;
}

@override
Widget build(BuildContext context) {
try{
print((jsonDecode(result.code!) as Map<String, dynamic>)['information']
as List);
try {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text('Requesting Information'),
),
body:
SizedBox(
body: SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: MediaQuery.of(context).size.width > MediaQuery.of(context).size.height? 1:4,
child: SingleChildScrollView(
child: Column(
children: ((jsonDecode(result.code!)
as Map<String, dynamic>)['information']
as List<dynamic>)
.map((e) => Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
e,
style: const TextStyle(fontSize: 14),
child: Column(crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: MediaQuery.of(context).size.width >
MediaQuery.of(context).size.height
? 1
: 4,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
const Expanded(
flex: 1,
child: Text(
"Following service provider request your approval for access your personal information")),
Expanded(
flex: 1,
child: Text(
processQR(widget.result)["verifier-name"],
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20),
),
),
const Expanded(
flex: 3,
child: SizedBox(
width: 300,
child: Image(
image: AssetImage(
'assets/images/contract-agreement.png')),
),
),
],
),
))
.toList(),
),
),
)),
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(2.0),
child: Button(
"Approve",
onPressed: () {},
)),
Padding(
padding: const EdgeInsets.all(2.0),
child: Button(
"Decline",
onPressed: () {},
color: Colors.red,
)),
],
),
)
],
),
)
// Center(
// child: Text(result.code != null ? 'Barcode Type: ${describeEnum(result.format)} Data: ${result.code}': 'No result'),
// ),
),
Expanded(flex: 1,
child: Column(crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(padding: const EdgeInsets.all(2.0),
child: Button("Approve", onPressed: () async{
var data = processQR(widget.result);
var contractService = UserContractService();
var contractAddress = await SecureStorageService.get("contract-address") as String;
var privateKey = await SecureStorageService.get("private-key") as String;
await contractService.verify(data['verifier-contract'], data['token'], contractAddress: contractAddress, privateKey: privateKey);
},)),
Padding(padding: const EdgeInsets.all(2.0),
child: Button("Decline", onPressed: () {
Navigator.popUntil(
context, ModalRoute.withName("/home"));
}, color: Colors.red,)),
],),)
],),)
// Center(
// child: Text(result.code != null ? 'Barcode Type: ${describeEnum(result.format)} Data: ${result.code}': 'No result'),
// ),
),);
} catch(e){
print(e);
return const ErrorPage(
message: "QR code not recognized!",
);
}
catch(e){
return const ErrorPage(message: "QR code not recognized!",);
}

}
}
78 changes: 77 additions & 1 deletion lib/services/user_contract_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ class UserContractService{
params: [],
sender: sender);

web3client.dispose();
return {
'Name': name[0] as String,
'Email': email[0] as String,
Expand All @@ -116,6 +115,83 @@ class UserContractService{
catch(e){
throw Exception("Non authorized access");
}
finally{
web3client.dispose();
}
}

Future<String> _setUserProperty(String setFunctionName, String newValue, {required String contractAddress, required String privateKey}) async {
EthereumAddress contract = EthereumAddress.fromHex(contractAddress);
EthPrivateKey credentials = EthPrivateKey.fromHex(privateKey);

Object abi = await _abiJSON;

DeployedContract smartContract = DeployedContract(ContractAbi.fromJson(jsonEncode(abi), "User"), contract);
ContractFunction setFunction = smartContract.function(setFunctionName);

Web3Client web3client = Web3Client(Config.rpcUrl, http.Client(), socketConnector: (){
return IOWebSocketChannel.connect(Config.wsUrl).cast<String>();
});

try{
var transactionId = await web3client.sendTransaction(credentials, Transaction.callContract(contract: smartContract, function: setFunction, parameters: [newValue]));
return transactionId;
}
catch(e){
throw Exception("Failed due to $e");
}
finally{
web3client.dispose();
}
}

Future<String> setName(String name, {required String contractAddress, required String privateKey}) async{
return _setUserProperty("setName", name, contractAddress: contractAddress, privateKey: privateKey);
}

Future<String> setEmail(String email, {required String contractAddress, required String privateKey}) async{
return _setUserProperty("setEmail", email, contractAddress: contractAddress, privateKey: privateKey);
}

Future<String> setCountry(String country, {required String contractAddress, required String privateKey}) async{
return _setUserProperty("setCountry", country, contractAddress: contractAddress, privateKey: privateKey);
}

Future<String> setMobile(String mobile, {required String contractAddress, required String privateKey}) async{
return _setUserProperty("setMobile", mobile, contractAddress: contractAddress, privateKey: privateKey);
}

Future<String> setGender(String gender, {required String contractAddress, required String privateKey}) async{
return _setUserProperty("setGender", gender, contractAddress: contractAddress, privateKey: privateKey);
}

Future<String> verify(String verifierContractAddress, String token, {required String contractAddress, required String privateKey}) async{
EthereumAddress contract = EthereumAddress.fromHex(contractAddress);
EthereumAddress verifierContract = EthereumAddress.fromHex(verifierContractAddress);
EthPrivateKey credentials = EthPrivateKey.fromHex(privateKey);

Object abi = await _abiJSON;

DeployedContract smartContract = DeployedContract(ContractAbi.fromJson(jsonEncode(abi), "User"), contract);
ContractFunction verifyFunction = smartContract.function("verify");

Web3Client web3client = Web3Client(Config.rpcUrl, http.Client(), socketConnector: (){
return IOWebSocketChannel.connect(Config.wsUrl).cast<String>();
});

try{
var transactionId = await web3client.sendTransaction(
credentials,
Transaction.callContract(contract: smartContract, function: verifyFunction, parameters: [verifierContract, contract, token])
);
return transactionId;
}
catch(e){
throw Exception("Failed due to $e");
}
finally{
web3client.dispose();
}
}

Object getAbiJson() {
Expand Down
4 changes: 2 additions & 2 deletions lib/widgets/qr_scanner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ class _QRScannerState extends State<QRScanner> {
setState(() {
result = scanData;
});
controller.pauseCamera();
Navigator.pushNamed(context, '/qrcode-result', arguments: scanData);
controller.pauseCamera()
.then((value) => Navigator.pushNamed(context, '/qrcode-result', arguments: scanData));
});
}

Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ flutter:
- assets/images/welcome2.png
- assets/images/welcome3.png
- assets/images/error.png
- assets/images/contract-agreement.png
# - images/a_dot_ham.jpeg

# An image asset can refer to one or more resolution-specific "variants", see
Expand Down
59 changes: 59 additions & 0 deletions test/services/user_contract_service_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,63 @@ void main(){
expect(service.getAll("0x949e1fB80027B3D9b7D33767A17a2B4ebfD1Cb73",
"2ffdcdececb76f1c6ff826cbb4c0138cac3f5f2950540a1ff1a0530cd5f5063f"), throwsException);
});

test('Test Setting Name: by the owner', () async{
final service = UserContractService();
await service.setName("test3", privateKey: "0xdb7a1fc3433dbe9d11b53357927dbfc80e3f9d5c211c6c29ce49acca3633dbf3", contractAddress: "0x547fda582EeEc9574BFF8Aa768786C15702AE0fD");

var result = await service.getAll("0x547fda582EeEc9574BFF8Aa768786C15702AE0fD",
"0xdb7a1fc3433dbe9d11b53357927dbfc80e3f9d5c211c6c29ce49acca3633dbf3");

expect(result, {"Name": "test3", "Email": "test@example.com", "Date of Birth": "2000/01/01", "Country": "Sri Lanka", "Phone": "+9412345678", "Gender": "Male"});

});

test('Testing verify function', () async{
final service = UserContractService();
String transactionId = await service.verify("0x1Ff8Ebe435cdD925EE58388c78a6b21f650247B6", "12345", privateKey: "0xdb7a1fc3433dbe9d11b53357927dbfc80e3f9d5c211c6c29ce49acca3633dbf3", contractAddress: "0x547fda582EeEc9574BFF8Aa768786C15702AE0fD");
expect(transactionId, startsWith("0x"));
});

group('User contract functons', (){
final service = UserContractService();
late final String privateKey;
late final String contractAddress;
test('Testing deployment of user contract', () async{

var result = await service.deploy(name: "user1", email: "user1@iblock.com", dob: "2000/01/01", country: "Sri Lanka", mobile: "+9412345678", gender: "Male");

print(result);
privateKey = result['private-key'] as String;
contractAddress = result['contract-address'] as String;
});

test('Test fetching details from user contract: called by owner', () async{
final service = UserContractService();
var result = await service.getAll(contractAddress, privateKey);
print(result);
expect(result, {"Name": "user1", "Email": "user1@iblock.com", "Date of Birth": "2000/01/01", "Country": "Sri Lanka", "Phone": "+9412345678", "Gender": "Male"});
});

test('Test Setting Name: by the owner', () async{
final service = UserContractService();
await service.setName("user2", contractAddress: contractAddress, privateKey: privateKey);
await service.setEmail("user2@iblock.com", contractAddress: contractAddress, privateKey: privateKey);
await service.setCountry("India", contractAddress: contractAddress, privateKey: privateKey);
await service.setGender("Female", contractAddress: contractAddress, privateKey: privateKey);
await service.setMobile("+123456789", contractAddress: contractAddress, privateKey: privateKey);


var result = await service.getAll(contractAddress, privateKey);

expect(result, {"Name": "user2", "Email": "user2@iblock.com", "Date of Birth": "2000/01/01", "Country": "India", "Phone": "+123456789", "Gender": "Female"});

});

test('Testing verify function', () async{
final service = UserContractService();
String transactionId = await service.verify("0x1Ff8Ebe435cdD925EE58388c78a6b21f650247B6", "12345", privateKey: privateKey, contractAddress: contractAddress);
expect(transactionId, startsWith("0x"));
});
});
}

0 comments on commit 90b81a5

Please sign in to comment.