Skip to content

Commit

Permalink
Merge pull request #83 from SecureDocsChain/Dev
Browse files Browse the repository at this point in the history
Merge to main
  • Loading branch information
QuenumGerald authored Jun 2, 2024
2 parents c126918 + e43465a commit 9c01f8a
Show file tree
Hide file tree
Showing 20 changed files with 814 additions and 113 deletions.
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"githubPullRequests.ignoredPullRequestBranches": [
"Dev"
]
}
112 changes: 108 additions & 4 deletions Backend/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,117 @@
# SecureVault Protocol

## Overview

The SecureVault protocol is a set of smart contracts designed for securely storing and managing metadata of documents on any EVM blockchain. The protocol leverages ERC721 tokens to represent and manage these documents. The key contracts in this protocol are:

1. **SecureVault.sol**: An ERC721 contract that stores metadata of documents and manages document visibility.
2. **SecureVaultFactory.sol**: A factory contract for deploying SecureVault contracts and minting tokens.
3. **SecureVaultReceiver.sol**: A contract that facilitates the reception of cross-chain messages containing document metadata.
4. **SecureVaultSender.sol**: A contract that allows users to send verified documents from their SecureVault across chains.

## Contracts

### SecureVault.sol

The `SecureVault` contract is an ERC721 contract that stores metadata of documents. It includes functionality for minting new document tokens and retrieve metadata associated with these tokens.

- **Functions:**
- `initialize(address initialOwner)`: Initializes the contract with the given owner.
- `mint(address verifier, uint8 visibility, bytes32 documentHash, bytes32[] memory keywords, string memory documentType, string memory uri)`: Mints a new token with the specified metadata.
- `getMetadata(uint256 tokenId)`: Returns the metadata of a given token ID.
- `tokenURI(uint256 tokenId)`: Returns the URI of a given token ID.
- **Modifiers:**
- `onlyOwner()`: Restricts access to owner-only functions.
- **Errors:**
- `Unauthorized()`: Emitted when an unauthorized action is attempted.
- `AlreadyInitialized()`: Emitted when an already initialized contract is attempted to be initialized again.
- `TransferOwnershipNotAllowed()`: Emitted when an ownership transfer is not allowed.

### SecureVaultFactory.sol

The `SecureVaultFactory` contract deploys new instances of the `SecureVault` contract and handles the minting of tokens. It also manages verifiers who are authorized to mint tokens.

- **Functions:**
- `deploy(address owner)`: Deploys a new `SecureVault` instance for the specified owner.
- `getSecureVault(address owner)`: Returns the address of the `SecureVault` associated with the given owner.
- `registerVerifier(address verifier, string memory name)`: Registers a new verifier with the specified address and name.
- `mint(address user, uint8 visibility, bytes32 documentHash, bytes32[] memory keywords, string memory documentType, string memory uri)`: Mints a new token with the specified metadata for the user.
- `getVerifier(address verifier)`: Returns the data of the specified verifier.
- **Events:**
- `Deployed(address indexed secureVault)`: Emitted when a new SecureVault is deployed.
- **Errors:**
- `Unauthorized()`: Emitted when an unauthorized action is attempted.
- `VerifierAlreadyExist()`: Emitted when a verifier already exists.
- `SecureVaultAlreadyDeployed()`: Emitted when a SecureVault is already deployed for an owner.

### SecureVaultReceiver.sol

The `SecureVaultReceiver` contract receives cross-chain messages containing document metadata and stores them.

- **Constructor:**
- `constructor(address router, address sender)`: Sets the router and the expected sender of the cross-chain messages.
- **Functions:**
- `_ccipReceive(Client.Any2EVMMessage memory any2EvmMessage)`: Internal function that processes received cross-chain messages.
- `verifyDocumentHash(address user, uint256 tokenId, bytes32 documentHash)`: Verifies the document hash for a given user and token ID.
- `getDocumentData(address user, uint256 tokenId)`: Returns the document data for a given user and token ID.
- **Events:**
- `MessageReceived(bytes32 indexed messageId, uint64 indexed sourceChainSelector, address sender, bytes data)`: Emitted when a message is received across chains.

### SecureVaultSender.sol

The `SecureVaultSender` contract allows users to send verified documents from their `SecureVault` to any address across chains.

- **Constructor:**
- `constructor(address factory)`: Sets the address of the `SecureVaultFactory` for deploying and managing vaults.
- **Functions:**
- `sendVerifiedDocumentCrossChain(address owner, uint256 tokenId, uint64 destinationChainSelector, address receiver)`: Sends a verified document from the owner's vault to a receiver on another chain.
- **Events:**
- `MessageSent(bytes32 indexed messageId, uint64 indexed destinationChainSelector, address receiver, bytes datas, address feeToken, uint256 fees)`: Emitted when a message is sent across chains.

## Deployment and Usage

1. **Deploy SecureVaultFactory**: Deploy the `SecureVaultFactory` contract first.
2. **Create a SecureVault**: Call `deploy()` on the `SecureVaultFactory` to create a new vault.
3. **Register Verifiers**: Use `registerVerifier()` to register verifiers who can mint tokens.
4. **Deploy SecureVaultReceiver and SecureVaultSender**: Deploy the `SecureVaultReceiver` and `SecureVaultSender` contracts, passing the address of the CCIP router.
5. **Mint Tokens and Store Metadata**: Use the `mint` function in `SecureVaultFactory` to mint new tokens and store document metadata.
6. **Send Verified Documents Across Chains**: Use the `sendVerifiedDocumentCrossChain` function in `SecureVaultSender` to send verified documents to `SecureVaultReceiver` on other chains.

