Skip to content

Instantly share code, notes, and snippets.

@hocyadav
Last active February 27, 2024 02:51
Show Gist options
  • Save hocyadav/73cb0eef68b619093958e3b8d6d7032e to your computer and use it in GitHub Desktop.
Save hocyadav/73cb0eef68b619093958e3b8d6d7032e to your computer and use it in GitHub Desktop.
// migrations/2_deploy_contracts.js
const IdentityVerification = artifacts.require("IdentityVerification"); // contracts/IdentityVerification.sol
module.exports = function (deployer) {
deployer.deploy(IdentityVerification);
};
node -v
npm install -g truffle
npm install -g ganache-cli -> not working -> install from official website ganache UI https://trufflesuite.com/ganache/
Ganache CLI : npm install ganache --global

npm install -g solc
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.3'
id 'io.spring.dependency-management' version '1.1.4'
id 'com.vaadin' version '24.3.5'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
ext {
set('vaadinVersion', "24.3.5")
}
dependencies {
// connect frontend to java
implementation 'com.vaadin:vaadin-spring-boot-starter'
// connect java to blockchain
// web3j dependency used by contract java file
implementation 'org.web3j:core:4.8.7'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "com.vaadin:vaadin-bom:${vaadinVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
package com.example.demo1;
import com.example.contract.IdentityVerificationABI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteFunctionCall;
import org.web3j.protocol.core.methods.response.EthAccounts;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tuples.generated.Tuple4;
import org.web3j.tx.gas.DefaultGasProvider;
import java.math.BigInteger;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Configuration
class AppConfig {
@Bean
public Web3j clientTalkToBlockchainNode(){
final String localGanacheBlockchainUrl = "http://localhost:8545";
return Web3j.build(new HttpService(localGanacheBlockchainUrl));
}
}
@Route("/user")
class MainView extends VerticalLayout {
public MainView(MyService myService) {
TextField textField = new TextField("Your Name");
TextField yourAge = new TextField("Your Age");
TextField country = new TextField("Your Country");
Button button = new Button("Create you digital identity in blockchain", buttonClickEvent -> {
System.out.println("name = " + textField.getValue());
Integer valueOf = Integer.valueOf(yourAge.getValue());
System.out.println("age = " + valueOf);
System.out.println("countryValue = " + country.getValue());
myService.foo(textField.getValue(), valueOf, country.getValue());
});
add(textField, yourAge, country, button);
}
}
@Route("/bank")
class MainView2 extends VerticalLayout {
public MainView2(MyService myService) {
TextField textField = new TextField("Enter you digital identity");
Button button = new Button("Verify your DID in Blockchain & create bank account", buttonClickEvent -> {
System.out.println("textFieldValue = " + textField.getValue());
});
add(textField, button);
}
}
@Service
class MyService {
public void foo(String name, Integer age, String country){
System.out.println("name = " + name + ", age = " + age + ", country = " + country);
}
}
@RequiredArgsConstructor
@SpringBootApplication
public class Demo1Application implements ApplicationRunner {
// Use your wallet's private key here
// first account from blockchain
// when truffle deploy then we can get this , and by default it used first account from blockchain
// user 1
public static final String USER_ACC_PRIVATE_KEY = "0xcbf3d88fff640bb69128aaf2401c75de85521e4a329cc7b244c092c01f77e812";
public static final String SMART_CONTRACT_ADDRESS = "0xE1fBD54F1Cf2FE67145511392dFB36e60dF20339";
private final Web3j web3j;
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
// print all accounts/address/public keys in blockchain
// take some address as user, some as bank
web3j.ethAccounts()
.send()
.getAccounts()
.forEach(ac -> System.out.println("ac = " + ac));
IdentityVerificationABI mySolidityContract = getSolidityContract();
// test contract fun 1
TransactionReceipt transactionReceipt1 = mySolidityContract.createIdentity(
"Rohit",
BigInteger.valueOf(27L),
"Indian"
)
.sendAsync()
.get();
System.out.println("transactionReceipt1 = " + transactionReceipt1);
Thread.sleep(10000);
// fun3
Boolean result = mySolidityContract.checkVerificationStatus(SMART_CONTRACT_ADDRESS)
.send();
System.out.println("verificationStatus = " + result);
//
//
//// String name = mySolidityContract.checkName(SMART_CONTRACT_ADDRESS).send();
//// System.out.println("name = " + name);
//
// // ✅ test contract fun 2
TransactionReceipt transactionReceipt = mySolidityContract.verifyIdentity(SMART_CONTRACT_ADDRESS)
.sendAsync()
.get();
System.out.println("transactionReceipt = " + transactionReceipt);
////
Thread.sleep(8000);
Boolean result2 = mySolidityContract.checkVerificationStatus(SMART_CONTRACT_ADDRESS)
.send();
System.out.println("verificationStatus = " + result2);
// // ✅ test contract fun 3
// Boolean result2 = mySolidityContract.checkVerificationStatus(SMART_CONTRACT_ADDRESS)
// .send();
// System.out.println("verificationStatus = " + result2);
// Now you can call methods on the contract instance
}
// private static void checkMyData(IdentityVerificationABI mySolidityContract) throws Exception {
//// Tuple4<String, BigInteger, String, Boolean> getIdentity = mySolidityContract.getIdentity(SMART_CONTRACT_ADDRESS).send();
// String NAME = mySolidityContract.getIdentity(SMART_CONTRACT_ADDRESS).send();
// System.out.println("NAME = " + NAME);
//// System.out.println("\nName: " + getIdentity.getValue1());
//// System.out.println("Age: " + getIdentity.getValue2());
//// System.out.println("Nationality: " + getIdentity.getValue3());
//// System.out.println("Verified: " + getIdentity.getValue4());
// System.out.println();
// }
@NotNull
private IdentityVerificationABI getSolidityContract() {
Credentials credentials = Credentials.create(USER_ACC_PRIVATE_KEY);
System.out.println("Account Address (public key) : " + credentials.getAddress());// this will print public key
ECKeyPair ecKeyPair = credentials.getEcKeyPair();
// System.out.println("publicKey = " + ecKeyPair.getPublicKey());
// System.out.println("privateKey = " + ecKeyPair.getPrivateKey());
DefaultGasProvider gasProvider = new DefaultGasProvider();
// Load the contract instance
IdentityVerificationABI mySolidityContract = IdentityVerificationABI.load(
SMART_CONTRACT_ADDRESS,
web3j,
credentials,
gasProvider
);
return mySolidityContract;
}
}

