Skip to content

Commit

Permalink
Ag 25 deploy contracts (#13)
Browse files Browse the repository at this point in the history
* feat(@agora): AG-25 configured evm compiler

configured the evm compiler in the hardhat configuration file

* refactor(@contracts): AG-25 refactored DECs Registry contract

refactored DECs registry contract

* refactor(@contracts): AG-25 refactored DEC contract

refactored DEC smart contract

* feat(@contracts): AG-25 added name property to DECs Registry

added name property to DECs Registry smart contract

* feat(@contracts): ignition modules implementation

implemented the ignition modules for contracts deploy

* fix(@contracts): AG-25 added folder to gitignore

added foldet to gitignore

* fix(@contracts): AG-25 ignored files

added files to gitignore
  • Loading branch information
g3k0 authored Mar 31, 2024
1 parent 07a2bad commit ed96d8d
Show file tree
Hide file tree
Showing 17 changed files with 258 additions and 105 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ node_modules
/coverage.json

# reports folder
report
report

#ignition files
/ignition/deployments
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ To setup the application follow these steps:
* `SEPOLIA_URL` You can find the data in your Alchemy account, after you create an app there;
* `ALCHEMY_API_KEY` You can find the data in your Alchemy account;
* `REPORT_GAS` enable or disable the gas report on smart contracts unit tests executions;
* `NODE_ENV` set `development` for your local machine;

## How to commit

Expand All @@ -51,6 +52,32 @@ Smart contracts code coverage documentation [here](https://www.npmjs.com/package

CI/CD workflow fails if the unit test code coverage threshold (**80% of lines of code**) for scripts is not met.

## Run the localhost development network

Hardhat framework provides a local blockchain network that lives in memory, that is useful to test local developments.
To start the network run the command:

`npm run node:start`

## Compile the smart contracts

Run the command: `npm run compile`

## Deploy the smart contract

The smart contracts deploy process is managed, under the hood, by [Ignition](https://hardhat.org/ignition/docs/getting-started#overview).

To deploy smart contract instances run the command:

`npm run deploy-contract <ignition-module-path> <network>`

Ignition will deploy the instances of the smart contract following the logic specified in the ignition module.

To deploy to a specific network (e.g. mainnet, sepora), the network must be configured in the `hardhat.config.ts` file.

For the local network the parameter to pass is `localhost`, there is no need to configure the local network.


# Donations
Support this project and offer me a crypto-coffee!!

Expand Down
76 changes: 38 additions & 38 deletions contracts/DEC.sol
Original file line number Diff line number Diff line change
@@ -1,66 +1,66 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

/// @title The Voter's Digital Electoral Cards
/// @title The Voter's Digital Electoral Card
/// @author Christian Palazzo <[email protected]>
/// @custom:experimental This is an experimental contract.
contract DEC {
address public owner;
bytes taxCode;
bytes municipality;
bytes region;
bytes country;

constructor() {
constructor(
bytes memory _taxCode,
bytes memory _municipality,
bytes memory _region,
bytes memory _country
) {
/// @dev only the owner of the contract has write permissions
owner = msg.sender;
taxCode = _taxCode;
municipality = _municipality;
region = _region;
country = _country;
}

modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}

/// @notice This is the Digital Electoral Card, emitted by a public third-party authority and owned by the Voter
/// @dev This data is encrypted with the Voter's public address and only the Voter can decrypt it using the private key
struct decData {
string taxCode;
string municipality;
string province;
string region;
string country;
function setTaxCode(bytes memory _taxCode) public onlyOwner {
taxCode = _taxCode;
}

event DECEncrypted(address indexed owner, bytes encryptedData);
function getTaxCode() public view returns (bytes memory) {
return taxCode;
}

/// @notice This function is used to encrypt ad digitally sign a DEC
function encryptDEC(
decData memory dec
) public onlyOwner returns (bytes memory) {
bytes memory encodedData = abi.encodePacked(
dec.taxCode,
dec.municipality,
dec.province,
dec.region,
dec.country
);
bytes32 hashedData = keccak256(encodedData);
bytes memory signature = signData(hashedData);
function setMunicipality(bytes memory _municipality) public onlyOwner {
municipality = _municipality;
}

emit DECEncrypted(msg.sender, abi.encodePacked(hashedData, signature));
function getMunicipality() public view returns (bytes memory) {
return municipality;
}

return abi.encodePacked(hashedData, signature);
function setRegion(bytes memory _region) public onlyOwner {
region = _region;
}

/// @notice This function is used to digitally sign the data
function signData(bytes32 data) private pure returns (bytes memory) {
bytes32 hash = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", data)
);
bytes1 v = bytes1(0);
bytes32 r = bytes32(0);
bytes32 s = uintToBytes32(1);
return abi.encodePacked(ecrecover(hash, uint8(v), r, s), r, s);
function getRegion() public view returns (bytes memory) {
return region;
}

/// @notice this function is used in signData function
function uintToBytes32(uint256 x) private pure returns (bytes32) {
return bytes32(x);
function setCountry(bytes memory _country) public onlyOwner {
country = _country;
}

function getCountry() public view returns (bytes memory) {
return country;
}


}
50 changes: 35 additions & 15 deletions contracts/DECsRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,57 @@ import "./DEC.sol";
/// @title The Registry of the Digital Electoral Cards
/// @author Christian Palazzo <[email protected]>
/// @custom:experimental This is an experimental contract.
contract DECsRegistry is DEC {
constructor() DEC() {}
contract DECsRegistry {
address public owner;
string public name;

/// @notice this is the list of stamps of elections in which the voter participated
/// @dev the first address is related to the Voter's EOA, the second array is the Voter's stamps list
/// @dev the first address is related to the Voter's DEC, the second array is the Voter's stamps list
mapping(address => address[]) electoralStamps;

/// @notice this function contains the list of DECs
/// @dev the address is related to the Voter's EOA
mapping(address => bytes) registry;
/// @dev the first address is related to the Voter's EOA, the second address is related to the DEC
mapping(address => address) registry;

event DECRegistered(address indexed voter, bytes dec);
event DECRegistered(address indexed voter, address dec);
event DECStamped(address indexed election, address indexed voter);

constructor(string memory _name) {
/// @dev only the owner of the contract has write permissions
owner = msg.sender;
name = _name;
}

modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}

/// @notice DECs REgistry name setter function
function setName(string memory _name) public onlyOwner {
name = _name;
}

/// @notice DECs REgistry name getter function
function getName() public view returns (string memory) {
return name;
}

/// @notice this function is used by the third party authority to register a Voter's DEC in the registry
/// @dev the DEC contains sensitive data that must be encrypted
function registerDEC(decData memory dec, address voter) public onlyOwner {
function registerDEC(address dec, address voter) public onlyOwner {
require(
registry[voter].length == 0,
registry[voter] == address(0),
"The Voter's DEC has been already registered"
);
registry[voter] = encryptDEC(dec);
registry[voter] = dec;
emit DECRegistered(voter, registry[voter]);
return;
}

/// @notice this function returns an encrypted DEC in order to check if a Voter has the voting rights
function getDEC(address voter) public view returns (bytes memory) {
function getDEC(address voter) public view returns (address) {
require(
registry[voter].length != 0,
registry[voter] != address(0),
"The Voter don't have a registered DEC"
);
return registry[voter];
Expand All @@ -54,9 +75,8 @@ contract DECsRegistry is DEC {
return false;
}

/// @notice this function put the election stamp on the Voter's DEC after the vote
/// @dev the owner of the DECs registry is the same of the election smart contract (third party authority)
function stampsTheDEC(address election, address voter) public onlyOwner {
/// @notice this function put the election stamp on the Voter's stamps list after the vote
function stamps(address election, address voter) public onlyOwner {
electoralStamps[voter].push(election);
emit DECStamped(election, voter);
return;
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
32 changes: 31 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,46 @@
import { HardhatUserConfig } from "hardhat/config";
import dotenv from "dotenv";
dotenv.config();
import "@nomicfoundation/hardhat-ignition-ethers";
import "@nomicfoundation/hardhat-toolbox";
import "solidity-coverage";
import "hardhat-gas-reporter";
import "hardhat-deploy";

const SEPOLIA_URL: string = process.env.SEPOLIA_URL || "";
const ALCHEMY_PRIVATE_KEY: string = process.env.ALCHEMY_PRIVATE_KEY || "";
const IS_OPTIMIZER_ENABLED =
process.env.NODE_ENV === "production" ? true : false;
const DEBUG = process.env.NODE_ENV === "production" ? "default" : "debug";

const config: HardhatUserConfig = {
solidity: "0.8.24",
solidity: {
version: "0.8.24",
settings: {
optimizer: {
enabled: IS_OPTIMIZER_ENABLED,
runs: 200,
details: {
deduplicate: true,
cse: true,
constantOptimizer: true,
},
},
// Version of the EVM to compile for.
// Affects type checking and code generation. Can be homestead,
// tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul or berlin
evmVersion: "byzantium",
debug: {
// How to treat revert (and require) reason strings. Settings are
// "default", "strip", "debug" and "verboseDebug".
// "default" does not inject compiler-generated revert strings and keeps user-supplied ones.
// "strip" removes all revert strings (if possible, i.e. if literals are used) keeping side-effects
// "debug" injects strings for compiler-generated internal reverts, implemented for ABI encoders V1 and V2 for now.
// "verboseDebug" even appends further information to user-supplied revert strings (not yet implemented)
revertStrings: DEBUG,
},
},
},
gasReporter: {
currency: "EUR",
enabled: process.env.REPORT_GAS ? true : false,
Expand Down
14 changes: 14 additions & 0 deletions ignition/modules/DECs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

export default buildModule("DEC", (m) => {
const DEC1 = m.contract("TomsDEC", [
"RSSMRA85C27H501W",
"Ardea",
"Lazio",
"Italy",
]);

m.call(DEC1, "getName", []);

return { DEC1 };
});
9 changes: 9 additions & 0 deletions ignition/modules/Registries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

export default buildModule("DECsRegistry", (m) => {
const italianRegistry = m.contract("DECsRegistry", ["Italy"]);

m.call(italianRegistry, "getName", []);

return { italianRegistry };
});
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
},
"scripts": {
"commit": "./script/commit",
"compile": "npx hardhat compile",
"coverage-contracts": "npx hardhat coverage",
"deploy-contract": "./script/deploy",
"duplicated": "npx jscpd",
"lint": "npx lint-staged",
"prepare": "husky prepare",
"prepare-commit": "git-cz",
"node:start": "npx hardhat node",
"test-contracts": "npx hardhat test",
"test-scripts": " jest --coverage --bail",
"lint": "npx lint-staged",
"duplicated": "npx jscpd"
"test-scripts": " jest --coverage --bail"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -56,6 +59,7 @@
"@commitlint/cli": "^19.2.1",
"@commitlint/config-conventional": "^19.1.0",
"@commitlint/cz-commitlint": "^19.2.0",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.0",
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@types/jest": "^29.5.12",
"@typescript-eslint/eslint-plugin": "^7.3.1",
Expand Down
11 changes: 11 additions & 0 deletions script/deploy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

if [ "$#" -ne 2 ]; then
echo "Usage: $0 <module_path> <network>"
exit 1
fi

MODULE_PATH="$1"
NETWORK="$2"

npx hardhat ignition deploy "$MODULE_PATH" --network "$NETWORK"
Loading

0 comments on commit ed96d8d

Please sign in to comment.