## Example Usage

```solidity
// Deploy the SecureVaultFactory
SecureVaultFactory factory = new SecureVaultFactory();
factory.deploy(msg.sender);
// Deploy the sender and receiver contracts
SecureVaultSender sender = new SecureVaultSender(factoryAddress);
SecureVaultReceiver receiver = new SecureVaultReceiver(routerAddress, senderAddress);
// Get the address of the new vault
address vaultAddress = factory.getSecureVault(msg.sender);
// Register a verifier
factory.registerVerifier(verifierAddress, verifierName);
// Mint a new token
factory.mint(userAddress, visibility, documentHash, keywords, documentType, uri);
// Send a verified document across chains
linkContractAddress.approve(sender, fee);
sender.sendVerifiedDocumentCrossChain(userAddress, tokenId, destinationChainSelector, receiverAddress);
```

## Foundry

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Foundry consists of:

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

Expand Down
29 changes: 18 additions & 11 deletions Backend/models/Document.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
// backend/models/Document.js
import mongoose from 'mongoose';
import mongoose from "mongoose";

const DocumentSchema = new mongoose.Schema({
userId: {
type: String,
required: true
required: true,
},
email: {
type: String,
required: true
required: true,
},
fileName: {
type: String,
required: true
required: true,
},
fileData: {
type: Buffer,
required: true
required: true,
},
hash: {
type: String,
required: true
required: true,
},
status: {
type: String,
enum: ['en attente', 'validé', 'rejeté'],
default: 'en attente'
enum: ["en attente", "validé", "rejeté"],
default: "en attente",
},
verifiedBy: {
type: String,
},
tokenId: {
type: Number,
},
createdAt: {
type: Date,
default: Date.now
}
default: Date.now,
},
});

export default mongoose.models.Document || mongoose.model('Document', DocumentSchema);
export default mongoose.models.Document ||
mongoose.model("Document", DocumentSchema);
62 changes: 37 additions & 25 deletions Backend/src/SecureVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,21 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own
import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";


error Unauthorized();
error AlreadyInitialized();
import {Metadata} from "./lib/Struct.sol";
import {Unauthorized, AlreadyInitialized, TransferOwnershipNotAllowed} from "./lib/Errors.sol";

enum Visibility {
Public,
Private
}

struct Metadata {
uint8 visibility;
uint256 timestamp;
bytes32 documentHash;
bytes32[] keywords;
string documentType;
string uri;
}

/**
* @title SecureVault
* @notice The SecureVault contract is an ERC721 contract that stores metadata of documents
*/
contract SecureVault is ERC721Upgradeable, OwnableUpgradeable {
uint256 public ptrTokenId;
address public router;

mapping(uint256 => Metadata) public metadata;

Expand All @@ -33,48 +28,59 @@ contract SecureVault is ERC721Upgradeable, OwnableUpgradeable {
_disableInitializers();
}

// @dev Initialize the contract with the provided parameters
/**
* @notice Initialize the contract
* @param initialOwner The owner of the contract
*/
function initialize(
address initialOwner
) external initializer {
__ERC721_init("SecureVault", "SV");
router = msg.sender;
ptrTokenId = 1;
_transferOwnership(initialOwner);
}

/// @dev Mint a new token with the provided metadata
/**
* @notice Mint a new token to the owner
* @param verifier the verifier address
* @param visibility The visibility of the token
* @param documentHash The hash of the document
* @param keywords The keywords of the document
* @param documentType The type of the document
* @param uri The URI of the document
*/
function mint(
address verifier,
uint8 visibility,
bytes32 documentHash,
bytes32[] memory keywords,
string memory documentType,
string memory uri
) external onlyOwner {
) external {
if (msg.sender != router) revert Unauthorized();
metadata[ptrTokenId] = Metadata({
verifier: verifier,
visibility: visibility,
timestamp: block.timestamp,
documentHash: documentHash,
keywords: keywords,
documentType: documentType,
uri: uri
});
_mint(msg.sender, ptrTokenId);
_mint(owner(), ptrTokenId);
unchecked { ptrTokenId++; }
}

/// @dev Get the metadata of a token
/**
* @notice Get the metadata of a token
* @param tokenId The token ID
* @return The metadata of the token
*/
function getMetadata(uint256 tokenId) external view returns (Metadata memory) {
return metadata[tokenId];
}

function name() public pure override returns (string memory) {
return "SecureVault";
}

function symbol() public pure override returns (string memory) {
return "SV";
}

/// @dev Get the token URI
function tokenURI(uint256 tokenId) public view override returns (string memory) {
// if tokenID does not exist, return empty string
Expand All @@ -88,4 +94,10 @@ contract SecureVault is ERC721Upgradeable, OwnableUpgradeable {
}
return super._update(to, tokenId, auth);
}

/// @dev Override _transferOwnership to prevent ownership transfer when owner is already set
function _transferOwnership(address newOwner) internal virtual override {
if (owner() != address(0)) revert TransferOwnershipNotAllowed();
super._transferOwnership(newOwner);
}
}
Loading

0 comments on commit 9c01f8a

Please sign in to comment.