Yes, Hardhat provides an interactive console similar to Truffle's console, allowing you to interact with your smart contracts directly from the command line. This is particularly useful for testing and debugging. To use Hardhat's console, you can run the following command in your terminal:

npx hardhat console

This command launches an interactive Hardhat environment in your terminal. Within this environment, you can interact with your deployed contracts, run scripts, and execute commands just like you would in a script file. However, the syntax for interacting with your contracts in the Hardhat console slightly differs from running a script. Here's how you can adapt your example for use directly in the Hardhat console:

  1. Compiling Contracts: Ensure your contracts are compiled. You can compile your contracts with the command:
npx hardhat compile
  1. Launching the Hardhat Console: Open the Hardhat console:
npx hardhat console
  1. Interacting with Your Contract: Once in the console, you can interact with your contracts. Here's how you might adapt your previous script for the console:
// Import ethers
const ethers = await hre.ethers;

// Get the contract factory
const IdentityVerification = await ethers.getContractFactory("IdentityVerification");

// Deploy the contract
const contractInstance = await IdentityVerification.deploy();
await contractInstance.deployed();

console.log("Contract deployed to:", contractInstance.address);

// Call a method on the deployed contract
await contractInstance.createIdentity("Hariom Yadav", 30, "Bangalore");

In the Hardhat console, you have access to the hre (Hardhat Runtime Environment) object. This object includes everything from Hardhat's environment, such as ethers, configured networks, and deployed contracts. You can use it to perform a wide variety of tasks.

Remember, in the Hardhat console, you're writing and executing JavaScript code in real-time, so you don't use the async/await syntax in the same way you would in a script file. Instead, if you need to wait for a promise to resolve, you use await directly with the command without wrapping it in an async function.

After you're done testing or interacting with your contracts, you can exit the Hardhat console by pressing Ctrl + C.

This console is powerful for quick tests and interactions, offering a streamlined way to work with your contracts without the need to constantly run scripts for each action.

pragma solidity ^0.8.0;
contract IdentityVerification {
struct Identity {
string name;
uint age;
string nationality;
bool verified;// by addhar : verifier entity
// bank 1: allow
// facebook : not allow
// ...
// map <String, Boolean> map;
// user 1 map ==> bank 1 == true
// user 1 map ==> facebook == false
// user 2 map ==> bank 1 == true
// user 2 map ==> facebook == true
}
mapping(address => Identity) public identities;
// this is like setter setIdentity -> and then store in blockchain
function createIdentity(string memory _name, uint _age, string memory _nationality) public {
identities[msg.sender] = Identity(_name, _age, _nationality, false);
}
function verifyIdentity(address _user) public {
// In a real scenario, verification would involve more checks
identities[_user].verified = true;
}
// bank, social net
function checkVerificationStatus(address _user) public view returns (bool) {
return identities[_user].verified;
}
}
package com.example.contract;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Bool;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.Utf8String;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteFunctionCall;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tuples.generated.Tuple4;
import org.web3j.tx.Contract;
import org.web3j.tx.TransactionManager;
import org.web3j.tx.gas.ContractGasProvider;
/**
* <p>Auto generated code.
* <p><strong>Do not modify!</strong>
* <p>Please use the <a href="https://docs.web3j.io/command_line.html">web3j command line tools</a>,
* or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the
* <a href="https://github.com/web3j/web3j/tree/master/codegen">codegen module</a> to update.
*
* <p>Generated with web3j version 1.5.2.
*/
@SuppressWarnings("rawtypes")
public class IdentityVerificationABI extends Contract {
public static final String BINARY = "Bin file was not provided";
public static final String FUNC_IDENTITIES = "identities";
public static final String FUNC_CREATEIDENTITY = "createIdentity";
public static final String FUNC_VERIFYIDENTITY = "verifyIdentity";
public static final String FUNC_CHECKVERIFICATIONSTATUS = "checkVerificationStatus";
@Deprecated
protected IdentityVerificationABI(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit);
}
protected IdentityVerificationABI(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
super(BINARY, contractAddress, web3j, credentials, contractGasProvider);
}
@Deprecated
protected IdentityVerificationABI(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit);
}
protected IdentityVerificationABI(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider);
}
public RemoteFunctionCall<Tuple4<String, BigInteger, String, Boolean>> identities(String param0) {
final Function function = new Function(FUNC_IDENTITIES,
Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(160, param0)),
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}, new TypeReference<Uint256>() {}, new TypeReference<Utf8String>() {}, new TypeReference<Bool>() {}));
return new RemoteFunctionCall<Tuple4<String, BigInteger, String, Boolean>>(function,
new Callable<Tuple4<String, BigInteger, String, Boolean>>() {
@Override
public Tuple4<String, BigInteger, String, Boolean> call() throws Exception {
List<Type> results = executeCallMultipleValueReturn(function);
return new Tuple4<String, BigInteger, String, Boolean>(
(String) results.get(0).getValue(),
(BigInteger) results.get(1).getValue(),
(String) results.get(2).getValue(),
(Boolean) results.get(3).getValue());
}
});
}
public RemoteFunctionCall<TransactionReceipt> createIdentity(String _name, BigInteger _age, String _nationality) {
final Function function = new Function(
FUNC_CREATEIDENTITY,
Arrays.<Type>asList(new org.web3j.abi.datatypes.Utf8String(_name),
new org.web3j.abi.datatypes.generated.Uint256(_age),
new org.web3j.abi.datatypes.Utf8String(_nationality)),
Collections.<TypeReference<?>>emptyList());
return executeRemoteCallTransaction(function);
}
public RemoteFunctionCall<TransactionReceipt> verifyIdentity(String _user) {
final Function function = new Function(
FUNC_VERIFYIDENTITY,
Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(160, _user)),
Collections.<TypeReference<?>>emptyList());
return executeRemoteCallTransaction(function);
}
public RemoteFunctionCall<Boolean> checkVerificationStatus(String _user) {
final Function function = new Function(FUNC_CHECKVERIFICATIONSTATUS,
Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(160, _user)),
Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {}));
return executeRemoteCallSingleValueReturn(function, Boolean.class);
}
@Deprecated
public static IdentityVerificationABI load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
return new IdentityVerificationABI(contractAddress, web3j, credentials, gasPrice, gasLimit);
}
@Deprecated
public static IdentityVerificationABI load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
return new IdentityVerificationABI(contractAddress, web3j, transactionManager, gasPrice, gasLimit);
}
public static IdentityVerificationABI load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
return new IdentityVerificationABI(contractAddress, web3j, credentials, contractGasProvider);
}
public static IdentityVerificationABI load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
return new IdentityVerificationABI(contractAddress, web3j, transactionManager, contractGasProvider);
}
}
  • create local smart contract project using truffle
mkdir IdentityVerification
cd IdentityVerification
truffle init
  • write own smart contract function then run below commands
truffle compile
truffle migrate --network development

  • test smart contract functions
  • first : start truffle console
truffle console --network development
  • second : call first function from truffle console
  • it will print txn details
// Get the deployed contract instance
let contractInstance = await IdentityVerification.deployed();

// Now you can call your contract's methods, for example:
// Assuming you have a method named 'createIdentity' in your contract
await contractInstance.createIdentity("Hariom Yadav", 30, "Bangalore");
  • test another smart contract function
  • 0x1f551d13206CFCcbf424424bF49Ba3C047E56b4D is contract address
await contractInstance.verifyIdentity("0x1f551d13206CFCcbf424424bF49Ba3C047E56b4D");
  • test 3rd smart contract function
let isVerified = await contractInstance.checkVerificationStatus("0x1f551d13206CFCcbf424424bF49Ba3C047E56b4D");
console.log(isVerified);
  • use case diagram

image


  • blockchain terminology

image

contract IdentityVerification {
struct Identity {
string name;
uint age;
string nationality;
bool verified;
map
mapping(address => bool) accessPermissions; // Mapping to track access permissions
address[] serviceProviders; // Array to store service provider addresses
}
mapping(address => Identity) private identities;
// Function to create an identity
function createIdentity(string memory _name, uint _age, string memory _nationality) public {
Identity storage identity = identities[msg.sender];
identity.name = _name;
identity.age = _age;
identity.nationality = _nationality;
identity.verified = false;
}
// Function to verify an identity
function verifyIdentity(address _user) public {
identities[_user].verified = true;
}
// Function to check verification status
function checkVerificationStatus(address _user) public view returns (bool) {
return identities[_user].verified;
}
// Function to grant access to a service provider
function grantAccess(address _serviceProvider) public {
require(identities[msg.sender].verified, "Identity must be verified to grant access");
identities[msg.sender].accessPermissions[_serviceProvider] = true;
}
// Function to revoke access from a service provider
function revokeAccess(address _serviceProvider) public {
require(identities[msg.sender].verified, "Identity must be verified to revoke access");
identities[msg.sender].accessPermissions[_serviceProvider] = false;
}
// Function to check if a service provider has access
function hasAccess(address _user, address _serviceProvider) public view returns (bool) {
return identities[_user].accessPermissions[_serviceProvider];
}
// Function to get the access permissions for all service providers for a user
function getServiceProvidersAccess(address _user) public view returns (address[] memory, bool[] memory) {
Identity storage identity = identities[_user];
uint length = identity.serviceProviders.length;
address[] memory serviceProviders = new address[](length);
bool[] memory permissions = new bool[](length);
for (uint i = 0; i < length; i++) {
serviceProviders[i] = identity.serviceProviders[i];
permissions[i] = identity.accessPermissions[serviceProviders[i]];
}
return (serviceProviders, permissions);
}
}
// contracts/IdentityVerification.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract IdentityVerification {
struct Identity {
string pk; // msg.sender ==> Ethereum address, which is a shorter, hashed version of the public key
string name;
uint age;
string nationality;
bool verified;
mapping(address => bool) accessPermissions; // Mapping to track access permissions
}
mapping(address => Identity) public identities;
// USER USE CASE
// ✅
function createIdentity(address _userAddress_for_key,
string memory _userAddress_str_for_struct,
string memory _name,
uint _age,
string memory _nationality) public {
// validation : if true then true , dont change to false
Identity storage identity = identities[_userAddress_for_key];
identity.pk = _userAddress_str_for_struct;
identity.name = _name;
identity.age = _age;
identity.nationality = _nationality;
identity.verified = false;
}
// AADHAAR OFFICE USE CASE
// ✅
function verifyIdentity(address _userAddress_for_key) public {
identities[_userAddress_for_key].verified = true;
}
// BANK USE CASE
// not required, since below return whole obj ✅, but for simple use case keep it
function checkVerificationStatus(address _userAddress_for_key) public view returns (bool) {
return identities[_userAddress_for_key].verified;
}
// USER USE CASE
// ✅
function getIdentityDetails(address _userAddress_for_key) public view returns (string memory pk, string memory name, uint age, string memory nationality, bool verified) {
// add validation like only key-value that are store in the map can access user datails -> 1. checkGrantAccessStatus if true then allow else return error
Identity storage identity = identities[_userAddress_for_key];// Change `memory` to `storage`
return (identity.pk, identity.name, identity.age, identity.nationality, identity.verified);
}
// BANK / FB use case
function getIdentityDetailsForService(address _userAddress_for_key, address _serviceProvider) public view returns (string memory pk, string memory name, uint age, string memory nationality, bool verified) {
// add validation like only key-value that are store in the map can access user datails -> 1. checkGrantAccessStatus if true then allow else return error
require(identities[_userAddress_for_key].verified, "Identity must be first verified by Verified Entity [e.g. Govt Aadhaar Office] to grant access");
// checkGrantAccessStatus
bool checkGrantGivenOrNot = checkGrantAccessStatus(_userAddress_for_key, _serviceProvider);
if (checkGrantGivenOrNot) {
return getIdentityDetails(_userAddress_for_key);
} else {
revert("Service Provider has not granted by user");// revert the txn
}
}
// USER USE CASE
// Function to grant access to a service provider✅
function giveGrantAccess(address _userAddress_for_key, address _serviceProvider) public {
require(identities[_userAddress_for_key].verified, "Identity must be first verified by Verified Entity [e.g. Govt Aadhaar Office] to grant access");
identities[_userAddress_for_key].accessPermissions[_serviceProvider] = true;
}
//✅
// BANK
//// // Function to check if a service provider has access
function checkGrantAccessStatus(address _userAddress_for_key, address _serviceProvider) public view returns (bool) {
return identities[_userAddress_for_key].accessPermissions[_serviceProvider];
}
// ✅ // Function to revoke access from a service provider
function revokeGrantAccess(address _userAddress_for_key, address _serviceProvider) public {
require(identities[_userAddress_for_key].verified, "User Identity must be first verified by Verified Entity [e.g. Govt Aadhaar Office] to revoke access");
identities[_userAddress_for_key].accessPermissions[_serviceProvider] = false;
}
}
@hocyadav
Copy link
Author

hocyadav commented Feb 17, 2024

image
- smart contract 
	- 3 fun
	- 1. create user identity
	- 2. varify user identity
	- 3. validate user identity

- 1. create user identity : CREATE
addhar -> aadahre deyails(aadhar id + name + dob + addre) -> blockchain store -> string id 
- input : addhar details
- output : string id: "123abc" // digital identity : DID , crypto hash

- 2. 
case 1: 
verifer -> addhar office -> addhar id + degital identity 123abc -> check in own addhar db  -> smart contract fun2_verify_user_identity() -> blcokchain entry txn -> ledge entry 
- 10 node all store its txn
n1: (123abc + valid)
n2: (123abc + valid)
n3: (123abc + valid)
n4: (123abc + valid)

cas2 : invalide -> blcochain -> invalid

- user check statu -> verify


---
3. 123abc (encapsulate)
- bank account / social website / addhar show ?
DID -> verify -> fun3 -> blockchain (conses) -> valid -> you are verify


user identity & authentication


old style : addhar detail -> fill in website -> bank / -> addhare office API(Centralize) -> velidate
new style : DID 123abc -> fill in website -> bank / -> blockchain system smart coing(de centralize) -> velidate
- benifit
	- privacy : not showing actual addhar detail

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment